2010-04-03 6 views
65

Non riesco a capire l'utilizzo di glOrtho. Qualcuno può spiegare a cosa serve?Spiegare l'uso di glOrtho()?

Aggiorna

viene usato per impostare l'intervallo di x ed y z coordinate limite?

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

significa che il x, yez intervallo va da -1 a 1?

+0

[Questo] (https://www.youtube.com/watch?v=8ryJMO6rBT4) video mi ha aiutato molto. – ViniciusArruda

risposta

117

Date un'occhiata a questa immagine: Graphical Projections enter image description here

Il comando glOrtho produce una proiezione "obliqua" che si vede nella fila 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 di salute, menu ecc) utilizzando il seguente codice ogni volta che viene ridimensionata la finestra:

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

Questo sarà rimappare l'OpenGL coordinate nei valori di pixel equivalenti (X che va da 0 a windowWidth e Y che vanno 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.

+3

grazie mille per chiarire il problema! :) – ufk

+74

oh mio dio TI AMO. Hai idea di quanto tempo ci vuole per trovare/capire questa singola riga di codice online? Grazie, chiamerò il mio primogenito dopo di te per questa – karpathy

+1

Nota: (su Android) anche se il modello ha solo valori z negativi, sembra necessario avere un valore positivo per il parametro finale (lontano). Ho fatto un semplice test a triangolo (con disabilitazione disabilitata), con vertici a 'z = -2'. Il triangolo era invisibile se ho usato 'glOrtho (.., 0.0f, -4.0f);', '..- 1.0f, -3.0f)', o '..- 3.0f, -1.0f)'. Per essere visibile, il parametro lontano doveva essere POSITIVO 2 o superiore; non sembrava importare quale fosse il parametro vicino. Ognuno di questi ha funzionato: '..0.0f, 2.0f)', '..- 1.0f, 2.0f)', '..- 3.0f, 2.0f)', o '..0.0f, 1000.0f' . – ToolmakerSteve

3

glOrtho descrive una trasformazione che produce un parallelo proiezione . La matrice corrente (vedi glMatrixMode) viene moltiplicato per questa matrice e il risultato sostituisce la matrice corrente, come se glMultMatrix stato chiamato con la seguente matrice come argomento:

OpenGL documentation (mio grassetto)

I numeri definire 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 quello in cui la telecamera si trova a una distanza infinita dall'oggetto e ha una lunghezza focale infinita, o "zoom".

+0

ciao grazie per le informazioni. Non riuscivo a capire la differenza tra proiezione parallela e prospettiva. Ho cercato un po 'su google e ho trovato la risposta in http://wiki.answers.com/Q/What_is_the_difference_between_orthogonal_and_perspective_projection – ufk

+6

Sfortunatamente le informazioni che hai ricevuto da answers.com sono piuttosto inutili. Una vista isometrica, ad esempio, è molto tridimensionale, tuttavia è una proiezione parallela senza prospettiva. Vedi qui, e ci sono anche link a molti altri esempi di proiezioni: http://en.wikipedia.org/wiki/Isometric_projection –

32

glOrtho: giochi 2D, oggetti vicini e lontani appaiono le stesse dimensioni:

glFrustrum: più vita reale come 3D, apparire più lontani oggetti identici più piccola:

Codice

#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

Ortho: camera è un piano, il volume visibile un rettangolo:

enter image description here

a tronco: telecamera è un punto, il volume visibile una fetta di una piramide:

enter image description here

Image source.

Parametri

Siamo sempre alla ricerca da + z alla -z con + y verso l'alto:

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

schema:

Image source.

Come funziona sotto il cofano

Alla fine, OpenGL sempre "usi":

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

Se usiamo né glOrthoglFrustrum, che è quello che si ottiene.

glOrtho e glFrustrum sono trasformazioni appena lineari (alias moltiplicazione matriciale) tale che:

  • glOrtho: prende un determinato rettangolo 3D nel cubo di default
  • glFrustrum: prende una data sezione piramide nel cubo predefinito

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

Image source.

Il passo finale dopo trasformazione è semplice:

  • rimuovere eventuali punti al di fuori del cubo (abbattimento): solo garantire che x, y e z sono in [-1, +1]
  • ignorare il componente z e prendere solo x e , che ora può essere inserito in uno schermo 2D

Con glOrtho, z viene ignorato, così si potrebbe anche utilizzare sempre 0.

Una ragione si potrebbe desiderare di utilizzare z != 0 è quello di rendere sprite nascondere lo sfondo con il buffer di profondità.

Deprecation

glOrtho è obsoleto partire OpenGL 4.5: il profilo compatibilità 12.1. "Fixed-FUNZIONE VERTICE trasformazioni" è in rosso.

Quindi non ne fanno uso 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 e quindi forniscono la matrice e tutti i punti da trasformare in OpenGL, che può fare le migliaia di moltiplicazioni di matrice per diversi punti molto velocemente in parallelo .

Scritto manualmente vertex shaders quindi fare esplicitamente la moltiplicazione, solitamente con i convenienti tipi di dati vettoriali di OpenGL Shading Language.

Dal momento che si scrive lo shader in modo esplicito, questo consente di ottimizzare l'algoritmo per le vostre esigenze. Tale flessibilità è una caratteristica importante di GPU più moderni, che a differenza di quelli vecchi che hanno fatto un algoritmo fisso con alcuni parametri di input, ora possono fare calcoli arbitrari.Vedi anche: https://stackoverflow.com/a/36211337/895245

Con un esplicito GLfloat transform[] sarebbe simile a questa:

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

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

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

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

come indicato nello OpenGL 2 docs.

Il glFrustum matrix non è troppo difficile da calcolare a mano, ma inizia a diventare fastidioso. Si noti come tronco non può essere fatta solo con il ridimensionamento e traduzioni come glOrtho, maggiori informazioni a: https://gamedev.stackexchange.com/a/118848/25171

Il GLM OpenGL C++ libreria matematica è 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.

+1

"cosa dovrebbe invece essere usato?" - Costruisci le tue matrici e assegnale direttamente. – Kromster