计算三维空间中直线和三角形的交点
前言
在3D编程中,处理点击事件等时可能会遇到判断鼠标是否点击了指定模型的问题,实际上该问题可以拆成几部分考虑:
- 根据三点确定一个平面,及两点确定一条直线的原理,可求出直线方程与平面方程。
- 两方程联立,可解出直线与平面交点坐标(暂不考虑直线在平面上或与平面平行的情况 )。
- 判断平面与直线的交点是否在三角形内部。
一、计算平面方程
3维空间中的平面方程通式为
a
x
+
b
y
+
c
z
+
d
=
0
ax+by+cz+d=0
ax+by+cz+d=0
P
1
(
x
1
,
y
1
,
z
1
)
P_1(x_1,y_1,z_1)
P1(x1,y1,z1)、
P
2
(
x
2
,
y
2
,
z
2
)
P_2(x_2,y_2,z_2)
P2(x2,y2,z2)、
P
3
(
x
3
,
y
3
,
z
3
)
P_3(x_3,y_3,z_3)
P3(x3,y3,z3) 为三角形三个顶点坐标
判断平面是否过原点的计算方式为 : 如果行列式 [ x 1 y 1 z 1 x 2 y 2 z 2 x 3 y 3 z 3 ] = 0 \left[ \begin{matrix} x_1 & y_1 & z_1 \\ x_2 & y_2 & z_2 \\ x_3 & y_3 & z_3 \end{matrix} \right]=0 ⎣⎡x1x2x3y1y2y3z1z2z3⎦⎤=0,平面过原点 ; 否则平面不过原点。
判断平面是否过 z z z 轴的计算方式为 : 在平面过原点的情况下,如果行列式 [ x 1 y 1 x 2 y 2 ] = 0 \left[ \begin{matrix} x_1 & y_1 \\ x_2 & y_2 \end{matrix} \right]=0 [x1x2y1y2]=0,平面过 z z z 轴 ; 否则平面不过 z z z 轴。
判断平面是否为 y O z yOz yOz 平面的计算方式为 : 在平面过 z z z 轴的情况下,如果 x 1 = 0 x_1=0 x1=0,平面为 y O z yOz yOz 平面 ; 否则平面不为 y O z yOz yOz 平面。
1.1 平面不过原点
如果平面不过原点,则 d ≠ 0 d \neq 0 d=0,由于三个点只能确定三个未知数,设 d = − 1 d=-1 d=−1,则方程为 a x + b y + c z = 1 ax+by+cz=1 ax+by+cz=1
分别将平面上的三个点
P
1
、
P
2
、
P
3
P_1、P_2、P_3
P1、P2、P3 代入公式,可得
{
a
x
1
+
b
y
1
+
c
z
1
=
1
a
x
2
+
b
y
2
+
c
z
2
=
1
a
x
3
+
b
y
3
+
c
z
3
=
1
\begin{cases} ax_1+by_1+cz_1=1 \\ ax_2+by_2+cz_2=1 \\ ax_3+by_3+cz_3=1 \end{cases}
⎩⎪⎨⎪⎧ax1+by1+cz1=1ax2+by2+cz2=1ax3+by3+cz3=1
转化为矩阵,即为
[
x
1
y
1
z
1
x
2
y
2
z
2
x
3
y
3
z
3
]
[
a
b
c
]
=
[
1
1
1
]
\left[ \begin{matrix} x_1 & y_1 & z_1 \\ x_2 & y_2 & z_2 \\ x_3 & y_3 & z_3 \end{matrix} \right] \left[ \begin{matrix} a \\ b \\ c \end{matrix} \right] = \left[ \begin{matrix} 1 \\ 1 \\ 1 \end{matrix} \right]
⎣⎡x1x2x3y1y2y3z1z2z3⎦⎤⎣⎡abc⎦⎤=⎣⎡111⎦⎤
求解
a
,
b
,
c
a,b,c
a,b,c,即
[
a
b
c
]
=
[
x
1
y
1
z
1
x
2
y
2
z
2
x
3
y
3
z
3
]
−
1
[
1
1
1
]
\left[ \begin{matrix} a \\ b \\ c \end{matrix} \right] = \left[ \begin{matrix} x_1 & y_1 & z_1 \\ x_2 & y_2 & z_2 \\ x_3 & y_3 & z_3 \end{matrix} \right] ^{-1} \left[ \begin{matrix} 1 \\ 1 \\ 1 \end{matrix} \right]
⎣⎡abc⎦⎤=⎣⎡x1x2x3y1y2y3z1z2z3⎦⎤−1⎣⎡111⎦⎤
即:将三个点坐标列为矩阵,求逆,然后右乘一个单位列向量,即可求出参数矩阵。
1.2 平面过原点
如果平面过原点,则
d
=
0
d=0
d=0,设
c
=
1
,
c=1,
c=1,,则方程为
a
x
+
b
y
+
z
=
0
ax+by+z=0
ax+by+z=0,此时只有两个未知数,只需要代入两个坐标点即可(两个坐标点都不可为原点 ),方程组为
{
a
x
1
+
b
y
1
=
−
z
1
a
x
2
+
b
y
2
=
−
z
2
\begin{cases} ax_1+by_1=-z_1 \\ ax_2+by_2=-z_2 \end{cases}
{ax1+by1=−z1ax2+by2=−z2
转化为矩阵,即为
[
x
1
y
1
x
2
y
2
]
[
a
b
]
=
[
−
z
1
−
z
2
]
\left[ \begin{matrix} x_1 & y_1 \\ x_2 & y_2 \end{matrix} \right] \left[ \begin{matrix} a \\ b \end{matrix} \right] = \left[ \begin{matrix} -z_1 \\ -z_2 \end{matrix} \right]
[x1x2y1y2][ab]=[−z1−z2]
求解
a
、
b
a、b
a、b,即
[
a
b
]
=
[
x
1
y
1
x
2
y
2
]
−
1
[
−
z
1
−
z
2
]
\left[ \begin{matrix} a \\ b \end{matrix} \right] = \left[ \begin{matrix} x_1 & y_1 \\ x_2 & y_2 \end{matrix} \right] ^{-1} \left[ \begin{matrix} -z_1 \\ -z_2 \end{matrix} \right]
[ab]=[x1x2y1y2]−1[−z1−z2]
{ c = 1 d = 0 \begin{cases} c=1 \\ d=0 \end{cases} {c=1d=0
1.3 平面过 z z z 轴
如果平面过
z
z
z 轴,则
c
=
d
=
0
c=d=0
c=d=0,设
b
=
1
,
b=1,
b=1,,则方程为
a
x
+
y
=
0
ax+y=0
ax+y=0,此时只有一个未知数,只需要代入一个坐标点即可(该坐标点
x
、
y
x、y
x、y 分量不可均为0 ),方程为
a
x
1
+
y
1
=
0
ax_1+y_1=0
ax1+y1=0
解得
{
a
=
−
y
1
z
1
b
=
1
c
=
0
d
=
0
\begin{cases} a=-\frac{y_1}{z_1} \\ b=1 \\ c=0 \\ d=0 \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧a=−z1y1b=1c=0d=0
1.4 平面为 y O z yOz yOz 平面
如果平面为
y
O
z
yOz
yOz 平面,则
{
a
=
1
b
=
0
c
=
0
d
=
0
\begin{cases} a=1 \\ b=0 \\ c=0 \\ d=0 \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧a=1b=0c=0d=0
至此, a , b , c , d a,b,c,d a,b,c,d 全部求出。
二、计算直线方程
3维空间中的直线方程通式为
x
−
x
1
x
−
x
2
=
y
−
y
1
y
−
y
2
=
z
−
z
1
z
−
z
2
=
t
\frac{x-x_1}{x-x_2}=\frac{y-y_1}{y-y_2}=\frac{z-z_1}{z-z_2}=t
x−x2x−x1=y−y2y−y1=z−z2z−z1=t
其中
P
1
(
x
1
,
y
1
,
z
1
)
P_1(x_1,y_1,z_1)
P1(x1,y1,z1)、
P
2
(
x
2
,
y
2
,
z
2
)
P_2(x_2,y_2,z_2)
P2(x2,y2,z2) 为直线上不重合的两个点,t为参数,值为点
P
(
x
,
y
,
z
)
P(x,y,z)
P(x,y,z) 到两点的距离比。
整理后可得
{
x
=
t
x
2
−
x
1
t
−
1
y
=
t
y
2
−
y
1
t
−
1
z
=
t
z
2
−
z
1
t
−
1
\begin{cases} x=\frac{tx_2-x_1}{t-1} \\ y=\frac{ty_2-y_1}{t-1} \\ z=\frac{tz_2-z_1}{t-1} \end{cases}
⎩⎪⎨⎪⎧x=t−1tx2−x1y=t−1ty2−y1z=t−1tz2−z1
三、计算交点坐标
联立方程组
{
x
=
t
x
2
−
x
1
t
−
1
y
=
t
y
2
−
y
1
t
−
1
z
=
t
z
2
−
z
1
t
−
1
−
−
−
−
−
−
−
−
−
−
(
3.1
)
\begin{cases} x=\frac{tx_2-x_1}{t-1} \\ y=\frac{ty_2-y_1}{t-1} \\ z=\frac{tz_2-z_1}{t-1} \end{cases} ----------(3.1)
⎩⎪⎨⎪⎧x=t−1tx2−x1y=t−1ty2−y1z=t−1tz2−z1−−−−−−−−−−(3.1)
a x + b y + c z + d = 0 − − − − − − − − − − ( 3.2 ) ax+by+cz+d=0 ----------(3.2) ax+by+cz+d=0−−−−−−−−−−(3.2)
可得
a
t
x
2
−
x
1
t
−
1
+
b
t
y
2
−
y
1
t
−
1
+
c
t
z
2
−
z
1
t
−
1
+
d
=
0
a\frac{tx_2-x_1}{t-1}+b\frac{ty_2-y_1}{t-1}+c\frac{tz_2-z_1}{t-1}+d=0
at−1tx2−x1+bt−1ty2−y1+ct−1tz2−z1+d=0
整理得
t
=
a
x
1
+
b
y
1
+
c
z
1
+
d
a
x
2
+
b
y
2
+
c
z
2
+
d
t=\frac{ax_1+by_1+cz_1+d}{ax_2+by_2+cz_2+d}
t=ax2+by2+cz2+dax1+by1+cz1+d
若 a x 2 + b y 2 + c z 2 + d = 0 ax_2+by_2+cz_2+d=0 ax2+by2+cz2+d=0,则交点为 P 2 P_2 P2 ; 否则将 t t t 代入式(3.1),可解出交点坐标。
四、判断交点是否在三角形内部
三角形ABC的三个点在同一个平面上,如果选中其中一个点,其他两个点不过是相对该点的位移而已,比如选择点
A
A
A 作为起点,那么点
B
B
B 相当于在
A
B
→
\overrightarrow{AB}
AB 方向移动一段距离得到,而点
C
C
C 相当于在
A
C
→
\overrightarrow{AC}
AC 方向移动一段距离得到。所以对于平面内任意一点,都可以由如下方程来表示 :
A
P
→
=
u
∗
A
B
→
+
v
∗
A
C
→
\overrightarrow{AP}=u*\overrightarrow{AB}+v*\overrightarrow{AC}
AP=u∗AB+v∗AC
如果系数
u
u
u 或
v
v
v 为负值,那么相当于朝相反的方向移动,即
B
A
→
\overrightarrow{BA}
BA 或
C
A
→
\overrightarrow{CA}
CA 方向。那么如果想让
P
P
P 位于三角形
A
B
C
ABC
ABC 内部,
u
u
u 和
v
v
v 必须满足什么条件呢?有如下三个条件:
{
u
≥
0
v
≥
0
u
+
v
<
=
1
\begin{cases} u \geq 0 \\ v \geq 0 \\ u + v <= 1 \end{cases}
⎩⎪⎨⎪⎧u≥0v≥0u+v<=1
几个边界情况,当 u = v = 0 u=v=0 u=v=0 时,就是点A,当 u = 0 , v = 1 u=0,v=1 u=0,v=1 时,就是点B,而当 u = 1 , v = 0 u=1,v=0 u=1,v=0 时,就是点C。
令
v
0
=
A
C
→
,
v
1
=
A
B
→
,
v
2
=
A
P
→
v_0=\overrightarrow{AC},v_1=\overrightarrow{AB},v_2=\overrightarrow{AP}
v0=AC,v1=AB,v2=AP,则
v
2
=
u
∗
v
0
+
v
∗
v
1
v_2=u*v_0+v*v_1
v2=u∗v0+v∗v1,现在是一个方程,两个未知数,无法解出
u
u
u 和
v
v
v,将等式两边分别点乘
v
0
v_0
v0 和
v
1
v_1
v1,得到两个等式 :
{
(
v
2
)
•
v
0
=
(
u
∗
v
0
+
v
∗
v
1
)
•
v
0
(
v
2
)
•
v
1
=
(
u
∗
v
0
+
v
∗
v
1
)
•
v
1
\begin{cases} (v2)•v0=(u*v0+v*v1)•v0 \\ (v2)•v1=(u*v0+v*v1)•v1 \end{cases}
{(v2)•v0=(u∗v0+v∗v1)•v0(v2)•v1=(u∗v0+v∗v1)•v1
注意到这里
u
、
v
u、v
u、v 是数,而
v
0
、
v
1
、
v
2
v_0、v_1、v_2
v0、v1、v2 是向量,所以可以将点积展开得到下面的式子 :
{
v
2
•
v
0
=
u
∗
(
v
0
•
v
0
)
+
v
∗
(
v
1
•
v
0
)
v
2
•
v
1
=
u
∗
(
v
0
•
v
1
)
+
v
∗
(
v
1
•
v
1
)
\begin{cases} v2•v0=u*(v0•v0)+v*(v1•v0) \\ v2•v1=u*(v0•v1)+v*(v1•v1) \end{cases}
{v2•v0=u∗(v0•v0)+v∗(v1•v0)v2•v1=u∗(v0•v1)+v∗(v1•v1)
解这个方程得到
{
u
=
(
(
v
1
•
v
1
)
(
v
2
•
v
0
)
−
(
v
1
•
v
0
)
(
v
2
•
v
1
)
)
/
(
(
v
0
•
v
0
)
(
v
1
•
v
1
)
−
(
v
0
•
v
1
)
(
v
1
•
v
0
)
)
v
=
(
(
v
0
•
v
0
)
(
v
2
•
v
1
)
−
(
v
0
•
v
1
)
(
v
2
•
v
0
)
)
/
(
(
v
0
•
v
0
)
(
v
1
•
v
1
)
−
(
v
0
•
v
1
)
(
v
1
•
v
0
)
)
\begin{cases} u=((v1•v1)(v2•v0)-(v1•v0)(v2•v1))/((v0•v0)(v1•v1)-(v0•v1)(v1•v0)) \\ v=((v0•v0)(v2•v1)-(v0•v1)(v2•v0))/((v0•v0)(v1•v1)-(v0•v1)(v1•v0)) \end{cases}
{u=((v1•v1)(v2•v0)−(v1•v0)(v2•v1))/((v0•v0)(v1•v1)−(v0•v1)(v1•v0))v=((v0•v0)(v2•v1)−(v0•v1)(v2•v0))/((v0•v0)(v1•v1)−(v0•v1)(v1•v0))
解出 u 、 v u、v u、v 后,根据上面的规则,即可判断点 P P P 是否在三角形 A B C ABC ABC 内部。