Comment utiliser glOrtho () dans OpenGL?
Je ne comprends pas l'utilisation de glOrtho
. Quelqu'un peut m'expliquer à quoi il sert?
Est-il utilisé pour définir la plage de X Y et Z limite de coordonnées?
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
Cela signifie que la plage x, y et z est de -1 à 1?
3 réponses
Regardez cette image: Projections graphiques
La commande glOrtho
produit une projection "Oblique" que vous voyez dans la rangée du bas. Peu importe à quelle distance les sommets sont 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 (comme 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 retourné les valeurs Y car les coordonnées OpenGL commencent à partir du coin inférieur gauche de la fenêtre. Donc, en retournant, j'obtiens un plus conventionnel (0,0) commençant plutôt dans le coin supérieur gauche de la fenêtre.
glOrtho
: jeux 2D, objets proches et loin apparaissent de la même taille:
glFrustrum
: Plus Réel comme la 3D, les objets identiques plus loin apparaissent plus petits:
Code
#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;
}
Schéma
Ortho: la caméra est un plan, le volume visible un rectangle:
Frustrum: caméra est un point, visible volume une tranche de un pyramide:
Les Paramètres
Nous regardons toujours de + z à-z avec +y vers le haut:
glOrtho(left, right, bottom, top, near, far)
-
left
: minimumx
, nous voyons -
right
: maximum dex
, nous voyons -
bottom
: minimumy
, nous voyons -
top
: maximum dey
, nous voyons -
-near
: minimumz
nous voir. Oui, ce-1
tempsnear
. Donc une entrée négative signifie positivez
. -
-far
: maximumz
nous voyons. Aussi négatif.
Schéma:
Comment il fonctionne sous le capot
À la fin, OpenGL "utilise" toujours:
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
Si nous utilisons ni glOrtho
ni glFrustrum
, c'est ce que nous obtenons.
glOrtho
et glFrustrum
ne sont que des transformations linéaires (aka multiplication matricielle) telles que:
-
glOrtho
: prend un rectangle 3D donné dans le cube par défaut -
glFrustrum
: prend une section pyramidale donnée dans le cube par défaut
Cette transformation est ensuite appliquée à tous les sommets. C'est ce que je veux dire en 2D:
La dernière étape après la transformation est simple:
- supprimer tous les points à l'extérieur du cube (abattage): il suffit de s'assurer que
x
,y
etz
sont[-1, +1]
- ignorez le composant
z
et ne prenez quex
ety
, qui peut maintenant être mis dans un écran 2D
Avec glOrtho
, z
est ignoré, ainsi vous pouvez toujours utiliser 0
.
Une raison pour laquelle vous pouvez utiliser z != 0
est de faire en sorte que les sprites masquent l'arrière-plan avec le tampon de profondeur.
La Dépréciation
glOrtho
est obsolète à partir de OpenGL 4.5 : le profil de compatibilité 12.1. "TRANSFORMATIONS de VERTEX à fonction fixe" est en rouge.
Ne l'utilisez donc pas pour la production. En tout cas, comprendre est un bon moyen d'obtenir un aperçu OpenGL.
Les programmes modernes 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 matricielles pour différents points très rapidement en parallèle.
Écrit manuellement vertex shaders{[69] } ensuite, faites la multiplication explicitement, généralement avec les types de données vectorielles pratiques de L'ombrage OpenGL Langue.
Puisque vous écrivez explicitement le shader, cela vous permet de modifier l'algorithme en fonction de vos besoins. Une telle flexibilité est une caractéristique majeure des GPU plus modernes, qui, contrairement aux anciens qui faisaient un algorithme fixe avec certains paramètres d'entrée, peuvent maintenant faire des calculs arbitraires. Voir aussi: https://stackoverflow.com/a/36211337/895245
Avec un GLfloat transform[]
explicite, cela ressemblerait à 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;
}
Sortie générée: http://imgur.com/QVW14Gu
La matrice pour glOrtho
est vraiment simple, composée uniquement de mise à l'échelle et de traduction:
scalex, 0, 0, translatex,
0, scaley, 0, translatey,
0, 0, scalez, translatez,
0, 0, 0, 1
Comme mentionné dans les documents OpenGL 2 .
Le glFrustum
la matrice n'est pas trop difficile à calculer à la main, mais commence à devenir ennuyeux. Notez comment frustum ne peut pas être composé avec seulement la mise à l'échelle et les traductions comme glOrtho
, plus d'informations à: https://gamedev.stackexchange.com/a/118848/25171
Le GLM OpenGL c++ math library est un choix populaire pour calculer de telles matrices. http://glm.g-truc.net/0.9.2/api/a00245.html documente les opérations ortho
et frustum
.
GlOrtho décrit une transformation qui produit une projectionparallèle . La matrice actuelle (Voir glMatrixMode) est multipliée par cette matrice et le résultat remplace la matrice actuelle, comme si glMultMatrix était appelée avec la matrice suivante comme argument:
Documentation OpenGL (mon gras)
Les nombres définissent les emplacements des plans de détourage (Gauche, Droite, Bas, Haut, près et loin).
La projection "normale" est un projection en perspective qui donne l'illusion de la profondeur. Wikipedia définit une projection parallèle comme:
Les projections parallèles ont des lignes de projection parallèles à la fois dans la réalité et dans le plan de projection.
La projection parallèle correspond à une projection en perspective avec un point de vue hypothétique-par exemple, celui où la caméra se trouve à une distance infinie de l'objet et a une longueur focale infinie, ou "zoom".