我无法理解的用法glOrtho
.有人可以解释它的用途吗?
是否用于设置xy和z坐标限制的范围?
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
这意味着x,y和z范围是-1到1?
看看这张图片:图形投影
该glOrtho
命令会生成一个"倾斜"投影,您可以在底行看到该投影.无论顶点在z方向上有多远,它们都不会退回到距离中.
每次调整窗口大小时,每次我需要在OpenGL中使用以下代码执行OpenGL中的2D图形(例如健康栏,菜单等)时,我都会使用glOrtho:
glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0f, windowWidth, windowHeight, 0.0f, 0.0f, 1.0f);
这会将OpenGL坐标重新映射到等效的像素值(X从0到windowWidth,Y从0到windowHeight).请注意,我已经翻转了Y值,因为OpenGL坐标从窗口的左下角开始.所以通过翻转,我得到一个更常规的(0,0)从窗口的左上角开始.
最小的可运行示例
glOrtho
:2D游戏,关闭和远处的对象看起来大小相同:
glFrustrum
:更像3D的现实生活,更远的相同物体看起来更小:
main.c中
#include#include #include #include 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上游.
编译:
gcc -ggdb3 -O0 -o main -std=c99 -Wall -Wextra -pedantic main.c -lGL -lGLU -lglut
运行glOrtho
:
./main 1
运行glFrustrum
:
./main
在Ubuntu 18.10上测试过.
架构
Ortho:相机是一个平面,可见体积是一个矩形:
Frustrum:相机是一个点,可见体积一片金字塔:
图像来源.
参数
我们总是从+ z到-z向上看+ y向上:
glOrtho(left, right, bottom, top, near, far)
left
:x
我们看到的最低限度
right
:x
我们看到的最大值
bottom
:y
我们看到的最低限度
top
:y
我们看到的最大值
-near
:z
我们看到的最低限度 是的,这是-1
时候了near
.所以负面输入意味着积极z
.
-far
:z
我们看到的最大值.也是消极的.
架构:
图像来源.
它是如何在引擎盖下工作的
最后,OpenGL总是"使用":
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
如果我们既不使用glOrtho
也不使用glFrustrum
,那就是我们得到的.
glOrtho
并且glFrustrum
只是线性变换(AKA矩阵乘法),这样:
glOrtho
:将给定的3D矩形放入默认的多维数据集中
glFrustrum
:将给定的金字塔部分放入默认的多维数据集中
然后将此变换应用于所有顶点.这就是我在2D中的意思:
图像来源.
转型后的最后一步很简单:
删除多维数据集之外的任何点(剔除):只需确保x
,y
并z
在其中[-1, +1]
忽略z
分量和仅取x
和y
,现在可以被放入2D屏幕
有glOrtho
,z
被忽略,所以你可能总是使用0
.
您可能想要使用的一个原因z != 0
是使精灵用深度缓冲区隐藏背景.
弃用
glOrtho
自OpenGL 4.5起不推荐使用:兼容性配置文件12.1."固定功能VERTEX转换"为红色.
所以不要用它来生产.无论如何,了解它是获得一些OpenGL洞察力的好方法.
现代OpenGL 4程序计算CPU上的变换矩阵(很小),然后将矩阵和所有点转换为OpenGL,这可以非常快速地并行地对不同点进行数千次矩阵乘法.
手动编写的顶点着色器然后显式地进行乘法,通常使用OpenGL着色语言的方便矢量数据类型.
由于您明确编写着色器,因此可以根据需要调整算法.这种灵活性是更现代GPU的一个主要特征,与使用某些输入参数执行固定算法的旧GPU不同,现在可以进行任意计算.另见:https://stackoverflow.com/a/36211337/895245
显式GLfloat transform[]
它看起来像这样:
#include#include #include #define GLEW_STATIC #include #include #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上游.
输出:
矩阵glOrtho
非常简单,仅由缩放和翻译组成:
scalex, 0, 0, translatex, 0, scaley, 0, translatey, 0, 0, scalez, translatez, 0, 0, 0, 1
正如OpenGL 2文档中提到的那样.
该glFrustum
矩阵是不是太硬手既可以计算,但开始变得讨厌.请注意,如何只使用缩放和翻译来弥补视锥glOrtho
,更多信息请访问:https://gamedev.stackexchange.com/a/118848/25171
GLM OpenGL C++数学库是计算此类矩阵的常用选择.http://glm.g-truc.net/0.9.2/api/a00245.html记录ortho
和frustum
操作.