Inertia's picture

DXT5 Parallax Mapping

This project was conceived as a proof-of-concept last week in the attempt to find an answer for the "geometry displacement vs. parallax mapping" question. Not sure if this is obvious or a stupid idea (never seen this used before in any app) so I'd like to hear some opinions about it.

In order to accomplish typical Parallax mapping, The shader requires these input textures:

RGBA8 Texture 1:

3 Channels: Diffuse Color R, G, B (called Dr, Dg, Db)
1 Channel: Specular Gloss (called Sg)

Order: [Dr][Dg][Db][Sg]

RGBA8 Texture 2:

3 Channels: Normal X, Y, Z (called Nx, Ny, Nz)
1 Channel: Parallax Height (called Ph)

Order: [Nx][Ny][Nz][Ph]

8 Bytes per Texel is quite a bit, so it would be desireable to use DXT5 compression to shrink the memory use. This works nicely for the first Texture, but the second Texture has notable artifacts when compressed. Storing the second Texture as RGBA8 is an obvious solution, but 'id Software' came up with the idea for Doom³ to reorder the second Texture like this so DXT5 can be used:

[E][Ny][E][Nx] (E=Empty, ie. 0)

Since we know the length of a normal, Nz can be calculated per fragment. However this isn't really helping with Parallax mapping, since the Red and Blue channels have quite poor precision when compressed so they cannot store the height properly.

My idea is to order the Channels like this to use DXT5 for both textures:

Texture1: [Dr][Dg][Db][Ph]
Texture2: [Sg][Ny][E][Nx]

This puts the height into the rather high precision Alpha channel of the first texture, and the Red channel from the second Texture appears to be sufficient for the gloss channel from my test textures. The blue channel is currently unused.

Free Image Hosting at

Both screenshots used the same scene setup and shaders, the only difference is that the left one uses 1024kb+256kb .bmp textures, the right one uses 342kb+86kb .dds textures (which include mipmap levels down to 4x4). The diffuse+height texture is 512², the normal+gloss is 256² (image is probably (C)(R)(bla) by Typhoon Labs, it originates from their ShaderDesigner distribution).

The blue channel of the second Texture could be used as a multiplier for cubemap reflection contribution (might be nice to control the mirror strength independently from specularity), or use it as s-texture coordinate to look up a 1D texture (e.g. looking up specular exponent rather than passing that as uniform), or gate a simple if (tex2.b < 0.2) discard; alpha mask.

Any thoughts?


Update: Added example application. Although the dds loader is included into the package, please discuss it here rather than using this topic. Thanks.

There's alot of room for improvement, don't expect to c&p this code and end up with Doom 5. The light does not consider attenuation and the Parallax effect is just a basic approach.

Controls probably require explanation too:

Mouse movement controls the light position.
Mouse wheel alters the camera's Y axis.
Q/A alter the Parallax' scaling.
W/S alter the Parallax' bias.
E/D alter the Material's shininess.
Space bar prints first GL error, Esc exits.
(See console window for feedback)

Edit: Added Download

Parallax.rar783.65 KB


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Inertia's picture

The original post now has a proper file attachment including release build and source code (compiles against 0.9.1 release) .

objarni's picture

Nice of you to share!

Sadly, .rar is not available under Ubuntu (except as shareware for 40 days). Maybe .zip is the most "platform independent" format these days? I think it is readily available on Windows, Linux and OSX.

Also the OpenTK.dll.config was missing in the bin/Release folder.

When running using "mono Parallax.exe" I get the output attached in "log.txt". I'm using the OpenTK 0.9.1 config file, mono 1.9.1 and have a GeForce 7800 GT.

log.txt840 bytes
the Fiddler's picture

For rar, just sudo apt-get install unrar (no need for shareware).

This error seems to be caused by EOF differences between the platforms. Can you try replacing the StreamReader with System.IO.File.ReadAllBytes?

Inertia's picture

Is the issue resolved or should I look into it? What Fiddler said would have been my answer too, if he didn't beat me to it. (The first line is a comment, so there shouldn't be a compile error there :P)

I won't update the attachment for the dll.config, since this example should be on svn the second the .dds loader is there too.

objarni's picture

Have you updated the original .rar since my comment ?

Inertia's picture

No, because there's no feedback whether the problem is related to unpacking the archive or the file itself. (Fragment.glsl ist just plain text)

the Fiddler's picture

Objarni, can you try opening the file with gedit (or another editor) and saving with unix line-endings? Alternatively, can you try my previous suggestion to replace the StreamReader? I've been using File.ReadAllBytes for my shaders and never had a line-ending problem.

objarni's picture

There was no problem unpacking the archive.

I'll try Fiddlers suggestions when I get to my home computer (in a few days).