dimanche 8 mars 2009

Enfin un shader utile

Ce n'est pas faute de m'être battu avec, mais pour l'instant, les seuls shaders que j'arrivais à faire fonctionner reproduisaient de fait le pipeline fixe de la carte vidéo, c'est à dire la même chose en moins bien et en moins efficace.

J'ai eu l'impression que le nombre de tutoriels sur les shaders était extrêmement réduit, surtout en ce qui concerne GLSL. Autant vous trouverez toujours des vidéos hallucinantes d'effets d'eau et autres, autant dès qu'il s'agit de montrer son code, tout le monde devient si pudique, les plus audacieux vous renvoyant vers l'épais bouquin "OpenGL shading language", lequel n'est quand même pas donné (mais si ça continue, je vais me laisser tenter!).

Basé sur ce tutoriel, la page de NeHe, cet autre là et les exemples d'OpenSceneGraph, voilà mon premier effet non trivial: la texture molle!

Partons d'un cube texturé tout bête:



L'idée est de déplacer les coordonnées de texture, en se servant d'une texture de "bruit". Cette texture va contenir de fait le décalage des coordonnées de l'image. Voilà la texture de bruit que j'ai utilisée.



Il ne reste plus qu'à charger les shaders.

Vertex:


varying vec3 N;
varying vec3 v;
varying vec2 texture_coordinate;
void main(void)
{
v = vec3(gl_ModelViewMatrix * gl_Vertex);
N = normalize(gl_NormalMatrix * gl_Normal);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
texture_coordinate = vec2(gl_MultiTexCoord0);
}


Fragment:

varying vec3 N;
varying vec3 v;
varying vec2 texture_coordinate;
uniform sampler2D color_texture;
uniform sampler2D noise_texture;
void main(void)
{
vec3 L = normalize(gl_LightSource[0].position.xyz - v);
vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);
Idiff = clamp(Idiff, 0.0, 1.0);

vec2 new_coord = texture_coordinate + vec2(texture2D(noise_texture, texture_coordinate)) / 255;

gl_FragColor = Idiff * texture2D(color_texture, new_coord);
}


Surtout, ne pas oublier de passer les deux textures en tant qu'uniform, pour color_texture et noise_texture.

Et voilà le résultat!



Les prochaines étapes seraient:
- Utiliser les canaux rouge et vert de la texture, afin d'avoir un déplacement qui n'aille pas dans la même direction en x et en y
- Envoyer également une texture unidimensionnelle, correspondant à la quantité d'effet que l'on veut mettre (par exemple, une sinusoïde), afin d'animer la texture

Aucun commentaire: