L'effetto di erosione di una primitiva si ottiene scartando, secondo un qualche algoritmo casuale, alcuni pixel della primitiva all'interno del fragment shader. In questo modo, alcune parti di essa risultano mancanti come se fosse stata corrosa.
Per questo esempio, si consiglia di disabilitare il back-face culling per avere una vista migliore anche dell'interno del poliedro.
L'idea di base è identica a quella già usata nella sezione precedente, quella sul bump mapping. L'oggetto viene immerso in una texture casuale solidale con l'oggetto stesso in modo che i "buchi", cioò i frammenti scartati, siano sempre nello stesso punto. Il vertex shader deve inviare al fragment shader le coordinate di modello, perciò è identico al precedente.
Con quelle coordinate, nel fragment shader si accede a uno qualunque dei tre canali del colore della texture e, se esso non è sufficientemente elevato, si scarta il frammento con la parola chiave discard.
#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() { float toDiscard = texture3D(random3d,oPosition).r; if (toDiscard < 0.5) discard; gl_FragColor = ApplyLight(gl_Color,veyeposition,normalize(vnormal),vmatspecular,vmatshininess); }
Il coefficiente che nell'esempio è 0.5 rappresenta la probabilità con la quale i frammenti sono scartati, cioò influisce sul numero di buchi presenti nella primitiva. In programmi complessi, sarà opportuno rendere questo parametro una variabile uniform impostata dal programma OpenGL.
Sono possibili alcune modifiche per migliorare l'effetto. Prima di tutto, è meglio aumentare le dimensioni delle chiazze rimosse, moltiplicando la posizione per un coefficiente di scala.
... float toDiscard = texture3D(random3d,oPosition * 0.5).r; ...
Come nell'esempio del bump mapping, la dimensione aumenta al diminuire del coefficiente.
Una seconda modifica serve a risolvere un ulteriore problema. Normalmente, un oggetto eroso presenta delle ampie chiazze mancanti, ma ai bordi esse mostrano un dettaglio molto fine. Allora, quel coefficiente di scala dovrebbe essere grande e piccolo contemporaneamente.
Senza usare complicate formule matematiche, una soluzione semplice è quella di usare due diverse texture casuali. Ad una si accede con un coefficiente di scala piccolo e indica i grossi buchi. Alla seconda si accede con un grande coefficiente di scala e serve per aggiungere dettaglio ai bordi.
Siccome si dispone di una texture con 3 canali casuali, ma solo 1 è usato, in questo esempio non è necessario caricare una seconda texture. Si usa la stessa texture, ma si legge un canale diverso per non avere interferenze.
I due canali sono poi miscelati con una media pesata, in cui i grossi buchi hanno peso molto maggiore. Il canale dei piccoli buchi deve essere significativo solo quando il valore dell'altro è indeciso (vicino a 0.5), cioè appunto lungo i bordi dei buchi.
#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() { float small = texture3D(random3d,oPosition * 0.5).r; float big = texture3D(random3d,oPosition * 0.05).g; float toDiscard = small * 0.10 + big * 0.90; if (toDiscard < 0.5) discard; gl_FragColor = ApplyLight(gl_Color,veyeposition,normalize(vnormal),vmatspecular,vmatshininess); }
#define SHADER_FOLDER "shaders/erode/" #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 false #define LOAD_NORMALS true #define TIMER_MS 0
Risultato senza la componente fine dell'erosione:
Risultato con solo la componente fine:
Risultato finale:
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.