如何创建限制最大 FOV 的透视矩阵?
我的意思是,如果我有一个如下所示的场景:
/-------\
|#######|
|#######|
\-------/
屏幕当前尺寸为 16:10,我可以看到:
/-------\
#######
#####
---
现在,如果我将屏幕大小调整为 16:9,我会看到以下内容(b 为黑色):
b/-------\b
|#######|
#######
-----
当我宁愿它剪掉更多的顶部/底部时。
我该怎么做?我正在使用 OpenGL 和 GLM。我正在使用 glm::perspective(yFov, width/height, zNear, zFar) 创建当前矩阵。
(尝试)澄清:问题是在我的应用程序中,我希望修复每侧地形所需的“边距”量。我试图解决的问题是,根据屏幕的宽高比,该值当前会发生变化。我可以设置 yFov,以便我始终能够在垂直方向看到相同的量。然而,随着屏幕变得越来越宽,我可以看到越来越多的水平方向。相反,我想要的是能够减少垂直方向的视野。感谢您的建议:)
我采用的解决方案:
projMat = glm::perspective(fov, aspect.x / aspect.y, zRange.x, zRange.y);
// ^ could be any other maths lib / code
if (aspect.x > aspect.y * 1.6f) {
float tanFov = std::tan(0.5f * fov);
projMat[0][0] = 1.f / tanFov / 1.6f;
projMat[1][1] = 1.f / (aspect.y / aspect.x * tanFov) / 1.6f;
}
1.6 是因为我希望“标准”比例为 16:10。这很好用:)
最佳答案
您可以更改投影的定义,以使用较大尺寸的视场角,而不是始终使用 y 尺寸。这意味着您在较大维度中看到给定范围的对象,而在较小维度中看到的范围较小。
虽然这可以通过将从矩阵库中获得的投影矩阵与附加缩放相结合来实现,但更简洁的方法是计算您自己的投影矩阵。
标准投影矩阵的计算如下所示:
float tanFov = tan(0.5f * fov);
float aspRat = (float)width / (float)height;
mat[0][0] = 1.0f / (aspRat * tanFov);
mat[0][1] = 0.0f;
mat[0][2] = 0.0f;
mat[0][3] = 0.0f;
mat[1][0] = 0.0f;
mat[1][1] = 1.0f / tanFov;
mat[1][2] = 0.0f;
mat[1][3] = 0.0f;
mat[2][0] = 0.0f;
mat[2][1] = 0.0f;
mat[2][2] = (zNear + zFar) / (zNear - zFar);
mat[2][3] = -1.0f;
mat[3][0] = 0.0f;
mat[3][1] = 0.0f;
mat[3][2] = 2.0f * zNear * zFar / (zNear - zFar);
mat[3][3] = 0.0f;
如果您使用建议的逻辑来计算投影矩阵,其中大部分内容将保持不变。如果 width<,则仅确定 x 和 y 维度缩放的元素
大于[0][0]
和 [1][1]
的计算方式不同高度
:
if (width > height) {
float aspRat = (float)height/ (float)width;
mat[0][0] = 1.0f / tanFov;
mat[1][1] = 1.0f / (aspRat * tanFov);
} else {
float aspRat = (float)width / (float)height;
mat[0][0] = 1.0f / (aspRat * tanFov);
mat[1][1] = 1.0f / tanFov;
}
如果height
大于width
,则与之前相同,否则交换两个方向的计算逻辑。
关于opengl - 水平和垂直限制 FOV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26997631/