路径追踪中的纹理过滤

问题引出

最近在做基于WebGL的路径追踪时,遇到了一个法线(凹凸)贴图的问题,如下图,凹凸效果走样特别严重。通过问题分析,目前渲染器还缺少对不同纹理过滤类型的实现,今天刚好完成了相关内容,趁热将其记录下来。

小球凹凸效果的问题

小球细节

其他渲染器的效果

原因分析

本文示例里小球的凹凸贴图如下图。通过凹凸贴图计算法线的过程如下:

  1. 通过对贴图采样得到点 <math xmlns="http://www.w3.org/1998/Math/MathML"> P P </math>P的高度 <math xmlns="http://www.w3.org/1998/Math/MathML"> h p h_p </math>hp;

  2. 分别右移和上移一个微小的距离得到 <math xmlns="http://www.w3.org/1998/Math/MathML"> h p + Δ x h_{p+\Delta{x}} </math>hp+Δx、 <math xmlns="http://www.w3.org/1998/Math/MathML"> h p + Δ y h_{p+\Delta{y}} </math>hp+Δy;

  3. 最终的法线可以表示为:

    <math xmlns="http://www.w3.org/1998/Math/MathML"> N ′ = N + α ( h p + Δ x − h p ) T + α ( h p + Δ y − h p ) ( N × T ) \mathbf{N}^{'} = \mathbf{N} + \alpha(h_{p+\Delta{x}}-h_p)\mathbf{T} + \alpha(h_{p+\Delta{y}}-h_p)(\mathbf{N}\times\mathbf{T}) </math>N′=N+α(hp+Δx−hp)T+α(hp+Δy−hp)(N×T)

    别忘了归一化: <math xmlns="http://www.w3.org/1998/Math/MathML"> N ′ ′ = N ′ ∥ N ′ ∥ \mathbf{N}^{''} = \tfrac{\mathbf{N}^{'}}{\begin{Vmatrix} \mathbf{N}^{'}\end{Vmatrix}} </math>N′′=∥ ∥N′∥ ∥N′

    上式中 <math xmlns="http://www.w3.org/1998/Math/MathML"> α \alpha </math>α为凹凸强度, <math xmlns="http://www.w3.org/1998/Math/MathML"> T \mathbf{T} </math>T为切向向量。

以上过程,最重要的便是 <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ x \Delta{x} </math>Δx和 <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ y \Delta{y} </math>Δy的选取。已知的是在屏幕空间水平和竖直方向的偏移分别为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 / r e s o l u t i o n x 1/resolution_x </math>1/resolutionx和 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 / r e s o l u t i o n y 1/resolution_y </math>1/resolutiony, <math xmlns="http://www.w3.org/1998/Math/MathML"> r e s o l u t i o n resolution </math>resolution为渲染屏幕的分辨率,我们需要通过屏幕空间中的偏移去求每个物体在其所在的UV空间的偏移 <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ x \Delta{x} </math>Δx和 <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ y \Delta{y} </math>Δy,最后采样求得最终的法线。显然 <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ x \Delta{x} </math>Δx和 <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ y \Delta{y} </math>Δy还与视角有关,即当物体离摄像机较近时,偏移很小,而距离增加时,偏移增大。

小球凹凸贴图( <math xmlns="http://www.w3.org/1998/Math/MathML"> 1500 ∗ 1500 1500*1500 </math>1500∗1500)

对于上述的根据视角自适应采样的方法如何实现?这篇文章详细的介绍了纹理采样,其中的基于MipMap的三线性过滤可以满足我们的要求。在我们使用光栅化渲染,当设置纹理的TEXTURE_MIN_FILTER或TEXTURE_MAG_FILTER为LINEAR_MIPMAP_LINEAR时,OpenGL/WebGL会自动的根据当前像素在UV上的变化率选取合适的MipMap,这是已经集成在硬件上的功能。

解决方案一

基于上述的分析,我们知道光栅化的时候,可以直接利用纹理过滤选项,让硬件帮我们完成最佳的采样。对于凹凸贴图,我们可以直接使用内置的微分函数 <math xmlns="http://www.w3.org/1998/Math/MathML"> d F d x dFdx </math>dFdx、 <math xmlns="http://www.w3.org/1998/Math/MathML"> d F d y dFdy </math>dFdy:

glsl 复制代码
float hp = texture2D(bump, uv).r;
float hpdx = texture2D(bump, uv + dFdx(uv)).r;
float hpdy = texture2D(bump, uv + dFdy(uv)),r;

我们怎么将上面的光栅化应用到光线追踪呢?我们可以把法线的结果通过光栅化预计算到FrameBuffer,将计算结果传入光追的Shader,通过坐标变换求得屏幕坐标,采样即可得到法线结果,下图分别为光栅化得到的法线以及最终渲染结果:

但,这种方案有哪些问题呢?

从这种方案的原理出发,很显然,可以预见它有如下的一些问题:

  1. 仅对摄像机视角内的像素点有效,且无法得到被遮挡的物体的法线结果;
  2. 折射/反射后失真;
  3. 视角转动需重新渲染法线结果的FrameBuffer;
  4. 光线追踪每个像素都会使用低差异序列的抗锯齿采样,而光栅化并无此特性,造成两者实际的渲染点不一致,容易引起物体边缘的不连续。

基于上述问题,引出本文的重点:光线微分法。

光线微分法

感兴趣的朋友可以搜索原论文:《Tracing ray differentials.》Igehy, H.本文结合这篇文章以及实际工程中的一些问题来介绍这个算法。 对于任一射线 <math xmlns="http://www.w3.org/1998/Math/MathML"> R → \overrightarrow {R} </math>R 可以表示为:

<math xmlns="http://www.w3.org/1998/Math/MathML"> R → = ⟨ P , D ⟩ \overrightarrow {R} = \lang \mathbf{P}, \mathbf{D}\rang </math>R =⟨P,D⟩

<math xmlns="http://www.w3.org/1998/Math/MathML"> P \mathbf{P} </math>P为射线的起点, <math xmlns="http://www.w3.org/1998/Math/MathML"> D \mathbf{D} </math>D为射线的方向向量。Ray Tracing的第一次求交时起点为相机的位置,求方向时将屏幕坐标考虑进来,令:

<math xmlns="http://www.w3.org/1998/Math/MathML"> d ( x , y ) = V i e w + x R i g h t + y U p \mathbf{d}(x,y) = \mathbf{View} + x\mathbf{Right} + y\mathbf{Up} </math>d(x,y)=View+xRight+yUp

<math xmlns="http://www.w3.org/1998/Math/MathML"> V i e w \mathbf{View} </math>View为相机的朝向, <math xmlns="http://www.w3.org/1998/Math/MathML"> R i g h t \mathbf{Right} </math>Right为相机的 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x轴方向向量, <math xmlns="http://www.w3.org/1998/Math/MathML"> U p \mathbf{Up} </math>Up为相机的 <math xmlns="http://www.w3.org/1998/Math/MathML"> y y </math>y轴方向向量,因此:

<math xmlns="http://www.w3.org/1998/Math/MathML"> D = d ∥ d ∥ = d ( d ⋅ d ) 1 / 2 \mathbf{D} = \tfrac{\mathbf{d}}{\begin{Vmatrix} \mathbf{d}\end{Vmatrix}} = \tfrac{\mathbf{d}}{(\mathbf{d}\cdot\mathbf{d})^{1/2}} </math>D=∥d∥d=(d⋅d)1/2d

初始化时:

<math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ P ∂ x = 0 \tfrac{\partial\mathbf{P}}{\partial{x}}=0 </math>∂x∂P=0

<math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ D ∂ x = ∂ ( d ( d ⋅ d ) 1 / 2 ) ∂ x = ( d ⋅ d ) R i g h t − ( d ⋅ R i g h t ) d ( d ⋅ d ) 3 / 2 \tfrac{\partial\mathbf{D}}{\partial{x}}=\tfrac{\partial({\tfrac{\mathbf{d}}{(\mathbf{d}\cdot\mathbf{d})^{1/2}})}}{\partial{x}}= \tfrac{(\mathbf{d}\cdot\mathbf{d})\mathbf{Right}-(\mathbf{d}\cdot\mathbf{Right})\mathbf{d}}{(\mathbf{d}\cdot\mathbf{d})^{3/2}} </math>∂x∂D=∂x∂((d⋅d)1/2d)=(d⋅d)3/2(d⋅d)Right−(d⋅Right)d

<math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ D ∂ y \tfrac{\partial\mathbf{D}}{\partial{y}} </math>∂y∂D的求解方法与 <math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ D ∂ x \tfrac{\partial\mathbf{D}}{\partial{x}} </math>∂x∂D类似,本文不再列出。

当光线沿着方向 <math xmlns="http://www.w3.org/1998/Math/MathML"> D \mathbf{D} </math>D传播时,直到与某点相交时,得到交点 <math xmlns="http://www.w3.org/1998/Math/MathML"> P ′ \mathbf{P}^{'} </math>P′: <math xmlns="http://www.w3.org/1998/Math/MathML"> P ′ = P + t D \mathbf{P}^{'}=\mathbf{P} + t\mathbf{D} </math>P′=P+tD,求微分,得:

<math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ P ′ ∂ x = ∂ P ∂ x + t ∂ D ∂ x + ∂ t ∂ x D \tfrac{\partial\mathbf{P}^{'}}{\partial{x}}=\tfrac{\partial\mathbf{P}}{\partial{x}}+t\tfrac{\partial\mathbf{D}}{\partial{x}}+\tfrac{\partial{t}}{\partial{x}}\mathbf{D} </math>∂x∂P′=∂x∂P+t∂x∂D+∂x∂tD

上式中的 <math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ D ∂ x \tfrac{\partial\mathbf{D}}{\partial{x}} </math>∂x∂D和前一步的 <math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ D ∂ x \tfrac{\partial\mathbf{D}}{\partial{x}} </math>∂x∂D一致,因为射线直线传播时方向不变,那么如何求 <math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ t ∂ x \tfrac{\partial{t}}{\partial{x}} </math>∂x∂t?

如上图,射线从点 <math xmlns="http://www.w3.org/1998/Math/MathML"> P P </math>P出发,沿方向 <math xmlns="http://www.w3.org/1998/Math/MathML"> D \mathbf{D} </math>D传播,与 <math xmlns="http://www.w3.org/1998/Math/MathML"> △ A B C \triangle{ABC} </math>△ABC相交于点 <math xmlns="http://www.w3.org/1998/Math/MathML"> P ′ P{'} </math>P′。设 <math xmlns="http://www.w3.org/1998/Math/MathML"> △ A B C \triangle{ABC} </math>△ABC的平面方程为 <math xmlns="http://www.w3.org/1998/Math/MathML"> A x + B y + C z = d Ax+By+Cz=d </math>Ax+By+Cz=d,则其法线 <math xmlns="http://www.w3.org/1998/Math/MathML"> N = [ A , B , C ] \mathbf{N}=[A,B,C] </math>N=[A,B,C],法线方向由三角形确定,与 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x、 <math xmlns="http://www.w3.org/1998/Math/MathML"> y y </math>y不相关。由几何关系得到:

<math xmlns="http://www.w3.org/1998/Math/MathML"> ( P − P ′ ) ⋅ N = − t N ⋅ D \mathbf{(P-P')\cdot\mathbf{N}} = -t\mathbf{N}\cdot\mathbf{D} </math>(P−P′)⋅N=−tN⋅D

<math xmlns="http://www.w3.org/1998/Math/MathML"> ⇒ t = − P ⋅ N N ⋅ D + d N ⋅ D \Rightarrow t = -\tfrac{\mathbf{P\cdot\mathbf{N}}}{\mathbf{N}\cdot\mathbf{D}}+\tfrac{d}{\mathbf{N}\cdot\mathbf{D}} </math>⇒t=−N⋅DP⋅N+N⋅Dd

对 <math xmlns="http://www.w3.org/1998/Math/MathML"> t t </math>t求微分,可得:

<math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ t ∂ x = − ( ∂ P ∂ x + ∂ D ∂ x ) ⋅ N N ⋅ D − d ⋅ ( N ⋅ ∂ D ∂ x ) ( N ⋅ D ) 2 \tfrac{\partial{t}}{\partial{x}}=-\tfrac{(\tfrac{\partial{\mathbf{P}}}{\partial{x}}+\tfrac{\partial{\mathbf{D}}}{\partial{x}})\cdot\mathbf{N}}{\mathbf{N}\cdot\mathbf{D}}-\tfrac{d\cdot(\mathbf{N}\cdot\tfrac{\partial{\mathbf{D}}}{\partial{x}})}{(\mathbf{N\cdot{D}})^2} </math>∂x∂t=−N⋅D(∂x∂P+∂x∂D)⋅N−(N⋅D)2d⋅(N⋅∂x∂D)

接下来我们来分析 <math xmlns="http://www.w3.org/1998/Math/MathML"> P ′ P{'} </math>P′处的UV坐标。已知 <math xmlns="http://www.w3.org/1998/Math/MathML"> P ′ P{'} </math>P′的UV、法线、顶点坐标均为点 <math xmlns="http://www.w3.org/1998/Math/MathML"> A 、 B 、 C A、B、C </math>A、B、C三个顶点内差所得,令点 <math xmlns="http://www.w3.org/1998/Math/MathML"> A 、 B 、 C A、B、C </math>A、B、C处的占比分别为 <math xmlns="http://www.w3.org/1998/Math/MathML"> α 、 β 、 γ \alpha、\beta、\gamma </math>α、β、γ,则满足以下条件:

<math xmlns="http://www.w3.org/1998/Math/MathML"> α + β + γ = 1 \alpha+\beta+\gamma=1 </math>α+β+γ=1

<math xmlns="http://www.w3.org/1998/Math/MathML"> α A + β B + γ C = P ′ \alpha\mathbf{A}+\beta\mathbf{B}+\gamma\mathbf{C}=\mathbf{P{}'} </math>αA+βB+γC=P′

<math xmlns="http://www.w3.org/1998/Math/MathML"> ⇒ [ A x A y A z B x B y B z C x C y C z 1 1 1 ] [ α β γ ] = [ P ′ x P ′ y P ′ z 1 ] \Rightarrow \left[ \begin{array}{ccc} \mathbf{A}_x & \mathbf{A}_y & \mathbf{A}_z \\ \mathbf{B}_x & \mathbf{B}_y & \mathbf{B}_z \\ \mathbf{C}_x & \mathbf{C}_y & \mathbf{C}_z \\ 1 & 1 & 1 \end{array} \right]\left[ \begin{array}{ccc} \alpha \\ \beta \\ \gamma \end{array} \right]=\left[ \begin{array}{ccc} \mathbf{P{'}}_x \\ \mathbf{P{'}}_y \\ \mathbf{P{'}}_z \\ 1 \end{array} \right] </math>⇒⎣ ⎡AxBxCx1AyByCy1AzBzCz1⎦ ⎤⎣ ⎡αβγ⎦ ⎤=⎣ ⎡P′xP′yP′z1⎦ ⎤

假定当前的交点是满足上述内差条件的,则可得:

<math xmlns="http://www.w3.org/1998/Math/MathML"> [ A x A y A z B x B y B z C x C y C z ] [ α β γ ] = [ P ′ x P ′ y P ′ z ] \left[ \begin{array}{ccc} \mathbf{A}_x & \mathbf{A}_y & \mathbf{A}_z \\ \mathbf{B}_x & \mathbf{B}_y & \mathbf{B}_z \\ \mathbf{C}_x & \mathbf{C}_y & \mathbf{C}_z \end{array} \right]\left[ \begin{array}{ccc} \alpha \\ \beta \\ \gamma \end{array} \right]=\left[ \begin{array}{ccc} \mathbf{P{'}}_x \\ \mathbf{P{'}}_y \\ \mathbf{P{'}}_z \end{array} \right] </math>⎣ ⎡AxBxCxAyByCyAzBzCz⎦ ⎤⎣ ⎡αβγ⎦ ⎤=⎣ ⎡P′xP′yP′z⎦ ⎤

且 <math xmlns="http://www.w3.org/1998/Math/MathML"> α + β + γ = 1 \alpha+\beta+\gamma=1 </math>α+β+γ=1。

设 <math xmlns="http://www.w3.org/1998/Math/MathML"> M = [ A x A y A z B x B y B z C x C y C z ] \mathbf{M}=\left[ \begin{array}{ccc} \mathbf{A}_x & \mathbf{A}_y & \mathbf{A}_z \\ \mathbf{B}_x & \mathbf{B}_y & \mathbf{B}_z \\ \mathbf{C}_x & \mathbf{C}_y & \mathbf{C}_z \end{array} \right] </math>M=⎣ ⎡AxBxCxAyByCyAzBzCz⎦ ⎤,若 <math xmlns="http://www.w3.org/1998/Math/MathML"> M \mathbf{M} </math>M可逆,可得:

<math xmlns="http://www.w3.org/1998/Math/MathML"> [ α β γ ] = M − 1 [ P ′ x P ′ y P ′ z ] \left[ \begin{array}{ccc} \alpha \\ \beta \\ \gamma \end{array} \right]=\mathbf{M}^{-1}\left[ \begin{array}{ccc} \mathbf{P{'}}_x \\ \mathbf{P{'}}_y \\ \mathbf{P{'}}_z \end{array} \right] </math>⎣ ⎡αβγ⎦ ⎤=M−1⎣ ⎡P′xP′yP′z⎦ ⎤

由此我们得到了内差系数 <math xmlns="http://www.w3.org/1998/Math/MathML"> α 、 β 、 γ \alpha、\beta、\gamma </math>α、β、γ和内差结果的变换关系。然而上述等式成立的条件是变换矩阵可逆,这个条件有的时候可能不满足,比如所有顶点都在 <math xmlns="http://www.w3.org/1998/Math/MathML"> x y xy </math>xy平面上,此时所有点的 <math xmlns="http://www.w3.org/1998/Math/MathML"> z z </math>z轴分量为0,矩阵不可逆。

为了解决这个问题,笔者构造了一个新的空间,使得该空间的 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x轴为三角形其中一边, <math xmlns="http://www.w3.org/1998/Math/MathML"> z z </math>z轴为与三角形所在平面的法线和新的 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x轴都成45度的向量, <math xmlns="http://www.w3.org/1998/Math/MathML"> y y </math>y轴即为两者的正交向量,令新空间的变换矩阵为 <math xmlns="http://www.w3.org/1998/Math/MathML"> M 1 \mathbf{M_1} </math>M1,则变换后的顶点 <math xmlns="http://www.w3.org/1998/Math/MathML"> A ′ 、 B ′ 、 C ′ \mathbf{A'}、\mathbf{B'}、\mathbf{C'} </math>A′、B′、C′分别为:

<math xmlns="http://www.w3.org/1998/Math/MathML"> A ′ = M 1 A \mathbf{A'}=\mathbf{M_1}\mathbf{A} </math>A′=M1A

<math xmlns="http://www.w3.org/1998/Math/MathML"> B ′ = M 1 B \mathbf{B'}=\mathbf{M_1}\mathbf{B} </math>B′=M1B

<math xmlns="http://www.w3.org/1998/Math/MathML"> C ′ = M 1 C \mathbf{C'}=\mathbf{M_1}\mathbf{C} </math>C′=M1C

且 <math xmlns="http://www.w3.org/1998/Math/MathML"> A ′ 、 B ′ 、 C ′ \mathbf{A'}、\mathbf{B'}、\mathbf{C'} </math>A′、B′、C′依旧满足:

<math xmlns="http://www.w3.org/1998/Math/MathML"> [ A ′ x A ′ y A ′ z B ′ x B ′ y B ′ z C ′ x C ′ y C ′ z ] [ α β γ ] = M 1 [ P ′ x P ′ y P ′ z ] \left[ \begin{array}{ccc} \mathbf{A'}_x & \mathbf{A'}_y & \mathbf{A'}_z \\ \mathbf{B'}_x & \mathbf{B'}_y & \mathbf{B'}_z \\ \mathbf{C'}_x & \mathbf{C'}_y & \mathbf{C'}_z \end{array} \right]\left[ \begin{array}{ccc} \alpha \\ \beta \\ \gamma \end{array} \right]=\mathbf{M_1}\left[ \begin{array}{ccc} \mathbf{P{'}}_x \\ \mathbf{P{'}}_y \\ \mathbf{P{'}}_z \end{array} \right] </math>⎣ ⎡A′xB′xC′xA′yB′yC′yA′zB′zC′z⎦ ⎤⎣ ⎡αβγ⎦ ⎤=M1⎣ ⎡P′xP′yP′z⎦ ⎤

令 <math xmlns="http://www.w3.org/1998/Math/MathML"> M 2 = [ A ′ x A ′ y A ′ z B ′ x B ′ y B ′ z C ′ x C ′ y C ′ z ] \mathbf{M_2}=\left[ \begin{array}{ccc} \mathbf{A'}_x & \mathbf{A'}_y & \mathbf{A'}_z \\ \mathbf{B'}_x & \mathbf{B'}_y & \mathbf{B'}_z \\ \mathbf{C'}_x & \mathbf{C'}_y & \mathbf{C'}_z \end{array} \right] </math>M2=⎣ ⎡A′xB′xC′xA′yB′yC′yA′zB′zC′z⎦ ⎤,则:

<math xmlns="http://www.w3.org/1998/Math/MathML"> [ α β γ ] = M 2 − 1 M 1 [ P ′ x P ′ y P ′ z ] \left[ \begin{array}{ccc} \alpha \\ \beta \\ \gamma \end{array} \right]=\mathbf{M_2^{-1}}\mathbf{M_1}\left[ \begin{array}{ccc} \mathbf{P{'}}_x \\ \mathbf{P{'}}_y \\ \mathbf{P{'}}_z \end{array} \right] </math>⎣ ⎡αβγ⎦ ⎤=M2−1M1⎣ ⎡P′xP′yP′z⎦ ⎤

对于 <math xmlns="http://www.w3.org/1998/Math/MathML"> P ′ P{'} </math>P′的UV坐标 <math xmlns="http://www.w3.org/1998/Math/MathML"> S ′ = [ u ′ v ′ 1 ] \mathbf{S^{'}}=\left[ \begin{array}{ccc} u^{'} \\ v^{'} \\ 1 \end{array} \right] </math>S′=⎣ ⎡u′v′1⎦ ⎤,依然满足内插规则:

<math xmlns="http://www.w3.org/1998/Math/MathML"> α S a + β S b + γ S c = S ′ \alpha\mathbf{S_a}+\beta\mathbf{S_b}+\gamma\mathbf{S_c}=\mathbf{S'} </math>αSa+βSb+γSc=S′

设 <math xmlns="http://www.w3.org/1998/Math/MathML"> M = M 2 − 1 M 1 M=\mathbf{M_2^{-1}}\mathbf{M_1} </math>M=M2−1M1,对 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x求微分:

<math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ S ′ ∂ x = ∂ α ∂ x S a + ∂ β ∂ x S b + ∂ γ ∂ x S c \tfrac{\partial{\mathbf{S'}}}{\partial{x}}=\tfrac{\partial{\alpha}}{\partial{x}}\mathbf{S}_a+\tfrac{\partial{\beta}}{\partial{x}}\mathbf{S}_b+\tfrac{\partial{\gamma}}{\partial{x}}\mathbf{S}_c </math>∂x∂S′=∂x∂αSa+∂x∂βSb+∂x∂γSc

<math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ S ′ ∂ x = M [ 0 ] ∂ P ′ ∂ x S a + M [ 1 ] ∂ P ′ ∂ x S b + M [ 2 ] ∂ P ′ ∂ x S c \tfrac{\partial{\mathbf{S'}}}{\partial{x}}=\mathbf{M}_{[0]}\tfrac{\partial{\mathbf{P'}}}{\partial{x}}\mathbf{S}a+\mathbf{M}{[1]}\tfrac{\partial{\mathbf{P'}}}{\partial{x}}\mathbf{S}b+\mathbf{M}{[2]}\tfrac{\partial{\mathbf{P'}}}{\partial{x}}\mathbf{S}_c </math>∂x∂S′=M[0]∂x∂P′Sa+M[1]∂x∂P′Sb+M[2]∂x∂P′Sc

<math xmlns="http://www.w3.org/1998/Math/MathML"> M [ i ] \mathbf{M}_{[i]} </math>M[i]为 <math xmlns="http://www.w3.org/1998/Math/MathML"> M \mathbf{M} </math>M的第 <math xmlns="http://www.w3.org/1998/Math/MathML"> i i </math>i行向量。

下两张图分别为使用光线微分和光栅化计算得到的 <math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ S ′ ∂ x \tfrac{\partial{\mathbf{S'}}}{\partial{x}} </math>∂x∂S′,为了显示更明显,将其值放大了10倍。

现在我们得到了 <math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ S ′ ∂ x \tfrac{\partial{\mathbf{S'}}}{\partial{x}} </math>∂x∂S′,对纹理进行采样时需要利用相关数据计算MipMap的等级。

渲染点 <math xmlns="http://www.w3.org/1998/Math/MathML"> P ′ P{'} </math>P′与其向右和向上一个像素点对应的UV差值为:

<math xmlns="http://www.w3.org/1998/Math/MathML"> Δ T x ≈ Δ x ∂ S ′ ∂ x \Delta\mathbf{T}_x\approx\Delta{x}\tfrac{\partial{\mathbf{S'}}}{\partial{x}} </math>ΔTx≈Δx∂x∂S′

<math xmlns="http://www.w3.org/1998/Math/MathML"> Δ T y ≈ Δ y ∂ S ′ ∂ y \Delta\mathbf{T}_y\approx\Delta{y}\tfrac{\partial{\mathbf{S'}}}{\partial{y}} </math>ΔTy≈Δy∂y∂S′

MipMap的等级 <math xmlns="http://www.w3.org/1998/Math/MathML"> l o d lod </math>lod可以表示为:

<math xmlns="http://www.w3.org/1998/Math/MathML"> l o d = 0.5 l o g 2 [ m a x ( Δ x ⋅ Δ x , Δ y ⋅ Δ y ) ] lod=0.5log_2[max(\Delta{x}\cdot\Delta{x},\Delta{y}\cdot\Delta{y})] </math>lod=0.5log2[max(Δx⋅Δx,Δy⋅Δy)]

计算出了 <math xmlns="http://www.w3.org/1998/Math/MathML"> l o d lod </math>lod的值,我们需要对纹理进行三线性插值计算:

插值计算的两级MipMap分别为:

<math xmlns="http://www.w3.org/1998/Math/MathML"> l o d s u b = f l o o r ( l o d ) lod_{sub} = floor(lod) </math>lodsub=floor(lod)

<math xmlns="http://www.w3.org/1998/Math/MathML"> l o d u p = f l o o r ( l o d ) + 1 lod_{up} = floor(lod)+1 </math>lodup=floor(lod)+1

<math xmlns="http://www.w3.org/1998/Math/MathML"> F u p = l o d − l o d s u b F_{up} = lod - lod_{sub} </math>Fup=lod−lodsub

分别采样 <math xmlns="http://www.w3.org/1998/Math/MathML"> l o d s u b lod_{sub} </math>lodsub和 <math xmlns="http://www.w3.org/1998/Math/MathML"> l o d u p lod_{up} </math>lodup两个等级的结果,再将两者进行线性插值,其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> l o d u p lod_{up} </math>lodup的占比为 <math xmlns="http://www.w3.org/1998/Math/MathML"> F u p F_{up} </math>Fup。

使用光线微分后,渲染的结果如下:

总结

要做出高质量的光线追踪渲染,在做纹理采样时需要应用纹理过滤,光线追踪时由于无法使用诸如 <math xmlns="http://www.w3.org/1998/Math/MathML"> d F d x dFdx </math>dFdx的函数,需要根据射线的表达式手动计算微分,而本文所用的光线微分便为其中一种方法。需要注意的是,本文仅对光线直线传播时进行了分析,当光线发生折射和反射时,光线的方向发生了变化,还需要将 <math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ N ∂ x \tfrac{\partial{\mathbf{N}}}{\partial{x}} </math>∂x∂N和 <math xmlns="http://www.w3.org/1998/Math/MathML"> ∂ N ∂ y \tfrac{\partial{\mathbf{N}}}{\partial{y}} </math>∂y∂N考虑进来,感兴趣的读者可以阅读上面的Paper,这部分的内容我也将在近期分享。

参考

《Tracing ray differentials.》Igehy, H. (1999). SIGGRAPH '99 Proceedings

相关推荐
小彭努力中2 天前
141. Sprite标签(Canvas作为贴图)
前端·深度学习·3d·webgl·three.js
Ian10253 天前
WebGL进阶(十一)层次模型
webgl
mirrornan4 天前
什么是Web3D?有何优势?有哪些应用场景?
3d·web3·webgl·3d模型
小彭努力中5 天前
138. CSS3DRenderer渲染HTML标签
前端·深度学习·3d·webgl·three.js
优雅永不过时·5 天前
three.js实现地球 外部扫描的着色器
前端·javascript·webgl·three.js·着色器
汪洪墩6 天前
【Mars3d】实现这个地图能靠左,不居中的样式效果
前端·javascript·vue.js·3d·webgl·cesium
allenjiao6 天前
webgl threejs 云渲染(服务器渲染、后端渲染)解决方案
webgl·云渲染·threejs·服务器渲染·后端渲染·云流化·三维云渲染
踏实探索7 天前
OpenLayers教程12_WebGL自定义着色器:实现高级渲染效果
前端·arcgis·vue·webgl·着色器
EasyNTS8 天前
H.265流媒体播放器EasyPlayer.js网页直播/点播播放器WebGL: CONTEXT_LOST_WEBGL错误引发的原因
javascript·webgl·h.265
那年那棵树9 天前
【Cesium】自定义材质,添加带有方向的滚动路线
vue·webgl·材质