2010-04-03 17 views
65

Nie mogę zrozumieć użycia glOrtho. Czy ktoś może wyjaśnić, do czego służy?Wyjaśnij użycie glOrtho()?

Aktualizacja

Jest on stosowany, aby ustawić zakres X Y i Z współrzędne granicę?

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

Oznacza to, że zakresy x, yiz mieszczą się w zakresie od -1 do 1?

+0

Wideo [to] (https://www.youtube.com/watch?v=8ryJMO6rBT4) wideo pomogło mi bardzo. – ViniciusArruda

Odpowiedz

117

Wystarczy popatrzeć na to zdjęcie: Graphical Projections enter image description here

Komenda glOrtho produkuje się „ukryte” projekcji, które można zobaczyć w dolnym rzędzie. Bez względu na to, jak daleko od siebie są wierzchołki w kierunku z, nie cofną się w dal.

używam glOrtho za każdym razem muszę zrobić grafiki 2D w OpenGL (takich jak bary zdrowia, menu itp) używając następującego kodu za każdym razem, gdy okno jest zmieniany:

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

Będzie przemapować OpenGL współrzędne do równoważnych wartości pikseli (X będzie od 0 do windowWidth i Y będzie od 0 do windowHeight). Zwróć uwagę, że odwróciłem wartości Y, ponieważ współrzędne OpenGL zaczynają się od lewego dolnego rogu okna. Więc odwracając, otrzymuję bardziej konwencjonalny (0,0), zaczynający się raczej w lewym górnym rogu okna.

+3

wielkie dzięki za wyjaśnienie problemu! :) – ufk

+74

o mój Boże, KOCHAM CIĘ. Czy masz pojęcie, ile czasu zajmuje znalezienie/wykreślenie tej linii kodu online? Dziękuję, podam imię mojego pierwszego dziecka po tobie dla tego Uwaga – karpathy

+1

: (na Androida), nawet jeśli model ma tylko ujemne wartości z, wydaje się konieczne, aby mieć wartość dodatnią dla końcowego (daleko) parametru. Zrobiłem prosty test na trójkąt (z wyłączonym wycinaniem), z wierzchołkami na 'z = -2'. Trójkąt był niewidoczny, gdy użyłem 'glortho (.., 0.0f, -4,0f);', '..- 1.0f, -3.0f)', lub '..- 3.0f, -1,0f)'. Aby być widocznym, parametr daleki musiał być POZYTYWNY 2 lub większy; nie miało znaczenia, jaki był najbliższy parametr. Dowolny z nich działał: '...0.0f, 2.0f)', '..- 1.0f, 2.0f)', '..- 3.0f, 2.0f)', lub '..0,0f, 1000.0f' . – ToolmakerSteve

3

glOrtho opisuje transformację wytwarza równolegle projekcję. Obecna matryca (patrz glMatrixMode) jest mnożona przez tę matrycę, a wynik zastępuje bieżącą macierz, jakby glMultMatrix nazywano z następującą matrycą jako argument:

OpenGL documentation (mój pogrubione)

Liczby zdefiniuj lokalizacje płaszczyzn przycinania (w lewo, w prawo, na dole, na górze, blisko i daleko).

"Normalna" projekcja jest projekcją perspektywiczną, która zapewnia iluzję głębi. Wikipedia definiuje rzut równoległy jako:

Równoległe projekcje mają linie rzutowania, które są równoległe zarówno w rzeczywistości, jak iw płaszczyźnie projekcji.

Projekcja równoległa odpowiada rzutowi perspektywicznemu z hipotetycznym punktem widzenia - np. Takim, w którym kamera znajduje się w nieskończonej odległości od obiektu i ma nieskończoną odległość ogniskową lub "zoom".

+0

Cześć dzięki za informacje. Nie bardzo rozumiałem różnicę między projekcją równoległą i perspektywiczną. trochę googlowałem i znalazłem odpowiedź w http://wiki.answers.com/Q/What_is_the_difference_between_orthogonal_and_perspective_projection – ufk

+6

Niestety informacje, które otrzymałeś od reply.com są dość bezwartościowe. Widok izometryczny jest na przykład bardzo trójwymiarowy, ale jest to projekcja równoległa bez perspektywy. Zobacz tutaj, a tam są również linki do wielu innych przykładów prognoz: http://en.wikipedia.org/wiki/Isometric_projection –

