Bump mapping

Il bump mapping è una tecnica per simulare piccole imperfezioni su una superificie attraverso una piccola alterazione delle normali.

Per ottenere questo effetto, si potrebbe applicare una texture alla superficie e poi usare il colore di quella texture come se fosse la normale all'interno del fragment shader. Tuttavia, se l'alterazione è casuale come in questo esempio, esiste un modo più semplice.

Si immerge l'oggetto in una texture tridimensionale, che si ripete in tutto lo spazio. In questo modo, si può usare la posizione (nelle coordinate di modello) del punto per indicizzare la superficie, senza bisogno di importare coordinate addizionali.

Non esiste una funzione rand all'interno degli shader. Anche se esistesse, non sarebbe utilizzabile in questa occasione, perché il suo valore cambierebbe ad ogni esecuzione dello shader e non sarebbe costante tra un ciclo di rendering e il successivo.

Esempio

Il vertex shader deve essere modificato soltanto per passare al fragment shader la posizione originale del punto, prima di essere trasformato dalla matrice di modelview e di proiezione. Si devono aggiungere solo 2 righe di codice:

varying vec3 oPosition;

nell'intestazione e

oPosition = gl_Vertex.xyz / gl_Vertex.w;

nel codice. Globalmente quindi:

#version 120

attribute float matshininess;
attribute vec3 matspecular;

varying float vmatshininess;
varying vec3 vmatspecular;

varying vec3 veyeposition;
varying vec3 vnormal;

varying vec3 oPosition;

void main()
  {
  vnormal = gl_NormalMatrix * gl_Normal;
  
  vec4 rp = gl_ModelViewMatrix * gl_Vertex;                   
  veyeposition = rp.xyz / rp.w;                     // use cartesian coordinates (works if w != 0)
  
  oPosition = gl_Vertex.xyz / gl_Vertex.w;
  
  gl_FrontColor = gl_Color;
  gl_BackColor = vec4(0.0,0.0,0.0,1.0);
  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
  
  vmatspecular = matspecular;
  vmatshininess = matshininess;
  }

Le modifiche al fragment shader sono leggermente più complesse. In questo esempio, si considera che la texture è inizializzata con valori casuali da 0.0 a 1.0 e che il programma la assegna alla variabile uniform sampler3D random3d;.

Si ottiene il punto in cui valutare la texture a partire dalla posizione originale proveniente dallo shader, opportunamente scalato. Modifiche a questo fattore di scala aumentano o diminuiscono le dimensioni delle imperfezioni sulla superficie, perché diminuiscono o aumentano le dimensioni dell'oggetto visualizzato rispetto alla texture.

Poi si ottiene la modifica alla normale sottraendo alla texture in quel punto 0.5, in modo che essa varii tra -0.5 e 0.5. Si moltiplica per un altro fattore di scala, che controlla la profondità delle imperfezioni.

La normale deve essere normalizzata due volte: una prima di applicare la modifica, perché è stata interpolata, e una dopo, per assicurarsi che abbia sempre modulo 1 dopo il bump mapping.

vec3 bump = (texture3D(random3d,oPosition * 0.1).xyz - vec3(0.5,0.5,0.5)) * 0.1;
vec3 newnormal = normalize(normalize(vnormal) + bump);

Il fragment shader diventa:

#version 120

varying float vmatshininess;
varying vec3 vmatspecular;

varying vec3 veyeposition;
varying vec3 vnormal;

vec4 ApplyLight(in vec4 oColor, in vec3 relativepos, in vec3 normal,in vec3 matspecular,in float matshininess);

uniform sampler3D random3d;

varying vec3 oPosition;

void main()
  {
  vec3 bump = (texture3D(random3d,oPosition * 0.1).xyz - vec3(0.5,0.5,0.5)) * 0.2;
  vec3 newnormal = normalize(normalize(vnormal) + bump);
  
  gl_FragColor = ApplyLight(gl_Color,veyeposition,newnormal,vmatspecular,vmatshininess);
  }

Configurazione per l'esempio

#define SHADER_FOLDER "shaders/bump_mapping/"

#define USE_VERTEX_SHADER true
#define USE_FRAGMENT_SHADER true
#define USE_GEOMETRY_SHADER false
#define USE_NORMAL_SHADER false
#define USE_VERTEX_LIGHT_SHADER false
#define USE_FRAGMENT_LIGHT_SHADER true
#define USE_TESSEVAL_LIGHT_SHADER false
#define USE_TESSELLATION_SHADERS false

#define GEOMETRY_INPUT_TYPE GL_TRIANGLES         // irrilevante
#define GEOMETRY_OUTPUT_TYPE GL_TRIANGLE_STRIP   // irrilevante
#define GEOMETRY_MAX_VERTICES 3                  // irrilevante

#define ENABLE_BACK_FACE_CULLING true
#define LOAD_NORMALS true
#define TIMER_MS 0

Risultato:

Risultato bump mapping

Copyright © 2011 Riccardo Monica
Eccetto ove espressamente indicato altrimenti, il contenuto di questa pagina è disponibile secondo la licenza Creative Commons Attribuzione - Condividi allo stesso modo 3.0.