Beleuchtung Standard-Codesequenz
← Lichtquellen zeichnen | ● | Uber-Shader →
Annahme: es gibt eine Initialisierungs-Funktion und eine Render-Funktion, die für jeden Frame aufgerufen wird.
Die hier vorgestellte Shader-Kombination ermöglicht beliebig viele Lichtquellen, direktionale und Punktlichtquellen, mit Abschwächung. Sie benutzt Uniform Arrays, um mehrere Lichtquellen zu verwalten. Die können wie einzelne Variablen auch benutzt werden. Die Abschwächung wird über Vorfaktoren für die drei Möglichkeiten Konstant (keine Abschwächung), Linear und Quadratisch bestimmt.
Es werden die Standard-Matrizen mv
, mvp
und mvit
benutzt, die mit lglProjection()
und lglModelView()
berechnet und gesetzt werden.
Aufgeführt sind nur die Änderungen zur Standard-Codesequenz:
Shader
Vertex-Shader
uniform mat4 mvp; // ModelViewProjection
uniform mat4 mv; // ModelView
uniform mat4 mvit; // inverse transposed ModelView
attribute vec4 vertex_position;
attribute vec3 vertex_normal;
// Lights
const int max_numlights = 4;
uniform int numlights;
uniform vec4 lightpos [max_numlights];
varying vec3 normal, view;
varying vec3 light[max_numlights];
void main () {
// Vertex Trafo -> projected coords
gl_Position = mvp * vertex_position;
// Normal Trafo -> eye coords (unprojected)
normal = normalize(mat3 (mvit) * vertex_normal);
// View vector: normalized reverted transformed vertex in eye coords
view = normalize (- vec3 (mv * vertex_position));
// Light vector in eye coords
// Loop over all lights, lights with homogenous component '0' are directional
for (int i=0; i < numlights; i++)
light[i] = vec3 (lightpos[i] - lightpos[i].w * mv * vertex_position);
}
Fragment-Shader
// Ambient, emissive, diffuse, specular material colors
uniform vec4 Ca;
uniform vec4 Ce;
uniform vec4 Cd;
uniform vec4 Cs;
uniform float kse = 100; // specular exponent
// Lights
const int max_numlights = 4;
uniform int numlights;
uniform vec4 lightcol[max_numlights];
uniform vec4 lightatt[max_numlights]; // attenuation: constant, linear, quadratic, max. value
varying vec3 normal, view;
varying vec3 light[max_numlights];
void main () {
// the normal vector needs to be normalized for C1 smoothness
vec3 n = normalize (normal);
vec4 col = Ce;
// Loop over all lights
for (int i=0; i < numlights; i++) {
float invdist = 1 / length (light[i]);
vec3 l = light[i] * invdist;
float att = min (lightatt[i].x + lightatt[i].y * invdist +
lightatt[i].z * invdist*invdist, lightatt[i].w);
// Diffuse light
float Id = max (dot (l, n), 0);
// Specular light
vec3 h = normalize (l + view);
float Is = pow (max (dot (h, n), 0), kse);
// Final Blinn-Phong Lighting
col += lightcol[i] * (Ca + (Cd*Id + Cs*Is) * att);
}
// In-Pixel Blooming: if max > 1, bloom out to other channels
vec4 bloom = max (col - vec4(1), 0);
col += vec4(vec3(bloom.x+bloom.y+bloom.z), 0);
// Alpha is by definition alpha of diffuse color
col.a = Cd.a;
gl_FragColor = col;
}
Init-Funktion
- Shader (und Locations und VBOs) wie in Einfache Standard-Codesequenz
- Uniform-Arrays bzw. Elemente können komplett mit
lglUniformfv("array", ...)
oder einzeln mitlglUniformfv("array[1]", ...
gesetzt werden. - Alles weitere wie gewohnt
Render-Funktion
- Projektions- und View-Matrizen berechnen, trackball
mat4 P = mat4::perspective(fovy, aspect, nearp, farp);
mat4 V = mat4::lookat(vec3(0,0,10), vec3(0,0,0), vec3(0,1,0));
mat4 MV = V * lglGetManip(); - Jedes Licht konfigurieren und Position in Augenkoordinaten umrechnen
mat4 mv_light0 = rotate (V, lightangle2, vec3 (0, 0, 1));
mv_light0 = translate (mv_light0, vec3 (2.2, 0, .8));
vec4 light_eye = mv_light0 * vec4(0,0,0,1);
lglUniformfv ("lightpos[0]", light_eye); - Für jede Geometrie bzw. VBO:
- ModelView, ModelViewProjection, Invers-transponierte ModelView berechnen und setzen
mat4f MV = translate (MV, vec3 (0, 0, -1));
mat4f MVP = P * MV;
mat4f MVIT = inverse (transpose (MV));
lglUniformfv ("mv", (float *) MV);
lglUniformfv ("mvp", (float *) MVP);
lglUniformfv ("mvit", (float *) MVIT); - oder vereinfacht:
lglProjection (proj); // Nur 1x nötig
lglModelView (mv); // Je Änderung - Materialparameter setzen
lglUniformfv ("Ca", vec4( 0, 0, .3, 0));
lglUniformfv ("Ce", vec4( 0, 0, 0, 0));
lglUniformfv ("Cd", vec4(.3, .5, 0, 0));
lglUniformfv ("Cs", vec4(.8, .8, .8, 0));
lglUniformf ("kse", 100); - Geometrie zeichnen
lglRender(...);
- ModelView, ModelViewProjection, Invers-transponierte ModelView berechnen und setzen
Hinweis: Die Lichtquellen selber zeichnet man über Proxy-Geometrien.
Live Demo: XMas Multi-Lights (T#14d)
← Lichtquellen zeichnen | ● | Uber-Shader →