我不了解的用法glOrtho
。有人可以解释它的用途吗?
是否用于设置xy和z坐标限制的范围?
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
这意味着x,y和z范围是-1到1?
Answers:
看看这张照片:图形投影
该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)。请注意,由于OpenGL坐标从窗口的左下角开始,所以我已经翻转了Y值。因此,通过翻转,我从窗口的左上角开始获得了更常规的(0,0)。
请注意,Z值从0剪切到1。因此,当为顶点位置指定Z值时,请注意,如果Z值超出该范围,则会被剪切。否则,如果它在该范围内,则除Z测试外,对位置无影响。
z= -2
。如果使用,或glOrtho(.., 0.0f, -4.0f);
,则三角形不可见。可见,far参数必须为POSITIVE 2或更大;似乎无关紧要的参数是什么。所有这些工作: ,,,或。..-1.0f, -3.0f)
..-3.0f, -1.0f)
..0.0f, 2.0f)
..-1.0f, 2.0f)
..-3.0f, 2.0f)
..0.0f, 1000.0f
最小的可运行示例
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上测试。
架构图
正交:相机是一个平面,可见体积是一个矩形:
截锥体:相机是一个点,可见体积是一块金字塔:
图片来源。
参量
我们一直在寻找从+ 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
:将给定的金字塔截面放入默认的多维数据集然后,此转换将应用于所有顶点。这就是我在二维中的意思:
图片来源。
转换后的最后一步很简单:
x
,y
并z
在[-1, +1]
z
组件,仅使用x
和y
,现在可以将其放到2D屏幕中使用glOrtho
,会z
被忽略,因此您最好还是使用0
。
您可能要使用的一个原因z != 0
是使精灵使用深度缓冲区隐藏背景。
弃用
glOrtho
从OpenGL 4.5开始不推荐使用:兼容性配置文件12.1。“固定功能顶点转换”为红色。
因此,请勿将其用于生产。无论如何,了解它是获得OpenGL见识的好方法。
现代OpenGL 4程序在CPU上计算转换矩阵(很小),然后将矩阵和所有要转换的点提供给OpenGL,OpenGL可以真正并行地对不同的点进行数千次矩阵乘法。
然后,手动编写的顶点着色器通常使用OpenGL着色语言的便捷矢量数据类型来显式进行乘法。
由于您明确编写了着色器,因此您可以根据需要调整算法。这种灵活性是更现代的GPU的一个主要功能,与旧的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
该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
操作。