 | Introduction |  |
Lighting is a critical part of 3D rendering, providing depth, realism, and mood to scenes by simulating how light interacts with surfaces. In WebGPU, lighting calculations are typically implemented in the fragment or vertex shader, with parameters for light type, position, intensity, and color. This chapter covers the main types of lighting—ambient, diffuse, and specular—and demonstrates how to implement them in WebGPU using WGSL.
Light sources in 3D graphics simulate real-world light to illuminate objects. Different types of lights can mimic the sun, lamps, or spotlights, each affecting surfaces in distinct ways. Lighting calculations in graphics consist of three main components:
1. Diffuse Lighting for non-shiny surfaces.
2. Specular Lighting for shiny surfaces that reflect light.
3. Ambient Lighting to ensure objects are not completely dark in shadowed areas.
 | Types of Light Sources |  |
Common light sources include:
• Directional Light: Mimics sunlight, where light rays are parallel and have a specific direction but no defined position.
• Point Light: A localized source radiating light equally in all directions.
• Spotlight: Projects light within a cone shape, illuminating only a portion of the scene.
• Area Light: Emits light over a surface area for softer shadows but is computationally more demanding.
 | Diffuse Lighting |  |
Diffuse lighting calculates the light reflected uniformly in all directions from a matte or dull surface. It depends on the angle between the light source direction and the surface normal, creating a soft lighting effect based on surface orientation.
Simple Diffuse Lighting Model
The Lambertian reflectance model defines diffuse lighting using the following equation:
\[
I_d = I \cdot k_d \cdot \max(0, \vec{L} \cdot \vec{N})
\]
where:
• \( I_d \) is the diffuse intensity.
• \( I \) is the light intensity.
• \( k_d \) is the diffuse reflection coefficient.
• \( \vec{L} \) is the light direction.
• \( \vec{N} \) is the surface normal.
Math for Diffuse Reflection
The diffuse component is maximal when \( \vec{L} \) is aligned with \( \vec{N} \) (i.e., light hits the surface perpendicularly) and diminishes as the angle between them increases.
 | Demo Program for Diffuse Lighting |  |
To implement diffuse lighting in WebGPU, we pass the light direction and color as uniforms and calculate the diffuse component in the fragment shader.
Diffuse Reflection in Shader Programs
In the fragment shader, we calculate \( \vec{L} \cdot \vec{N} \) and use this value to modulate the color.
struct Uniforms { lightDir: vec3<f32>; lightColor: vec3<f32>; kd: f32; };
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
@fragment fn main(@location(0) normal: vec3<f32>) -> @location(0) vec4<f32> { let n = normalize(normal); let l = normalize(-uniforms.lightDir); let diffuseFactor = max(dot(n, l), 0.0); let diffuseColor = uniforms.lightColor * diffuseFactor * uniforms.kd; return vec4(diffuseColor, 1.0); }
In this example, we use a directional light. For point lights, additional calculations for distance attenuation would be necessary.
 | Specular Lighting |  |
Specular lighting simulates the shiny highlights visible on smooth surfaces, based on the light source, viewer position, and surface properties.
Specular Lighting Model
Specular reflection is calculated using the Phong reflection model:
\[
I_s = I \cdot k_s \cdot \max(0, \vec{R} \cdot \vec{V})^{\alpha}
\]
where:
• \( I_s \) is the specular intensity.
• \( I \) is the light intensity.
• \( k_s \) is the specular reflection coefficient.
• \( \vec{R} \) is the reflection vector.
• \( \vec{V} \) is the view direction.
• \( \alpha \) is the shininess factor (higher values create sharper reflections).
Calculating the Reflection Vector
The reflection vector \( \vec{R} \) is computed as:
\[
\vec{R} = 2(\vec{L} \cdot \vec{N})\vec{N} - \vec{L}
\]
where \( \vec{L} \) is the light direction, and \( \vec{N} \) is the normal.
 | Demo Program for Specular Reflection |  |
A similar setup to diffuse lighting is used, with additional calculations for the reflection vector and view direction.
Specular Reflection in Shader Programs
In the vertex shader, we compute the necessary vectors to pass to the fragment shader.
Vertex Shader
@vertex fn main(@location(0) position: vec3<f32>, @location(1) normal: vec3<f32>) -> VertexOutput { // Transform position and calculate normals here }
Fragment Shader
struct Uniforms { lightDir: vec3<f32>; viewDir: vec3<f32>; lightColor: vec3<f32>; ks: f32; shininess: f32; };
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
@fragment fn main(@location(0) normal: vec3<f32>) -> @location(0) vec4<f32> { let n = normalize(normal); let l = normalize(-uniforms.lightDir); let r = reflect(-l, n); let v = normalize(uniforms.viewDir); let specFactor = pow(max(dot(r, v), 0.0), uniforms.shininess); let specularColor = uniforms.lightColor * specFactor * uniforms.ks; return vec4(specularColor, 1.0); }
 | Ambient Lighting |  |
Ambient lighting provides a base illumination level across the entire scene, ensuring that objects are visible even when not directly lit.
 | Combining Ambient, Diffuse, and Specular Lighting |  |
The final lighting model combines ambient, diffuse, and specular components:
\[
I = I_a + I_d + I_s
\]
where:
• \( I_a \) is ambient lighting.
• \( I_d \) is diffuse lighting.
• \( I_s \) is specular lighting.
 | Fragment Shader Debugging |  |
Debugging shaders often requires visualizing intermediate values. You can output these values as colors in the fragment shader to examine the results at each step.
 | Light Attenuation |  |
Light attenuation simulates the weakening of light over distance, essential for point and spotlight sources. The attenuation factor is calculated as:
\[
\text{attenuation} = \frac{1}{c_0 + c_1 d + c_2 d^2}
\]
where \( d \) is the distance from the light source, and \( c_0 \), \( c_1 \), and \( c_2 \) are constants that control the rate of decay.
 | Types of Light Sources |  |
Sun Light Source
Simulates sunlight with a directional light source, providing even lighting across the scene.
Spotlight Light Source
A spotlight illuminates within a cone shape, requiring additional calculations to determine if a fragment is within the cone’s bounds.
Area Light Source
An area light provides soft, diffused light, but implementing it requires complex calculations for realistic shadows.
Multiple Light Sources in a Scene
Combining multiple lights involves calculating and summing the contributions from each light source in the shader.
 | Summary |  |
This chapter explored lighting models in WebGPU, covering diffuse, specular, and ambient lighting and their implementation in WGSL. By combining these components and adjusting for attenuation and light types, we can simulate realistic lighting effects, enhancing the visual depth and realism of 3D scenes.
|