Lighting Models in DirectX
Lighting is a fundamental aspect of computer graphics, simulating how light interacts with surfaces to create realistic or stylized visuals. DirectX provides robust support for implementing various lighting models, allowing developers to control the appearance of their 3D scenes.
Understanding Light Interaction
Light interaction with a surface can be broadly categorized into three components:
- Ambient Light: A non-directional, uniform light that illuminates all objects equally. It simulates indirect lighting and prevents surfaces from being completely black.
- Diffuse Light: Light that is scattered equally in all directions from a surface. The intensity of diffuse light depends on the angle between the surface's normal and the light source's direction.
- Specular Light: Light that is reflected from a surface in a mirror-like fashion. This component is responsible for highlights and shininess on surfaces. The intensity depends on the viewing angle and the angle of reflection.
Common Lighting Models
1. Phong Lighting Model
The Phong lighting model is a widely used empirical model that combines ambient, diffuse, and specular components. It's a fast and effective way to simulate basic lighting.
The formula for Phong lighting at a given point on a surface is:
LightIntensity = Ambient + Diffuse + Specular
Where:
- Ambient:
Ia * Ka(Light Ambient Intensity * Material Ambient Reflectivity) - Diffuse:
Id * Kd * max(0, dot(N, L))(Light Diffuse Intensity * Material Diffuse Reflectivity * Maximum of 0 and the dot product of the surface normal (N) and the light direction (L)) - Specular:
Is * Ks * pow(max(0, dot(R, V)), Shininess))(Light Specular Intensity * Material Specular Reflectivity * Maximum of 0 and the dot product of the reflection vector (R) and the view vector (V), raised to the power of Shininess)
The dot(N, L) term ensures that surfaces facing away from the light are not illuminated. The Shininess parameter controls the size and intensity of the specular highlight.
2. Blinn-Phong Lighting Model
The Blinn-Phong model is a variation of the Phong model that often provides similar visual results but is computationally less expensive. It replaces the reflection vector calculation with a halfway vector.
The specular component is calculated using the halfway vector (H) between the light direction (L) and the view direction (V):
H = normalize(L + V)
Specular = Is * Ks * pow(max(0, dot(N, H)), Shininess))
This simplification avoids the explicit calculation of the reflection vector, making it faster for real-time rendering.
3. Physically Based Rendering (PBR)
Physically Based Rendering aims to simulate light interaction more accurately based on real-world physics. Instead of empirical models like Phong, PBR uses parameters that correspond to real-world material properties.
Key concepts in PBR include:
- Albedo: The base color of the surface, unaffected by lighting.
- Metallic: A value indicating whether the material is metallic (conductive) or dielectric (insulating). This significantly impacts how light reflects.
- Roughness: Controls the micro-surface variations that scatter light. Higher roughness leads to a more diffuse reflection, while lower roughness results in sharp, mirror-like reflections.
- Fresnel Effect: The phenomenon where reflectivity increases at glancing angles.
PBR models are more complex but yield more consistent and realistic results across different lighting conditions and viewing angles.
Implementation in DirectX (HLSL)
Lighting calculations are typically performed within the pixel shader using High-Level Shading Language (HLSL). The shader will receive information about light sources, surface normals, material properties, and camera position.
Here's a simplified example of a Phong lighting calculation in an HLSL pixel shader:
struct PixelInput
{
float4 position : SV_POSITION;
float3 normal : NORMAL;
float3 worldPos : WORLD_POSITION;
};
float4 AmbientColor = float4(0.1, 0.1, 0.1, 1.0);
float4 LightColor = float4(1.0, 1.0, 1.0, 1.0);
float3 LightDirection = normalize(float3(-1.0, -1.0, -1.0));
float3 CameraPosition = float3(0.0, 0.0, -10.0);
float4 MaterialAmbient = float4(0.2, 0.2, 0.2, 1.0);
float4 MaterialDiffuse = float4(0.8, 0.8, 0.8, 1.0);
float4 MaterialSpecular = float4(1.0, 1.0, 1.0, 1.0);
float MaterialShininess = 32.0;
float4 main(PixelInput input) : SV_TARGET
{
float3 normal = normalize(input.normal);
float3 worldPos = input.worldPos;
float3 lightDir = normalize(LightDirection);
float3 viewDir = normalize(CameraPosition - worldPos);
// Ambient
float4 ambient = MaterialAmbient * AmbientColor;
// Diffuse
float diffuseFactor = max(0.0, dot(normal, lightDir));
float4 diffuse = MaterialDiffuse * LightColor * diffuseFactor;
// Specular
float3 reflectDir = reflect(-lightDir, normal);
float specularFactor = pow(max(0.0, dot(viewDir, reflectDir)), MaterialShininess);
float4 specular = MaterialSpecular * LightColor * specularFactor;
float4 finalColor = ambient + diffuse + specular;
return finalColor;
}
Shader Parameters
| Parameter | Description |
|---|---|
normal |
The surface normal vector (interpolated from vertex shader). |
worldPos |
The position of the pixel in world space. |
lightDir |
The direction from the surface to the light source. |
viewDir |
The direction from the surface to the camera. |
MaterialAmbient |
The ambient reflectivity of the material. |
MaterialDiffuse |
The diffuse reflectivity of the material. |
MaterialSpecular |
The specular reflectivity of the material. |
MaterialShininess |
The shininess of the material (for Phong/Blinn-Phong). |
LightColor |
The color and intensity of the light source. |
Further Exploration
To delve deeper into advanced lighting and rendering techniques, consider exploring: