【实时渲染】UE新版大气渲染(论文及分析)

UE4新版的大气实现性能上完全碾压基于预计算大气散射方法,它是在论文A Scalable and Production Ready Sky and Atmosphere Rendering Technique的基础上实现的。

从篇幅就可以看出来这篇论文的主要看点在Multi Scatter部分,几乎是剩下三个LUT篇幅和的两倍。

Multiple scattering LUT

其实这个新的方法只是比之前的预计算大气散射多想了一步近似。

为了保持符号相同,后文都用预计算大气散射论文的公式进行分析:
L = L 0 + ( R + S ) L 0 + ( R + S ) [ ( R + S ) L 0 ] + . . . . . . L=L_0+(R+S)L_0+(R+S)[(R+S)L_0]+...... L=L0+(R+S)L0+(R+S)[(R+S)L0]+......
= L 0 + R [ L ∗ ] + S [ L ∗ ] =L_0+R[L_*]+S[L_*] =L0+R[L]+S[L]

看到这个公式,我们容易会有下面的想法,只要知道R+S不就知道全部阶数了吗?
L 1 = ( R + S ) L 0 L_1=(R+S)L_0 L1=(R+S)L0
L 2 = ( R + S ) L 1 L_2=(R+S)L_1 L2=(R+S)L1

但是R和S里面还包含了L,R+S没法分离,新方法做的第一步就是把R给忽略,不考虑地面的反射。只剩下S了,S里面还有L,这是个递归的过程,怎么终结这个递归,很简单,把S里面的L设为一个固定数值就可以了。

所以这个方法总结下来就两点,忽略地面反射并设n-1阶的L是个固定的值。

近似1:
L n = R [ L n − 1 ] + S [ L n − 1 ] L_n=R[L_{n-1}]+S[L_{n-1}] Ln=R[Ln1]+S[Ln1]
L n = S [ L n − 1 ] L_n=S[L_{n-1}] Ln=S[Ln1]

近似2:
L n = S [ L n − 1 ] = ∫ T ( ∫ Ω σ s × p h a s e ( ) × L n − 1 d w ) d x L_n=S[L_{n-1}]=\int T(\int_{\Omega}\sigma_s\times phase()\times L_{n-1}dw)dx Ln=S[Ln1]=T(Ωσs×phase()×Ln1dw)dx
L n = S [ L n − 1 ] = L n − 1 ∫ T ( ∫ Ω σ s × p h a s e ( ) d w ) d x L_n=S[L_{n-1}]=L_{n-1}\int T(\int_{\Omega}\sigma_s\times phase()dw)dx Ln=S[Ln1]=Ln1T(Ωσs×phase()dw)dx
L n = S [ L n − 1 ] = L n − 1 ∫ T ( ∫ Ω σ s × 1 4 π d w ) d x L_n=S[L_{n-1}]=L_{n-1}\int T(\int_{\Omega}\sigma_s\times \frac{1}{4\pi}dw)dx Ln=S[Ln1]=Ln1T(Ωσs×4π1dw)dx

L n = L n − 1 f m s L_n=L_{n-1}f_{ms} Ln=Ln1fms

