渲染中的几何:从隐式表示到几何求交

2,290 阅读6分钟

几何定义

射线

射线由起点 OO 和方向 DD 决定,在 tt 时刻可取得射线所到达的点 PP

O+tD=PO + tD = P

平面

平面可以由平面内任一点 PP 与垂直于该平面的任意法线 NN 决定。平面上任一点 PP 和给定一点 PP^{\prime} 所构成的向量 PPPP^{\prime} 与法线 NN 点乘结果为 00

(PP)N=0(P-P^{\prime}) \cdot N = 0

球体

已知球体的方程为 x2+y2+z2=Rx^2+y^2+z^2 = R ,则球体表面上的任一点 P(x,y,z)P(x,y,z) 的坐标即为方程的解。设球心坐标为 CC ,则球体表面上任一点 PP 与球心 CC 的距离应该为球半径 RR

(PC)(PC)=R2(P-C) \cdot (P-C) = R^2

面积和体积

面积

两向量叉乘的模即为平行四边形的面积,而任意两个二维向量组合成矩阵,其行列式的绝对值即为二者所围成的平行四边形的面积。

S=a×b=det(a,b)S = \left\| \mathbf{a} \times \mathbf{b}\right\| = |det(\mathbf{a},\mathbf{b})|

体积

由相邻的三个矢量所构成的平行六面体,其体积可以表示为三个矢量的标量三重积的绝对值。

V=a(b×c)=det([a,b,c])=a1a2a3b1b2b3c1c2c3V=|\mathbf{a} \cdot(\mathbf{b} \times \mathbf{c})|= |det([\mathbf{a},\mathbf{b},\mathbf{c}])| = \left\|\begin{array}{lll} a_{1} & a_{2} & a_{3} \\ b_{1} & b_{2} & b_{3} \\ c_{1} & c_{2} & c_{3} \end{array}\right\|

三角形重心坐标的求解

三角形 ABC\triangle ABC 所在平面任一点 PP 与顶点 AA 组成的边,都可以由三角形 ABC\triangle ABC 两边的线性组合表示,进一步地拆分该表达式,可以得到三角形所在平面任一点 PP 可由三角形 ABC\triangle ABC 地三个顶点组成的线性组合,其系数即所谓的重心坐标。

AP=uAB+vACAP=u(AB)+v(AC)P=(1uv)A+uB+vC{A P}=u {A B}+v {A C} \\ A-P=u(A-B)+v(A-C) \\ P=(1-u-v) A+u B+v C

将由三角形 ABC\triangle ABC 两边的线性组合表示 APAP 的表达式变形为向量乘法,即可得到两向量点乘为 00 的结果。

uAB+vAC+PA=0u {A B}+v {A C}+{P A}=0
[uv1][ABxACxPAx]=0\left[\begin{array}{l} u \\ v \\ 1 \end{array}\right] \cdot \left[\begin{array}{l} {A B_{x}} \\ {A C}_{x} \\ {P A_{x}} \end{array}\right]=0
[uv1][AByACyPAy]=0\left[\begin{array}{l} u \\ v \\ 1 \end{array}\right] \cdot \left[\begin{array}{l} {A B_{y}} \\ {A C}_{y} \\ {P A_{y}} \end{array}\right]=0

两向量点乘为 00 ,则互相垂直,因此向量 [u,v,1]T[u,v,1]^T 与后两者分别是垂直的。由叉乘的性质又可知,通过后两者叉乘就可以得垂直于两者得向量 [u,v,1]T[u,v,1]^T

[ABxACxPAx]×[AByACyPAy]=[uv1]\left[\begin{array}{l} {A B_{x}} \\ {A C}_{x} \\ {P A_{x}} \end{array}\right] \times \left[\begin{array}{l} {A B_{y}} \\ {A C}_{y} \\ {P A_{y}} \end{array}\right] = \left[\begin{array}{l} u \\ v \\ 1 \end{array}\right]

还可以通过直接计算的方式求出重心坐标。

α=(xxB)(yCyB)+(yyB)(xCxB)(xAxB)(yCyB)+(yAyB)(xCxB)β=(xxC)(yAyC)+(yyC)(xAxC)(xBxC)(yAyC)+(yByC)(xAxC)γ=1αβ\begin{aligned} \alpha &=\frac{-\left(x-x_{B}\right)\left(y_{C}-y_{B}\right)+\left(y-y_{B}\right)\left(x_{C}-x_{B}\right)}{-\left(x_{A}-x_{B}\right)\left(y_{C}-y_{B}\right)+\left(y_{A}-y_{B}\right)\left(x_{C}-x_{B}\right)} \\ \beta &=\frac{-\left(x-x_{C}\right)\left(y_{A}-y_{C}\right)+\left(y-y_{C}\right)\left(x_{A}-x_{C}\right)}{-\left(x_{B}-x_{C}\right)\left(y_{A}-y_{C}\right)+\left(y_{B}-y_{C}\right)\left(x_{A}-x_{C}\right)} \\ \gamma &=1-\alpha-\beta \end{aligned}

