shader Bumpmapping: Unterschied zwischen den Versionen
Flash (Diskussion | Beiträge) K (→Bumpmapping-Shader) |
|||
Zeile 21: | Zeile 21: | ||
==Beschreibung== | ==Beschreibung== | ||
− | + | Der Bumpmapping Shader basiert auf dem [[shader_PerPixelLighting|Per Pixel-Beleuchtung]]-Shader. Der Unterschied zu diesem besteht darin, das wir die Normale nicht einfach so benutzen, wie sie an den Shader übergeben wurde, sondern wir sie erst mit den Daten aus der NormalMap manipulieren müssen. Dazu basteln wir uns eine Matrix aus der Sicht der Textur zusammen basteln: x-Achse = Tangente, y-Achse = Bitangente und z-Achse = Normale. Zunächst berechnen wir aus den Ableitungen der TexturKoordinaten den Gradienten, dieser liegt auf der X-Y-Ebene (z = 0) und zeigt an in welche Richtung die Funktion am stärksten ansteigt. Demzufolge zeigt der Gradient in die selbe Richtung wie die Tangente, wenn man sie auf die X-Y-Ebene vereinfachen würde: | |
+ | <source lang="glsl">vec2 TexCoord = vec2(gl_TexCoord[0]); | ||
+ | vec3 G = normalize(vec3(dFdx(TexCoord.s), dFdy(TexCoord.t), 0.0));</source> | ||
+ | |||
+ | |||
+ | Nun berechnen wir aus dem VektorProdukt von Gradient und Normale die Bitangente. Diese muss noch um 45° entgegen des Uhrzeigers um die Normale gedreht werden, dass das Licht dann auch aus der richtigen Richtung kommt. Die Normale muss nicht neu berechnet werden, da diese ja schon mit den Vertexdaten an den Shader übergeben wurde: | ||
+ | <source lang="glsl">vec3 B = normalize(rotate(N, cross(N, G), -0.25*PI));</source> | ||
+ | |||
+ | |||
+ | Die Tangente berechnet sich aus dem VektorPrordukt von Bitangente und Normale: | ||
+ | <source lang="glsl">vec3 T = normalize(cross(B, N));</source> | ||
+ | |||
+ | |||
+ | Um weiter zu rechnen setzen wur nun die 3 Achsen zu einer Matrix zusammen: | ||
+ | <source lang="glsl">mat3 M = mat3(T, B, N);</source> | ||
+ | |||
+ | |||
+ | Um die Normale zu erzeugen, welche dann zur Lichtberechnung genutzt wird lesen wir zunächst die Daten aus der NormalMap. Da die Farbewerte immer im Bereich [0..1] liegen, eine Normale aber immer in alle Richtungen zeigen kann und nicht nur in die positiven, müssen wir von jedem Farbewert noch 0.5 abziehen und den Farbvektor dann normalisieren. Dann multiplizieren wir noch mit der zuvor erzeugten Matrix und der NormalMatrix: | ||
+ | <source lang="glsl">vec3 normal = normalize((vec3(texture2D(Texture1, TexCoord)) - vec3(0.5, 0.5, 0.5)) * M); | ||
+ | normal = gl_NormalMatrix * normal;</source> | ||
+ | |||
==Code== | ==Code== | ||
Zeile 39: | Zeile 59: | ||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; | gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; | ||
}</source> | }</source> | ||
+ | |||
Fragmentshader: | Fragmentshader: | ||
Zeile 60: | Zeile 81: | ||
void main(void){ | void main(void){ | ||
− | vec2 TexCoord = vec2(gl_TexCoord[0]); | + | vec2 TexCoord = vec2(gl_TexCoord[0]); //TexturKoordinaten zwischenspeichern |
− | vec3 G = normalize(vec3(dFdx(TexCoord.s), dFdy(TexCoord.t), 0.0)); | + | vec3 G = normalize(vec3(dFdx(TexCoord.s), dFdy(TexCoord.t), 0.0)); //Gradient berechnen |
− | vec3 B = normalize(rotate(N, cross(N, G), -0.25*PI)); | + | vec3 B = normalize(rotate(N, cross(N, G), -0.25*PI)); //Bitangente berechnen |
− | vec3 T = normalize(cross(B, N)); | + | vec3 T = normalize(cross(B, N)); //Tangente berechnen |
− | mat3 M = mat3(T, B, N); | + | mat3 M = mat3(T, B, N); //Werte zu Matrix zusammensetzen |
+ | //normale aud den NormalMapDaten und den Matricen errechnen | ||
vec3 normal = normalize((vec3(texture2D(Texture1, TexCoord)) - vec3(0.5, 0.5, 0.5)) * M); | vec3 normal = normalize((vec3(texture2D(Texture1, TexCoord)) - vec3(0.5, 0.5, 0.5)) * M); | ||
normal = gl_NormalMatrix * normal; | normal = gl_NormalMatrix * normal; | ||
+ | //Normale Lichtberechnung aus dem Per-Pixel-light-Shader | ||
vec3 Eye = normalize(-V); | vec3 Eye = normalize(-V); | ||
vec4 EndColor = vec4(0.0, 0.0, 0.0, 0.0); | vec4 EndColor = vec4(0.0, 0.0, 0.0, 0.0); | ||
Zeile 82: | Zeile 105: | ||
EndColor += gl_FrontMaterial.emission; | EndColor += gl_FrontMaterial.emission; | ||
− | gl_FragColor = (gl_FrontLightModelProduct.sceneColor + EndColor) * | + | gl_FragColor = (gl_FrontLightModelProduct.sceneColor + EndColor) * texture2D(Texture0, TexCoord); |
− | |||
}</source> | }</source> |
Version vom 1. März 2010, 00:47 Uhr
Inhaltsverzeichnis
Bumpmapping-Shader
Zurück zur Shadersammlung
Beschreibung | Autor | Version |
---|---|---|
per-Pixel-Beleuchtung unter Zuhilfenahme einer Normalmap um einen Bumpmapping Effekt zu erzeugen. | Bergmann | 1.0 |
Bilder
Beschreibung
Der Bumpmapping Shader basiert auf dem Per Pixel-Beleuchtung-Shader. Der Unterschied zu diesem besteht darin, das wir die Normale nicht einfach so benutzen, wie sie an den Shader übergeben wurde, sondern wir sie erst mit den Daten aus der NormalMap manipulieren müssen. Dazu basteln wir uns eine Matrix aus der Sicht der Textur zusammen basteln: x-Achse = Tangente, y-Achse = Bitangente und z-Achse = Normale. Zunächst berechnen wir aus den Ableitungen der TexturKoordinaten den Gradienten, dieser liegt auf der X-Y-Ebene (z = 0) und zeigt an in welche Richtung die Funktion am stärksten ansteigt. Demzufolge zeigt der Gradient in die selbe Richtung wie die Tangente, wenn man sie auf die X-Y-Ebene vereinfachen würde:
vec2 TexCoord = vec2(gl_TexCoord[0]);
vec3 G = normalize(vec3(dFdx(TexCoord.s), dFdy(TexCoord.t), 0.0));
Nun berechnen wir aus dem VektorProdukt von Gradient und Normale die Bitangente. Diese muss noch um 45° entgegen des Uhrzeigers um die Normale gedreht werden, dass das Licht dann auch aus der richtigen Richtung kommt. Die Normale muss nicht neu berechnet werden, da diese ja schon mit den Vertexdaten an den Shader übergeben wurde:
vec3 B = normalize(rotate(N, cross(N, G), -0.25*PI));
Die Tangente berechnet sich aus dem VektorPrordukt von Bitangente und Normale:
vec3 T = normalize(cross(B, N));
Um weiter zu rechnen setzen wur nun die 3 Achsen zu einer Matrix zusammen:
mat3 M = mat3(T, B, N);
Um die Normale zu erzeugen, welche dann zur Lichtberechnung genutzt wird lesen wir zunächst die Daten aus der NormalMap. Da die Farbewerte immer im Bereich [0..1] liegen, eine Normale aber immer in alle Richtungen zeigen kann und nicht nur in die positiven, müssen wir von jedem Farbewert noch 0.5 abziehen und den Farbvektor dann normalisieren. Dann multiplizieren wir noch mit der zuvor erzeugten Matrix und der NormalMatrix:
vec3 normal = normalize((vec3(texture2D(Texture1, TexCoord)) - vec3(0.5, 0.5, 0.5)) * M);
normal = gl_NormalMatrix * normal;
Code
Vertexshader:
const int LIGHT_COUNT = 1; //Anzahl der berücksichtigten Lichter
varying vec3 N; //NormalenVektor
varying vec3 V; //VertexVektor
varying vec3 lightvec[LIGHT_COUNT]; //LichtVektor(en)
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
N = normalize(gl_Normal);
V = vec3(gl_ModelViewMatrix * gl_Vertex);
for(int i = 0; i < LIGHT_COUNT; i++){
lightvec[i] = normalize(gl_LightSource[i].position.xyz - V);
}
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Fragmentshader:
const float PI = 3.14159265; //Pi, zur Berechnung der Rotation
const int LIGHT_COUNT = 1; //Anzahl der berücksichtigten Lichter
varying vec3 N; //NormalenVektor
varying vec3 V; //VertexVektor
varying vec3 lightvec[LIGHT_COUNT]; //LichtVektor(en)
uniform sampler2D Texture0; //normale Textur
uniform sampler2D Texture1; //NormalMap
//dreht einen Punkt um eine Achse im Raum
//@a: Achse um die gedreht wird
//@p: Punkt der gedreht werden soll
//@rad: Winkel im BogenMaß
vec3 rotate(vec3 a, vec3 p, float rad){
vec3 p1 = cos(rad) * p +
sin(rad) * cross(a, p);
return p1;
}
void main(void){
vec2 TexCoord = vec2(gl_TexCoord[0]); //TexturKoordinaten zwischenspeichern
vec3 G = normalize(vec3(dFdx(TexCoord.s), dFdy(TexCoord.t), 0.0)); //Gradient berechnen
vec3 B = normalize(rotate(N, cross(N, G), -0.25*PI)); //Bitangente berechnen
vec3 T = normalize(cross(B, N)); //Tangente berechnen
mat3 M = mat3(T, B, N); //Werte zu Matrix zusammensetzen
//normale aud den NormalMapDaten und den Matricen errechnen
vec3 normal = normalize((vec3(texture2D(Texture1, TexCoord)) - vec3(0.5, 0.5, 0.5)) * M);
normal = gl_NormalMatrix * normal;
//Normale Lichtberechnung aus dem Per-Pixel-light-Shader
vec3 Eye = normalize(-V);
vec4 EndColor = vec4(0.0, 0.0, 0.0, 0.0);
for(int i = 0; i < LIGHT_COUNT; i++){
vec3 Reflected = normalize(reflect(-lightvec[i], normal));
vec4 IAmbient = gl_LightSource[i].ambient * gl_FrontMaterial.ambient;
vec4 IDiffuse = gl_LightSource[i].diffuse * gl_FrontMaterial.diffuse *
max(dot(normal, lightvec[i]), 0.0);
vec4 ISpecular = gl_LightSource[i].specular * gl_FrontMaterial.specular *
pow( max( dot(Reflected, Eye), 0.0), gl_FrontMaterial.shininess);
EndColor += (IAmbient+IDiffuse+ISpecular);
}
EndColor += gl_FrontMaterial.emission;
gl_FragColor = (gl_FrontLightModelProduct.sceneColor + EndColor) * texture2D(Texture0, TexCoord);
}