我无法理解glOrtho
的用法。有人可以解释它的用途吗?
是否用于设置x y和z坐标限制的范围?
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
这意味着x,y和z范围是-1到1?
答案 0 :(得分:133)
看看这张图片:Graphical Projections
glOrtho
命令会生成您在底行中看到的“倾斜”投影。无论顶点在z方向上有多远,它们都不会退回到距离中。
每次我需要在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)。
答案 1 :(得分:42)
最小可运行示例
glOrtho
:2D游戏,近距离和远距离的物体看起来大小相同:
glFrustrum
:更像3D的现实生活,更远的相同物体看起来更小:
的main.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;
}
编译:
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总是&#34;使用&#34;:
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
的一个原因是让精灵用深度缓冲区隐藏背景。
<强>弃用强>
自OpenGL 4.5起不推荐使用 glOrtho
:兼容性配置文件12.1。 &#34;固定功能VERTEX转换&#34;是红色的。
所以不要将它用于生产。无论如何,了解它是获得OpenGL洞察力的好方法。
现代OpenGL 4程序计算CPU上的变换矩阵(很小),然后将矩阵和所有点转换为OpenGL,这可以非常快速地并行地对不同点进行数千次矩阵乘法。
手动编写vertex shaders然后显式地进行乘法,通常使用OpenGL着色语言的方便矢量数据类型。
由于您明确编写着色器,因此可以根据需要调整算法。这种灵活性是更现代GPU的一个主要特征,与使用某些输入参数执行固定算法的旧GPU不同,现在可以进行任意计算。另见:https://stackoverflow.com/a/36211337/895245
使用明确的GLfloat transform[]
,它看起来像这样:
#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;
}
输出:
glOrtho
的矩阵非常简单,仅由缩放和翻译组成:
scalex, 0, 0, translatex,
0, scaley, 0, translatey,
0, 0, scalez, translatez,
0, 0, 0, 1
如OpenGL 2 docs中所述。
glFrustum
matrix也不难用手算,但开始变得烦人。请注意,仅使用缩放和翻译(例如glOrtho
)无法弥补视锥,更多信息请参见:https://gamedev.stackexchange.com/a/118848/25171
GLM OpenGL C ++数学库是计算此类矩阵的常用选择。 http://glm.g-truc.net/0.9.2/api/a00245.html记录了ortho
和frustum
操作。
答案 2 :(得分:5)
glOrtho描述了一种产生平行投影的转换。当前矩阵(请参阅glMatrixMode)乘以此矩阵,结果将替换当前矩阵,就好像使用以下矩阵作为参数调用glMultMatrix一样:
OpenGL documentation(我的大胆)
数字定义剪裁平面的位置(左,右,底,顶,近和远)。
“正常”投影是透视投影,提供深度幻觉。 Wikipedia将平行投影定义为:
平行投影的投影线在现实和投影平面上都是平行的。
平行投影对应于具有假设视点的透视投影 - 例如,相机与物体无限距离且具有无限焦距或“变焦”的投影。