Cómo usar glOrtho () en OpenGL?


No puedo entender el uso de glOrtho. ¿Puede alguien explicar para qué se usa?

¿ Se usa para establecer el rango del límite de coordenadas x y y z?

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

¿Significa que el rango x, y y z es de -1 a 1?

 69

3 answers

Mira esta imagen: Proyecciones gráficas introduzca la descripción de la imagen aquí

El comando glOrtho produce una proyección "oblicua" que se ve en la fila inferior. No importa cuán lejos estén los vértices en la dirección z, no retrocederán en la distancia.

Uso glOrtho cada vez que necesito hacer gráficos 2D en OpenGL (como barras de salud, menús, etc) usando el siguiente código cada vez que se redimensiona la ventana:

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

Esto reasignará las coordenadas de OpenGL en los valores de píxel equivalentes (X va de 0 a WindowWidth e Y va de 0 a WindowHeight). Tenga en cuenta que he volteado los valores Y porque las coordenadas de OpenGL comienzan desde la esquina inferior izquierda de la ventana. Así que al voltear, obtengo un más convencional (0,0) a partir de la esquina superior izquierda de la ventana en lugar.

 124
Author: Mikepote,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-30 16:59:13

glOrtho: Juegos 2D, objetos cerca y lejos aparecen del mismo tamaño:

glFrustrum: más en la vida real como el 3D, los objetos idénticos más alejados parecen más pequeños:

Código

#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;
}

Schema

Orto: la cámara es un plano, el volumen visible es un rectángulo: {[47]]}

introduzca la descripción de la imagen aquí

Frustrum: la cámara es un punto, volumen visible una rebanada de un pirámide:

introduzca la descripción de la imagen aquí

Image source .

Parámetros

Siempre estamos buscando de +z a-z con +y hacia arriba:

glOrtho(left, right, bottom, top, near, far)
  • left: mínimo x vemos
  • right: máximo x vemos
  • bottom: mínimo y vemos
  • top: máximo y vemos
  • -near: mínimo z vemos. , esto es -1 veces near. Así que una entrada negativa significa positivo z.
  • -far: máximo z vemos. También negativo.

Esquema:

Image source .

Cómo funciona bajo el capó

Al final, OpenGL siempre "usa":

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

Si no usamos ni glOrtho ni glFrustrum, eso es lo que obtenemos.

glOrtho y glFrustrum son solo transformaciones lineales (también conocida como multiplicación de matrices) tales que:

  • glOrtho: toma un rectángulo 3D dado en el cubo predeterminado
  • glFrustrum: toma una sección de pirámide dada en el cubo predeterminado

Esta transformación se aplica a todos los vértices. Esto es lo que quiero decir en 2D:

Image source .

El paso final después de la transformación es simple: {[47]]}

  • eliminar cualquier punto fuera del cubo( sacrificio): solo asegúrese de que x, y y z están en [-1, +1]
  • ignore el componente z y tome solo x y y, que ahora se puede poner en una pantalla 2D

Con glOrtho, z se ignora, por lo que también puede usar siempre 0.

Una razón por la que podría querer usar z != 0 es para hacer que los sprites oculten el fondo con el búfer de profundidad.

Obsolescencia

glOrtho está obsoleto a partir de OpenGL 4.5 : el perfil de compatibilidad 12.1. "TRANSFORMACIONES DE VÉRTICES DE FUNCIÓN FIJA" está en rojo.

Así que no lo use para la producción. En cualquier caso, entenderlo es una buena manera de obtener información de OpenGL.

Los programas modernos de OpenGL 4 calculan la matriz de transformación (que es pequeña) en la CPU, y luego dan la matriz y todos los puntos a transformar a OpenGL, que puede hacer los miles de multiplicaciones de matriz para diferentes puntos realmente rápido en paralelo.

Escrito manualmente los sombreadores de vértices luego hacen la multiplicación explícitamente, generalmente con los tipos de datos vectoriales convenientes del Sombreado de OpenGL Idioma.

Dado que escribe el sombreador explícitamente, esto le permite ajustar el algoritmo a sus necesidades. Tal flexibilidad es una característica importante de las GPU más modernas, que a diferencia de las antiguas que hacían un algoritmo fijo con algunos parámetros de entrada, ahora pueden hacer cálculos arbitrarios. Véase también: https://stackoverflow.com/a/36211337/895245

Con un GLfloat transform[] explícito se vería algo así: {[47]]}

#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;
}

Salida Generada: http://imgur.com/QVW14Gu

La matriz para glOrtho es realmente simple, compuesta solo de escalado y traducción:

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

Como se menciona en el OpenGL 2 docs.

El glFrustum matrix tampoco es demasiado difícil de calcular a mano, pero comienza a ser molesto. Tenga en cuenta cómo frustum no se puede hacer con solo escalado y traducciones como glOrtho, más información en: https://gamedev.stackexchange.com/a/118848/25171

El GLM OpenGL C++ math library es una opción popular para calcular tales matrices. http://glm.g-truc.net/0.9.2/api/a00245.html documenta las operaciones ortho y frustum.

 39
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-25 05:24:37

GlOrtho describe una transformación que produce una proyección paralela. La matriz actual (ver glMatrixMode) se multiplica por esta matriz y el resultado reemplaza a la matriz actual, como si se llamara a glMultMatrix con la siguiente matriz como argumento:

Documentación de OpenGL (mi negrita)

Los números definen las ubicaciones de los planos de recorte (izquierda, derecha, abajo, arriba, cerca y lejos).

La proyección "normal" es una proyección de perspectiva que proporciona la ilusión de profundidad. Wikipedia define una proyección paralela como:

Las proyecciones paralelas tienen líneas de proyección que son paralelas tanto en la realidad como en el plano de proyección.

La proyección paralela corresponde a una proyección en perspectiva con un punto de vista hipotético, por ejemplo, uno donde la cámara se encuentra a una distancia infinita del objeto y tiene una distancia focal infinita, o "zoom".

 4
Author: ChrisF,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-03 14:16:52