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

  1. Lighting Models: Techniques to simulate light interaction with surfaces.
  2. Material Properties: Characteristics of surfaces that determine how they reflect light.
  3. Light Types: Different sources of light such as directional, point, and spotlights.
  4. 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

  1. Implement a simple scene with a cube.
  2. Apply a directional light and a point light to the scene.
  3. Define material properties for the cube.

Solution

  1. Define Light and Material Structures: As shown in the code snippets above.
  2. Update Constant Buffers: Ensure your constant buffers include the light and material structures.
  3. Write Shaders: Use the provided vertex and pixel shaders.
  4. 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.

© Copyright 2024. All rights reserved