In order to demonstrate a number of different hlsl shaders in DirectX11, I created a 3D scene using a framework I was given by a lecturer in my 3rd year of university.
Aspects of the scene:
- Basic vertex manipulation – Vertex shaders.
- Shadows using shadow mapping – Depth shader, shadow shader.
- Height map that makes use of tessellation – Hull shader, domain shader, pixel shader.
- Gaussian blur post-processing – horizontal and vertical blur shaders.
Basic vertex manipulation shader:
To create a basic simulation of flowing water, a large plane can be passed through a vertex manipulation shader that makes use of a small formula that manipulates the Y co-ordinate of each vertex based on a cosine wave. The cosine formula is added to a time variable which gives movement to the wave. On top of this, a water texture is added to the plane. The final product is shown in the following gif:
To simulate shadows within the scene, a flat plane and a model are passed through a depth shader which calculates the depth of each pixel from the point of view of the light that casts the shadow.
The depth texture is given to the shadow shaders, along with the texture of each object and the position of the light. The resulting shadow map is then given to the pixel shader which determines that anything in the shadow map cannot be in shadow – thus the resulting pixels are lit – leaving the rest of the scene in shadow.
Tessellated Height Map:
Tessellation is used in games to create very highly detailed textures. As an example, I passed a height map through a tessellator in order to show the difference that tessellation can make.
To begin with, the vertex shader receives and processes the control points, ready to send to the hull shader. The constant hull shader receives all of the control points and makes use of the tessellation factor that is passed in. It will then output the tessellation factor for each edge and interior of the patch. The control point hull shader sets up each control point for the tessellator. The tessellator now only has to subdivide each patch based on the tessellation factors that were calculated in the hull shader stage. The new vertices are then passed onto the domain shader stage.
The domain shader will act as a vertex shader and calculate the vertex manipulation based on a height map texture that is passed in. Using the tessellated vertices, the domain shader makes use of linear interpolation to calculate the position of the vertices, texture co-ordinates and normals of the plane. The texture co-ordinates are then used to increase the height of the Y vertices, based on the colour of the heightmap texture.
After the vertex manipulation, the pixel shader applies light calculations using a texture and two separate lights.
Post Processing – Gaussian Blur
Post-processing in general can be quite taxing on the performance of any program. To alleviate this slightly, the process of gaussian blur in this program down-samples the scene texture before blurring and up-samples the scene texture again after blurring.
The blurring process is also split into two separate shaders – horizontal blurring and vertical blurring. This significantly cuts down the amount of samples per pixel compared to if the process was done all in one.
The scene before and after the gaussian blur is applied: