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:
Frustrum: Aparat jest punktem, widoczna objętość plaster piramidy:
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
.
Wideo [to] (https://www.youtube.com/watch?v=8ryJMO6rBT4) wideo pomogło mi bardzo. – ViniciusArruda