1. 射线与平面求交
射线可以描述为:
p(t)=p0+t∗u→
p(t) = p_0 + t*\overrightarrow{u}
p(t)=p0+t∗u
其中,p0是射线的起始点,u是射线的方向向量(需要单位化),t是参数,表示射线上任意一点到起点的距离。
计算射线与三角形平面的交点的数学公式可以分为两部分:首先找到射线与三角形所在平面的交点,然后判断该交点是否在三角形内部。以下是详细的步骤和公式:
平面可以描述为:
n→⋅(p−p0’)=0
\overrightarrow{n}\cdot(p-p_{0}^{’}) = 0
n⋅(p−p0’)=0
其中,p 是平面上的任意一点,n 是平面的单位法向量,p0' 是平面上任意一点(可以是三角形的任意一个顶点)。
为了找到射线与平面的交点,我们需要将射线的方程代入平面的方程中,并解出参数 t:
n→⋅(p0+t∗u→−p0’)=0n→⋅p0+t(n→⋅u→)−n→⋅p0’=0t(n→⋅u→)=n→⋅p0−n→⋅p0’t=(n→⋅p0−n→⋅p0’)/(n→⋅u→)
\overrightarrow{n}\cdot(p_0 + t*\overrightarrow{u}-p_{0}^{’})=0 \\
\overrightarrow{n}\cdot p_0+t(\overrightarrow{n} \cdot \overrightarrow{u}) - \overrightarrow{n}\cdot p_{0}^{’} = 0 \\
t(\overrightarrow{n} \cdot \overrightarrow{u}) = \overrightarrow{n}\cdot p_0 - \overrightarrow{n}\cdot p_{0}^{’} \\
t = (\overrightarrow{n}\cdot p_0 - \overrightarrow{n}\cdot p_{0}^{’}) / (\overrightarrow{n} \cdot \overrightarrow{u})
n⋅(p0+t∗u−p0’)=0n⋅p0+t(n⋅u)−n⋅p0’=0t(n⋅u)=n⋅p0−n⋅p0’t=(n⋅p0−n⋅p0’)/(n⋅u)
如果 n · u ≠ 0(即射线的方向向量与平面的法向量不垂直),则可以求出 t 的值,进而求出交点 p(t)。
2. 判断交点是否在三角形内部
求出交点后,我们需要判断该交点是否在三角形内部。这可以通过重心坐标法来实现
啥是重心坐标:

