Introduction
Lighting and materials are fundamental concepts in 3D graphics that significantly affect the visual quality of rendered scenes. In this section, we will explore how to implement basic lighting models and material properties in DirectX.
Key Concepts
- Lighting Models: Techniques to simulate light interaction with surfaces.
- Material Properties: Characteristics of surfaces that determine how they reflect light.
- Light Types: Different sources of light such as directional, point, and spotlights.
- Shader Implementation: Writing shaders to handle lighting calculations.
Types of Lights
Directional Light
- Description: Simulates light coming from a specific direction, like sunlight.
- Properties:
- Direction
- Color
- Intensity
Point Light
- Description: Emits light in all directions from a single point, like a light bulb.
- Properties:
- Position
- Color
- Intensity
- Attenuation (how light diminishes over distance)
Spotlight
- Description: Emits light in a cone shape, like a flashlight.
- Properties:
- Position
- Direction
- Color
- Intensity
- Inner and Outer Cone Angles
- Attenuation
Material Properties
Ambient
- Description: The base color of the material when not directly lit.
- Properties:
- Ambient Color
Diffuse
- Description: The color of the material under direct light.
- Properties:
- Diffuse Color
Specular
- Description: The color of the material's highlights.
- Properties:
- Specular Color
- Specular Power (shininess)
Emissive
- Description: The color the material emits as if it were a light source.
- Properties:
- Emissive Color
Implementing Lighting in DirectX
Step 1: Define Light Structures
struct DirectionalLight { XMFLOAT3 Direction; float Padding; // Padding to align to 16 bytes XMFLOAT4 Color; }; struct PointLight { XMFLOAT3 Position; float Range; XMFLOAT3 Attenuation; float Padding; // Padding to align to 16 bytes XMFLOAT4 Color; }; struct SpotLight { XMFLOAT3 Position; float Range; XMFLOAT3 Direction; float Spot; XMFLOAT3 Attenuation; float Padding; // Padding to align to 16 bytes XMFLOAT4 Color; };
Step 2: Define Material Structure
struct Material { XMFLOAT4 Ambient; XMFLOAT4 Diffuse; XMFLOAT4 Specular; // w = SpecPower XMFLOAT4 Emissive; };
Step 3: Update Constant Buffers
Ensure your constant buffers include the light and material structures.
struct ConstantBuffer { XMMATRIX World; XMMATRIX View; XMMATRIX Projection; DirectionalLight DirLight; PointLight PtLight; SpotLight SpLight; Material Mat; XMFLOAT3 EyePosW; float Padding; // Padding to align to 16 bytes };
Step 4: Write Shaders
Vertex Shader
cbuffer ConstantBuffer : register(b0) { matrix World; matrix View; matrix Projection; DirectionalLight DirLight; PointLight PtLight; SpotLight SpLight; Material Mat; float3 EyePosW; }; struct VS_INPUT { float3 Pos : POSITION; float3 Normal : NORMAL; }; struct PS_INPUT { float4 Pos : SV_POSITION; float3 Normal : NORMAL; float3 WorldPos : POSITION1; }; PS_INPUT VS(VS_INPUT input) { PS_INPUT output; float4 worldPos = mul(float4(input.Pos, 1.0f), World); output.WorldPos = worldPos.xyz; output.Normal = mul(input.Normal, (float3x3)World); output.Pos = mul(worldPos, View); output.Pos = mul(output.Pos, Projection); return output; }
Pixel Shader
float4 CalcDirectionalLight(DirectionalLight light, float3 normal) { float3 lightDir = normalize(-light.Direction); float diff = max(dot(normal, lightDir), 0.0f); float4 diffuse = diff * light.Color * Mat.Diffuse; return diffuse; } float4 CalcPointLight(PointLight light, float3 normal, float3 worldPos) { float3 lightDir = light.Position - worldPos; float dist = length(lightDir); lightDir /= dist; float diff = max(dot(normal, lightDir), 0.0f); float attenuation = 1.0f / (light.Attenuation.x + light.Attenuation.y * dist + light.Attenuation.z * dist * dist); float4 diffuse = diff * light.Color * Mat.Diffuse * attenuation; return diffuse; } float4 CalcSpotLight(SpotLight light, float3 normal, float3 worldPos) { float3 lightDir = light.Position - worldPos; float dist = length(lightDir); lightDir /= dist; float diff = max(dot(normal, lightDir), 0.0f); float spotEffect = dot(lightDir, -light.Direction); if (spotEffect > light.Spot) { float attenuation = 1.0f / (light.Attenuation.x + light.Attenuation.y * dist + light.Attenuation.z * dist * dist); float4 diffuse = diff * light.Color * Mat.Diffuse * attenuation * pow(spotEffect, light.Spot); return diffuse; } return float4(0, 0, 0, 0); } float4 PS(PS_INPUT input) : SV_TARGET { float3 normal = normalize(input.Normal); float4 color = Mat.Ambient * DirLight.Color; color += CalcDirectionalLight(DirLight, normal); color += CalcPointLight(PtLight, normal, input.WorldPos); color += CalcSpotLight(SpLight, normal, input.WorldPos); return color; }
Practical Exercise
Task
- Implement a simple scene with a cube.
- Apply a directional light and a point light to the scene.
- Define material properties for the cube.
Solution
- Define Light and Material Structures: As shown in the code snippets above.
- Update Constant Buffers: Ensure your constant buffers include the light and material structures.
- Write Shaders: Use the provided vertex and pixel shaders.
- Render the Scene: Create a cube and apply the lighting and material properties.
Common Mistakes
- Incorrect Light Direction: Ensure the light direction is normalized.
- Incorrect Normal Calculation: Ensure normals are transformed correctly in the vertex shader.
- Missing Attenuation: For point and spotlights, ensure attenuation is calculated to avoid unrealistic lighting.
Conclusion
In this section, we covered the basics of lighting and materials in DirectX. We explored different types of lights, material properties, and how to implement them in shaders. Understanding these concepts is crucial for creating visually appealing 3D scenes. In the next section, we will delve into advanced lighting techniques to further enhance the realism of your scenes.
DirectX Programming Course
Module 1: Introduction to DirectX
- What is DirectX?
- Setting Up the Development Environment
- Understanding the DirectX API
- Creating Your First DirectX Application
Module 2: Direct3D Basics
Module 3: Working with Shaders
Module 4: Advanced Rendering Techniques
Module 5: 3D Models and Animation
Module 6: Performance Optimization
- Profiling and Debugging
- Optimizing Rendering Performance
- Memory Management
- Multithreading in DirectX