0 前言
平面的表達方式有很多,常用的就兩種。向量形式的點法式,標量形式的平面方程。兩者可以互相轉化。
\[(\mathbf{p}-\mathbf{p_0})\cdot\mathbf{n}=0
\]
\[Ax + By + Cz + D = 0
\]
\[A = \mathbf{n}.x,\; B = \mathbf{n}.y,\; C = \mathbf{n}.z,\; D = \mathbf{n} \cdot -\mathbf{p_0}
\]
平面方程就是任意一點到平面的垂直投影距離。距離以法線為座標基。
以點法式來看,平面方程有兩種意義:
-
任意一點p投影到n上的距離,減去p0投影到n上的距離。
-
向量p-p0投影到n上的距離。
可以把n想象為一根一維數軸,投影距離區分正負的。
1 平面的應用 物理碰撞
加abs()是因為要切換包圍盒的頂點。
// Test if AABB b intersects plane p
int TestAABBPlane(AABB b, Plane p) {
// Convert AABB to center-extents representation
Point c = (b.max + b.min) * 0.5f; // Compute AABB center
Point e = b.max - c; // Compute positive extents
// 此處只有聰明人才能懂為什麼加絕對值,這個和unreal的判斷異曲同工之妙
float r = e[0]*Abs(p.n[0]) + e[1]*Abs(p.n[1]) + e[2]*Abs(p.n[2]);
// Compute distance of box center from plane
float s = Dot(p.n, c) - p.d;
// Intersection occurs when distance s falls within [-r,+r] interval
return Abs(s) <= r;
}
2 Unreal Math 平面位置關係
判斷正負也是因為要切換包圍盒的頂點。
// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
UnMath.cpp: Unreal math routines
=============================================================================*/
int32 FMath::PlaneAABBRelativePosition(const FPlane& P, const FBox& AABB)
{
// find diagonal most closely aligned with normal of plane
FVector Vmin, Vmax;
// Bypass the slow FVector[] operator. Not RESTRICT because it won't update Vmin, Vmax
FVector::FReal* VminPtr = (FVector::FReal*)&Vmin;
FVector::FReal* VmaxPtr = (FVector::FReal*)&Vmax;
// Use restrict to get better instruction scheduling and to bypass the slow FVector[] operator
const FVector::FReal* RESTRICT AABBMinPtr = (const FVector::FReal*)&AABB.Min;
const FVector::FReal* RESTRICT AABBMaxPtr = (const FVector::FReal*)&AABB.Max;
const FPlane::FReal* RESTRICT PlanePtr = (const FPlane::FReal*)&P;
for(int32 Idx=0;Idx<3;++Idx)
{
if(PlanePtr[Idx] >= 0.f)
{
VminPtr[Idx] = AABBMinPtr[Idx];
VmaxPtr[Idx] = AABBMaxPtr[Idx];
}
else
{
VminPtr[Idx] = AABBMaxPtr[Idx];
VmaxPtr[Idx] = AABBMinPtr[Idx];
}
}
// if either diagonal is right on the plane, or one is on either side we have an interesection
FPlane::FReal dMax = P.PlaneDot(Vmax);
FPlane::FReal dMin = P.PlaneDot(Vmin);
// if Max is below plane, or Min is above we know there is no intersection.. otherwise there must be one
if (dMax < 0.f)
{
return -1;
}
else if (dMin > 0.f)
{
return 1;
}
return 0;
}
bool FMath::PlaneAABBIntersection(const FPlane& P, const FBox& AABB)
{
return PlaneAABBRelativePosition(P, AABB) == 0;
}
X. Reff
- https://en.wikipedia.org/wiki/Line–plane_intersection
- https://gdbooks.gitbooks.io/3dcollisions/
- 《Games Physicks CookBook》