空间图形的几何表示
曲线
什么是埃尔米特曲线?
**埃尔米特曲线(Hermit)**是一种插值曲线,也是样条曲线家族中最好理解的一种曲线。
Hermit曲线给定曲线两个端点的位置矢量P 0 P_0 P 0 、P 1 P_1 P 1 和切线矢量T 0 T_0 T 0 、T 1 T_1 T 1 ,通过插值获得曲线在定义域[0,1]上的三次参数方程:
我们设目标参数方程为P ( t ) = a t 3 + b t 2 + c t + d P(t)=at^3+bt^2+ct+d P ( t ) = a t 3 + b t 2 + c t + d ,则有P ′ ( t ) = 3 a t 2 + 2 b t + c P'(t)=3at^2+2bt+c P ′ ( t ) = 3 a t 2 + 2 b t + c ,将0和1代入t易得:{ P ( 0 ) = d P ( 1 ) = a + b + c + d P ′ ( 0 ) = c P ′ ( 1 ) = 3 a + 2 b + c (14)
\left \{ \begin{array}{c}
\ P(0)&=&d\\\ P(1)&=&a+b+c+d\\\ P'(0)&=&c\\\ P'(1)&=&3a+2b+c
\end{array}\right.\tag{14}
⎩ ⎪ ⎪ ⎨ ⎪ ⎪ ⎧ P ( 0 ) P ( 1 ) P ′ ( 0 ) P ′ ( 1 ) = = = = d a + b + c + d c 3 a + 2 b + c ( 1 4 )
现在我们设h 0 = P ( 0 ) , h 1 = P ( 1 ) , h 2 = P ′ ( 0 ) , h 3 = P ′ ( 1 ) h_0=P(0),h_1=P(1),h_2=P'(0),h_3=P'(1) h 0 = P ( 0 ) , h 1 = P ( 1 ) , h 2 = P ′ ( 0 ) , h 3 = P ′ ( 1 ) ,则有:[ h 0 h 1 h 2 h 3 ] = [ 0 0 0 1 1 1 1 1 0 0 1 0 3 2 1 0 ] [ a b c d ] ⇒ [ a b c d ] = [ 2 − 2 1 1 − 3 3 − 2 − 1 0 0 1 0 1 0 0 0 ] [ h 0 h 1 h 2 h 3 ]
\begin{bmatrix}
h_0\\h_1\\h_2\\h_3
\end{bmatrix}=\begin{bmatrix}
0&0&0&1\\1&1&1&1\\0&0&1&0\\3&2&1&0
\end{bmatrix}\begin{bmatrix}
a\\b\\c\\d
\end{bmatrix}\\\Rightarrow\begin{bmatrix}
a\\b\\c\\d
\end{bmatrix}=\begin{bmatrix}
2&-2&1&1\\-3&3&-2&-1\\0&0&1&0\\1&0&0&0
\end{bmatrix}\begin{bmatrix}
h_0\\h_1\\h_2\\h_3
\end{bmatrix}
⎣ ⎢ ⎢ ⎡ h 0 h 1 h 2 h 3 ⎦ ⎥ ⎥ ⎤ = ⎣ ⎢ ⎢ ⎡ 0 1 0 3 0 1 0 2 0 1 1 1 1 1 0 0 ⎦ ⎥ ⎥ ⎤ ⎣ ⎢ ⎢ ⎡ a b c d ⎦ ⎥ ⎥ ⎤ ⇒ ⎣ ⎢ ⎢ ⎡ a b c d ⎦ ⎥ ⎥ ⎤ = ⎣ ⎢ ⎢ ⎡ 2 − 3 0 1 − 2 3 0 0 1 − 2 1 0 1 − 1 0 0 ⎦ ⎥ ⎥ ⎤ ⎣ ⎢ ⎢ ⎡ h 0 h 1 h 2 h 3 ⎦ ⎥ ⎥ ⎤
我们将参数方程P ( t ) = a t 3 + b t 2 + c t + d P(t)=at^3+bt^2+ct+d P ( t ) = a t 3 + b t 2 + c t + d 写成矩阵形式:P ( t ) = [ a b c d ] [ t 3 t 2 t 1 ]
P(t)=\begin{bmatrix}
a&b&c&d
\end{bmatrix}\begin{bmatrix}
t^3\\t^2\\t\\1
\end{bmatrix}
P ( t ) = [ a b c d ] ⎣ ⎢ ⎢ ⎡ t 3 t 2 t 1 ⎦ ⎥ ⎥ ⎤
将列向量abcd的表达式转置,代入上式,得到:P ( t ) = [ h 0 h 1 h 2 h 3 ] [ 2 − 3 0 1 − 2 3 0 0 1 − 2 1 0 1 − 1 0 0 ] [ t 3 t 2 t 1 ]
P(t)=\begin{bmatrix}
h_0&h_1&h_2&h_3
\end{bmatrix}\begin{bmatrix}
2&-3&0&1\\-2&3&0&0\\1&-2&1&0\\1&-1&0&0
\end{bmatrix}\begin{bmatrix}
t^3\\t^2\\t\\1
\end{bmatrix}
P ( t ) = [ h 0 h 1 h 2 h 3 ] ⎣ ⎢ ⎢ ⎡ 2 − 2 1 1 − 3 3 − 2 − 1 0 0 1 0 1 0 0 0 ⎦ ⎥ ⎥ ⎤ ⎣ ⎢ ⎢ ⎡ t 3 t 2 t 1 ⎦ ⎥ ⎥ ⎤
将后两项乘起来可以得到:
P ( t ) = ∑ i = 0 3 h i H i ( t )
P(t)=\sum_{i=0}^3h_iH_i(t)\\
P ( t ) = i = 0 ∑ 3 h i H i ( t )
其中h 1 = P ( 0 ) = P 0 h_1=P(0)=P_0 h 1 = P ( 0 ) = P 0 ,h 2 = P ( 1 ) = P 1 h_2=P(1)=P_1 h 2 = P ( 1 ) = P 1 ,h 3 = P ′ ( 0 ) = T 0 h_3=P'(0)=T_0 h 3 = P ′ ( 0 ) = T 0 ,0h 4 = P ′ ( 1 ) = T 1 h_4=P'(1)=T_1 h 4 = P ′ ( 1 ) = T 1 。
什么是贝塞尔曲线?
贝塞尔曲线也是参数格式的曲线,n阶贝塞尔曲线是n次参数方程,其原理图如下:
贝塞尔曲线完全由其控制点决定其形状,n个控制点对应着n-1阶的贝塞尔曲线,并且可以通过递归的方式来绘制。贝塞尔曲线是典型的递归法曲线。
一阶贝塞尔曲线就是对两个控制点进行线性插值,其参数方程为:B 1 ( t ) = P 0 + ( P 1 − P 0 ) t = ( 1 − t ) P 0 + t P 1 , t ∈ [ 0 , 1 ]
B_1(t)=P_0+(P_1-P_0)t=(1-t)P_0+tP_1,t\in[0,1]
B 1 ( t ) = P 0 + ( P 1 − P 0 ) t = ( 1 − t ) P 0 + t P 1 , t ∈ [ 0 , 1 ]
二阶贝塞尔曲线由三个控制点组成,假设三个控制点依次为P0 、P1 、P2 ,先分别对P0 P1 和P1 P2 两段进行线性插值得到两个新控制点P0 ’、P1 ’,将二阶贝塞尔曲线降为一阶:P 0 ′ = ( 1 − t ) P 0 + t P 1 P 1 ′ = ( 1 − t ) P 1 + t P 2
P'_0=(1-t)P_0+tP_1\\
P'_1=(1-t)P_1+tP_2
P 0 ′ = ( 1 − t ) P 0 + t P 1 P 1 ′ = ( 1 − t ) P 1 + t P 2
然后再对P0 ’P1 ’求线性插值:B 2 ( t ) = ( 1 − t ) P 0 ′ + t P 1 ′ = ( 1 − t ) 2 P 0 + 2 t ( 1 − t ) P 1 + t 2 P 2
B_2(t)=(1-t)P'_0+tP'_1=(1-t)^2P_0+2t(1-t)P_1+t^2P_2
B 2 ( t ) = ( 1 − t ) P 0 ′ + t P 1 ′ = ( 1 − t ) 2 P 0 + 2 t ( 1 − t ) P 1 + t 2 P 2
三阶贝塞尔曲线由四个控制点组成,假设四个控制点依次为P0 、P1 、P2 、P3 ,先分别对P0 P1 、P1 P2 和P2 P3 三段求线性插值得到三个新控制点P0 ’、P1 ’、P2 ’,将三阶贝塞尔曲线降为二阶:P 0 ′ = ( 1 − t ) P 0 + t P 1 P 1 ′ = ( 1 − t ) P 1 + t P 2 P 2 ′ = ( 1 − t ) P 2 + t P 3
P'_0=(1-t)P_0+tP_1\\
P'_1=(1-t)P_1+tP_2\\
P'_2=(1-t)P_2+tP_3
P 0 ′ = ( 1 − t ) P 0 + t P 1 P 1 ′ = ( 1 − t ) P 1 + t P 2 P 2 ′ = ( 1 − t ) P 2 + t P 3
然后再利用新控制点求二阶贝塞尔曲线:P 0 ′ ′ = ( 1 − t ) P 0 ′ + t P 1 ′ P 1 ′ ′ = ( 1 − t ) P 1 ′ + t P 2 ′
P''_0=(1-t)P'_0+tP'_1\\
P''_1=(1-t)P'_1+tP'_2
P 0 ′ ′ = ( 1 − t ) P 0 ′ + t P 1 ′ P 1 ′ ′ = ( 1 − t ) P 1 ′ + t P 2 ′
最后对P0 ’‘和P1 ’'进行线性插值:B 3 ( t ) = ( 1 − t ) P 0 ′ ′ + t P 1 ′ ′ = ( 1 − t ) 3 P 0 + 3 t ( 1 − t ) 2 P 1 + 3 t 2 ( 1 − t ) P 2 + t 3 P 3
B_3(t)=(1-t)P''_0+tP''_1=(1-t)^3P_0+3t(1-t)^2P_1+3t^2(1-t)P_2+t^3P_3
B 3 ( t ) = ( 1 − t ) P 0 ′ ′ + t P 1 ′ ′ = ( 1 − t ) 3 P 0 + 3 t ( 1 − t ) 2 P 1 + 3 t 2 ( 1 − t ) P 2 + t 3 P 3
不难发现,n阶贝塞尔曲线展开式系数是n阶二项式展开系数,可以得到n阶贝塞尔曲线的通项公式:B n ( t ) = ∑ i = 0 n n ! i ! ( n − i ) ! t i ( 1 − t ) n − i P i , t ∈ [ 0 , 1 ]
B_n(t)=\sum_{i=0}^n\frac{n!}{i!(n-i)!}t^i(1-t)^{n-i}P_i,\ t\in[0,1]
B n ( t ) = i = 0 ∑ n i ! ( n − i ) ! n ! t i ( 1 − t ) n − i P i , t ∈ [ 0 , 1 ]
其中,n阶贝塞尔曲线的第i项系数Bi,n (t)又被记作Bernstein基函数 。B i , n ( t ) = n ! i ! ( n − i ) ! t i ( 1 − t ) n − 1 B n ( t ) = B i , n ( t ) P i , t ∈ [ 0 , 1 ]
B_{i,n}(t)=\frac{n!}{i!(n-i)!}t^i(1-t)^{n-1}\\
B_n(t)=B_{i,n}(t)P_i,\ t\in[0,1]
B i , n ( t ) = i ! ( n − i ) ! n ! t i ( 1 − t ) n − 1 B n ( t ) = B i , n ( t ) P i , t ∈ [ 0 , 1 ]
对n阶贝塞尔曲线进行求导可得:B n ′ ( t ) = ∑ i = 0 n − 1 B i , n − 1 ( t ) [ n ( P i + 1 − P i ) ] , t ∈ [ 0 , 1 ]
B'_n(t)=\sum_{i=0}^{n-1}B_{i,n-1}(t)[n(P_{i+1}-P_i)],\ t\in[0,1]
B n ′ ( t ) = i = 0 ∑ n − 1 B i , n − 1 ( t ) [ n ( P i + 1 − P i ) ] , t ∈ [ 0 , 1 ]
经观察,n阶贝塞尔曲线的导数显然是n-1阶贝塞尔曲线,其控制点为原曲线控制点的组合。
贝塞尔曲线具有端点性质 :第一个控制点和最后一个控制点恰好是曲线的起点和重点。
贝塞尔曲线具有凸包性质 :贝塞尔曲线始终位于包含了所有控制点的最小凸多边形 中。注意,不是按控制点顺序围成的凸多边形。
贝塞尔曲线具有端点导数性质 :贝塞尔曲线在P0 和Pn 处的斜率分别等于直线P0 P1 和直线Pn-1 Pn 的斜率,即贝塞尔曲线端点的一阶导数仅同其相邻的一条边向量有关,与更远的各边无关。推广的,贝塞尔曲线端点的r阶导数仅同其相邻的r条边向量有关,与更远的各边无关。
贝塞尔曲线最大的问题在于,高阶贝塞尔曲线的路径不够直观,很难让美术人员利用贝塞尔曲线进行设计。但我们注意到,由于贝塞尔曲线具有端点性质和端点导数性质,二阶和三阶贝塞尔曲线的形状相对直观。所以在实际使用中我们会讨论到将多个贝塞尔曲线尤其是二、三阶贝塞尔曲线拼接成直观曲线的算法。
如何拼接贝塞尔曲线?
我们先聊聊什么是连续性 。
在讨论曲线连续性时,我们经常见到Cn 连续 和Gn 连续 的说法。如果不同曲线都用参数方程来描述,那么在连接点处n阶导数连续,就被称为Cn 连续。在图形学中,一般最高只要求C2 连续,因为更高阶的连续已经超出了人眼视觉能识别的层次。但Cn 连续有一个致命的缺陷,那就是连续性会随参数的选取而变化,这使得Cn 连续不具备普适性,不能用于广泛的学术交流。
为了避免这个缺陷,人们引入了几何连续性和自然参数方程,定义曲线的弧长s作为自然参数,这样任何参数方程都可以转换为自然参数方程,在连接点处自然参数方程的n阶导数连续,就称为Gn 连续。在图形学中,一般最高也只要求G2 连续。
考察G0 ,G1 ,G2 连续的几何意义。G0 就是满足位置连续,即两曲线端点重合。G1 满足两曲线在端点上具有相同的切线方向。G2 满足曲线在端点上具有相同的自然参数二阶导失,也就是对一般参数方程具有相同的曲率矢量。
曲率矢量的求法:k = r ′ ( t ) × r ′ ′ ( t ) ∣ r ′ ( t ) ∣ 3
k=\frac{r'(t)\times r''(t)}{|r'(t)|^3}
k = ∣ r ′ ( t ) ∣ 3 r ′ ( t ) × r ′ ′ ( t )
设两条贝塞尔曲线P和Q的参数方程P(t)和Q(t),它们的控制点序列分别是P0 、P1 ……Pn 和Q0 、Q1 ……Qm ,则满足C0 和G0 的连接条件是P(1)=G(0),即Pn =Q0 。满足G1 的连接条件是Pn-1 、Pn =Q0 、Q1 这三点共线且顺序排列 。在满足G1 连接的基础上,如果**|Pn-1 Pn |=|Q0 Q1 |**,则满足C1 连接。
根据端点导数性质,C2 和G2 的达成与Pn-2 和Q2 有关。记ai =Pi -Pi-1 ,bi =Qi -Qi-1 ,则对曲线P和Q的端点求其曲率,也就是曲率矢量的模,得:K P ( 1 ) = ( n − 1 ) ∣ a n − 1 × a n ∣ n ∣ a n ∣ 3 K Q ( 0 ) = ( m − 1 ) ∣ b 1 × b 2 ∣ m ∣ b 1 ∣ 3
K_P(1)=\frac{(n-1)|a_{n-1}\times a_n|}{n|a_n|^3}\\
K_Q(0)=\frac{(m-1)|b_1\times b_2|}{m|b_1|^3}
K P ( 1 ) = n ∣ a n ∣ 3 ( n − 1 ) ∣ a n − 1 × a n ∣ K Q ( 0 ) = m ∣ b 1 ∣ 3 ( m − 1 ) ∣ b 1 × b 2 ∣
将Pn-1 、Pn =Q0 、Q1 所在的公切线记为直线l,an-1 与an 之间的夹角记为θ,b1 与b2 之间的夹角记为φ,Pn-2 到l的距离记为h1 ,Q2 到l的距离记为h2 。根据几何关系可知:∣ a n − 1 × a n ∣ = ∣ a n − 1 ∣ × ∣ a n ∣ × sin θ = ∣ a n − 1 ∣ × ∣ a n ∣ × h 1 ∣ a n − 1 ∣ = ∣ a n ∣ h 1 ∣ b 1 × b 2 ∣ = ∣ b 1 ∣ × ∣ b 2 ∣ × sin θ = ∣ b 1 ∣ × ∣ b 2 ∣ × h 2 ∣ b 1 ∣ = ∣ b 1 ∣ h 2
|a_{n-1}\times a_n|= |a_{n-1}|\times|a_n|\times\sin\theta
=|a_{n-1}|\times|a_n|\times\frac{h_1}{|a_{n-1}|}=|a_n|h_1\\
|b_1\times b_2|= |b_1|\times|b_2|\times\sin\theta
=|b_1|\times|b_2|\times\frac{h_2}{|b_1|}=|b_1|h_2\\
∣ a n − 1 × a n ∣ = ∣ a n − 1 ∣ × ∣ a n ∣ × sin θ = ∣ a n − 1 ∣ × ∣ a n ∣ × ∣ a n − 1 ∣ h 1 = ∣ a n ∣ h 1 ∣ b 1 × b 2 ∣ = ∣ b 1 ∣ × ∣ b 2 ∣ × sin θ = ∣ b 1 ∣ × ∣ b 2 ∣ × ∣ b 1 ∣ h 2 = ∣ b 1 ∣ h 2
过端点Pn =Q0 作公切线l的垂线v,过端点Pn-2 和Q2 分别作l的平行线交v于点A、B。连接APn-1 、BQ1 ,过点Pn-1 作线端APn-1 的垂线CPn-1 交v于C,过点Q1 作线端BQ1 的垂线DQ1 交v于D。记C到l的距离为g1 ,D到l的距离为g2 。
在直角三角形ACPn-1 和直角三角形BDQ1 中,有:a n 2 = h 1 g 1 b 1 2 = h 2 g 2
a_n^2=h_1g_1\\
b_1^2=h_2g_2
a n 2 = h 1 g 1 b 1 2 = h 2 g 2
于是将曲率变形为:K P ( 1 ) = n − 1 n ∣ a n ∣ h 1 ∣ a n ∣ 3 = n − 1 n 1 g 1 K Q ( 0 ) = m − 1 m ∣ b 1 ∣ h 2 ∣ b 1 ∣ 3 = m − 1 m 1 g 2
K_P(1)=\frac{n-1}{n}\frac{|a_n|h_1}{|a_n|^3}=\frac{n-1}{n}\frac1{g_1}\\
K_Q(0)=\frac{m-1}{m}\frac{|b_1|h_2}{|b_1|^3}=\frac{m-1}{m}\frac1{g_2}
K P ( 1 ) = n n − 1 ∣ a n ∣ 3 ∣ a n ∣ h 1 = n n − 1 g 1 1 K Q ( 0 ) = m m − 1 ∣ b 1 ∣ 3 ∣ b 1 ∣ h 2 = m m − 1 g 2 1
满足G2 的条件是KQ (0)=βKP (1),此时:β = n ( m − 1 ) m ( n − 1 ) g 1 g 2
\beta=\frac{n(m-1)}{m(n-1)}\frac{g_1}{g_2}
β = m ( n − 1 ) n ( m − 1 ) g 2 g 1
满足C2 的条件是β=1且两曲线具有公共的切平面,要满足β=1即:g 1 = m ( n − 1 ) n ( m − 1 ) g 2
g_1=\frac{m(n-1)}{n(m-1)}g_2
g 1 = n ( m − 1 ) m ( n − 1 ) g 2
在特殊条件下,若m=n,则满足β=1的条件是g1 =g2 。
要满足两曲线具有公共切平面,则点Pn-2 、Pn-1 、Pn =Q0 、Q1 、Q2 五点必须共面,并且点Pn-2 和点Q2 应位于另三个顶点所在公切线的同侧。
如何获得匀速贝塞尔曲线?
我们已经得到了贝塞尔曲线的参数方程,但显然,如果将参数t作为时间变量,将物体沿曲线运动,我们很难得到一个匀速的运动效果。事实上,在靠近控制点处运动的较慢,而在曲线中段则运行的较快。同时,我们也很难在贝塞尔曲线的拼接处获得良好的平滑速度。
我们可以先求得B(t)相对于t的速度公式,我们先将t看作时间变量,在单个方向上对t求导就可以得到v ( t ) = B x ′ ( t ) 2 + B y ′ ( t ) 2 + B z ′ ( t ) 2
v(t)=\sqrt{B_x'(t)^2+B_y'(t)^2+B_z'(t)^2}
v ( t ) = B x ′ ( t ) 2 + B y ′ ( t ) 2 + B z ′ ( t ) 2
现在我们以二阶贝塞尔曲线为例,记B x ′ ( t ) 2 + B y ′ ( t ) 2 + B z ′ ( t ) 2 = A t 2 + B t + C B_x'(t)^2+B_y'(t)^2+B_z'(t)^2 = At^2+Bt+C B x ′ ( t ) 2 + B y ′ ( t ) 2 + B z ′ ( t ) 2 = A t 2 + B t + C ,将左式展开:KaTeX parse error: No such environment: equation at position 8:
\begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲\begin{split}
…
注意到,A为完全平方式,我们设α = 2 P 0 − 4 P 1 + 2 P 2 \alpha = 2P_0-4P_1+2P_2 α = 2 P 0 − 4 P 1 + 2 P 2 ,则A = α x 2 + α y 2 + α x 2 A=\alpha_x^2+\alpha_y^2+\alpha_x^2 A = α x 2 + α y 2 + α x 2 。同理我们记β = 2 P 0 − 2 P 1 \beta=2P_0-2P_1 β = 2 P 0 − 2 P 1 ,则有C = β x 2 + β y 2 + β z 2 C=\beta_x^2+\beta_y^2+\beta_z^2 C = β x 2 + β y 2 + β z 2 ,B = − 2 ( α x β x + α z β y + α z β z ) B=-2(\alpha_x\beta_x+\alpha_z\beta_y+\alpha_z\beta_z) B = − 2 ( α x β x + α z β y + α z β z ) 。经整理得:KaTeX parse error: No such environment: equation at position 8:
\begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲\begin{split}
…
写成向量形式即:KaTeX parse error: No such environment: equation at position 8:
\begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲\begin{split}
…
根据这个公式得出贝塞尔曲线得长度公式L ( t ) L(t) L ( t ) :KaTeX parse error: No such environment: equation at position 8:
\begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲\begin{split}
…
显然,整条曲线的长度为L(1),我们求变量t的函数T ( t ) T(t) T ( t ) ,使得L ( T ( t ) ) = L ( 1 ) ∗ t L(T(t))=L(1)*t L ( T ( t ) ) = L ( 1 ) ∗ t ,则T ( t ) = L − 1 [ L ( 1 ) ∗ t ] T(t)=L^{-1}[L(1)*t] T ( t ) = L − 1 [ L ( 1 ) ∗ t ] 。由于对L(t)求逆函数几乎不可能,在这里我们利用L(t)的导数v(t),使用牛顿切线法求出离散的近似解:T n + 1 = T n + Δ L v ( T n )
T_{n+1}=T_n+\frac{\Delta L}{v(T_n)}
T n + 1 = T n + v ( T n ) Δ L
其中Δ L \Delta L Δ L 是每次前进的长度,如果按t ∈ [ 0 , 1 ] t\in [0,1] t ∈ [ 0 , 1 ] 来计算前进的长度则:Δ L = L ( 1 ) × t − T n
\Delta L = L(1)\times t -T_n
Δ L = L ( 1 ) × t − T n
有了上面的经验,我们再来求三阶贝塞尔曲线的T n T_n T n ,记B x ′ ( t ) 2 + B y ′ ( t ) 2 + B z ′ ( t ) 2 = A t 4 + B t 3 + C t 2 + D t + E B_x'(t)^2+B_y'(t)^2+B_z'(t)^2 = At^4+Bt^3+Ct^2+Dt+E B x ′ ( t ) 2 + B y ′ ( t ) 2 + B z ′ ( t ) 2 = A t 4 + B t 3 + C t 2 + D t + E ,将左式展开得:KaTeX parse error: No such environment: equation at position 8:
\begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲\begin{split}
…
观察到,A和E为完全平方式,我们取α = 3 P 0 − 9 P 1 + 9 P 2 − 3 P 3 \alpha=3P_0-9P_1+9P_2-3P_3 α = 3 P 0 − 9 P 1 + 9 P 2 − 3 P 3 ,则A = α x 2 + α y 2 + α z 2 A=\alpha_x^2+\alpha_y^2+\alpha_z^2 A = α x 2 + α y 2 + α z 2 。取β = 3 P 0 − 3 P 1 \beta=3P_0-3P_1 β = 3 P 0 − 3 P 1 ,则E = β x 2 + β y 2 + β z 2 E=\beta_x^2+\beta_y^2+\beta_z^2 E = β x 2 + β y 2 + β z 2 。注意到,D是β的倍数,我们取γ = 3 P 0 − 6 P 1 + 3 P 2 \gamma=3P_0-6P_1+3P_2 γ = 3 P 0 − 6 P 1 + 3 P 2 ,有D = − 4 ( β x γ x + β y γ y + β z γ z ) D=-4(\beta_x\gamma_x+\beta_y\gamma_y+\beta_z\gamma_z) D = − 4 ( β x γ x + β y γ y + β z γ z ) 。类似的,又得到B = − 4 ( α x γ x + α y γ y + α z γ z ) B=-4(\alpha_x\gamma_x+\alpha_y\gamma_y+\alpha_z\gamma_z) B = − 4 ( α x γ x + α y γ y + α z γ z ) 。
C的推导过程比较繁琐,但核心思路如下:设a = m 3 − m 2 , b = m 2 − m 1 , c = m 1 − m 0 a=m_3-m_2,b=m_2-m_1,c=m_1-m_0 a = m 3 − m 2 , b = m 2 − m 1 , c = m 1 − m 0 ,将C配方得到与a、b、c、a+b、b+c、a+b+c有关得表达式,然后展开得到C = 18 [ 2 b 2 + 3 c 2 + a c − 6 b c ] C=18[2b^2+3c^2+ac-6bc] C = 1 8 [ 2 b 2 + 3 c 2 + a c − 6 b c ] ,易得:C = ∑ m m ∈ { x , y , z } 4 γ m 2 + 2 α m β m
C=\sum_m^{m\in \{x,y,z\}}4\gamma_m^2+2\alpha_m\beta_m
C = m ∑ m ∈ { x , y , z } 4 γ m 2 + 2 α m β m
最后整理整个公式:KaTeX parse error: No such environment: equation at position 8:
\begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲\begin{split}
…
写成向量形式即:KaTeX parse error: No such environment: equation at position 8:
\begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲\begin{split}
…
什么是B样条曲线?
仅修改贝塞尔曲线的一个控制点,也会影响到整个曲线的形状。为了弥补这个缺陷,deBoor发明了B样条曲线,B样条曲线基于deBoor-Cox递推公式 实现。
B样条曲线本质上是对多段短贝塞尔曲线的连续拼接。
n段p次B样条曲线由n+1个控制点 P0 、P1 ……Pn 练成的n段的控制折线,和一个m维节点向量 U={u0 ,u1 ,……,um }组成。
其中ui 为节点(pnots) ,m个节点将完整的B样条曲线划分成了m-1个曲线段,每个曲线段都定义在一个节点区间上。对p次的B样条曲线来说,这m-1个曲线段都是p次的贝塞尔曲线。
如果ui =ui+1 =……=ui+k-1 ,那么ui 节点被称为一个重复度(multiplicity)为k的 多重节点 ,1 < k ≤ p 1<k\le p 1 < k ≤ p ,节点的重复度也被称为度数。否则如果一个节点只出现一次,那么这就是一个简单节点 。如果u1 -u0 =u2 -u1 =……=um -um-1 ,即节点等距,则称节点向量为均匀的,称B样条曲线为均匀B样条曲线,否则称节点向量为非均匀的,称B样条曲线为非均匀B样条曲线。
p次B样条曲线要求满足m=n+p+1 ,显然,不同于贝塞尔曲线,B样条曲线的次数与控制点的数量无关。贝塞尔曲线中的t取值范围是[0,1],而B样条曲线中的u取值范围可能比[0,1]更小。
B样条曲线和贝塞尔曲线的核心差别是,B样条曲线用B样条基函数 替代Bernstein基函数,B样条曲线的公式为:C ( u ) = ∑ i = 0 n N i , p ( u ) P i
C(u)=\sum_{i=0}^nN_{i,p}(u)P_i
C ( u ) = i = 0 ∑ n N i , p ( u ) P i
其中Ni,p (u)是第i个p次B样条基函数 ,也叫调和函数,或者p次规范B样条基函数。这个函数使用deBoor-Cox递推公式,其定义如下:N i , 0 ( u ) = { 1 u i ≤ u < u i + 1 0 o t h e r w i s e N i , p ( u ) u − u i u i + p − u i N i , p − 1 ( u ) + u i + p + 1 − u u i + p + 1 − u i + 1 N i + 1 , p − 1 ( u )
N_{i,0}(u)=\left \{ \begin{array}{c}
1&u_i\le u<u_{i+1}\\0&otherwise
\end{array}\right.\\
N_{i,p}(u)\frac{u-u_i}{u_{i+p}-u_i}N_{i,p-1}(u)+\frac{u_{i+p+1}-u}{u_{i+p+1}-u_{i+1}}N_{i+1,p-1}(u)
N i , 0 ( u ) = { 1 0 u i ≤ u < u i + 1 o t h e r w i s e N i , p ( u ) u i + p − u i u − u i N i , p − 1 ( u ) + u i + p + 1 − u i + 1 u i + p + 1 − u N i + 1 , p − 1 ( u )
注:在该递推公式中认为0÷0=0。
可见,B样条基函数的形态主要受ui 的取值影响。以U={0,0.25,0.5,0.75,1}的2段2次B样条曲线为例直观的感受B样条基函数的形象:
可以归纳得出,基函数Ni,p (u)在区间[ui ,ui+p+1 )上非零。反过来,在区间[ui ,ui+1 )上,共有p+1个p次基函数非零,分别是:Ni-p,p (u),Ni-p+1,p (u),Ni-p+2,p (N)……Ni-1,p (u)和Ni,p (u)。
当计算Ni,p (u)时,它在区间[ui ,ui+p+1 )上非零。在deBoor-Cox递推公式中,Ni,p (u)被拆解为一个Ni,p-1 (u)项和一个Ni+1,p-1 (u)项,前者在[ui .,ui+p )上非零,如果u∈[ui .,ui+p ),那么u − u i u i + p − u i \frac{u-u_i}{u_{i+p}-u_i} u i + p − u i u − u i 恰好是u和这个区间左端的距离与这个区间长度的比;同理,后者在[ui+1 ,ui+p+1 )上非零,如果u∈[ui+1 ,ui+p+1 ),那么u i + p + 1 − u u i + p + 1 − u i + 1 \frac{u_{i+p+1}-u}{u_{i+p+1}-u_{i+1}} u i + p + 1 − u i + 1 u i + p + 1 − u 恰好是u和这个区间右端的距离与这个区间长度的比。如图所示:
B样条线的形状与节点的度数直接关联,两种具有特殊度数格式的B样条曲线如下:
一般的B样条曲线称为开B样条曲线 ,即曲线不会与控制折线的第一边和最后一边接触,对于开B样条曲线,其定义域为[up ,um-p ]。可见,均匀B样条曲线就是一种特殊的开B样条曲线。
强制第一个节点和最后一个节点的重复度为p+1,那么产生的曲线就会分别与第一边和最后一边相切,这样的曲线被称为clamped-B样条曲线 。可见,准均匀B样条曲线就是一种特殊的clamped-B样条曲线。
通过重复节点和控制点,可以使产生的曲线形成闭环,称为闭B样条曲线 。生成闭B样条曲线的方法有两种:
Wrapping控制点
设计一个m+1个节点的节点序列U={u 0 = 0 , u 1 = 1 m , u 2 = 2 m , . . . u m − 1 = m − 1 m , u m = 1 u_0=0,u_1=\frac1m,u_2=\frac2m,...u_{m-1}=\frac{m-1}m,u_m=1 u 0 = 0 , u 1 = m 1 , u 2 = m 2 , . . . u m − 1 = m m − 1 , u m = 1 },对曲线的头p个和尾p个控制点,令P 0 = P n − p + 1 P_0=P_{n-p+1} P 0 = P n − p + 1 ,P 1 = P n − p + 2 P_1=P{n-p+2} P 1 = P n − p + 2 ,…,P p − 2 = P n − 1 P{p-2}=P_{n-1} P p − 2 = P n − 1 ,P p − 1 = P n P_{p-1}=P_n P p − 1 = P n 。曲线的定义域为[u p , u n − p u_p,u_{n-p} u p , u n − p ],且在连接点C(u p u_p u p )=C(u n − p u_{n-p} u n − p )上保证Cp-1 连续性。
Wrapping节点
设计n+1个控制点,并使P n = P 0 P_n=P_0 P n = P 0 。先找到具有n个节点的单调节点序列U,在U基础上增加p+1个节点,并使u n + 1 = u 0 , u n + 2 = u 1 , . . . , u n + p = u p − 1 , u n + p + 1 = u p u_{n+1}=u_0,u_{n+2}=u_1,...,u_{n+p}=u_{p-1},u_{n+p+1}=u_p u n + 1 = u 0 , u n + 2 = u 1 , . . . , u n + p = u p − 1 , u n + p + 1 = u p ,这样得到一个定义域为[u 0 , u n + 1 u_0,u_{n+1} u 0 , u n + 1 ]的闭曲线,在连接点C(u 0 u_0 u 0 )=C(u n + 1 u_{n+1} u n + 1 )上保证Cp-1 连续性。
曲线是如何被光栅化的?
曲线是通过被细分成许多段直线进行光栅化的,所以我们必须先了解平面上直线的光栅化。
设直线的斜率为k,当k = 0 , k = ± 1 , k = ± ∞ k=0,k=\pm1,k=\pm\infty k = 0 , k = ± 1 , k = ± ∞ 时,直线的光栅化方法显而易见。所以我们只考虑在0 < ∣ k ∣ < 1 0\lt|k|\lt1 0 < ∣ k ∣ < 1 的情况下直线的光栅化算法,这样也可以类比推出在1 < ∣ k ∣ < ∞ 1<|k|<\infty 1 < ∣ k ∣ < ∞ 下的算法。
DDA算法 是最简单的直线光栅化算法,它的核心思路在于步进和通过舍入选择像素。
当0 < ∣ k ∣ < 1 0\lt|k|\lt1 0 < ∣ k ∣ < 1 时,选择对x进行步进,即x i + 1 = x i ± 1 x_{i+1}=x_i\pm1 x i + 1 = x i ± 1 ,则y i + 1 = y i + k y_{i+1}=y_i+k y i + 1 = y i + k 。相对的,当1 < ∣ k ∣ < ∞ 1<|k|<\infty 1 < ∣ k ∣ < ∞ 时,选择对y进行步进,即y i + 1 = y i ± 1 y_{i+1}=y_i\pm1 y i + 1 = y i ± 1 ,x i + 1 = x i ± 1 k x_{i+1}=x_i\pm\frac1k x i + 1 = x i ± k 1 。最后选择对x i + 1 x_{i+1} x i + 1 和y i + 1 y_{i+1} y i + 1 进行舍入后的像素点进行光栅化。
中点画线法 是经典的直线光栅化算法。它相比于DDA的进步在于巧妙的避免了浮点运算,有效提升了渲染效率。
直线的一般式方程为F ( x , y ) = 0 F(x,y)=0 F ( x , y ) = 0 ,这条直线将平面分为三个区域:直线上方的点、直线下方的点以及直线上的点。其中,对于直线上方的点,F ( x , y ) > 0 F(x,y)>0 F ( x , y ) > 0 ;直线下方的点,F ( x , y ) < 0 F(x,y)<0 F ( x , y ) < 0 ;直线上的点,F ( x , y ) = 0 F(x,y)=0 F ( x , y ) = 0 。
中点画线法也使用步进思想,但它在每次移动时,根据中点误差项判断而非舍入来决定是在水平/竖直方向上移动一个像素,还是在斜方向上移动一个像素。
在上图中,像素点P ( x i , y i ) P(x_i,y_i) P ( x i , y i ) 已经被选中,接下来直线既穿过了像素点又P d P_d P d 穿过了像素点P u P_u P u ,我们应当在这两个像素中选择一个进行绘制。我们考察直线与线段P d P u P_dP_u P d P u 的交点Q Q Q ,如果它更靠近P d P_d P d 则绘制P d P_d P d ,否则绘制P u P_u P u 。
于是我们将P u P_u P u 与P d P_d P d 的中点M M M 纳入考量,将M M M 点坐标代入方程F ( x i , y i ) F(x_i,y_i) F ( x i , y i ) ,即,如果结果小于0,则M M M 在Q Q Q 下方,取P u P_u P u ,如果结果大于0,则M M M 在Q Q Q 上方,取P d P_d P d 。如果恰等于0,则两者皆可。
我们记d i = F ( x i + 1 , y i + 0.5 ) d_i=F(x_i+1,y_i+0.5) d i = F ( x i + 1 , y i + 0 . 5 ) ,当然,每次移动都代入方程来计算d i d_i d i 是合理的,但并不高效。我们试图通过找到递推公式d i + 1 = d i + Δ d d_{i+1}=d_i+\Delta d d i + 1 = d i + Δ d 来减少代入方程带来的计算。d i = F ( x i + 1 , y i + 0.5 ) = A ( x i + 1 ) + B ( y i + 0.5 ) + C
d_i=F(x_i+1,y_i+0.5)=A(x_i+1)+B(y_i+0.5)+C
d i = F ( x i + 1 , y i + 0 . 5 ) = A ( x i + 1 ) + B ( y i + 0 . 5 ) + C
当d i < 0 d_i<0 d i < 0 时,取P u P_u P u ,即右上方的像素,则d i + 1 = F ( x i + 2 , y i + 1.5 ) = A ( x i + 2 ) + B ( y i + 1.5 ) + C = d i + A + B
d_{i+1}=F(x_i+2,y_i+1.5)=A(x_i+2)+B(y_i+1.5)+C=d_i+A+B
d i + 1 = F ( x i + 2 , y i + 1 . 5 ) = A ( x i + 2 ) + B ( y i + 1 . 5 ) + C = d i + A + B
当d i ≥ 0 d_i \ge 0 d i ≥ 0 时,取P d P_d P d ,即右方的像素,则d i + 1 = F ( x i + 2 , y i + 0.5 ) = A ( x i + 2 ) + B ( y i + 0.5 ) + C = d i + A
d_{i+1}=F(x_i+2,y_i+0.5)=A(x_i+2)+B(y_i+0.5)+C=d_i+A
d i + 1 = F ( x i + 2 , y i + 0 . 5 ) = A ( x i + 2 ) + B ( y i + 0 . 5 ) + C = d i + A
总结可得:d i + 1 = { d i + A + B d < 0 d i + A d ≥ 0 , d 0 = A + 0.5 B
d_{i+1}=
\left \{ \begin{array}{c}
d_i+A+B&d<0\\d_i+A&d\ge 0
\end{array}\right.\ \ \ \ \ \ \ \ \ \ ,d_0=A+0.5B
d i + 1 = { d i + A + B d i + A d < 0 d ≥ 0 , d 0 = A + 0 . 5 B
由于d只关心符号,所以可以使用2d代替d来避免浮点运算,进一步提升性能。
Bresenham算法 与中点画线法实际上是同一算法,只是对算法的解释不同,在此不多赘述。
在光栅化曲线时,只需要将曲线参数方程映射到像素坐标系下,对不同的参数取值将曲线细分成多条线段,在线端上应用直线光栅化算法即可。
曲面
什么是贝塞尔曲面?
我们先复习贝塞尔曲线的定义:B n ( t ) = ∑ i = 0 n B i , n ( t ) P i , t ∈ [ 0 , 1 ]
B_n(t)=\sum_{i=0}^nB_{i,n}(t)P_i,\ t\in[0,1]
B n ( t ) = i = 0 ∑ n B i , n ( t ) P i , t ∈ [ 0 , 1 ]
其中B i , n ( t ) B_{i,n}(t) B i , n ( t ) 是Bernstein基函数:B i , n ( u ) = n ! i ! ( n − i ) ! u i ( 1 − u ) n − 1
B_{i,n}(u)=\frac{n!}{i!(n-i)!}u^i(1-u)^{n-1}
B i , n ( u ) = i ! ( n − i ) ! n ! u i ( 1 − u ) n − 1
贝塞尔曲面本质上就是先对每一行做贝塞尔曲线,然后将这些贝塞尔曲线的结果作为列贝塞尔曲线的控制点。
我们用两个参数u、v代替t,分别在两个方向上描述贝塞尔曲面的形状,相对应的,我们需要n×m个控制点控制整个曲面,记控制点为P i j , i ∈ n , j ∈ m P_{ij},i\in n,j\in m P i j , i ∈ n , j ∈ m 。
在上图中,q i ( u ) q_i (u) q i ( u ) 由每行的m个控制点控制,是一条m-1阶的贝塞尔曲线。即:q i ( u ) = ∑ j = 0 m B j , n ( u ) P i j
q_i(u)=\sum_{j=0}^mB_{j,n}(u)P_{ij}
q i ( u ) = j = 0 ∑ m B j , n ( u ) P i j
紧接着,这n条贝塞尔曲线q i ( u ) q_i (u) q i ( u ) 在u = u 0 u=u_0 u = u 0 上取得了n个点,将这n个点作为v方向上的贝塞尔曲线的控制点得到整个贝塞尔曲面的方程:P ( u , v ) = ∑ i = 0 n B i , n ( v ) q i ( u ) P ( u , v ) = ∑ i = 0 n [ B i , n ( v ) ∑ j = 0 m B j , n ( u ) P i j ]
P(u,v)=\sum_{i=0}^nB_{i,n}(v)q_i(u)\\
P(u,v)=\sum_{i=0}^n\ [B_{i,n}(v)\sum_{j=0}^mB_{j,n}(u)P_{ij}]
P ( u , v ) = i = 0 ∑ n B i , n ( v ) q i ( u ) P ( u , v ) = i = 0 ∑ n [ B i , n ( v ) j = 0 ∑ m B j , n ( u ) P i j ]
显然,贝塞尔曲面的定义域是参数范围[0,1]×[0,1]。
什么是B样条曲面?
B样条曲面的思路和贝塞尔曲面一致,我们也用两个参数u、v代替t,使用n×m个控制点,则相对的,我们需要节点矢量U={u0 ,u1 ,…,un+p }和V={v0 ,v1 ,…vm+q },他们分别由n+p+1和m+q+1个节点组成,它们的要求和B样条曲线中一致。
只需将贝塞尔曲面中的Bernstein基函数改为B样条基函数就可以得到B样条曲面的定义,在此我们先复习一下B样条基函数的deBoor-Cox递推公式:N i , 0 ( u ) = { 1 u i ≤ u < u i + 1 0 o t h e r w i s e N i , p ( u ) u − u i u i + p − u i N i , p − 1 ( u ) + u i + p + 1 − u u i + p + 1 − u i + 1 N i + 1 , p − 1 ( u )
N_{i,0}(u)=\left \{ \begin{array}{c}
1&u_i\le u<u_{i+1}\\0&otherwise
\end{array}\right.\\
N_{i,p}(u)\frac{u-u_i}{u_{i+p}-u_i}N_{i,p-1}(u)+\frac{u_{i+p+1}-u}{u_{i+p+1}-u_{i+1}}N_{i+1,p-1}(u)
N i , 0 ( u ) = { 1 0 u i ≤ u < u i + 1 o t h e r w i s e N i , p ( u ) u i + p − u i u − u i N i , p − 1 ( u ) + u i + p + 1 − u i + 1 u i + p + 1 − u N i + 1 , p − 1 ( u )
用B样条基函数替换Bernstein基函数:P ( u , v ) = P ( u , v ) = ∑ i = 0 n [ N i , n ( v ) ∑ j = 0 m N j , n ( u ) P i j ]
P(u,v)=P(u,v)=\sum_{i=0}^n\ [N_{i,n}(v)\sum_{j=0}^mN_{j,n}(u)P_{ij}]
P ( u , v ) = P ( u , v ) = i = 0 ∑ n [ N i , n ( v ) j = 0 ∑ m N j , n ( u ) P i j ]
显然,B样条曲面的定义域是参数范围[up ,un+1 ]×[vq ,vq+1 ]。
什么是Nurbs曲面?
Nurbs 是非均匀有理B样条 的缩写,B样条曲面是Nurbs曲面的一种特例。Nurbs建模(也被称为曲面建模 )是工业3D建模的一个重要方式,另一种更常见的建模方式则是多边形建模 。
Nurbs相比一般B样条曲面的改进在于,通过调整曲面中控制点的权,来产生更好的平滑性。我们记W i j W_{ij} W i j 为控制点P i j P_{ij} P i j 的权值,除此之外的定义都与B样条曲线相同。
下面直接给出Nurbs曲面的参数方程:S ( u , v ) = ∑ i = 0 n ∑ j = 0 m N i , p ( u ) N j , q ( v ) W i j P i j ∑ i = 0 n ∑ j = 0 m N i , p ( u ) N j , q ( v ) W i j
S(u,v)=\frac
{\sum_{i=0}^n\sum_{j=0}^mN_{i,p}(u)N_{j,q}(v)W_{ij}P_{ij} }
{\sum_{i=0}^n\sum_{j=0}^mN_{i,p}(u)N_{j,q}(v)W_{ij}}
S ( u , v ) = ∑ i = 0 n ∑ j = 0 m N i , p ( u ) N j , q ( v ) W i j ∑ i = 0 n ∑ j = 0 m N i , p ( u ) N j , q ( v ) W i j P i j
其中N i , p ( u ) N_{i,p}(u) N i , p ( u ) 是B样条基函数。
显然,Nurbs曲面的定义域也是参数范围[up ,un+1 ]×[vq ,vq+1 ]。
曲面如何进行渲染?
由于曲面是矢量图形,我们采用和曲线一样的渲染思路,在参数空间上以任意精细度对参数点进行采样,将采样结果组成四边形或三角形,然后就可以以多边形的方式对其进行渲染。
对于更高级的渲染方案,可以通过在距离摄像机近处密集采样,距离摄像机远除粗略采样,来提升渲染性能。
多边形
多变形是如何被光栅化的?
什么是消隐算法?
如何进行多边形的三角形化?