Hight field: apply material and normal map on a single mesh. It is still the dominant way to generate terrain.
To use Adaptive Mesh Tesselation, we edit the original mesh
However, when we sub-divide the above two triangle by adding line ED
, observe that shape AEBC
is no longer a triangle. To solve this problem, it is typical to split the shape into AEB
and ABC
as two triangle. The resulting graph is as follow:
Due to floating point error, the small triangle can be rendered in overlap with the bigger triangle, causing either pixel to be drawn twice or never drawn. This might not seem as bad, but it can cause problems with transparency or stencil operations.
The reason for floating point error to be significant: The triangle location (converted from floating point) on screen space is discrete as screen-space triangle is stored in
(X, Y)
integer pair. If floating points were used, triangle set-up can be inaccurate for long-thin triangles. For more, read stackoverflow
A popular method is to force split triangle in the following manner to avoid T-Junction:
The performance of binary tree subdivision is good. However, it is unintuitive to construct and hard for resource management. Therefore a more popular method is quad-tree based subdivision.
For Example:
Block: file-based division, usually 512x512
meter in size.
Patch: 64x64
meter within a block.
Note that this method is not based on triangle, rather on squares as we can easily apply texture in this manner since textures are always stored in square, not triangles.
Similar to Binary Tree Subdivision, Quad Tree Subdivision will also generate T-Junction, we "stich" it by edit the topology of the graph:
In above example, we used a triangle of 0
size, this is commonly called degenerate triangle. The graphics pipeline will avoid drawing triangle of 0
size.
Another method is to pre-process mesh to avoid drawing more triangles than needed on flat surfaces. This technique can only be used in very flat surfaces, and therefore every little game actually use it.
GPU can dynamically calculate subdivision rules at rendering-time.
Hull Shader: transform input mesh into control points and tells tesselation how many subdivision is needed.
Tesselator: tesselate given mesh
Domain Shader: move vertex point based on height map
However, this hardware-based Geometry Shader is not ideal, new DirectX12 or above (Win10 or above) support Mesh Shader Pipeline
Since GPU-based rendering-time tesselation dirrect berried within redering pipeline allow us to transform geometry in real time.
Deformable terrain for snow ground is easier than, for example, big cannonball holes in war-related games because it does not interfere with physics. Cannonball holes require updates to physics.
Traditionally, caves and other non-flat topology is accomplished by inserting mesh into heightfield terrain.
Other methods involving marking vertex position as NaN
, in which the vertex will be disconnected from other vertex in tesselation step. Using this, we can create holes in heightfield terrain. Artists then use object to patch the hole for desired outcome.
The volumetric representation is consists of a set of occupancy points in 3D space and then interpreted by marching cude.
Interestingly, marching cube is also used in reconstruction of Visible Human Project
There are also related solution to adjusting LOD of volumetric marching cube.
The blend is too smooth and does not obey physics.
The solution is to use height field.
The above solution generates high frequency signal that might cause problem. We add some transparency near the boundary.
In practice, textures are loaded in an array (of hundreds of elements) for fast sampling and alpha interpolation.
Sparse/Streaming Virtual Texture (SVT): store all baked texture map on drive. We load the texture of the whole world tile by tile of the same size.
Mipmap Streaming: store mipmap level and load level by level.
Procedural Virtual Texture (PVT): a balance between Procedural Splatting and SVT. It pre-calculate texture baking on the run.
Adaptive Virtual Texture (AVT): instead of loading tile by tile, we dynamically calculate the area we should load the texture based on view direction.
Instead of rendering using world coordinate, it is suggested to use camera coordinate as the floating point precision near the camera is greatest. Therefore, only far-away object will have inaccuracy due to floating point precision error.
Road: provide artists with to to edit road and change heightfield accordingly Decal: decal baked onto virtual texture. Therefore such mix is happening at bake time, not run time.
The above calculation is easy but it is not adjustable to different weathers and only restricted to ground-view.
In reality, light will bounce depending on the composition of different participating media.
Radiative Transfer Equation (RTE): a 3D function involving Laplace that incorporates 4 (or 3 if without emission) interactions
absorption
out-scattering
emission
in-scattering
If we integrate above formula, we get the volume rendering equation:
Rayleigh Scattering: when light hit air particles (N_2, O_3, O_3) that is much smaller than the wavelength of radiation
for smaller wavelength, it scatter less
for larger wavelength, it scatter more
Mie Scattering: when light hit aerosols (Dust, Sand) that is similar or larger than the wavelength of radiation
Mie Scattering explains fog and halo of the Sun.
Air Molecules Absorption:
Ozone (O_3): absorb reds, oranges, yellows, and some invisible wavelengths
Methane (CH_4): absorb reds
Single Scattering: assuming particles are independent from each other
Multi Scattering: particles can light up each other
We pre-calculate atmospheric scattinging using ray marching and store it in a 2D map for fast look up.
And then we combine those to to do n-order scattering to generate a multi-scattering lookup table.
This produce the state-of-the-art effect.
Challenge:
pre-computation is costly
artists can't interact with scattering parameters due to large pre-computation
can't change parameters dynamically according to weather
runtime lookup and interpolate is costly
A Scalable and Production Ready Sky and Atmosphere Rendering Technique
Since scattering is homogeneous and uniform, we approximate scatting as percentage decay of the original light and sum them into a series to infinity.
We also reduce look up table by eliminating height h and the angle of the sun. What we get is a 2D map with 2 angles.
Old way of doing clouds:
3D model
Billboard
Now we do realtime volumetic rendering for clouds. We first generate a cloud map represent cloud coverage. We generate columns of cloud according to coverage and erose it using noise function to approximate fractals.
But then clouds not just receive light from the sun, but also from the sky.
For realtime, there is only two main methods: approximate and pre-compute.
Table of Content