如何有条不紊地选择透视投影的近剪裁平面距离?

Kev*_*eid 14 3d projection webgl opengl-es-2.0

我有一个3D场景和一个使用gluPerspective定义的相机.我有一个固定的FOV,我知道任何几何体与相机的最小距离(它是第一人称视角,因此这是从视点到角色碰撞体积的最小距离).

无论玩家如何移动和观看,我怎样才能选择最近的剪裁平面(最佳深度缓冲分辨率),不会造成任何剪裁

这些距离不是简单相等,因为近平面的离原点比中心更远.

Kev*_*eid 14

式:

nearPlane = nearestApproachToPlayer/sqrt(1 + tan (fov/2)2 ·(aspectRatio 2 + 1)))

JavaScript代码:

  var nearPlane = nearestApproachToPlayer 
                  / Math.sqrt(1 + Math.pow(Math.tan(fov/180*Math.PI/2), 2)
                                  * (Math.pow(aspectRatio, 2) + 1));
Run Code Online (Sandbox Code Playgroud)

推导:

在几何上,考虑金字塔,其基部是近剪裁平面,尖端是原点.让nearPlane成为金字塔的高度,wh是金字塔底座的宽度和高度.

w = aspectRatio·h

FOV确定金字塔的高轴方向的斜率:

斜率 = TAN(FOV/2)

H/nearPlane = 2黄褐色(FOV/2)

ħ/2 = nearPlane黄褐色(FOV/2)

近剪裁平面的任何角点都从剪辑平面的中心偏移(w/2,h/2),因此距离是sqrt((w/2)2 +(h/2)2).距离角点原点距离是由nearPlane和前一距离形成的直角三角形的斜边,因此是sqrt((w/2)2 +(h/2)2 + nearPlane 2).

我们希望到角点的距离等于任何几何的最近距离.

nearestApproachToPlayer = sqrt((w/2)2 +(h/2)2 + nearPlane 2)

应用直接代数产生上面给出的公式.

我还没有检查过我的代数,但是我已经通过实验测试了公式:如果我将nearPlane乘以1.1,那么它产生的剪裁平面对于各种宽高比来说有点太过分了.我没有尝试过比60°不同的FOV.


dat*_*olf 8

选择近距离和远距离剪辑距离的最佳做法是使它们紧密地包围场景,即尽可能地使近剪裁平面和远剪辑平面尽可能接近.

大多数3D应用用于透视变换的标准平截头体投影是平行平面投影.这意味着从视点确定平面距离.这实际上很简单:

您将在3D渲染程序中携带的参数之一是视图矢量,即摄像机指向的方向.假设您将此向量标准化(即单位长度),然后将标量(=点)乘积与对象位置一起给出与原点的平面距离.这是一种更直接的方法,因为它直接为您提供所需的值,而不需要正方形,平方根和除法.它只是乘法和,即MAD指令,它们由SIMD指令集直接支持.


Nic*_*las 5

无论玩家如何移动和观看,我怎样才能选择最近的剪裁平面(最佳深度缓冲分辨率),不会造成任何剪裁?

简单:关闭近剪裁.我无法相信人们还没有听说过这个.您可以启用深度钳制,这会导致小于近(或远远)的近(远)值被钳位,而不是被削波.

这不会阻止实际在相机后面的物体被剪裁.并且由于深度被夹紧,因此对于发生夹紧的区域,您将失去深度缓冲器的效用.如果你不能选择距离太近的近夹子,那么在合理的地方使用它仍然是一个好主意.

通常最好是启用夹紧并推动近夹子,而不是选择绝对最小近夹子.