Fragment Shader
Nachdem wir den Vertex-Shader betrachtet haben, wenden wir uns dem Fragment-Shader unseres Beispiels zu. Er ist für das schwarz-weiße Streifenmuster und die Beleuchtung der Kugel verantwortlich.
@fragmentfn fragmentMain( @location(0) worldNormal: vec3f, @location(1) worldPosition: vec3f) -> @location(0) vec4f { let normal = normalize(worldNormal); let lightDir = normalize(uniforms.lightDirection.xyz); let viewDir = normalize( uniforms.cameraPosition.xyz - worldPosition );
// Geschwungene schwarz-weiße Streifen let stripePosition = worldPosition.y * 180.0 + sin(worldPosition.x * 80.0) * 5.0;
let stripe = smoothstep( -0.15, 0.15, sin(stripePosition) );
let zebraColor = mix( vec3f(0.025, 0.025, 0.035), vec3f(0.95, 0.95, 0.90), stripe );
// Phong-Beleuchtung let ambient = uniforms.ambientFactor * zebraColor;
let diffuseBrightness = max(dot(normal, lightDir), 0.0);
let diffuse = zebraColor * diffuseBrightness * uniforms.diffuseStrength;
let reflected = reflect(-lightDir, normal);
let specularFactor = pow( max(dot(reflected, viewDir), 0.0), uniforms.shininess );
let specular = vec3f(1.0) * specularFactor;
return vec4f( ambient + diffuse + specular, 1.0 );}Auch hier sollten wir bereits einiges wiedererkennen.
Mit @fragment kennzeichnen wir den Einstiegspunkt des Fragment-Shaders. Die Parameter worldNormal und worldPosition sind Interstage-Variablen. Ihre Werte stammen aus dem Vertex-Shader und wurden während der Rasterisierung interpoliert.
Über uniforms greifen wir auf die gemeinsamen Uniform-Werte zu, die wir bereits im vorherigen Abschnitt kennengelernt haben.
Auch die Datentypen f32, vec3f und vec4f, die Vektorkomponenten .xyz, .x und .y sowie die Rechenoperationen sollten uns vertraut sein.
Der Rückgabewert @location(0) vec4f enthält die berechnete Fragmentfarbe. Die vier Komponenten stehen für Rot, Grün, Blau und Alpha.
Ein Blick nach vorn
Abschnitt betitelt „Ein Blick nach vorn“Unser Fragment-Shader kombiniert die bereits bekannte Phong-Beleuchtung mit einem prozedural erzeugten Streifenmuster. Die Funktionen sin(), smoothstep() und mix() zeigen dabei, wie sich Oberflächenfarben direkt im Shader berechnen lassen.
Das ist allerdings nur ein kleiner Ausschnitt dessen, was Fragment-Shader leisten können. In späteren Kapiteln beschäftigen wir uns ausführlicher mit Farben und Farbräumen, Texturen und UV-Koordinaten, Materialien sowie Transparenz und Blending.
Dabei werden wir sehen, wie sich das Erscheinungsbild dreidimensionaler Oberflächen gezielt gestalten lässt – von einfachen Farben über Bildtexturen bis hin zu komplexeren Materialeffekten.