Comment utiliser glOrtho () dans OpenGL?

Je ne comprends pas l'utilisation de glOrtho. Quelqu'un peut m'expliquer à quoi il sert?

Est-il utilisé pour définir la plage de X Y et Z limite de coordonnées?

glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

Cela signifie que la plage x, y et z est de -1 à 1?

69

3 réponses

Regardez cette image: Projections graphiques entrez la description de l'image ici

La commande glOrtho produit une projection "Oblique" que vous voyez dans la rangée du bas. Peu importe à quelle distance les sommets sont dans la direction z, ils ne reculeront pas dans la distance.

J'utilise glOrtho chaque fois que j'ai besoin de faire des graphiques 2D dans OpenGL (comme les barres de santé, les menus, etc) en utilisant le code suivant chaque fois que la fenêtre est redimensionnée:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, windowWidth, windowHeight, 0.0f, 0.0f, 1.0f);

Cela remappera les coordonnées OpenGL dans les valeurs de pixels équivalentes (X allant de 0 à windowWidth et Y allant de 0 à windowHeight). Notez que j'ai retourné les valeurs Y car les coordonnées OpenGL commencent à partir du coin inférieur gauche de la fenêtre. Donc, en retournant, j'obtiens un plus conventionnel (0,0) commençant plutôt dans le coin supérieur gauche de la fenêtre.

124
répondu Mikepote 2017-05-30 16:59:13

glOrtho: jeux 2D, objets proches et loin apparaissent de la même taille:

glFrustrum: Plus Réel comme la 3D, les objets identiques plus loin apparaissent plus petits:

Code

#include <stdlib.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

static int ortho = 0;

static void display(void) {
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    if (ortho) {
    } else {
        /* This only rotates and translates the world around to look like the camera moved. */
        gluLookAt(0.0, 0.0, -3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    }
    glColor3f(1.0f, 1.0f, 1.0f);
    glutWireCube(2);
    glFlush();
}

static void reshape(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (ortho) {
        glOrtho(-2.0, 2.0, -2.0, 2.0, -1.5, 1.5);
    } else {
        glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
    }
    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    if (argc > 1) {
        ortho = 1;
    }
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return EXIT_SUCCESS;
}

Schéma

Ortho: la caméra est un plan, le volume visible un rectangle:

entrez la description de l'image ici

Frustrum: caméra est un point, visible volume une tranche de un pyramide:

entrez la description de l'image ici

Source de l'Image.

Les Paramètres

Nous regardons toujours de + z à-z avec +y vers le haut:

glOrtho(left, right, bottom, top, near, far)
  • left: minimum x, nous voyons
  • right: maximum de x, nous voyons
  • bottom: minimum y, nous voyons
  • top: maximum de y, nous voyons
  • -near: minimum z nous voir. Oui, ce -1 temps near. Donc une entrée négative signifie positive z.
  • -far: maximum z nous voyons. Aussi négatif.

Schéma:

Source de l'Image.

Comment il fonctionne sous le capot

À la fin, OpenGL "utilise" toujours:

glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

Si nous utilisons ni glOrtho ni glFrustrum, c'est ce que nous obtenons.

glOrtho et glFrustrum ne sont que des transformations linéaires (aka multiplication matricielle) telles que:

  • glOrtho: prend un rectangle 3D donné dans le cube par défaut
  • glFrustrum: prend une section pyramidale donnée dans le cube par défaut

Cette transformation est ensuite appliquée à tous les sommets. C'est ce que je veux dire en 2D:

Source de l'Image.

La dernière étape après la transformation est simple:

  • supprimer tous les points à l'extérieur du cube (abattage): il suffit de s'assurer que x, y et z sont [-1, +1]
  • ignorez le composant z et ne prenez que x et y, qui peut maintenant être mis dans un écran 2D

Avec glOrtho, z est ignoré, ainsi vous pouvez toujours utiliser 0.

Une raison pour laquelle vous pouvez utiliser z != 0 est de faire en sorte que les sprites masquent l'arrière-plan avec le tampon de profondeur.

La Dépréciation

glOrtho est obsolète à partir de OpenGL 4.5 : le profil de compatibilité 12.1. "TRANSFORMATIONS de VERTEX à fonction fixe" est en rouge.

Ne l'utilisez donc pas pour la production. En tout cas, comprendre est un bon moyen d'obtenir un aperçu OpenGL.

Les programmes modernes OpenGL 4 calculent la matrice de transformation (qui est petite) sur le CPU, puis donnent la matrice et tous les points à transformer en OpenGL, qui peut faire les milliers de multiplications matricielles pour différents points très rapidement en parallèle.

Écrit manuellement vertex shaders{[69] } ensuite, faites la multiplication explicitement, généralement avec les types de données vectorielles pratiques de L'ombrage OpenGL Langue.

Puisque vous écrivez explicitement le shader, cela vous permet de modifier l'algorithme en fonction de vos besoins. Une telle flexibilité est une caractéristique majeure des GPU plus modernes, qui, contrairement aux anciens qui faisaient un algorithme fixe avec certains paramètres d'entrée, peuvent maintenant faire des calculs arbitraires. Voir aussi: https://stackoverflow.com/a/36211337/895245

Avec un GLfloat transform[] explicite, cela ressemblerait à ceci:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define GLEW_STATIC
#include <GL/glew.h>

#include <GLFW/glfw3.h>

#include "common.h"

static const GLuint WIDTH = 800;
static const GLuint HEIGHT = 600;
/* ourColor is passed on to the fragment shader. */
static const GLchar* vertex_shader_source =
    "#version 330 core\n"
    "layout (location = 0) in vec3 position;\n"
    "layout (location = 1) in vec3 color;\n"
    "out vec3 ourColor;\n"
    "uniform mat4 transform;\n"
    "void main() {\n"
    "    gl_Position = transform * vec4(position, 1.0f);\n"
    "    ourColor = color;\n"
    "}\n";
static const GLchar* fragment_shader_source =
    "#version 330 core\n"
    "in vec3 ourColor;\n"
    "out vec4 color;\n"
    "void main() {\n"
    "    color = vec4(ourColor, 1.0f);\n"
    "}\n";
static GLfloat vertices[] = {
/*   Positions          Colors */
     0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
    -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
     0.0f,  0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};

int main(void) {
    GLint shader_program;
    GLint transform_location;
    GLuint vbo;
    GLuint vao;
    GLFWwindow* window;
    double time;

    glfwInit();
    window = glfwCreateWindow(WIDTH, HEIGHT, __FILE__, NULL, NULL);
    glfwMakeContextCurrent(window);
    glewExperimental = GL_TRUE;
    glewInit();
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glViewport(0, 0, WIDTH, HEIGHT);

    shader_program = common_get_shader_program(vertex_shader_source, fragment_shader_source);

    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    /* Position attribute */
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    /* Color attribute */
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    glBindVertexArray(0);

    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shader_program);
        transform_location = glGetUniformLocation(shader_program, "transform");
        /* THIS is just a dummy transform. */
        GLfloat transform[] = {
            0.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f,
        };
        time = glfwGetTime();
        transform[0] = 2.0f * sin(time);
        transform[5] = 2.0f * cos(time);
        glUniformMatrix4fv(transform_location, 1, GL_FALSE, transform);

        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glBindVertexArray(0);
        glfwSwapBuffers(window);
    }
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);
    glfwTerminate();
    return EXIT_SUCCESS;
}

