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
Vertex Displacement Mapping using GLSL

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

Initial draft: March 26, 2006
Update: November 5, 2006
Update: November 22, 2006

[ Index ]

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

�Next Page

3 - The Displacement Vertex Shader

The vertex shader is relatively simple once the required conditions to the good work are met. Like any technological progress in the world of 3D graphics controllers, vertex displacement mapping has some little limitations which, if they are not taken into account, will transform your Ultra-Boosted 7800 GTX into an old S3 trio (do you remember...).

To achieve vertex displacement mapping, there are two main constraints:

  • the displacement map must be in floating point format. In OpenGL terms, that means an internal pixel format that is set to GL_RGBA_FLOAT32_ATI (valid on ATI as well as on nVidia).
  • the displacement map must not be filtered: no linear or trilinear filtering. Nearest mode is the only one accepted.
Thus once the displacement map is loaded in floating point format with nearest filtering, displacement mapping becomes really simple as shown in the following vertex / pixel shader:

uniform sampler2D displacementMap;

void main(void)
	vec4 newVertexPos;
	vec4 dv;
	float df;
	gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;
	dv = texture2D( displacementMap, gl_MultiTexCoord0.xy );
	df = 0.30*dv.x + 0.59*dv.y + 0.11*dv.z;
	newVertexPos = vec4(gl_Normal * df * 100.0, 0.0) + gl_Vertex;
	gl_Position = gl_ModelViewProjectionMatrix * newVertexPos;


uniform sampler2D colorMap;

void main(void)
   gl_FragColor = texture2D(colorMap, gl_TexCoord[0].xy);

We fetch the displacement map the same way as we do for texture fetching in the pixel shader: using the texture2D() GLSL function.

The Demoniak3D demo shows the deformation of a 80000-polygons mesh with a simple BMP image:

Fig. 4 - DEMO_displacement_mapping.xml

The nearest filtering mode is the only mode available in the vertex shader of today's hardware. But nothing can prevent us from implementing our own version of the bilinear filtering mode. Here is the function (adapted from nVidia's Cg code) that does the job:

#define textureSize 256.0
#define texelSize 1.0 / 256.0

vec4 texture2D_bilinear( uniform sampler2D tex, vec2 uv )
	vec2 f = fract( uv.xy * textureSize );
	vec4 t00 = texture2D( tex, uv );
	vec4 t10 = texture2D( tex, uv + vec2( texelSize, 0.0 ));
	vec4 tA = mix( t00, t10, f.x );
	vec4 t01 = texture2D( tex, uv + vec2( 0.0, texelSize ) );
	vec4 t11 = texture2D( tex, uv + vec2( texelSize, texelSize ) );
	vec4 tB = mix( t01, t11, f.x );
	return mix( tA, tB, f.y );

The use of this function is really simple. Just remplace texture2D() by texture2D_bilinear():

dv = texture2D_bilinear( displacementMap, gl_MultiTexCoord0.xy );

This code works fine in both vertex and pixel shaders.

[ 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.0023272037506104 seconds.