Come usare glOrtho () in OpenGL?

Non riesco a capire l’uso di glOrtho . Qualcuno può spiegare a cosa serve?

È usato per impostare l’intervallo di limiti delle coordinate xy e z?

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

Significa che l’intervallo x, yez è compreso tra -1 e 1?

Dai un’occhiata a questa immagine: Proiezioni grafiche inserisci la descrizione dell'immagine qui

Il comando glOrtho produce una proiezione “Oblique” che vedi nella riga in basso. Non importa quanto siano lontani i vertici nella direzione z, non si allontaneranno in lontananza.

Io uso glOrtho ogni volta che ho bisogno di fare grafica 2D in OpenGL (come barre della salute, menu, ecc.) Usando il seguente codice ogni volta che la finestra viene ridimensionata:

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

Questo rimappare le coordinate OpenGL nei valori di pixel equivalenti (X passando da 0 a windowWidth e Y passando da 0 a windowHeight). Nota che ho invertito i valori Y perché le coordinate OpenGL iniziano dall’angolo in basso a sinistra della finestra. Sfogliando, invece, ottengo un più convenzionale (0,0) che inizia nell’angolo in alto a sinistra della finestra.

glOrtho : giochi 2D, oggetti vicini e lontani appaiono della stessa dimensione:

glFrustrum : più realtà come il 3D, gli oggetti identici più lontani appaiono più piccoli:

Codice

 #include  #include  #include  #include  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 fotocamera è un piano, il volume visibile un rettangolo:

inserisci la descrizione dell'immagine qui

Frustrum: la fotocamera è un punto, il volume visibile una fetta di una piramide:

inserisci la descrizione dell'immagine qui

Fonte immagine

parametri

Stiamo sempre guardando da + z a -z con + y in su:

 glOrtho(left, right, bottom, top, near, far) 
  • left : minimo x vediamo
  • right : massimo x vediamo
  • bottom : minimo y vediamo
  • top : massimo si vede
  • -near : minimo z vediamo , questo è -1 volte near . Quindi un input negativo significa positivo z .
  • -far : massimo z vediamo Anche negativo.

Schema:

Fonte immagine

Come funziona sotto il cofano

Alla fine, OpenGL “usa” sempre:

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

Se non usiamo né glOrthoglFrustrum , questo è ciò che otteniamo.

glOrtho e glFrustrum sono solo trasformazioni lineari (moltiplicazione di matrice AKA) tali che:

  • glOrtho : prende un dato rettangolo 3D nel cubo predefinito
  • glFrustrum : prende una data sezione piramidale nel cubo predefinito

Questa trasformazione viene quindi applicata a tutti i vertici. Questo è ciò che intendo in 2D:

Fonte immagine

Il passaggio finale dopo la trasformazione è semplice:

  • rimuovi qualsiasi punto al di fuori del cubo (selezionando): assicurati che x , y e z siano in [-1, +1]
  • ignora il componente z e prendi solo x e y , che ora possono essere inseriti in uno schermo 2D

Con glOrtho , z viene ignorato, quindi potresti sempre usare 0 .

Una ragione per cui potresti voler usare z != 0 è far sì che gli sprite nascondano lo sfondo con il buffer di profondità.

deprecazione

glOrtho è obsoleto a partire da OpenGL 4.5 : il profilo di compatibilità 12.1. “TRASFORMAZIONI VERTEX A FUNZIONE FISSA” è in rosso.

Quindi non usarlo per la produzione. In ogni caso, comprenderlo è un buon modo per ottenere una visione di OpenGL.

I moderni programmi OpenGL 4 calcolano la matrice di trasformazione (che è piccola) sulla CPU, quindi assegnano la matrice e tutti i punti da trasformare in OpenGL, che può fare le migliaia di moltiplicazioni di matrice per diversi punti in modo veramente veloce in parallelo.

I vertex shader scritti manualmente eseguono quindi la moltiplicazione in modo esplicito, solitamente con i convenienti tipi di dati vettoriali del linguaggio OpenGL Shading.

Poiché scrivi lo shader in modo esplicito, questo ti consente di modificare l’algoritmo in base alle tue esigenze. Tale flessibilità è una caratteristica importante delle GPU più moderne, che a differenza di quelle vecchie che eseguivano un algoritmo fisso con alcuni parametri di input, ora possono eseguire calcoli arbitrari. Vedi anche: https://stackoverflow.com/a/36211337/895245

Con una esplicita GLfloat transform[] sarebbe simile a questa:

 #include  #include  #include  #define GLEW_STATIC #include  #include  #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; } 

Output generato: http://imgur.com/QVW14Gu

La matrice per glOrtho è davvero semplice, composta solo da ridimensionamento e traduzione:

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

come menzionato nei documenti OpenGL 2 .

La matrice glFrustum non è troppo difficile da calcolare a mano, ma inizia a diventare fastidiosa. Nota come il trambusto non può essere compensato con il solo ridimensionamento e le traduzioni come glOrtho , maggiori informazioni su: https://gamedev.stackexchange.com/a/118848/25171

La libreria matematica GLM OpenGL C ++ è una scelta popolare per il calcolo di tali matrici. http://glm.g-truc.net/0.9.2/api/a00245.html documenta entrambe le operazioni ortho e frustum .

glOrtho descrive una trasformazione che produce una proiezione parallela . La matrice corrente (vedi glMatrixMode) viene moltiplicata per questa matrice e il risultato sostituisce la matrice corrente, come se glMultMatrix fosse chiamata con la seguente matrice come argomento:

Documentazione OpenGL (il mio grassetto)

I numeri definiscono le posizioni dei piani di ritaglio (a sinistra, a destra, in basso, in alto, vicino e lontano).

La proiezione “normale” è una proiezione prospettica che fornisce l’illusione della profondità. Wikipedia definisce una proiezione parallela come:

Le proiezioni parallele hanno linee di proiezione parallele sia nella realtà che nel piano di proiezione.

La proiezione parallela corrisponde a una proiezione prospettica con un ipotetico punto di vista, ad esempio, uno in cui la telecamera si trova a una distanza infinita dall’object e ha una lunghezza focale infinita, o “zoom”.