射线与几何相交

射线与球相交

已知射线和球体的定义,若二者相交,将射线定义代入球体定义后即可得到二者交点的定义。

(O+tDC)(O+tDC)=r2DDt2+2(OC)Dt+(OC)(OC)R2=0(O+tD-C) \cdot (O+tD-C) = r^2 \\ D \cdot Dt^2 + 2(O-C) \cdot Dt + (O-C) \cdot (O-C) -R^2 = 0

经过变形可以得到一个以时间 tt 为未知数的一元二次方程。解出一元二次方程得到射线与球体相交的时间 tt ,再代入射线定义即可得到交点坐标。

a=DDb=2(OC)Dc=(OC)(OC)R2x=b±b24ac2a\begin{array} {l} a = D \cdot D \\ b = 2(O-C) \cdot D \\ c= (O-C) \cdot (O-C) -R^2 \\ \\ x=\frac{-b \pm \sqrt{b^2 -4ac}}{2 a} \end{array}

h=b2h = \frac{b}{2} ,可以简化求根公式,若确保光线的方向 DD 是归一化的矢量,则求根公式可以进一步简化。

x=h±h2acax=h±h2cx=\frac{-h \pm \sqrt{h^2 -ac}}{a} \\\\ x=-h \pm \sqrt{h^2 -c}

射线与平面相交

和球体相交相同,只需要将射线的定义代入平面的定义即可,且为一个简单的以时间 tt 为未知数的一元一次方程。

(O+tDP)N=0t=(PO)NDN(O+tD-P^{\prime}) \cdot N = 0 \\ \\ t = \frac{(P^{\prime} - O) \cdot N}{D \cdot N}

射线与矩形相交

给定矩形 ABCDABCD 上一顶点 A=PA = P^{\prime} ,求出射线与矩形所在平面相交的时间 tt ,代入射线定义后求出交点 PP 。若交点 PP 在矩形内,则交点 PP 各维度坐标都应在矩形 ABCDABCD 顶点各维度坐标最大值和最小值的范围内。

P=O+tDxmin<xp<xmaxymin<yp<ymaxzmin<zp<zmaxP = O+tD \\ \\ x_{min} < x_p < x_{max} \\ y_{min} < y_p < y_{max} \\ z_{min} < z_p < z_{max}

射线与三角形相交

假设点 PP 在三角形 ABC\triangle ABC 所在平面内,分别连接 PP 点和三角形三边,使三角形三边与AP,BP,CPAP, BP, CP 分别叉乘,当叉乘结果同号时,即可判定点 PP 在三角形。

还可以使用三角形所在平面内任意一点 PP 都可以写成该三角形三点坐标的线性组合的方法判定。若同时满足 α+β+γ=1\alpha + \beta + \gamma = 1 ,则点 PP 在三角形内,且称 (α,β,γ)(\alpha,\beta,\gamma) 为点 PP 的重心坐标。

P(x,y)=αA+βB+γCα+β+γ=1P(x,y) = \alpha A + \beta B + \gamma C’ \\\\ \alpha + \beta + \gamma = 1

或者以三角形 ABC\triangle ABC 所在平面建立坐标系,设点 PP 为原点,向 xx 轴方向发射一条射线。求出直线 y=yp y = y_p 与三角形相交的两个交点,两点必定分别在点 PP 左右。

Möller–Trumbore 算法统一了射线与平面相交和确定一点是否在三角形内,即在 t 时刻射线到达的点 PP 即三角形重心坐标所表示的三角形平面上一点 PP

O+tD=αA+βB+(1αβ)CO+tD=αA+βB+CαCβCOC=α(AC)+β(BC)tDO+ tD = \alpha A + \beta B + (1 - \alpha - \beta)C \\\\ O + tD = \alpha A + \beta B + C - \alpha C - \beta C \\\\ O - C = \alpha (A - C) + \beta(B - C) - tD

S=OC,E1=AC,E2=BCS = O - C, E_1 = A - C, E_2 = B - C ,可以看出这是一个拥有三个未知数的线性方程组,可以化为矩阵乘法形式。

tD+αE1+βE2=S[DE1E2][tαβ]=S-tD + \alpha E_1 + \beta E_2 = S \\\\ \left[ \begin{array}{ccc} -D & E 1 & E 2 \end{array} \right] \left[ \begin{array}{l} t \\ \alpha \\ \beta \end{array} \right] =S

由克拉默法则可解未知数,未知数的结果是行列式的比值,而行列式可以转换为标量三重积形式。其中标量三重积可以交换点积和叉积的顺序不变,初等变换变换正负号。