如图,对于空间三角形P1、P2、P3内任一点P,必定唯一存在三个数w1、w2、w3,满足:
w1+w2+w3=1P=w1∗P1+w2∗P2+w3+P3
w_1+w_2+w_3 = 1 \\
P = w_1 * P_1 + w_2 * P_2 + w_3 + P_3
w1+w2+w3=1P=w1∗P1+w2∗P2+w3+P3
则(w1,w2,w3)就称为此三角形上P点的(归一化)重心坐标。
重心坐标求解
构建方程组,求解P点坐标
{w1+w2+w3=1Px=w1∗P1x+w2∗P2x+w3∗P3xPy=w1∗P1y+w2∗P2y+w3∗P3y={Px−P3x=w1∗(P1x−P3x)+w2∗(P2x−P3x)Py−P3y=w1∗(P1y−P3y)+w2∗(P2y−P3y)w3=1−w1−w2
\begin{cases}
w_1 + w_2 + w_3 = 1 \\
P_x = w_1 * P_{1x} + w_2 * P_{2x} + w_3 * P_{3x} \\
P_y = w_1 * P_{1y} + w_2 * P_{2y} + w_3 * P_{3y}
\end{cases}
=\\
\begin{cases}
P_x - P_{3x} = w_1 * (P_{1x} - P_{3x}) + w_2 * (P_{2x} - P_{3x}) \\
P_y - P_{3y} = w_1 * (P_{1y} - P_{3y}) + w_2 * (P_{2y} - P_{3y}) \\
w_3 = 1 - w_1 - w_2\\
\end{cases}
⎩⎨⎧w1+w2+w3=1Px=w1∗P1x+w2∗P2x+w3∗P3xPy=w1∗P1y+w2∗P2y+w3∗P3y=⎩⎨⎧Px−P3x=w1∗(P1x−P3x)+w2∗(P2x−P3x)Py−P3y=w1∗(P1y−P3y)+w2∗(P2y−P3y)w3=1−w1−w2
设向量C、A、B,分别为C = P - P3,A=P1-P3,B=P2-P3

故方程组可写为如下表达式
{Cx=w1Ax+w2BxCy=w1Ay+w2Byw3=1−w1−w2={w1=CxBy−CyBxAxBy−AyBx=C→×B→A→×B→=(C→×B→)⋅(A→×B→)(A→×B→)⋅(A→×B→)w2=CxAy−CyAxAxBy−AyBx=C→×A→A→×B→=(C→×A→)⋅(A→×B→)(A→×B→)⋅(A→×B→)w3=1−w1−w2
\begin{cases}
C_x = w_1 A_x + w_2 B_x \\
C_y = w_1 A_y + w_2 B_y \\
w_3 = 1 - w_1 - w_2
\end{cases}
= \\
\begin{cases}
w_1 = \frac{C_x B_y - C_yB_x}{A_x B_y - A_yB_x} = \frac{\overrightarrow{C}\times\overrightarrow{B}}{\overrightarrow{A}\times\overrightarrow{B}}=
\frac{(\overrightarrow{C}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}
{(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}\\
w_2 = \frac{C_x A_y - C_yA_x}{A_x B_y - A_yB_x} =\frac{\overrightarrow{C}\times\overrightarrow{A}}{\overrightarrow{A}\times\overrightarrow{B}}
=\frac{(\overrightarrow{C}\times\overrightarrow{A})\cdot(\overrightarrow{A}\times\overrightarrow{B})}
{(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}\\
w_3 = 1 - w_1 - w_2
\end{cases}
⎩⎨⎧Cx=w1Ax+w2BxCy=w1Ay+w2Byw3=1−w1−w2=⎩⎨⎧w1=AxBy−AyBxCxBy−CyBx=A×BC×B=(A×B)⋅(A×B)(C×B)⋅(A×B)w2=AxBy−AyBxCxAy−CyAx=A×BC×A=(A×B)⋅(A×B)(C×A)⋅(A×B)w3=1−w1−w2
以下过程,要将叉乘转为点乘,在<<OpenGL编程指南(原书第9版)>>一书,关于transform feedback的例程中,着色器计算射线与三角形的交点时,用的点乘进行计算,遂进行分析推导,如下:
通过标量三重积公式:
a→⋅(b→×c→)=b→⋅(c→×a→)=c→⋅(a→×b→)
\overrightarrow{a}\cdot(\overrightarrow{b}\times\overrightarrow{c})
=\overrightarrow{b}\cdot(\overrightarrow{c}\times\overrightarrow{a})
=\overrightarrow{c}\cdot(\overrightarrow{a}\times\overrightarrow{b})
a⋅(b×c)=b⋅(c×a)=c⋅(a×b)
可得
w1=(C→×B→)⋅(A→×B→)(A→×B→)⋅(A→×B→)=A→⋅[(C→×B→)×B→](A→×B→)⋅(A→×B→)w2=(C→×A→)⋅(A→×B→)(A→×B→)⋅(A→×B→)=B→⋅[(C→×A→)×A→](A→×B→)⋅(A→×B→)
w_1 = \frac{(\overrightarrow{C}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}
{(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}
= \frac{\overrightarrow{A} \cdot [(\overrightarrow{C}\times\overrightarrow{B})\times\overrightarrow{B}]}{(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}\\
w_2 =\frac{(\overrightarrow{C}\times\overrightarrow{A})\cdot(\overrightarrow{A}\times\overrightarrow{B})}
{(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}
= \frac{\overrightarrow{B} \cdot [(\overrightarrow{C}\times\overrightarrow{A})\times\overrightarrow{A}]}{(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B})}\\
w1=(A×B)⋅(A×B)(C×B)⋅(A×B)=(A×B)⋅(A×B)A⋅[(C×B)×B]w2=(A×B)⋅(A×B)(C×A)⋅(A×B)=(A×B)⋅(A×B)B⋅[(C×A)×A]
通过向量三重积公式:
a→×(b→×c→)=(a→⋅c→)b→−(a→⋅b→)c→
\overrightarrow{a}\times(\overrightarrow{b}\times\overrightarrow{c})
=(\overrightarrow{a}\cdot\overrightarrow{c})\overrightarrow{b} - (\overrightarrow{a}\cdot\overrightarrow{b})\overrightarrow{c}
a×(b×c)=(a⋅c)b−(a⋅b)c
由此可得:
A→⋅[(C→×B→)×B→]=A→⋅((B→⋅B→)C→−(B→⋅C→)B→)=(B→⋅B→)(A→⋅C→)−(B→⋅C→)(A→⋅B→)B→⋅[(C→×A→)×A→]=B→⋅((A→⋅A→)C→−(A→⋅C→)A→)=(A→⋅A→)(B→⋅C→)−(A→⋅C→)(A→⋅B→)
\overrightarrow{A} \cdot [(\overrightarrow{C}\times\overrightarrow{B})\times\overrightarrow{B}]
= \overrightarrow{A} \cdot ((\overrightarrow{B}\cdot\overrightarrow{B})\overrightarrow{C} - (\overrightarrow{B}\cdot\overrightarrow{C})\overrightarrow{B})
=(\overrightarrow{B}\cdot\overrightarrow{B})(\overrightarrow{A} \cdot \overrightarrow{C} ) - (\overrightarrow{B}\cdot\overrightarrow{C})(\overrightarrow{A} \cdot \overrightarrow{B}) \\
\overrightarrow{B} \cdot [(\overrightarrow{C}\times\overrightarrow{A})\times\overrightarrow{A}] =
\overrightarrow{B} \cdot ((\overrightarrow{A}\cdot\overrightarrow{A})\overrightarrow{C} - (\overrightarrow{A}\cdot\overrightarrow{C})\overrightarrow{A}) =
(\overrightarrow{A}\cdot\overrightarrow{A})(\overrightarrow{B}\cdot\overrightarrow{C}) - (\overrightarrow{A}\cdot\overrightarrow{C})(\overrightarrow{A}\cdot\overrightarrow{B})
A⋅[(C×B)×B]=A⋅((B⋅B)C−(B⋅C)B)=(B⋅B)(A⋅C)−(B⋅C)(A⋅B)B⋅[(C×A)×A]=B⋅((A⋅A)C−(A⋅C)A)=(A⋅A)(B⋅C)−(A⋅C)(A⋅B)
而根据拉格朗日恒等式:
(a→⋅b→)2+(a→×b→)⋅(a→×b→)=∥a→∥2∥b→∥2
(\overrightarrow{a} \cdot \overrightarrow{b})^2+(\overrightarrow{a}\times\overrightarrow{b})⋅(\overrightarrow{a}\times\overrightarrow{b})=\lVert\overrightarrow{a}\rVert^2\lVert\overrightarrow{b}\rVert^2
(a⋅b)2+(a×b)⋅(a×b)=∥a∥2∥b∥2
由此可得:
(A→×B→)⋅(A→×B→)=∥A→∥2∥B→∥2−(A→⋅B→)2
(\overrightarrow{A}\times\overrightarrow{B})\cdot(\overrightarrow{A}\times\overrightarrow{B}) =\lVert\overrightarrow{A}\rVert^2\lVert\overrightarrow{B}\rVert^2 - (\overrightarrow{A} \cdot \overrightarrow{B})^2
(A×B)⋅(A×B)=∥A∥2∥B∥2−(A⋅B)2
故
w1=(B→⋅B→)(A→⋅C→)−(B→⋅C→)(A→⋅B→)(A→⋅A→)(B→⋅B→)−(A→⋅B→)(A→⋅B→)w2=(A→⋅A→)(B→⋅C→)−(A→⋅C→)(A→⋅B→)(A→⋅A→)(B→⋅B→)−(A→⋅B→)(A→⋅B→)
w_1 = \frac{(\overrightarrow{B}\cdot\overrightarrow{B})(\overrightarrow{A} \cdot \overrightarrow{C} ) - (\overrightarrow{B}\cdot\overrightarrow{C})(\overrightarrow{A} \cdot \overrightarrow{B}) }{(\overrightarrow{A}\cdot\overrightarrow{A})(\overrightarrow{B}\cdot\overrightarrow{B}) - (\overrightarrow{A} \cdot \overrightarrow{B})(\overrightarrow{A} \cdot \overrightarrow{B})}\\
w_2 =\frac{(\overrightarrow{A}\cdot\overrightarrow{A})(\overrightarrow{B}\cdot\overrightarrow{C}) - (\overrightarrow{A}\cdot\overrightarrow{C})(\overrightarrow{A}\cdot\overrightarrow{B})}{(\overrightarrow{A}\cdot\overrightarrow{A})(\overrightarrow{B}\cdot\overrightarrow{B}) - (\overrightarrow{A} \cdot \overrightarrow{B})(\overrightarrow{A} \cdot \overrightarrow{B})}
w1=(A⋅A)(B⋅B)−(A⋅B)(A⋅B)(B⋅B)(A⋅C)−(B⋅C)(A⋅B)w2=(A⋅A)(B⋅B)−(A⋅B)(A⋅B)(A⋅A)(B⋅C)−(A⋅C)(A⋅B)
着色器代码
原例程代码如下:
bool intersect(vec3 origin, vec3 direction, vec3 v0, vec3 v1, vec3 v2, out vec3 point)
{
vec3 u, v, n;
vec3 w0, w;
float r, a, b;
u = (v1 - v0);
v = (v2 - v0);
n = cross(u, v);
w0 = origin - v0;
a = -dot(n, w0);
b = dot(n, direction);
r = a / b;
if (r < 0.0 || r > 1.0)
return false;
point = origin + r * direction;
float uu, uv, vv, wu, wv, D;
uu = dot(u, u);
uv = dot(u, v);
vv = dot(v, v);
w = point - v0;
wu = dot(w, u);
wv = dot(w, v);
D = uv * uv - uu * vv;
float s, t;
s = (uv * wv - vv * wu) / D;
if (s < 0.0 || s > 1.0)
return false;
t = (uv * wu - uu * wv) / D;
if (t < 0.0 || (s + t) > 1.0)
return false;
return true;
}
为了更清楚的与上面对应,变量改为如下
bool intersect(vec3 P0, vec3 u, vec3 P1, vec3 P2, vec3 P3, out vec3 P)
{
vec3 A, B, n;
vec3 w0, w;
float t, a, b;
//三角形边向量,以及法向量
A = (P1 - P3);
B = (P2 - P3);
n = cross(A, B);
w0 = P0 - P3;
a = -dot(n, w0);
b = dot(n, u);
//求参数t
t = a / b;
//t < 0.0,交点在射线起点之前
//t > 1.0,交点在射线延伸方向之外
if (t < 0.0 || t > 1.0)
return false;
//计算交点
P = P0 + r * u;
float AA, AB, BB, CA, CB, D;
AA = dot(A, A);
AB = dot(A, B);
BB = dot(B, B);
C = P - P3;
CA = dot(C, A);
CB = dot(C, B);
D = AB * AB - AA * BB;
float w1, w2;
w1 = (AB * CB - BB * CA) / D;
if (w1 < 0.0 || w1 > 1.0)
return false;
w2 = (AB * CA - AA * CB) / D;
if (w2 < 0.0 || (w1 + w2) > 1.0)
return false;
return true;
}
329