32

glOrtho: Gry 2D, obiekty blisko i daleko pojawić się ten sam rozmiar:

glFrustrum: więcej rzeczywistym życie jak 3D, identyczne obiekty dalej wydają się mniejsze:

Kod

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

Schemat

Orto: Aparat jest płaszczyzną, widoczna objętość prostokąta:

enter image description here

Frustrum: Aparat jest punktem, widoczna objętość plaster piramidy:

enter image description here

Image source.

Parametry

Jesteśmy zawsze patrząc od + Z do -Z z + y wzwyż:

glOrtho(left, right, bottom, top, near, far) 
  • left: minimum x widzimy
  • right: maksymalna x widzimy
  • bottom: minim um y widzimy
  • top: maksymalna y widzimy
  • -near: minimum z widzimy. Tak, to jest -1 razy near. Tak więc ujemne wejście oznacza pozytywne z.
  • -far: najwyżej z widzimy. Również negatywne.

Schema:

Image source.

Jak to działa pod maską

W końcu, OpenGL zawsze "zastosowania":

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

Jeśli używamy ani glOrtho ani glFrustrum, że to, co mamy.

glOrtho i glFrustrum są przekształcenia tylko liniowe (inaczej Mnożenie macierzy), takich, że:

  • glOrtho: zajmuje dane prostokąta 3D do domyślnej kostki
  • glFrustrum: wyraża danej sekcji ostrosłup do domyślnej kostki

Ta transformacja jest następnie stosowana do wszystkich wierzchołków. To, co mam na myśli w 2D:

Image source.

Ostatnim krokiem po transformacji jest prosta:

  • usunąć punkty zewnątrz sześcianu (uboju): po prostu upewnić się, że x, y i z są w [-1, +1]
  • ignorować składnika z i podjąć tylko x i y, które można teraz umieścić w ekranie 2D:

Z glOrtho, z jest ignorowany, więc równie dobrze możesz zawsze używać 0.

Jednym z powodów, dla których warto zastosować z != 0, jest sprawienie, aby duszki ukrywały tło za pomocą bufora głębi.

Deprecation

glOrtho jest przestarzała od OpenGL 4.5: profil zgodności 12.1. "FIXED-FUNCTION TRANSFORMACJE VERTEX" jest na czerwono.

Nie używaj go do produkcji. W każdym razie zrozumienie tego jest dobrym sposobem na uzyskanie wglądu OpenGL.

Nowoczesne programy OpenGL 4 obliczają macierz transformacji (która jest mała) na procesorze, a następnie nadają macierz i wszystkie punkty do przekształcenia na OpenGL, która może wykonywać tysiące multiplikacji macierzy dla różnych punktów bardzo szybko równolegle .

Ręcznie napisane vertex shaders następnie wykonaj mnożenie jawnie, zwykle z wygodnymi wektorowymi typami języka cieniowania OpenGL.

Po napisaniu modułu cieniującego w sposób jawny umożliwia to dostosowanie algorytmu do własnych potrzeb. Taka elastyczność jest główną cechą bardziej nowoczesnych procesorów graficznych, które w odróżnieniu od starych, które zrobiły stały algorytm z niektórymi parametrami wejściowymi, mogą teraz wykonywać dowolne obliczenia.Zobacz także: https://stackoverflow.com/a/36211337/895245

z wyraźną GLfloat transform[] to wyglądać mniej więcej tak:

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

Generowane wyjście: http://imgur.com/QVW14Gu

Matryca glOrtho jest naprawdę prosta, składa się tylko z skalowanie i tłumaczenie:

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

jak wspomniano w OpenGL 2 docs.

Nie jest to trudne do obliczenia ręcznie, ale zaczyna denerwować. Zauważ, że nie można zmywać frustum tylko przy skalowaniu i tłumaczeniach takich jak glOrtho, więcej informacji: https://gamedev.stackexchange.com/a/118848/25171

Biblioteka matematyczna GLM OpenGL C++ jest popularnym wyborem do obliczania takich matryc. http://glm.g-truc.net/0.9.2/api/a00245.html dokumentuje zarówno operacje ortho i frustum.

+1

"co powinno się zamiast tego stosować?" - skonstruuj własne macierze i przypisz je bezpośrednio. – Kromster

Powiązane problemy