2010-04-03 49 views
65

No puedo entender el uso de glOrtho. ¿Alguien puede explicar para qué se usa?Explicar el uso de glOrtho()?

actualización

es lo utiliza para establecer el rango de x y y z coordenadas límite?

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?

+0

[Este] (https://www.youtube.com/watch?v=8ryJMO6rBT4) video me ayudó mucho. – ViniciusArruda

Respuesta

117

Tenga una mirada en esta imagen: Graphical Projections enter image description here

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.

utilizo glOrtho cada vez que necesita hacer gráficos 2D en OpenGL (como barras de salud, menús, etc.) utilizando el siguiente código cada vez que se cambia el tamaño de la ventana:

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

Este remapeará el OpenGL coordina 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 OpenGL comienzan desde la esquina inferior izquierda de la ventana. Así que volteando, me sale más convencional (0,0) empezando por la esquina superior izquierda de la ventana.

+3

¡muchas gracias por aclarar el problema! :) – ufk

+74

oh mi dios TE AMO. ¿Tienes idea de cuánto tiempo lleva encontrar/descubrir esta línea de código en línea? Gracias, nombraré a mi primer hijo después de usted para este – karpathy

+1

Nota: (en Android) incluso si el modelo tiene solo valores z negativos, parece que es necesario tener un valor positivo para el parámetro final (lejano). Hice una prueba de triángulo simple (con descarte deshabilitado), con vértices en 'z = -2'. El triángulo era invisible si usaba 'glOrtho (.., 0.0f, -4.0f);', '..- 1.0f, -3.0f)', o '..- 3.0f, -1.0f)'. Para ser visible, el parámetro lejos tenía que ser POSITIVO 2 o mayor; no parecía importar cuál era el parámetro cercano. Cualquiera de estos funcionó: '..0.0f, 2.0f)', '..- 1.0f, 2.0f)', '..- 3.0f, 2.0f)', o '..0.0f, 1000.0f' . – ToolmakerSteve

3

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

OpenGL documentation (mi negrita)

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

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

proyecciones paralelas tienen líneas de proyección que son paralelas tanto en la realidad y 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".

+0

hola gracias por la información. no pude entender la diferencia entre la proyección paralela y perspectiva. busqué en Google un poco y encontré la respuesta en http://wiki.answers.com/Q/What_is_the_difference_between_orthogonal_and_perspective_projection – ufk

+6

Lamentablemente, la información que recibiste de answers.com es bastante inútil. Una vista isométrica, por ejemplo, es muy tridimensional, pero es una proyección paralela sin perspectiva. Vea aquí, y también hay enlaces a muchos otros ejemplos de proyecciones: http://en.wikipedia.org/wiki/Isometric_projection –

32

glOrtho: los juegos en 2D, los objetos de cerca y de lejos parecen del mismo tamaño:

glFrustrum: más de la vida real como en 3D, objetos idénticos alejar los 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; 
} 

esquema

Ortho: cámara es un plano, el volumen visible un rectángulo:

enter image description here

frustrum: cámara es un punto, el volumen visible una rebanada de una pirámide:

enter image description here

Image source.

Parámetros

Estamos siempre en busca de + z para -Z con + y hacia arriba:

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

esquema:

Image source.

Cómo funciona bajo el capó

Al final, OpenGL siempre "usos":

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

Si utilizamos ni glOrtho ni glFrustrum, eso es lo que tenemos.

glOrtho y glFrustrum son transformaciones simplemente lineales (También conocido como matriz de multiplicación) tal que:

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

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:

  • eliminar cualquier puntos fuera del cubo (sacrificio): simplemente asegurar que x, y y z son en [-1, +1]
  • ignoran el componente z y tome solamente x y y, que ahora se puede poner en una pantalla 2D

Con 0.123., z se ignora, por lo que también podría utilizar siempre 0.

Una razón por la que es posible que desee utilizar z != 0 es hacer que los sprites oculten el fondo con el búfer de profundidad.

Deprecation

glOrtho está obsoleta de OpenGL 4.5: el perfil de compatibilidad 12,1. "TRANSFORMACIONES DE VERTEX DE FUNCIÓN FIJA" está en rojo.

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

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

Manualmente escrito vertex shaders luego haga la multiplicación explícitamente, generalmente con los tipos de datos vectoriales convenientes del Lenguaje de Sombreado OpenGL.

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

Con una explícita GLfloat transform[] se vería algo como esto:

#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 de glOrtho es muy simple, compuesta sólo por la ampliación y la 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 que el triturado no se puede componer con solo escalas y traducciones como glOrtho, más información en: https://gamedev.stackexchange.com/a/118848/25171

La biblioteca matemática GLM OpenGL C++ 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.

+1

"¿qué se debe usar en su lugar?" - construye tus propias matrices y las asigna directamente. – Kromster

Cuestiones relacionadas