Le vertex shader est relativement simple une fois les conditions nécessaires au bon fonctionnement réunies. Comme toutes les avancées
et nouveautés technologiques au niveau des cartes 3D, le vertex displacement mapping possède ses petites limitations qui, si elles ne
sont pas prises en compte, vont faire passer votre Geforce 7800 GTX Ultra boostée au même niveau qu'une bonne vieille S3 Trio (un peu vieux tout ça...!).
Pour faire du vertex displacement mapping, il y a deux contraintes principales:
- la texture de displacement doit être en virgule flottante (floating point texture). En OpenGL, cela correspond au format de pixel
interne GL_RGBA_FLOAT32_ATI
(valable aussi bien sur ATI que sur nVidia).
- la texture de displacement ne doit pas être filtrée: pas de filtrage linéaire ou trilinéaire. Seul le mode nearest est accepté.
Donc une fois que la texture de displacement est chargée en mode virgule flottante et qu'elle est filtrée en nearest, le displacement
mapping devient très simple comme le montre le vertex / pixel shader suivant:
[Vertex_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;
}
[Pixel_Shader]
uniform sampler2D colorMap;
void main(void)
{
gl_FragColor = texture2D(colorMap, gl_TexCoord[0].xy);
}Nous accédons à la displacement map de la même manière que nous le ferions pour une texture classique dans un pixel
shader: en utilisant la fonction GLSL texture2D().
La démo Demoniak3D montre la déformation d'un mesh de 80000 polygones avec une simple image BMP:

Fig. 4 - DEMO_displacement_mapping.xmlLe mode de filtrage nearest est le seul mode disponible dans le vertex shader sur les cartes graphiques actuelles. Mais rien
ne peut nous empêcher d'implémenter notre propre version du filtrage bilinear. Voici la fonction (adaptée d'un code Cg de nVidia)
qui fait le boulot:
#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 );
}L'utilisation de cette fonction est très simple. Il suffit juste de remplacer texture2D() par texture2D_bilinear():
dv = texture2D_bilinear( displacementMap, gl_MultiTexCoord0.xy );
Ce code fonctionne aussi bien dans le vertex shader que dans le pixel shader.