Sortie générée: http://imgur.com/QVW14Gu

La matrice pour glOrtho est vraiment simple, composée uniquement de mise à l'échelle et de traduction:

scalex, 0,      0,      translatex,
0,      scaley, 0,      translatey,
0,      0,      scalez, translatez,
0,      0,      0,      1

Comme mentionné dans les documents OpenGL 2 .

Le glFrustum la matrice n'est pas trop difficile à calculer à la main, mais commence à devenir ennuyeux. Notez comment frustum ne peut pas être composé avec seulement la mise à l'échelle et les traductions comme glOrtho, plus d'informations à: https://gamedev.stackexchange.com/a/118848/25171

Le GLM OpenGL c++ math library est un choix populaire pour calculer de telles matrices. http://glm.g-truc.net/0.9.2/api/a00245.html documente les opérations ortho et frustum.

39

GlOrtho décrit une transformation qui produit une projectionparallèle . La matrice actuelle (Voir glMatrixMode) est multipliée par cette matrice et le résultat remplace la matrice actuelle, comme si glMultMatrix était appelée avec la matrice suivante comme argument:

Documentation OpenGL (mon gras)

Les nombres définissent les emplacements des plans de détourage (Gauche, Droite, Bas, Haut, près et loin).

La projection "normale" est un projection en perspective qui donne l'illusion de la profondeur. Wikipedia définit une projection parallèle comme:

Les projections parallèles ont des lignes de projection parallèles à la fois dans la réalité et dans le plan de projection.

La projection parallèle correspond à une projection en perspective avec un point de vue hypothétique-par exemple, celui où la caméra se trouve à une distance infinie de l'objet et a une longueur focale infinie, ou "zoom".

4
répondu ChrisF 2010-04-03 14:16:52