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 {
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:
./main
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: minimum xon voit
right: maximum que xnous voyons
bottom: minimum yon voit
top: maximum que ynous voyons
-near: minimum que znous voyons. Oui , c'est le -1temps near. Donc, une entrée négative signifie positive z.
-far: maximum que znous 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 glOrthoni glFrustrum, c'est ce que nous obtenons.
glOrthoet ne glFrustrumsont que des transformations linéaires (multiplication de matrice AKA) telles que:
glOrtho: prend un rectangle 3D donné dans le cube par défaut
glFrustrum: prend une section de pyramide 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:

Source de l'image .
La dernière étape après la transformation est simple:
- supprimer tous les points de l' extérieur du cube (culling): il suffit de faire en sorte que
x, yet zsont[-1, +1]
- ignorer le
zcomposant et ne prendre que xet y, qui peut maintenant être placé dans un écran 2D
Avec glOrtho, zest ignoré, vous pouvez donc toujours utiliser 0.
Une des raisons que vous pourriez vouloir utiliser z != 0est de faire en sorte que les sprites masquent l'arrière-plan avec le tampon de profondeur.
Désapprobation
glOrthoest 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;
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[] = {
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);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
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");
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 glOrthoest 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 glFrustummatrice 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 comme glOrtho, plus d'informations sur: https://gamedev.stackexchange.com/a/118848/25171
La 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 orthoet frustum.