平面是3D圖形學重要部分.平面有兩個重要概念.
1.3D平面都無窮遠延伸
2.所有平面都將整個空間分成兩個半空間.正半空間為法線指向空間,負半空間則是令一則空間.這個特性對於碰撞算法重要
平面描敘如下:
平面法線向量:n=(a,b,c)
平面任意點:p0=(x0,y0,z0)
平面任意點:p=(x,y,z)
平面與原點距離:d平面位移常量(plane-shift constant)
因為法線n與向量(p0->p)垂直. 因兩垂直向量點積為零:
n * (p0->p) = 0
轉為分量表示
(a,b,c)*(x-x0,y-y0,z-z0)=0
轉為『頂點』與『法線』表示
a(x-x0)+b(y-y0)+c*(z-z0)=0
ax+by+cz+(-ax0-by0-cz0)=0
令d=-ax0-by0-c*z0
『平面方程』如下:
ax+by+c*z+d=0
這足以定義平面結構
typedef struct PLANE3D_TYP{
VECTOR3D n;//平面法線向量(不必是單位向量)
float dist;//平面到原點最近距離
POINT3D p0;//平面上最近原點的點
}PLANE3D,*PLANE3D_PTR;
判斷『點』位於『平面』那個半空
3D世界中『視點』、『角色』並不能穿越牆壁.要做到這步需判斷點位於平正空間(法線指向)還是負空間.
要判斷這點需要下面的平面方程
hs=a(x-x0)+b(y-y0)+c*(z-z0)
只需將點(x,y,z)帶入方程中並計算結果
如果hs=0則該點位於平面之上
如果hs>0則該點位於平面正半空間(法線指向)中
如果hs<0則該點位於平面負半空間中
float Compute_Point_In_Plane3D(PLANE3D_PTR plane,VECTOR3D_PTR pt){
float hs = plane->A * pt->x + plane->B * pt->y + plane->C * pt->z + plane->D;
return(hs); // 返回半空間值
}
計算平面與直線之相交點(3D空間)
平面『頂點』與『法線』方程如下:
a(x-x0)+b(y-y0)+c*(z-z0)=0
3D直線方程如下:
(x-x0)/a = (y-y0)/b = (z-z0)/c
計算多邊形法線與直線方向點積
double a = plane->n % (line->v);
若為零則直線與平面平行
VECTOR3D Intersect;
if (a == 0)
Intersect = line->p0;
計算相交點
Intersect = line->p0 – (line->v) * ((plane->n % line->p0 + plane->D) / a);
3D線段與3D平面交點函式:
bool Intersect_Line3D_Plane3D(PLANE3D_PTR plane, PARMLINE3D_PTR line,POINT3D_PTR pt){
// 計算直線方向與多邊形法線點積
double a = plane->n % (line->v);
if (a == 0)
return false;
// 計算相交點
*pt = line->p0 – (line->v) * ((plane->n % line->p0 + plane->D) / a);
return true;
}
計算頂點是否為於多邊形之上,
首先計算頂點與多邊形所有頂點之間角度總和.如果該頂點位於多邊形之上.那麼此頂點與多邊形所有頂點之間角度總和將等於或接近2PI
bool Intersect_Vector3D_Polygon3D(VECTOR3D_PTR polygon, int num,VECTOR3D_PTR v){
VECTOR3D segment1, segment2;// 頂點 到 多邊形頂點 矢量
double length1, length2;// 矢量長度
double sumAngle = 0;// 矢量之間角度總和
double cosAngle = 0;// 兩矢量余弦角
// 編曆多邊形所有頂點
for (int index = 0; index < num; ++index) {
segment1 = polygon[index] – *v;
segment2 = polygon[(index+1) % num] – *v; // % num 確保數值環形加一
length1 = Length_VECTOR3D(&segment1);
length2 = Length_VECTOR3D(&segment2);// 矢量長度
//檢查頂點是否落在多邊形邊界上
if ( length1 * length2 <= 0.0000001f){
// 多邊形邊界被認為是多邊形內部
sumAngle = PI2; // pai * 2
break;
}
// 計算上述兩個矢量之間余弦角
cosAngle = (segment1 % segment2) / (length1 * length2);
// 將計算結果累加入角度總和
sumAngle = sumAngle + acosf(cosAngle);
}
if ((sumAngle <= PI2 + 0.0000001f) && (sumAngle >= PI2 – 0.0000001f))
return true;// 頂點與多邊形發生碰撞
else
return false;
return true;
}
使用三個頂點初始化(定義)3D平面!
void Init_PLANE3D(PLANE3D_PTR plane,VECTOR3D_PTR va,VECTOR3D_PTR vb,VECTOR3D_PTR vc){
VECTOR3D normalA = *vc – *va;// 計算頂點C->A向量
VECTOR3D normalB = *vc – *vb;// 計算頂點C->B向量
plane->n = Cross_VECTOR3D(&normalA, &normalB);// 計算兩個3D向量叉積
plane->D = Dot_VECTOR3D(&(-(*va)), &plane->n); //距離等於va求返後與n求點積
}