再回到最初的式子
L = L 0 + ( R + S ) L 0 + ( R + S ) [ ( R + S ) L 0 + . . . . . . L=L_0+(R+S)L_0+(R+S)[(R+S)L_0+...... L=L0+(R+S)L0+(R+S)[(R+S)L0+......
L = L 0 + ( R + S ) L 0 + L 2 + f m s L 2 + f m s 2 L 2 + . . . . . . L=L_0+(R+S)L_0+L_2+f_{ms}L_2+f_{ms}^2L_2+...... L=L0+(R+S)L0+L2+fmsL2+fms2L2+......

运用几何级数
L = L 0 + ( R + S ) L 0 + L 2 ( 1 + f m s + f m s 2 + . . . . . . ) L=L_0+(R+S)L_0+L_2(1+f_{ms}+f_{ms}^2+......) L=L0+(R+S)L0+L2(1+fms+fms2+......)
L = L 0 + ( R + S ) L 0 + L 2 ( 1 / ( 1 − f m s ) ) L=L_0+(R+S)L_0+L_2(1/(1-f_{ms})) L=L0+(R+S)L0+L2(1/(1fms))

这样就是整个论文的核心了,后文可以不看了,只需要计算出下面的式子就可以了。

f m s = ∫ T r ( ∫ Ω σ s × 1 4 π d w ) d x f_{ms}=\int Tr(\int_{\Omega}\sigma_s\times \frac{1}{4\pi}dw)dx fms=Tr(Ωσs×4π1dw)dx

是不是很无脑。

大气模型

Raylei和Mie的海拔密度分布公式如下:
d r ( h ) = e − h 8 k m d^r(h)=e^{-\frac{h}{8km}} dr(h)=e8kmh
d m ( h ) = e − h 12 k m d^m(h)=e^{-\frac{h}{12km}} dm(h)=e12kmh
臭氧是天空呈现天蓝色的重要因素,它对散射没有贡献,仅仅吸收Light。
d o ( h ) = m a x ( 0 , 1 − ∣ h − 25 ∣ 15 ) d^o(h)=max(0,1-\frac{|h-25|}{15}) do(h)=max(0,115h25)

	const float densityMie = exp(Atmosphere.MieDensityExpScale * viewHeight);
	const float densityRay = exp(Atmosphere.RayleighDensityExpScale * viewHeight);
	const float densityOzo = saturate(viewHeight < Atmosphere.AbsorptionDensity0LayerWidth ?
		Atmosphere.AbsorptionDensity0LinearTerm * viewHeight + Atmosphere.AbsorptionDensity0ConstantTerm :
		Atmosphere.AbsorptionDensity1LinearTerm * viewHeight + Atmosphere.AbsorptionDensity1ConstantTerm);

论文假设Rayleigh没有吸收,只有散射。
σ a r = ( 5.802 , 13.558 , 33.1 ) \sigma_a^r=(5.802,13.558,33.1) σar=(5.802,13.558,33.1)
σ s r = ( 0 , 0 , 0 ) \sigma_s^r=(0,0,0) σsr=(0,0,0)
σ t r = σ a r + σ s r \sigma_t^r=\sigma_a^r+\sigma_s^r σtr=σar+σsr

接着乘上海拔密度
σ a r ∗ = d r ( h ) \sigma_a^r*=d^r(h) σar=dr(h)

最后把Raylei、Mie和臭氧对应系数相加。

	s.scatteringMie = densityMie * Atmosphere.MieScattering;
	s.absorptionMie = densityMie * Atmosphere.MieAbsorption;
	s.extinctionMie = densityMie * Atmosphere.MieExtinction;

	s.scatteringRay = densityRay * Atmosphere.RayleighScattering;
	s.absorptionRay = 0.0f;
	s.extinctionRay = s.scatteringRay + s.absorptionRay;

	s.scatteringOzo = 0.0;
	s.absorptionOzo = densityOzo * Atmosphere.AbsorptionExtinction;
	s.extinctionOzo = s.scatteringOzo + s.absorptionOzo;

	s.scattering = s.scatteringMie + s.scatteringRay + s.scatteringOzo;
	s.absorption = s.absorptionMie + s.absorptionRay + s.absorptionOzo;
	s.extinction = s.extinctionMie + s.extinctionRay + s.extinctionOzo;

Sky-View LUT

用RayMarching进行Sample的消耗还是很大。作者观察到Earth-like sky的效果其实是非常低频的,所以论文将Sky的渲染结果放大一个低分辨率的LUT(192x108)中,在后续的进行upsample以减少消耗。

1.对于给定视点,文章将Sky渲染到一张latitude-longitude坐标的纹理上,上半部分是天空,下半部分是地面,中间是地平线,同时由于在接近地平线的部分是相对高频的信息,文章对latitude 进行非线性映射,使得接近地平线的部分存储更多信息。
v = 0.5 + 0.5 sign ⁡ ( l ) ⋅ l π / 2 v=0.5+0.5\operatorname{sign}(l)\cdot\sqrt{\frac{l}{\pi/2}} v=0.5+0.5sign(l)π/2l

	float coord = (acos(viewZenithCosAngle) - ZenithHorizonAngle) / Beta;
	coord = sqrt(coord);
	uv.y = coord * 0.5f + 0.5f;

2.同时由于分辨率较低以及非线性映射的原因,sun disk在最后与Sky-View LUT进行合成。

output.Luminance = float4(SkyViewLutTexture.SampleLevel(samplerLinearClamp, uv, 0).rgb + GetSunLuminance(WorldPos, WorldDir, Atmosphere.BottomRadius), 1.0);

Aerial Perspective LUT

和Sky-View LUT类似,为了减少消耗,文章将各位置的in-scattering and transmittance进行计算并存储到一张32x32x32的Texture中,可以覆盖32km的场景。

在最后计算时根据这一点的pixel得到对应Pos,对LUT查找得到最终结果。

上一篇文章的基于预计算的方法需要RayMarching来Sample,本文计算时通过实例渲染和GS来进行绘制,相当于计算32x32x32次,效率提升很明显。

const float4 AP = Weight * AtmosphereCameraScatteringVolume.SampleLevel(samplerLinearClamp, float3(pixPos / float2(gResolution), w), 0);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值