En aquest tema, explorarem els conceptes fonamentals de la il·luminació i els materials en DirectX. Aprendrem com crear efectes de llum realistes i com aplicar materials a objectes 3D per millorar la seva aparença visual.

Objectius del Tema

  • Comprendre els conceptes bàsics de la il·luminació en 3D.
  • Aprendre a configurar diferents tipus de llums en DirectX.
  • Aplicar materials a objectes 3D per simular diferents propietats de superfícies.
  • Implementar il·luminació bàsica en una escena 3D.

Conceptes Bàsics de la Il·luminació

Tipus de Llums

En DirectX, podem utilitzar diversos tipus de llums per il·luminar una escena. Els més comuns són:

  1. Llum Direccional (Directional Light):

    • Simula una font de llum llunyana, com el sol.
    • Tots els raigs de llum són paral·lels.
    • No té posició, només direcció.
  2. Llum Puntual (Point Light):

    • Emana llum en totes direccions des d'un punt específic.
    • Té una posició i una atenuació basada en la distància.
  3. Llum de Focal (Spot Light):

    • Similar a la llum puntual, però la llum es concentra en un con.
    • Té una posició, direcció i angle de con.

Fórmula de la Il·luminació

La il·luminació en una escena 3D es calcula utilitzant la fórmula de la il·luminació de Phong, que inclou components ambientals, difusos i especulars:

\[ I = I_{ambient} + I_{diffuse} + I_{specular} \]

  • Il·luminació Ambiental (Ambient Light): Llum uniforme que afecta tota l'escena.
  • Il·luminació Difusa (Diffuse Light): Llum que depèn de l'angle entre la llum i la superfície.
  • Il·luminació Especular (Specular Light): Llum reflectida que crea punts brillants.

Configuració de Llums en DirectX

Exemple de Codi: Configuració d'una Llum Direccional

// Estructura per a una llum direccional
struct DirectionalLight
{
    XMFLOAT4 Ambient;
    XMFLOAT4 Diffuse;
    XMFLOAT4 Specular;
    XMFLOAT3 Direction;
    float Pad; // Padding per alinear a 16 bytes
};

// Configuració d'una llum direccional
DirectionalLight dirLight;
dirLight.Ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
dirLight.Diffuse = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
dirLight.Specular = XMFLOAT4(0.7f, 0.7f, 0.7f, 1.0f);
dirLight.Direction = XMFLOAT3(0.577f, -0.577f, 0.577f);

Exemple de Codi: Configuració d'una Llum Puntual

// Estructura per a una llum puntual
struct PointLight
{
    XMFLOAT4 Ambient;
    XMFLOAT4 Diffuse;
    XMFLOAT4 Specular;
    XMFLOAT3 Position;
    float Range;
    XMFLOAT3 Att;
    float Pad; // Padding per alinear a 16 bytes
};

// Configuració d'una llum puntual
PointLight pointLight;
pointLight.Ambient = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f);
pointLight.Diffuse = XMFLOAT4(0.7f, 0.7f, 0.7f, 1.0f);
pointLight.Specular = XMFLOAT4(0.9f, 0.9f, 0.9f, 1.0f);
pointLight.Position = XMFLOAT3(0.0f, 5.0f, 0.0f);
pointLight.Range = 10.0f;
pointLight.Att = XMFLOAT3(0.0f, 0.1f, 0.0f);

Aplicació de Materials

Estructura de Material

struct Material
{
    XMFLOAT4 Ambient;
    XMFLOAT4 Diffuse;
    XMFLOAT4 Specular; // w = SpecPower
    XMFLOAT4 Reflect;
};

// Configuració d'un material
Material mat;
mat.Ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
mat.Diffuse = XMFLOAT4(0.8f, 0.8f, 0.8f, 1.0f);
mat.Specular = XMFLOAT4(1.0f, 1.0f, 1.0f, 16.0f); // SpecPower = 16
mat.Reflect = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);

Exemple de Codi: Aplicació de Material a un Objecte

// Assignar material a un objecte
objectMaterial = mat;

// Enviar material al shader
cbMaterial.Ambient = objectMaterial.Ambient;
cbMaterial.Diffuse = objectMaterial.Diffuse;
cbMaterial.Specular = objectMaterial.Specular;
cbMaterial.Reflect = objectMaterial.Reflect;

Implementació de la Il·luminació Bàsica

