Zum Inhalt springen

Vertex Shader

Betrachten wir nun den Vertex-Shader aus unserem vollständigen Beispiel mit der beleuchteten Kugel und dem prozeduralen Streifenmuster.

WGSL
struct VertexOutput {
@builtin(position) position: vec4f,
@location(0) worldNormal: vec3f,
@location(1) worldPosition: vec3f,
};
struct Uniforms {
color: vec4f,
lightDirection: vec4f,
cameraPosition: vec4f,
ambientFactor: f32,
diffuseStrength: f32,
shininess: f32,
padding: f32,
modelMatrix: mat4x4f,
viewMatrix: mat4x4f,
projectionMatrix: mat4x4f,
normalMatrix: mat4x4f,
};
@group(0) @binding(0)
var<uniform> uniforms: Uniforms;
@vertex
fn vertexMain(
@location(0) position: vec3f,
@location(1) normal: vec3f
) -> VertexOutput {
let worldPosition =
uniforms.modelMatrix * vec4f(position, 1.0);
let viewPosition =
uniforms.viewMatrix * worldPosition;
let clipPosition =
uniforms.projectionMatrix * viewPosition;
let worldNormal = normalize(
(uniforms.normalMatrix * vec4f(normal, 0.0)).xyz
);
return VertexOutput(
clipPosition,
worldNormal,
worldPosition.xyz
);
}

Auf den ersten Blick enthält dieser Shader einige neue Berechnungen. Vieles sollten wir inzwischen aber bereits wiedererkennen.

Die Eingabeparameter position und normal sind Vertex-Attribute, die über @location(0) und @location(1) mit den Vertex-Buffern verbunden werden.

Mit @group(0) und @binding(0) greifen wir auf einen Uniform-Buffer zu. Die Struktur Uniforms enthält Werte, die unser JavaScript-Programm bereitstellt.

Auch die Struktur VertexOutput ist uns vertraut. Sie enthält die berechnete Vertex-Position sowie zwei Interstage-Variablen, die an den Fragment-Shader weitergegeben und dabei interpoliert werden.

Innerhalb der Funktion begegnen uns außerdem bekannte WGSL-Datentypen wie vec3f, vec4f und mat4x4f, die Funktion normalize() sowie der Zugriff auf Vektorkomponenten mit .xyz.

Die vier Matrizen modelMatrix, viewMatrix, projectionMatrix und normalMatrix haben wir bisher noch nicht näher behandelt.

Sie werden verwendet, um die Positionen und Normalen der Kugel in unterschiedliche Koordinatensysteme zu transformieren. Die Berechnungen hängen mit der Positionierung von Objekten, der Kamera und der perspektivischen Darstellung zusammen.

Diese Themen behandeln wir später ausführlich im Kapitel über Kameras und Transformationen. Für den Moment genügt es zu wissen, dass der Vertex-Shader die Position jedes Vertex für die Darstellung vorbereitet und die benötigten Oberflächendaten an den Fragment-Shader weitergibt.