Distortion Sample
This sample demonstrates how to implement a variety of screen-space distortion effects with a general post-processing technique.Sample Overview
The techniques shown here are an invisibility cloak, heat haze, and privacy glass. The effect is extremely flexible, and can be tuned for everything from explosion shockwaves to full-screen underwater vision perturbation.
Sample Controls
This sample uses the following keyboard and gamepad controls.
| Action | Keyboard control | Gamepad control |
|---|---|---|
| Rotate the camera | LEFT ARROW, RIGHT ARROW | Left analog D-pad |
| Cycle the distorter | SPACEBAR, A | A |
| Enable/Disable distorter blur | Left CTRL, X | X |
| Show/Hide the distortion map | TAB, B | B |
| Exit the sample | ESC or ALT+F4 | BACK |
How the Sample Works
This distortion effect is a post-processing technique that requires two additional passes. The full three passes are as follows.
- The scene is drawn normally, and resolved into a texture.
-
A distortion map is created by rendering the distorting model using techniques from Distorters.fx, which is then resolved into another texture. The three techniques used are:
- Pull-in (invisibility cloak): The normals of the model are used to generate the map.
- Heat haze: The texture coordinates of the model are used to generate the map.
- Distortion map: A special texture, applied to the model, is used to generate the map.
- A full-screen quad (two triangles) is drawn that uses the distortion map as a lookup table into the scene texture, a technique found in Distort.fx.
Distortion Maps
A distortion map is a 2D vector field stored in a texture. In this implementation, the red channel represents displacement along the x-axis, and the green channel represents displacement along the y-axis. High-level shader language represents texture channels as floating-point values in the range [0, 1], but displacement can take place in either the positive or negative direction along an axis. Therefore, a color channel value of 0.5 is understood to mean a vector component of 0. With this in mind, a pixel color value of 0.5 red and 0.5 green (a yellow-brown color) will result in no displacement.
The following figure depicts a distortion map that is displacing along the x-axis by varying the red color channel. The arrows represent nonzero vectors. Notice how the lower red values (the greener squares) have greater displacement to the left, while the higher red values (the more orange squares) have greater displacement to the right. The y-displacement is completely independent of the red channel.
In this sample, however, the final sampling (see "Applying Distortion") may use a Gaussian blur to smooth out the distortion effect. To constrain the blur to the desired area, the areas of the distortion map with no change are left at black, which simplifies the comparison in Distort.fx.
Applying Distortion
Once the scene and distortion maps have been created, the scene is redrawn onto a full-screen quad. The texture coordinates of the quad are looked up in the distortion map. The retrieved displacement vector is then added to the initial texture coordinate. The new texture coordinate is used to lookup the final color in the scene texture.
The value 0.5, the value we have taken to mean zero displacement, cannot be exactly represented with an 8-bit color channel. Half of 255 is 127.5, and we must account for the rounding error. Failing to account for the error leaves a single pixel border on the top and left edges of the screen, and it also forces the texture sampler to sample multiple texels, which can lower the overall image quality. To avoid this, we can take 127.0 to be a 0 vector component by simply subtracting 0.5 / 255 from each component.
Depending on the technique used to generate the distortion map, the displacement vectors may vary continuously, resulting in horizontal or vertical lines of identical pixels. One option this sample explores to improve visual quality is performing multiple samples around the desired pixel in the scene texture, using a Gaussian blur implementation first seen in the BloomPostprocess sample. This blur may not suit all distortion maps. For example, the heat-haze technique is noticeably improved, but the distortion-map technique is slightly compromised by the blur. Note that this does increase the number of texture samples performed, increasing the minimum pixel shader version and the cost of shading each pixel. The blur represents a trade-off between performance and visual quality.
Mesh Preparation
Each model that is loaded into this sample is processed by a custom processor, included as a separate project in this sample. All models are modified to specify the Distorters.fx effect file that this sample provides.
If the model has a texture, the texture is converted in a normal map, using the NormalMapProcessor class provided in the Sprite Effects sample. That normal map is converted into a two-dimensional displacement map in the DisplacementMapProcessor class. This map is sampled in the Displacement-Mapped technique in Distorters.fx. Only Window.x has a texture assigned to it in this sample (PrivacyGlass.png, which is in the content directory), so only that model will appear correct when used with the displacement-mapped technique.
Ideas to Expand
The following are some ideas for further exploration.
- Try modifying the displacement map texture to provide a variety of striking effects. In particular, you may want to use models that have a more typical normal map than PrivacyGlass.png, usually produced to improve lighting quality.
- The code and effect that accompany Dude.fx in the Skinning sample may be added to this sample, and Dude may be animated. If the vertex shaders are carefully integrated, then the distortion effects will still work.
- The existing effects are applied to models, which are tested against depth and only distort the part of the image that lies behind them. Try experimenting with full-screen distortion effects that affect everything in the scene. In particular, the DrawFullscreenQuad function found in the DistortionComponent class, combined with PrivacyGlass.png, could be effective.
- Alternate blur techniques may provide more exact, or interesting, visual effects. For example, you may want to try calculating sample weights using the position of the displaced texture coordinate relative to the center of the texel.