Je ne comprends pas l'utilisation de glOrtho
. Quelqu'un peut-il expliquer à quoi il sert?
Est-il utilisé pour définir la plage de limites des coordonnées xy et z?
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
Cela signifie que la plage x, y et z va de -1 à 1?
Réponses:
Jetez un œil à cette image: Projections graphiques
La
glOrtho
commande produit une projection "Oblique" que vous voyez dans la rangée du bas. Quelle que soit la distance entre les sommets dans la direction z, ils ne reculeront pas dans la distance.J'utilise glOrtho chaque fois que j'ai besoin de faire des graphiques 2D dans OpenGL (tels que les barres de santé, les menus, etc.) en utilisant le code suivant chaque fois que la fenêtre est redimensionnée:
glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0f, windowWidth, windowHeight, 0.0f, 0.0f, 1.0f);
Cela remappera les coordonnées OpenGL dans les valeurs de pixels équivalentes (X allant de 0 à windowWidth et Y allant de 0 à windowHeight). Notez que j'ai inversé les valeurs Y car les coordonnées OpenGL partent du coin inférieur gauche de la fenêtre. Donc en retournant, j'obtiens plutôt un (0,0) plus conventionnel en partant du coin supérieur gauche de la fenêtre.
Notez que les valeurs Z sont coupées de 0 à 1. Soyez donc prudent lorsque vous spécifiez une valeur Z pour la position de votre sommet, elle sera coupée si elle tombe en dehors de cette plage. Sinon, s'il se trouve dans cette plage, il semblera n'avoir aucun effet sur la position, sauf pour les tests Z.
la source
z= -2
. Le triangle est invisible si jeglOrtho(.., 0.0f, -4.0f);
,..-1.0f, -3.0f)
ou..-3.0f, -1.0f)
. Pour être visible, le paramètre far devait être POSITIF 2 ou supérieur; il ne semblait pas important quel était le paramètre proche. Chacune de ces travaillé:..0.0f, 2.0f)
,..-1.0f, 2.0f)
,..-3.0f, 2.0f)
ou..0.0f, 1000.0f
.Exemple exécutable minimal
glOrtho
: Les jeux 2D, les objets proches et éloignés ont la même taille:glFrustrum
: plus réaliste que la 3D, les objets identiques plus éloignés apparaissent plus petits:principal c
#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; }
GitHub en amont .
Compiler:
gcc -ggdb3 -O0 -o main -std=c99 -Wall -Wextra -pedantic main.c -lGL -lGLU -lglut
Courir avec
glOrtho
:./main 1
Courir avec
glFrustrum
:Testé sur Ubuntu 18.10.
Schéma
Ortho: la caméra est un plan, le volume visible un rectangle:
Frustrum: la caméra est un point, le volume visible une tranche de pyramide:
Source de l'image .
Paramètres
Nous cherchons toujours de + z à -z avec + y vers le haut:
glOrtho(left, right, bottom, top, near, far)
left
: minimumx
on voitright
: maximum quex
nous voyonsbottom
: minimumy
on voittop
: maximum quey
nous voyons-near
: minimum quez
nous voyons. Oui , c'est le-1
tempsnear
. Donc, une entrée négative signifie positivez
.-far
: maximum quez
nous voyons. Aussi négatif.Schéma:
Source de l'image .
Comment ça marche sous le capot
Au final, OpenGL "utilise" toujours:
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
Si nous n'utilisons ni
glOrtho
niglFrustrum
, c'est ce que nous obtenons.glOrtho
et neglFrustrum
sont que des transformations linéaires (multiplication de matrice AKA) telles que:glOrtho
: prend un rectangle 3D donné dans le cube par défautglFrustrum
: prend une section de pyramide donnée dans le cube par défautCette transformation est ensuite appliquée à tous les sommets. C'est ce que je veux dire en 2D:
Source de l'image .
La dernière étape après la transformation est simple:
x
,y
etz
sont[-1, +1]
z
composant et ne prendre quex
ety
, qui peut maintenant être placé dans un écran 2DAvec
glOrtho
,z
est ignoré, vous pouvez donc toujours utiliser0
.Une des raisons que vous pourriez vouloir utiliser
z != 0
est de faire en sorte que les sprites masquent l'arrière-plan avec le tampon de profondeur.Désapprobation
glOrtho
est obsolète à partir d' OpenGL 4.5 : le profil de compatibilité 12.1. «TRANSFORMATIONS VERTEX À FONCTION FIXE» est en rouge.Alors ne l'utilisez pas pour la production. Dans tous les cas, le comprendre est un bon moyen d'obtenir un aperçu d'OpenGL.
Les programmes modernes d'OpenGL 4 calculent la matrice de transformation (qui est petite) sur le CPU, puis donnent la matrice et tous les points à transformer en OpenGL, qui peut faire les milliers de multiplications de matrice pour différents points très rapidement en parallèle.
Les nuanceurs de vertex écrits manuellement effectuent ensuite la multiplication explicitement, généralement avec les types de données vectorielles pratiques du langage OpenGL Shading.
Puisque vous écrivez explicitement le shader, cela vous permet d'ajuster l'algorithme à vos besoins. Une telle flexibilité est une caractéristique majeure des GPU plus modernes, qui, contrairement aux anciens qui utilisaient un algorithme fixe avec certains paramètres d'entrée, peuvent désormais effectuer des calculs arbitraires. Voir aussi: https://stackoverflow.com/a/36211337/895245
Avec un explicite,
GLfloat transform[]
cela ressemblerait à quelque chose comme ceci:#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; }
GitHub en amont .
Production:
La matrice pour
glOrtho
est vraiment simple, composée uniquement de mise à l'échelle et de translation:scalex, 0, 0, translatex, 0, scaley, 0, translatey, 0, 0, scalez, translatez, 0, 0, 0, 1
comme mentionné dans la documentation OpenGL 2 .
La
glFrustum
matrice n'est pas trop difficile à calculer à la main non plus, mais commence à devenir ennuyeuse. Notez comment le frustum ne peut pas être composé uniquement avec une mise à l'échelle et des traductions commeglOrtho
, plus d'informations sur: https://gamedev.stackexchange.com/a/118848/25171La bibliothèque mathématique GLM OpenGL C ++ est un choix populaire pour le calcul de telles matrices. http://glm.g-truc.net/0.9.2/api/a00245.html documente à la fois les opérations
ortho
etfrustum
.la source
Documentation OpenGL (mon gras)
Les nombres définissent les emplacements des plans de détourage (gauche, droite, bas, haut, proche et éloigné).
La projection «normale» est une projection en perspective qui donne l'illusion de la profondeur. Wikipedia définit une projection parallèle comme:
la source