glOrtho
: trò chơi 2D, các đối tượng gần gũi và xuất hiện xa cùng kích thước:
glFrustrum
: hơn thực tế cuộc sống như 3D, các đối tượng giống hệt nhau xa xuất hiện nhỏ hơn:
Mã
#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;
}
Schema
Ortho: máy ảnh là một chiếc máy bay, khối lượng có thể nhìn thấy một hình chữ nhật:
Frustrum: máy ảnh là một điểm, khối lượng có thể nhìn thấy một lát một kim tự tháp:
Image source.
thông số
Chúng tôi luôn tìm kiếm từ + z để -Z với + y trở lên:
glOrtho(left, right, bottom, top, near, far)
left
: tối thiểu x
right
chúng ta thấy: tối đa x
chúng ta thấy
bottom
: giảm thiểu um y
chúng ta thấy
top
: tối đa y
chúng ta thấy
-near
: tối thiểu z
chúng ta thấy. Có, đây là -1
lần near
. Vì vậy, một đầu vào tiêu cực có nghĩa là tích cực z
.
-far
: tối đa z
chúng tôi thấy. Cũng tiêu cực.
Schema:
Image source.
Cách thức hoạt động dưới mui xe
Cuối cùng, OpenGL luôn "sử dụng":
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
Nếu chúng ta sử dụng không glOrtho
cũng không glFrustrum
, đó là những gì chúng tôi nhận được.
glOrtho
và glFrustrum
là biến đổi chỉ tuyến tính (AKA nhân ma trận) sao cho:
glOrtho
: mất một hình chữ nhật 3D cho vào khối mặc định
glFrustrum
: mất một phần kim tự tháp được vào khối mặc định
Chuyển đổi này sau đó được áp dụng cho tất cả các đỉnh. Đây là những gì tôi muốn nói trong 2D:
Image source.
Bước cuối cùng sau khi chuyển đổi rất đơn giản:
- loại bỏ bất kỳ điểm bên ngoài của khối lập phương (tiêu huỷ): chỉ cần đảm bảo rằng
x
, y
và z
là trong [-1, +1]
- bỏ qua các thành phần
z
và chăm chỉ x
và y
, hiện có thể được đưa vào màn hình 2D
Với glOrtho
, z
bị bỏ qua, vì vậy bạn cũng có thể sử dụng 0
.
Một lý do bạn có thể muốn sử dụng z != 0
là làm cho hình ảnh ẩn ẩn nền với bộ đệm độ sâu.
Deprecation
glOrtho
bị phản đối như của OpenGL 4.5: hồ sơ cá nhân tương thích 12.1. "FIXED-FUNCTION VERTEX TRANSFORMATIONS" có màu đỏ.
Vì vậy, không sử dụng nó để sản xuất. Trong bất kỳ trường hợp nào, việc hiểu nó là một cách hay để có được một số thông tin chi tiết về OpenGL.
Chương trình OpenGL 4 hiện đại tính ma trận chuyển đổi (nhỏ) trên CPU, sau đó cung cấp ma trận và tất cả các điểm được chuyển thành OpenGL, có thể thực hiện hàng nghìn phép nhân cho các điểm khác nhau. .
Viết thủ công vertex shaders sau đó thực hiện phép nhân một cách rõ ràng, thường với các loại dữ liệu vectơ thuận tiện của Ngôn ngữ đổ bóng OpenGL.
Vì bạn viết bóng đổ một cách rõ ràng, điều này cho phép bạn tinh chỉnh thuật toán theo nhu cầu của mình. Tính linh hoạt như vậy là một tính năng chính của các GPU hiện đại hơn, không giống như các GPU cũ đã thực hiện một thuật toán cố định với một số tham số đầu vào, giờ đây có thể thực hiện các phép tính tùy ý.Xem thêm: https://stackoverflow.com/a/36211337/895245
Với một rõ ràng GLfloat transform[]
nó sẽ giống như thế này:
#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;
}
tạo đầu ra: http://imgur.com/QVW14Gu
Ma trận cho glOrtho
là thực sự đơn giản, chỉ gồm các mở rộng quy mô và bản dịch:
scalex, 0, 0, translatex,
0, scaley, 0, translatey,
0, 0, scalez, translatez,
0, 0, 0, 1
như đã đề cập trong OpenGL 2 docs.
glFrustum
matrix cũng không quá khó để tính bằng tay, nhưng bắt đầu trở nên khó chịu. Lưu ý mức độ thất vọng không thể được thực hiện chỉ với quy mô lớn và các bản dịch như glOrtho
, thông tin khác tại: https://gamedev.stackexchange.com/a/118848/25171
Thư viện toán GLM OpenGL C++ là một lựa chọn phổ biến để tính toán các ma trận đó. http://glm.g-truc.net/0.9.2/api/a00245.html tài liệu cả hoạt động ortho
và frustum
.
[This] (https://www.youtube.com/watch?v=8ryJMO6rBT4) video đã giúp tôi rất nhiều. – ViniciusArruda