t=det([SE1E2])det([DE1E2])t= \frac {\operatorname{det} \left( \left[ \begin{array}{ccc} S & E_{1} & E_{2} \end{array} \right] \right) } {\operatorname{det} \left( \left[ \begin{array}{ccc} -D & E_{1} & E_{2} \end{array} \right] \right) }
t=(S×E1)E2(D×E1)E2)=(S×E1)E2D(E1×E2)=(S×E1)E2E1(D×E2)t = \frac {(S \times E_1) \cdot E_2} {(-D \times E_1) \cdot E_2)} = \frac {(S \times E_1) \cdot E_2} {-D \cdot (E_1 \times E_2)} = \frac {(S \times E_1) \cdot E_2} {E_1 \cdot (D \times E_2)}

S1=D×E2,S2=S×E1S_1 = D \times E_2, S_2 = S \times E_1 ,以简化后面的计算。同时根据克拉默法则求出 α,β\alpha,\beta 的标量三重积形式,即可得到三个未知数的解。

t=S2E2E1S1α=SS1E1S1β=DS2E1S1t = \frac {S_2 \cdot E_2} {E_1 \cdot S_1} , \alpha = \frac {S \cdot S_1} {E_1 \cdot S_1} , \beta = \frac {D \cdot S_2} {E_1 \cdot S_1}
[tαβ]=1S1E1[S2E2S1SS2D]\left[\begin{array}{l} t \\ \alpha \\ \beta \end{array}\right]=\frac{1}{S_{1} \cdot E_{1}}\left[\begin{array}{c} S_{2} \cdot E_{2} \\ S_{1} \cdot S \\ S_{2} \cdot D \end{array}\right]

验证时间 tt 的范围和重心坐标即可确定射线与三角形是否相交。

tmin<t<tmaxα+β<1,(α>0,β>0)t_{min}<t<t_{max} \\ \\ \alpha + \beta < 1 , (\alpha > 0, \beta > 0)

射线与包围盒相交

二维矩形可由两个互相平行的对边组成,在二维矩形所在平面上的射线必定会与两个对边相交。若射线经过二维矩形,则射线经过两对边的时间必定有重叠的部分。可以说只有射线和两个对边都第一次相交了才是真正地进入了矩形,只要有一个对边第二次相交了就已经离开了矩形。

将二维矩形的情形推广到三维的包围盒,包围盒是由三个互相平行的对面组成的。已知平面定义是由平面内任一点 PP 与垂直于该平面的任意法线 NN 决定,而包围盒的最小点坐标和最大点坐标就是能囊括在于包围盒六个面的平面内任一点。对于轴向包围盒,所有平面的法向量N都是单位向量,因此只需要点坐标的任一维即可计算出在该维度时间 tt ,即可以直接一步到位计算出三个对面所需的时间 tt

t=(PO)NDNt = \frac{(P^{\prime} - O) \cdot N}{D \cdot N}
[txtytz]=POD \begin{bmatrix} t_x \\ t_y \\ t_z \end{bmatrix} = \frac {P^{\prime} - O} {D}

分别将最小点坐标和最大点坐标代入 PP^{\prime} ,解出两个三维的时间矢量。但计算出的时间大小顺序并不是最小点坐标和最大点坐标决定,而是光线的方向来决定。因此将两个矢量在各维度最小值和最大值重新分配为最小时间矢量和最大时间矢量 Tmin,TmaxT_{min}, T_{max}

在二维情形我们已经知道只有射线和两个对边都第一次相交了才是真正地进入了矩形,只要有一个对边第二次相交了就已经离开了矩形。三维情形下也是同样的道理,选取最小时间矢量 TminT_{min} 中的最大值 tentert_{enter}TmaxT_{max} 中的最小值 texitt_{exit} 。只有当离开的时间大于 0 ,且离开的时间大于等于进入的时间时,我们才认为射线击中了包围盒。

texit>0texit+eps>tentert_{exit}>0 \\ t_{exit} + eps > t_{enter}

浮点值精度问题

由于浮点数精度的问题,当 texitt_{exit} 大于 tentert_{enter} 但二者又特别接近时,可能会出现 texitt_{exit} 反而小于了 tentert_{enter} 。所以建议为 texitt_{exit} 增加一个 epsilon=0.0001epsilon = 0.0001 左右大小的修正值。

除零问题

在除以光线方向 DD 时,存在一个除零问题。如果光线方向 DD 在任一维度为 00 ,根据 IEEE 的浮点数标准,会得到正无穷 (1.#INF00 ) 或负无穷 (-1.#INF00)。而分出最大时间矢量和最小时间矢量,然后选取最小值时间矢量中的最大值,最大时间矢量中的最小值,可以将无穷值排除掉。极端情况下光线方向 DD 三个维度都为 00,比如我们的最大值最小值都是正无穷,由于我们的条件是 texit+eps>tentert_{exit} + eps > t_{enter} ,正无穷大于正无穷的比较是返回 false 的。

如果 POP^{\prime}-O 与光线方向 DD 同时为 00 ,根据 IEEE 的浮点数标准会得到 NaN (1.#IND00) 表示这不是数。NaN 和任何数进行任何比较结果都是 false

几何碰撞

二维多边形碰撞

分离轴法

未完待续......