限制水平和垂直FOV

时间:2014-11-18 15:13:54

标签: opengl math 3d

如何创建限制最大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。这非常有效:)

1 个答案:

答案 0 :(得分:1)

您可以更改投影的定义,以使用较大尺寸的视野角度,而不是始终用于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;

如果使用建议的逻辑来计算投影矩阵,大部分将保持不变。如果[0][0]大于[1][1],则仅计算确定x和y维度缩放的元素widthheight

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,则与之前相同,否则将交换两个方向的计算逻辑。