视锥体剔除:考虑对视椎体所拥有的六个面进行遍历,每次遍历考虑当前平面与物体的位置关系。且由于是剔除,所以只需要考虑两种情况:物体完全在该平面的外侧,或者对该情况的否定。
物体本身形状可能非常复杂,因此为简化计算以提升性能,剔除时仅考虑物体的长方体包围盒与当前平面的关系,设物体的包围盒中心为Pc\mathbf{P_c}Pc(即代码中的position),包围盒的半大小向量为L\mathbf{L}L(即代码中的extent),当前平面的方程为f(p):N⋅p+D=0f(\mathbf{p}):\mathbf{N}\cdot \mathbf{p}+D=0f(p):N⋅p+D=0,其中N\mathbf{N}N为当前平面的单位法向量(其指向的方向即为平面的外侧,在代码中为plane.normal),DDD为平面到原点的有向距离(从原点做垂直相交于平面,那么这条“原点-交点”的向量代表的就是−D-D−D,当该向量与法向量方向相同时,−D-D−D为正数;方向相反时为负数。在代码中为plane.distance)
其中平面的内外侧来自于法向量的朝向:法向量指向的方向为平面外侧,反方向为平面内侧。 那么判断某一点是否在平面外侧,由平面方程定义“点p\mathbf{p}p位于平面上⇔N⋅p+D=0\Leftrightarrow \mathbf{N}\cdot \mathbf{p}+D=0⇔N⋅p+D=0”可知:
点p\mathbf{p}p在平面外侧⇔N⋅p+D>0\Leftrightarrow \mathbf{N}\cdot \mathbf{p}+D>0⇔N⋅p+D>0
证明如下:
- 充分性:考虑过该点p\mathbf{p}p做平面的垂直,相交平面于p0\mathbf{p}_0p0,那么根据外侧的定义可知p=p0+ϵN (ϵ>0)\mathbf{p}=\mathbf{p}_0+\epsilon\mathbf{N}\ \ (\epsilon>0)p=p0+ϵN (ϵ>0),所以N⋅p+D=⇔N⋅(p0+ϵN)+D=ϵ∣N∣2>0\mathbf{N}\cdot \mathbf{p}+D=\Leftrightarrow \mathbf{N}\cdot (\mathbf{p}_0+\epsilon\mathbf{N})+D=\epsilon |\mathbf{N}|^2>0N⋅p+D=⇔N⋅(p0+ϵN)+D=ϵ∣N∣2>0
- 必要性:考虑反证法,如果存在这样的p\mathbf{p}p在平面内侧,那么考虑以p\mathbf{p}p为起点,N\mathbf{N}N为方向发出射线,易知这样的射线会与平面相交,设交点为p′\mathbf{p'}p′,且由p\mathbf{p}p在平面内侧结合射线定义可知p′=p+δN\mathbf{p'}=\mathbf{p}+\delta \mathbf{N}p′=p+δN,其中δ>0\delta >0δ>0,再由平面方程可知0=N⋅p′+D=N⋅(p+δN)+D=N⋅p+D+δ∣N∣20=\mathbf{N}\cdot\mathbf{p'}+D=\mathbf{N}\cdot(\mathbf{p}+\delta\mathbf{N})+D=\mathbf{N}\cdot \mathbf{p}+D+\delta |\mathbf{N}|^20=N⋅p′+D=N⋅(p+δN)+D=N⋅p+D+δ∣N∣2,其中N⋅p+D>0,δ∣N∣2>0\mathbf{N}\cdot \mathbf{p}+D>0,\delta |\mathbf{N}|^2>0N⋅p+D>0,δ∣N∣2>0两者均成立,此时发生矛盾,所以假设不成立
点ppp在平面内侧⇔N⋅p+D<0\Leftrightarrow \mathbf{N}\cdot \mathbf{p}+D<0⇔N⋅p+D<0 同理可得
然而物体的包围盒是一个长方体而不是单个点,不过好在长方体是个凸多面体,所以只需要考虑每个顶点是否在平面外侧就可以,换句话来说,只要“离平面最近”的顶点在平面外侧,那么物体完全在该平面的外侧就成立,而这八个顶点恰是Pc\mathbf{P_c}Pc为起点,长度为∣L∣|\mathbf{L}|∣L∣的向量终点,且这八个向量的各分量绝对值均等于L\mathbf{L}L,只是符号不同(八次是正负号选择的三次方),设带不同符号的八个半大小向量所组成集合为{Si}\{\mathbf{S}_i\}{Si},那么这八个顶点可表示为{Pc+Si}\{\mathbf{P}_c+\mathbf{S}_i\}{Pc+Si}。易知当Si\mathbf{S_i}Si的各符号分量与法向量N\mathbf{N}N恰好相反时,N⋅(Pc+Si)+D\mathbf{N}\cdot(\mathbf{P}_c+\mathbf{S}_i)+DN⋅(Pc+Si)+D是八个顶点中的最小值,因此只需要判断此时的计算结果是否大于0,即可得知包围盒与平面的位置关系。换句话说,只需要让各分量取绝对值的法向量N\mathbf{N}N与L\mathbf{L}L计算点积,再与N⋅Pc+D\mathbf{N}\cdot \mathbf{P}_c+DN⋅Pc+D比较大小即可
private static bool PlaneTest(ref Matrix4x4 ObjectToWorld, ref Vector3 extent, ref Vector3 position)
{
for (int i = 0; i < 6; i++)
{
Plane plane = frustumPlanes[i];
float radius = extents.x * Mathf.Abs(plane.normal.x) +
extents.y * Mathf.Abs(plane.normal.y) +
extents.z * Mathf.Abs(plane.normal.z);
float distance = Vector3.Dot(position, plane.normal) + plane.distance;
if (distance < -radius)
{
return false;
}
}
return true;
}

5446

被折叠的 条评论
为什么被折叠?



