Note that this Project was written during my undergraduate studies. Some points may be incorrect.
Brief Introduction to UE’s Implementation
This project is based on the implementation of the unreal engine. I assume that you have a basic knowledge of volume rendering and will not go into detail about it. If you are interested, you can read my blog about Volume Rendering In Offline Rendering. Here are some basic terms about the sky atmosphere rendering:
σa: absorption coefficient, the probability density that light is absorbed per unit distance traveled in the medium. σs: scattering coefficient, the probability of an out-scattering event occurring per unit distance. σt: attenuation coefficient, the sum of the absorption coefficient and the scattering coefficient, describes the combined effect of the absorption and out scattering. σt=σa+σs T(a,b): transmittance, the fraction of radiance that is transmitted between two points T(a,b)=e−∫abσt(h)ds ϕu: phase function, the angular distribution of scattered radiation at a point
Volume Rendering Euqation: The lighting result at the point x from direct v equals the combination of single scattering and multi-scattering:
L(x,v)=L1(x,v)+Ln(x,v)
The single scattering result at point x from point p in direction v is the sum of the transmitted radiance reflected from the ground and the integration of the radiance from the view point to the ground or sky:
N-bounce multi-scattering (Ln) integrate the Gn in the point along the view direction, where Gn is the integration of the Ln−1 scattering result from the direction on the sphere. Multi-Scattering is difficult to calculate compared to Single-Scattering. There are many simplifications that are made in UE’s sky-atmosphere for multi-scattering, we will be introducing it later.
There are two important properties of beam transmittance. The first property is that the transmittance between two points is the same in both directions if the attenuation coefficient satisfies the directional symmetry σt(w)=σt(−w):
T(a,b)=T(b,a)
Another important property, true in all media, is that transmittance is multiplicative along points on a ray:
T(a,b)=T(a,c)T(c,b)
This property enables us to calculate the transmittance between any two points quickly by precalculating the transmittance between these two points and the boundary of the sky atmosphere:
T(a,b)=T(b,boundnary)T(a,boundnary) T(a,b) is a 3-dimensional function of the dimension x,y and z. We can convert this function to a 2-dimensional function of the view height and view zenith angle, since the earth is symmetric horizontally.
Transmittance lut’s u coordinate is view zenith cosine angle ranging from -1 to 1. In addition, the v coordinate is mapped to the view height ranging from the bottom radius to the top radius. Bruneton’s paper use a generic mapping, working for any atmosphere, but still providing an increased sampling rate near the horizon. In the following figure, the red curve represents Bruneton’s implementation, while the purple curve represents a linear interpolation.
We can get the world position and world direction from the view height and the view zenith angle mapped from the texture coordinates.
The medium extinction contains two parts: mie extinction and rayleigh extinction, which is a expontial function of the view height:
σt(h)=σt_mi(h)+σt_rayleigh(h)
Participating media following the Rayleigh and Mie theories have an altitude density distribution of dt_mi(h)=e8km−h and dt_ray(h)=e1.2km−h , respectively. Rayleigh participation media components have different coefficients, which results in a blue sky at noon and a red sky at dusk.
Our next step is to precompute the 4π1∫Ωfmsdw value and store it in the two-dimensional LUT table.UE’s sky atmosphere has three different integration methods for different quality levels. The first implementation is to integrate the fms on the uniform sphere, which is expensive and only used in case of high quality.The second one is to integrate fms 8 times with the following ray direction:
What we employed in the xengine is the last approach: sample twice from the view direction and negative direction:
The remaining single scattering term is the integration along the view direction:
L=∫0b(Vis(p,v)T(p,v)(σs_mieϕmie+σs_rayϕray)+σsGall)dt, where Vis is the shadow term in this position and the transmittance term is obtained from transmittance lut.
Another important term is the phase function term, which indicates the relative ratio of light lost in a particular direction after a scattering event. Here is the rayleigh phase function. The 16π3 coefficient serves as a normalisation factor, so that the integral over a unit sphere is 1:
ϕray(θ)=16π3(1+cos2(θ))
We use the simpler Henyey-Greenstein phase function for mie scattering:
1 2 3 4 5 6
floatHgPhase(float G, float CosTheta) { float Numer = 1.0f - G * G; float Denom = 1.0f + G * G + 2.0f * G * CosTheta; return Numer / (4.0f * PI * Denom * sqrt(Denom)); }
Latitude/Longtitude Texture
UE’s implementation renders the distant sky into a latitude/longtitude sky-view LUT texture in a low resolution and upscales the texture on the lighting pass.In order to better represent the high-frequency visual features toward the horizon, unreal engine applies a non-linear transformation to the latitude l when computing the texture coordinate v in [0,1] that will compress more texels near the horizon:
Sky-View LUT doesn’t calculate sun disk luminance, since it is high-frequency lighting, which should be computed at full resolution in the lighting pass based on the view direction and the light direction. The rest low-frequency part can be obtained by looking up the sky-view LUT directly. Below is the result of our implementation in XEngine.