Vertex Shader

cbuffer cbPerObject
{
    float4x4 gWorldViewProj;
    float4x4 gWorld;
    float4x4 gWorldInvTranspose;
    Material gMaterial;
};

struct VertexIn
{
    float3 PosL : POSITION;
    float3 NormalL : NORMAL;
};

struct VertexOut
{
    float4 PosH : SV_POSITION;
    float3 PosW : POSITION;
    float3 NormalW : NORMAL;
};

VertexOut VS(VertexIn vin)
{
    VertexOut vout;

    // Transformar posició i normal
    vout.PosW = mul(float4(vin.PosL, 1.0f), gWorld).xyz;
    vout.NormalW = mul(float4(vin.NormalL, 0.0f), gWorldInvTranspose).xyz;
    vout.PosH = mul(float4(vin.PosL, 1.0f), gWorldViewProj);

    return vout;
}

Pixel Shader

cbuffer cbPerFrame
{
    DirectionalLight gDirLight;
    float3 gEyePosW;
};

struct VertexOut
{
    float4 PosH : SV_POSITION;
    float3 PosW : POSITION;
    float3 NormalW : NORMAL;
};

float4 PS(VertexOut pin) : SV_Target
{
    // Normalitzar la normal
    float3 N = normalize(pin.NormalW);

    // Calcular la direcció de la llum
    float3 L = normalize(-gDirLight.Direction);

    // Calcular la il·luminació difusa
    float diffuse = max(dot(N, L), 0.0f);

    // Calcular la il·luminació especular
    float3 R = reflect(-L, N);
    float3 V = normalize(gEyePosW - pin.PosW);
    float spec = pow(max(dot(R, V), 0.0f), gMaterial.Specular.w);

    // Composar la il·luminació final
    float4 ambient = gMaterial.Ambient * gDirLight.Ambient;
    float4 diffuseColor = gMaterial.Diffuse * gDirLight.Diffuse * diffuse;
    float4 specular = gMaterial.Specular * gDirLight.Specular * spec;

    return ambient + diffuseColor + specular;
}

Exercici Pràctic

Objectiu

Implementar una escena 3D amb una llum direccional i aplicar materials a diversos objectes.

Passos

  1. Configura una llum direccional.
  2. Defineix materials per a diferents objectes.
  3. Aplica els materials als objectes.
  4. Implementa els shaders per calcular la il·luminació.

Solució

// Configuració de la llum direccional
DirectionalLight dirLight;
dirLight.Ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
dirLight.Diffuse = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
dirLight.Specular = XMFLOAT4(0.7f, 0.7f, 0.7f, 1.0f);
dirLight.Direction = XMFLOAT3(0.577f, -0.577f, 0.577f);

// Configuració de materials
Material mat1;
mat1.Ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
mat1.Diffuse = XMFLOAT4(0.8f, 0.0f, 0.0f, 1.0f);
mat1.Specular = XMFLOAT4(1.0f, 1.0f, 1.0f, 16.0f);
mat1.Reflect = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);

Material mat2;
mat2.Ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
mat2.Diffuse = XMFLOAT4(0.0f, 0.8f, 0.0f, 1.0f);
mat2.Specular = XMFLOAT4(1.0f, 1.0f, 1.0f, 16.0f);
mat2.Reflect = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);

// Assignar materials a objectes
object1Material = mat1;
object2Material = mat2;

// Enviar materials als shaders
cbMaterial1.Ambient = object1Material.Ambient;
cbMaterial1.Diffuse = object1Material.Diffuse;
cbMaterial1.Specular = object1Material.Specular;
cbMaterial1.Reflect = object1Material.Reflect;

cbMaterial2.Ambient = object2Material.Ambient;
cbMaterial2.Diffuse = object2Material.Diffuse;
cbMaterial2.Specular = object2Material.Specular;
cbMaterial2.Reflect = object2Material.Reflect;

Resum

En aquest tema, hem après els conceptes bàsics de la il·luminació i els materials en DirectX. Hem vist com configurar diferents tipus de llums i com aplicar materials a objectes 3D per crear efectes visuals realistes. També hem implementat shaders per calcular la il·luminació en una escena 3D. Aquests coneixements són fonamentals per crear gràfics 3D realistes i atractius en les teves aplicacions DirectX.

© Copyright 2024. Tots els drets reservats