【unity】三维数学应用(计算线和面的交点)
实现方法有多种,下面介绍一种简单的方法。利用一个点指向面上任意点的向量,到该面法线的投影长度相同的基本原理,结合相似三角形既可以求出交点。
原理
如下图
GD组成的线段和ABC组成的三角形相交与E点,ABCDG的坐标已知求E点坐标。
首先用叉乘求出ABC面的法线 N ⃗ \vec{N} N;(D点到ABC点的向量在 N ⃗ \vec{N} N上的投影是相同的,同样到E点的向量在 N ⃗ \vec{N} N的投影也是一样的)
分别用点乘的方法求出, D A ⃗ \vec{DA} DA到 N ⃗ \vec{N} N的投影模长a和 D G ⃗ \vec{DG} DG到 N ⃗ \vec{N} N的投影模长b;
∵ D E ⃗ \vec{DE} DE到 N ⃗ \vec{N} N的投影模长同样等于a
∴由相似三角形可得
a b = ∣ D E ⃗ ∣ ∣ D G ⃗ ∣ \frac{a}{b}=\frac{|\vec{DE}|}{|\vec{DG}|} ba=∣DG∣∣DE∣
由次可得E点的坐标
实现代码
Vector3 GetIntersectPoint(Vector3 C1, Vector3 C2, Vector3 C3, Vector3 L1, Vector3 L2){//求面的法线Vector3 n0 = (C2 - C1).normalized;Vector3 n1 = (C2 - C3).normalized;Vector3 N = Vector3.Cross(n0, n1);//线段的向量和到面上点的向量Vector3 line1 = L2 - L1;Vector3 line2 = C1 - L1;//与面法线点成比,得到线段点到面的模长float dis1 = Vector3.Dot(N, line1);float dis2 = Vector3.Dot(N, line2);float magnitude = (dis2 / dis1)*line1.magnitude;//用线段的单位向量乘模长求出交点Vector3 direction = line1.normalized * magnitude;return L1 + direction;}
同样的方法也可以计算两条线段的加点
Vector3 GetIntersectPoint(Vector3 C1, Vector3 C2, Vector3 P1, Vector3 P2){// 分别求出两个线段的单位向量Vector3 L0=(C2 - C1).normalized;Vector3 L1=( P2 - P1).normalized;//俩次差乘建立 L0为一个坐标轴的的坐标系Vector3 H = Vector3.Cross(L0, L1);Vector3 N = Vector3.Cross( L0, H);float dis1 = Vector3.Dot(N, L1);float dis2 = Vector3.Dot(N, (P1-C1));float magnitude = dis2 / dis1;return L1 * magnitude + P1;}
叉乘判断线段和面是否相交
//判断面和线段是否相相交bool isCut(Vector3 C1, Vector3 C2, Vector3 L1, Vector3 L2){Vector3 V0 = squeeze( C2 - C1);Vector3 V1 = squeeze( L1 - C1);Vector3 V2 = squeeze( L2 - C1);Vector3 Cross1 = Vector3.Cross(V0, V1).normalized;Vector3 Cross2 = Vector3.Cross(V0, V2).normalized;float Dot = Vector3.Dot(Cross1, Cross2);if (Dot>0){//同边不相交return false;}else{//同异边相交return true;}}//坐标平面化,去除y值Vector3 squeeze(Vector3 vector){return new Vector3(vector.x, 0, vector.z);}
判断两条线段是否相交
bool isCut(Vector3 C1, Vector3 C2, Vector3 L1, Vector3 L2){Vector3 V0 =C2 - C1;Vector3 V1 =L1 - C1;Vector3 V2 = L2 - C1;Vector3 Cross1 = Vector3.Cross(V0, V1).normalized;Vector3 Cross2 = Vector3.Cross(V0, V2).normalized;float Dot = Vector3.Dot(Cross1, Cross2);if (Dot>0){//同边不相交return false;}else{//同异边相交return true;}}