了解 OpenGL 投影矩阵
Understanding the OpenGL projection matrix
我一直在编写一个程序来使用 OpenGL 显示 3d 模型,直到现在我一直使用正交投影,但我想切换到透视投影,这样当相机朝向模型时,它看起来像更大。我知道我必须将三个矩阵(模型、视图和投影)相乘才能正确应用我的所有变换。正如您在以下代码中看到的,我已尝试这样做,并且能够正确地创建模型和视图矩阵。我知道这些工作正常,因为当我将模型和视图投影相乘时,我可以旋转和平移对象,以及更改相机的位置和角度。我的问题是,当我将该乘积乘以投影矩阵时,我再也看不到屏幕上的对象了。
此处相机结构的默认值为 {0,0,-.5},但我使用键盘操纵该值来移动相机。
我正在使用 GLFW+glad,linmath.h
用于矩阵数学运算。
//The model matrix controls where the object is positioned. The
//identity matrix means no transformations.
mat4x4_identity(m);
//Apply model transformations here.
//The view matrix controls camera position and angle.
vec3 eye={camera.x,camera.y,camera.z};
vec3 center={camera.x,camera.y,camera.z+1};
vec3 up={0,1,0};
mat4x4_look_at(v,eye,center,up);
//The projection matrix flattens the world to 2d to be rendered on a
//screen.
mat4x4_perspective(p, 1.57, width/(float)height, 1,10); //FOV of 90°
//mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);
//Apply the transformations. mvp=p*v*m.
mat4x4_mul(mvp, p, v);
mat4x4_mul(mvp, mvp, m);
透视投影矩阵设置好后,到近平面和远平面的距离也就设置好了。在您的情况下,近平面为 1,远平面为 10:
mat4x4_perspective(p, 1.57, width/(float)height, 1,10);
模型被近平面裁剪。模型必须在剪辑 space.
中
相机视锥体(截棱锥)中的眼睛 space 坐标映射到立方体(归一化设备坐标)。
所有不在平截头体体积内的几何体都被剪裁。
这意味着模型到相机的距离必须大于到近平面的距离 (1) 并且小于到远平面的距离 (10)。
由于您可以在不使用任何投影矩阵时 "see" 模型,因此到模型的实际距离在 [-1, 1] 范围内(归一化设备 space)。请注意,如果您不使用投影矩阵,则投影矩阵就是单位矩阵。这就像正交投影,近平面距离为 -1,远平面距离为 1。
更改摄像头位置解决问题:
例如
vec3 eye = {camera.x, camera.y, camera.z - 5}; // <--- 5 is in range [1, 10]
vec3 center = {camera.x, camera.y, camera.z};
vec3 up = {0, 1, 0};
mat4x4_look_at(v, eye, center, up);
我一直在编写一个程序来使用 OpenGL 显示 3d 模型,直到现在我一直使用正交投影,但我想切换到透视投影,这样当相机朝向模型时,它看起来像更大。我知道我必须将三个矩阵(模型、视图和投影)相乘才能正确应用我的所有变换。正如您在以下代码中看到的,我已尝试这样做,并且能够正确地创建模型和视图矩阵。我知道这些工作正常,因为当我将模型和视图投影相乘时,我可以旋转和平移对象,以及更改相机的位置和角度。我的问题是,当我将该乘积乘以投影矩阵时,我再也看不到屏幕上的对象了。
此处相机结构的默认值为 {0,0,-.5},但我使用键盘操纵该值来移动相机。
我正在使用 GLFW+glad,linmath.h
用于矩阵数学运算。
//The model matrix controls where the object is positioned. The
//identity matrix means no transformations.
mat4x4_identity(m);
//Apply model transformations here.
//The view matrix controls camera position and angle.
vec3 eye={camera.x,camera.y,camera.z};
vec3 center={camera.x,camera.y,camera.z+1};
vec3 up={0,1,0};
mat4x4_look_at(v,eye,center,up);
//The projection matrix flattens the world to 2d to be rendered on a
//screen.
mat4x4_perspective(p, 1.57, width/(float)height, 1,10); //FOV of 90°
//mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);
//Apply the transformations. mvp=p*v*m.
mat4x4_mul(mvp, p, v);
mat4x4_mul(mvp, mvp, m);
透视投影矩阵设置好后,到近平面和远平面的距离也就设置好了。在您的情况下,近平面为 1,远平面为 10:
mat4x4_perspective(p, 1.57, width/(float)height, 1,10);
模型被近平面裁剪。模型必须在剪辑 space.
中
相机视锥体(截棱锥)中的眼睛 space 坐标映射到立方体(归一化设备坐标)。
所有不在平截头体体积内的几何体都被剪裁。
这意味着模型到相机的距离必须大于到近平面的距离 (1) 并且小于到远平面的距离 (10)。
由于您可以在不使用任何投影矩阵时 "see" 模型,因此到模型的实际距离在 [-1, 1] 范围内(归一化设备 space)。请注意,如果您不使用投影矩阵,则投影矩阵就是单位矩阵。这就像正交投影,近平面距离为 -1,远平面距离为 1。
更改摄像头位置解决问题:
例如
vec3 eye = {camera.x, camera.y, camera.z - 5}; // <--- 5 is in range [1, 10]
vec3 center = {camera.x, camera.y, camera.z};
vec3 up = {0, 1, 0};
mat4x4_look_at(v, eye, center, up);