Minimal lauffähiges Beispiel
glOrtho: 2D-Spiele, Objekte in der Nähe und in der Ferne haben dieselbe Größe:

glFrustrum: realistischer wie 3D erscheinen identische Objekte weiter entfernt kleiner:

Haupt 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 stromaufwärts .
Kompilieren:
gcc -ggdb3 -O0 -o main -std=c99 -Wall -Wextra -pedantic main.c -lGL -lGLU -lglut
Laufen Sie mit glOrtho:
./main 1
Laufen Sie mit glFrustrum:
./main
Getestet unter Ubuntu 18.10.
Schema
Ortho: Kamera ist eine Ebene, sichtbares Volumen ein Rechteck:

Frustrum: Kamera ist ein Punkt, sichtbares Volumen ein Stück einer Pyramide:

Bildquelle .
Parameter
Wir schauen immer von + z nach -z mit + y nach oben:
glOrtho(left, right, bottom, top, near, far)
left: Minimum sehen xwir
right: Maximum sehen xwir
bottom: Minimum sehen ywir
top: Maximum sehen ywir
-near: Minimum sehen zwir. Ja , das ist -1mal near. Ein negativer Eingang bedeutet also positiv z.
-far: Maximum sehen zwir. Auch negativ.
Schema:

Bildquelle .
Wie es unter der Haube funktioniert
Am Ende "verwendet" OpenGL immer:
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
Wenn wir weder glOrthonoch verwenden glFrustrum, bekommen wir das.
glOrthound glFrustrumsind nur lineare Transformationen (AKA-Matrixmultiplikation), so dass:
glOrtho: Nimmt ein bestimmtes 3D-Rechteck in den Standardwürfel auf
glFrustrum: nimmt einen bestimmten Pyramidenabschnitt in den Standardwürfel auf
Diese Transformation wird dann auf alle Scheitelpunkte angewendet. Das meine ich in 2D:

Bildquelle .
Der letzte Schritt nach der Transformation ist einfach:
- entfernen Sie alle Punkte außerhalb des Würfels (Culling): Stellen Sie sicher , dass nur
x, yund zsind in[-1, +1]
- ignoriere die
zKomponente und nimm nur xund y, das jetzt in einen 2D-Bildschirm eingefügt werden kann
Mit glOrtho, zignoriert wird, so könnten Sie auch immer verwenden 0.
Ein Grund, den Sie möglicherweise verwenden möchten, z != 0besteht darin, dass Sprites den Hintergrund mit dem Tiefenpuffer ausblenden.
Missbilligung
glOrthoist ab OpenGL 4.5 veraltet : das Kompatibilitätsprofil 12.1. "VERTEX-TRANSFORMATIONEN MIT FESTFUNKTION" ist rot.
Verwenden Sie es also nicht für die Produktion. In jedem Fall ist das Verstehen ein guter Weg, um OpenGL-Einblicke zu erhalten.
Moderne OpenGL 4-Programme berechnen die Transformationsmatrix (die klein ist) auf der CPU und geben dann die Matrix und alle zu transformierenden Punkte in OpenGL an, wodurch die Tausenden von Matrixmultiplikationen für verschiedene Punkte sehr schnell parallel ausgeführt werden können.
Manuell geschriebene Vertex-Shader führen dann die Multiplikation explizit durch, normalerweise mit den praktischen Vektordatentypen der OpenGL Shading Language.
Da Sie den Shader explizit schreiben, können Sie den Algorithmus an Ihre Bedürfnisse anpassen. Diese Flexibilität ist ein Hauptmerkmal moderner GPUs, die im Gegensatz zu den alten, die einen festen Algorithmus mit einigen Eingabeparametern verwendet haben, jetzt beliebige Berechnungen durchführen können. Siehe auch: https://stackoverflow.com/a/36211337/895245
Mit einem expliziten GLfloat transform[]würde es ungefähr so aussehen:
#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 stromaufwärts .
Ausgabe:

Die Matrix für glOrthoist wirklich einfach und besteht nur aus Skalierung und Übersetzung:
scalex, 0, 0, translatex,
0, scaley, 0, translatey,
0, 0, scalez, translatez,
0, 0, 0, 1
wie in den OpenGL 2-Dokumenten erwähnt .
Die glFrustumMatrix ist auch nicht allzu schwer von Hand zu berechnen, wird aber nervig. Beachten Sie, dass Kegelstumpf nicht nur mit Skalierung und Übersetzungen wie möglich hergestellt werden glOrthokann. Weitere Informationen finden Sie unter: https://gamedev.stackexchange.com/a/118848/25171
Die GLM OpenGL C ++ - Mathematikbibliothek ist eine beliebte Wahl für die Berechnung solcher Matrizen. http://glm.g-truc.net/0.9.2/api/a00245.html dokumentiert sowohl eine orthoals auch frustumOperationen.