从正交投影切换到透视投影

Switching from orthogonal to perspective projection

我正在尝试为现有引擎添加视差效果。到目前为止,引擎使用的是正交投影。对象放置在屏幕上的像素坐标中。问题是我不知道如何用透视投影矩阵等复制相同的投影。我可以为深度添加 Z 坐标。

我已经尝试了各种矩阵和 z 坐标的组合,结果总是黑屏。

我要替换的矩阵:

glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(1280.0f), static_cast<GLfloat>(720.0f), 0.0f, 0.0f, -100.0f);

顶点着色器:

// Shader code (I tested this while having identity matrices for view and model

#version 330 core

layout (location = 0) in vec2 vertex;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;

void main() {
    gl_Position = projection * view * model * vec4(vertex.xy, 1.0f, 1.0f);
}

我认为可能有效的投影代码:

    glm::mat4 model = glm::mat4(1.0f);
    model = glm::translate(model, glm::vec3(-640, -310.0f, 0.0f));
    model = glm::scale(model, glm::vec3(1.0f / 1280.0f, 1.0f / 720.0f, 1.0f));

    glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 0.0f);
    glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
    glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
    glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); 
    glm::mat4 projection = glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, -100.0f);

预计在没有黑屏的情况下,矩形仍会显示在相似位置(我可以在某些东西起作用后更正细节)。

Perspective projection矩阵的规范错误。

glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, -100.0f);

glm::perspective defines a Viewing frustum 通过沿 y 轴的视角、纵横比以及到近平面和远平面的距离。
所以 nearfar 平面必须是正值(> 0)并且 near 必须小于 :

0 < near < far

例如:

glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, 100.0f);

几何体必须位于近平面和远平面之间,否则会被裁剪。
投影面积的大小与深度的比例是线性的,可以计算。取决于视场角:

float fov_y = glm::radians(45.0f);
float ratio_size_depth = tan(fov_y / 2.0f) * 2.0f;

注意,如果一个对象在视口上的投影中应该以一半的大小出现,则对象到相机的距离(深度)必须加倍。

因此着色器中校正后的模型平移矩阵和所需深度以在平面上匹配坐标如下:

int width = 1280.0f;
int height = 720.0f;

glm::mat4 model = glm::mat4(1.0f);  
model = glm::scale(model, glm::vec3(-1.0f / width, -1.0f / height, 1.0f));
model = glm::translate(model, glm::vec3(-((float)width / 2.0f), -((float)height / 2.0f), 0.0f));

glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, 1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); 
glm::mat4 projection = glm::perspective(glm::radians(45.0f), 1.0f, 0.1f, 100.0f);

带 Z 值的着色器:

#version 330 core

layout (location = 0) in vec2 vertex;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;

void main() {
    gl_Position = projection * view * model * vec4(vertex.xy, 1.208f, 1.0f);
}

这将等效于此正交矩阵:

glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(this->width), static_cast<GLfloat>(this->height), 0.0f, 0.0f, -100.0f);

也可以将这些矩阵相乘,以便只有一个投影矩阵传递给着色器。这将使实际模型矩阵与网格等一起传递变得更容易。