Current version: 0.45.1
>GeeXLab homepage

Current version: 1.30.0
>FurMark homepage

GPU Caps Viewer
Current version:
>GPU Caps Viewer homepage

GPU Shark
Current version:
>GPU Shark homepage

>JeGX's HackLab

Geeks3D's Articles
>GPU Memory Speed Demystified

>Multi-Threading Programming Resources

>GeForce and Radeon OpenCL Overview

>How to Get your Multi-core CPU Busy at 100%

>How To Make a VGA Dummy Plug

>Night Vision Post Processing Filter

PhysX FluidMark
Current version: 1.5.4
>FluidMark homepage

Current version: 0.3.0
>TessMark homepage

Current version: 0.3.0
>ShaderToyMark homepage
>ShaderToyMark Scores

Current Version: 1.23.0
>Libraries and Plugins
>Online Help - Reference Guide
>Codes Samples
Normal Map Compression
Swizzled DXT5 - ATI 3Dc

By Jerome Guinot aka 'JeGX' - jegx [at] ozone3d (dot) net

Initial draft: March 11, 2006
Update: March 16, 2006

[ Index ]

Introduction | Page 2 | Page 3 | Page 4 | Conclusion

�Next Page

1 - Introduction

2 - Renormalisation

3 - Generating the Z component or Swizzled DXT5

4 - ATI 3Dc

5 - Conclusion

6 - Structure of the O3TC format and OpenGL Demo

7 - Further Resources

8 - Downloads

Required knowledge

1 - Introduction

The compression of texture S3TC is a destructive compression (with losses) rather like the jpg format, destructive in the sense that a part of the information contained by the non compressed texture is definitely lost after compression. For textures containing color data (color-map or classical image) this loss of information is not a problem, but for textures containing normal vectors (normal-map) this could be more problematic. We are going to see the problems caused by texture compression with normal maps and some techniques to resolve these problems.

Figure 1 shows the rendering of the accompanying project (available at the bottom of the page). We will use the Demoniak3D platform in order to test the various techniques to render the normal-maps.

Fig. 1 - Overall view

The different project files use the following vertex/pixel shader, written in GLSL (OpenGL Shading Language), to create the bump mapping:

varying vec3 lightVec; 
varying vec3 viewVec;
varying vec2 texCoord;
attribute vec3 tangent; 
void main(void)
	gl_Position = ftransform();
	texCoord = gl_MultiTexCoord0.xy;
	vec3 n = normalize(gl_NormalMatrix * gl_Normal);
	vec3 t = normalize(gl_NormalMatrix * tangent);
	vec3 b = cross(n, t);
	vec3 v;
	vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
	vec3 lVec = gl_LightSource[0] - vVertex;

	v.x = dot(lVec, t);
	v.y = dot(lVec, b);
	v.z = dot(lVec, n);
	lightVec = v;

	vec3 vVec = -vVertex;
	v.x = dot(vVec, t);
	v.y = dot(vVec, b);
	v.z = dot(vVec, n);
	viewVec = v;

varying vec3 lightVec;
varying vec3 viewVec;
varying vec2 texCoord;
uniform sampler2D normalMap;
void main (void)
	vec3 lVec = normalize(lightVec);
	vec3 vVec = normalize(viewVec);
	vec3 bump = texture2D(normalMap, texCoord).xyz * 2.0 - 1.0;
	float diffuse = max( dot(lVec, bump), 0.0 );
	float specular = pow(clamp(dot(reflect(-lVec, bump),vVec),
					 0.0, 1.0), 
					 gl_FrontMaterial.shininess );
	vec4 vAmbient = gl_LightSource[0].ambient * 
	vec4 vDiffuse = gl_LightSource[0].diffuse * 
					gl_FrontMaterial.diffuse * 
	vec4 vSpecular = gl_LightSource[0].specular * 
					 gl_FrontMaterial.specular *
	gl_FragColor = vAmbient + (vDiffuse + vSpecular);	

This shader will serve as the reference for the demo’s different XML files. The variations will be found in the pixel shader along the following line:

vec3 bump = texture2D(normalMap, texCoord).xyz * 2.0 - 1.0;

Now let us make a closer analysis. To do this, load into Demoniak3D the xml bump_map_uncompressed_non_normalized.xml file. The rendering should be the same as figure 2:

Fig. 2 - Uncompressed and non-normalized bump map

Then load the xml bump_map_compressed_non_normalized.xml file. This code loads a compressed normal-map (bulge_DXT5.o3tc) with the O3TC format.

For information, do not forget that the 03TC format possesses practically the same characteristics as the DDS format. It supports the DXT1 and DXT5 compression and the mipmaps, in short, the essential elements for texture compression. The O3TC format is created with the DXTViewer tool. See part 4 for more information on O3TC format. A normal-map in DDS format will give the same result. The shader used is always the same.

Fig. 3 - Compressed bump map (DXT5)

We clearly see the damage due to compression. The specular highlights are very ugly, a sort of grid pattern has appeared. The grid pattern is due to the DXT algorithm which uses internally blocks of 4 x 4 pixels. Picture 4 clearly shows such a block. The large rectangle marks the block and the small rectangle marks a pixel. This picture was obtained by suppressing the bilinear filtering by default: it suffices to insert the filtering_mode="NONE" attribute in the texture element.

Fig. 4 - Block of 4 x 4 pixels used in the DXT1 and DXT5 algos

It is not really very visible in picture 4, but perform the test by disabling the texture filter and you will easily see the blocks.

[ Index ]

Introduction | Page 2 | Page 3 | Page 4 | Conclusion

�Next Page

GeeXLab demos

GLSL - Mesh exploder

PhysX 3 cloth demo

Normal visualizer with GS

Compute Shaders test on Radeon

Raymarching in GLSL

>Texture DataPack #1
>Asus Silent Knight CPU Cooler
Page generated in 0.0032448768615723 seconds.