射线
已知射线方程为 P ( t ) = P ˉ + t ∗ D ˉ P(t)=\bar{P}+t*\bar{D} P(t)=Pˉ+t∗Dˉ,其中 P ˉ \bar{P} Pˉ为射线的起点 ( x 0 , y 0 , z 0 ) (x_0,y_0,z_0) (x0,y0,z0), D ˉ \bar{D} Dˉ为射线的方向向量,其模长为 1 1 1,只要知道距离 t t t,我们就可以计算出对应点的坐标。
球体求交
不妨设球体的方程为
(
X
ˉ
−
C
ˉ
)
2
=
R
2
(\bar{X}-\bar{C})^2=R^2
(Xˉ−Cˉ)2=R2,其中
X
ˉ
\bar{X}
Xˉ为球体上任意一点的坐标,
C
ˉ
\bar{C}
Cˉ为球心,
R
R
R为半径。射线与球体求交,首先需要将射线方程作为
X
ˉ
\bar{X}
Xˉ带入球体方程,然后把
t
t
t作为未知变量,化简即可得到下式:
D
2
t
2
+
2
(
P
ˉ
∗
D
ˉ
−
C
ˉ
∗
D
ˉ
)
t
−
2
C
ˉ
∗
P
ˉ
+
P
2
+
C
2
−
R
2
=
0
D^2t^2+2(\bar{P}*\bar{D}-\bar{C}*\bar{D})t-2\bar{C}*\bar{P}+P^2+C^2-R^2=0
D2t2+2(Pˉ∗Dˉ−Cˉ∗Dˉ)t−2Cˉ∗Pˉ+P2+C2−R2=0
显然我们可以把上式当作一个关于
t
t
t的一元二次方程:
a
t
2
+
b
t
+
c
=
0
at^2+bt+c=0
at2+bt+c=0,判断是否存在交点即判断该一元二次方程的判别式:
Δ
=
b
2
−
4
∗
a
∗
c
Δ=b^2-4*a*c
Δ=b2−4∗a∗c是否大于等于
0
0
0,如果是的话说明方程有解,通过求根公式得到两个解:
t
1
=
−
b
2
−
4
a
c
/
(
2
∣
a
∣
)
−
b
/
(
2
a
)
t_1=-\sqrt{b^2-4ac}/(2|a|)-b/(2a)
t1=−b2−4ac/(2∣a∣)−b/(2a)
t
2
=
b
2
−
4
a
c
/
(
2
∣
a
∣
)
−
b
/
(
2
a
)
t_2=\sqrt{b^2-4ac}/(2|a|)-b/(2a)
t2=b2−4ac/(2∣a∣)−b/(2a)排除掉无效解(<0的解)后,取最小的那个解即可。
三角求交
这个过程可以分成两步,
(
1
)
(1)
(1)计算射线和平面
A
B
C
ABC
ABC的交点
Q
Q
Q;
(
2
)
(2)
(2)判断
Q
Q
Q是否在三角形
A
B
C
ABC
ABC内部。
计算交点Q
我们知道一个平面方程可以写成
a
x
+
b
y
+
c
z
=
d
ax+by+cz=d
ax+by+cz=d的形式,且这个平面的法向量为
(
a
,
b
,
c
)
(a,b,c)
(a,b,c),证明如下:在平面上任取两点
A
、
B
A、B
A、B,显然有
a
x
1
+
b
y
1
+
c
z
1
=
d
,
a
x
2
+
b
y
2
+
c
z
2
=
d
ax_1+by_1+cz_1=d,ax_2+by_2+cz_2=d
ax1+by1+cz1=d,ax2+by2+cz2=d,两式相减可得:
a
(
x
2
−
x
1
)
+
b
(
y
2
−
y
1
)
+
c
(
z
2
−
z
1
)
=
0
a(x_2-x_1)+b(y_2-y_1)+c(z_2-z_1)=0
a(x2−x1)+b(y2−y1)+c(z2−z1)=0,假设
n
=
(
a
,
b
,
c
)
n=(a,b,c)
n=(a,b,c),上市其实就等于
n
ˉ
∗
A
B
ˉ
=
0
\bar{n}*\bar{AB}=0
nˉ∗ABˉ=0,所以
n
ˉ
\bar{n}
nˉ就是平面的法向量。那么这个平面方程可以写成:
n
ˉ
∗
x
ˉ
=
d
\bar{n}*\bar{x}=d
nˉ∗xˉ=d,将射线方程带入化简可得:
所以我们需要先判断
n
ˉ
∗
d
ˉ
\bar{n}*\bar{d}
nˉ∗dˉ是否为
0
0
0,如果为
0
0
0说明射线和平面平行,否则可以根据上式计算出
t
t
t从而计算出
Q
Q
Q的坐标。
关于平面的一些问题
上面的推导来源于平面方程
a
x
+
b
y
+
c
z
=
d
ax+by+cz=d
ax+by+cz=d,然而现在我们仅仅知道三角形三个顶点
A
、
B
、
C
A、B、C
A、B、C的坐标,如何计算
n
ˉ
\bar{n}
nˉ和
d
d
d就成为一个问题。计算法向量比较简单,利用叉积即可完成:
n
ˉ
=
A
B
ˉ
×
A
C
ˉ
\bar{n}=\bar{AB}×\bar{AC}
nˉ=ABˉ×ACˉ(记得归一化),那么由之前的推导可知
d
=
n
ˉ
∗
x
ˉ
d=\bar{n}*\bar{x}
d=nˉ∗xˉ,
x
ˉ
\bar{x}
xˉ为平面内任意点的坐标,我们可以选取顶点
A
A
A:
d
=
n
ˉ
∗
A
d=\bar{n}*A
d=nˉ∗A(上面这个英文
p
d
f
pdf
pdf写得这么多,只是在探讨叉积的方向问题)。
判断Q是否在三角形内部
简单来说,就是通过叉乘的方向来判断。可以看上面的图示,感觉比较清晰。这个操作我们称为
3
D
i
n
s
i
d
e
−
o
u
t
s
i
d
e
t
e
s
t
3D\ inside-outside\ test
3D inside−outside test
3
D
3D
3D内外检测需要的计算量比较大,我们可以考虑将三角形投影到
2
D
2D
2D平面上,然后再做
2
D
i
n
s
i
d
e
−
o
u
t
s
i
d
e
t
e
s
t
2D\ inside-outside\ test
2D inside−outside test。如何选择投影平面呢?首先计算出法向量
N
ˉ
\bar{N}
Nˉ,取它的三个维度
x
、
y
、
z
x、y、z
x、y、z中绝对值最大的那个维度消去即可。比如
N
ˉ
=
(
0
,
0
,
−
1
)
\bar{N}=(0,0,-1)
Nˉ=(0,0,−1),就消去维度
z
z
z,将其投影到
x
O
y
xOy
xOy平面上。
计算重心坐标
我们称
α
、
β
、
γ
α、β、γ
α、β、γ为
Q
Q
Q的关于
A
、
B
、
C
A、B、C
A、B、C的重心坐标。
α
、
β
、
γ
α、β、γ
α、β、γ可以通过面积比来计算出来,如下图:
重心坐标可以用于插值,比如材质性能、纹理坐标、法向量。其中法向量插值又称为
P
h
o
n
g
Phong
Phong插值,可以为三角形网格提供更加平滑的着色外观。下面介绍一下法向量插值:
根据三角形面积的比值计算出
α
、
β
、
γ
α、β、γ
α、β、γ,然后根据三个顶点的法向量进行插值,
N
Q
N_Q
NQ可以用于后续的着色、反射和折射计算。