En este módulo, aprenderemos sobre los conceptos fundamentales de iluminación y materiales en DirectX. La iluminación es crucial para dar realismo a las escenas 3D, y los materiales determinan cómo los objetos interactúan con la luz. Exploraremos diferentes tipos de luces y cómo configurar materiales para obtener efectos visuales deseados.
Conceptos Clave
-
Tipos de Luces:
- Luz Ambiental: Luz que ilumina uniformemente toda la escena.
- Luz Direccional: Luz que simula una fuente de luz lejana, como el sol.
- Luz Puntual: Luz que emana desde un punto en todas direcciones.
- Luz Focal: Luz que emana desde un punto en una dirección específica, similar a un foco.
-
Componentes de Materiales:
- Difuso: Cómo la luz se dispersa en la superficie del objeto.
- Especular: Cómo la luz se refleja en la superficie del objeto.
- Emisivo: Luz que el objeto emite por sí mismo.
- Ambiente: Cómo el objeto interactúa con la luz ambiental.
Configuración de la Iluminación
Luz Direccional
Primero, configuraremos una luz direccional en nuestra escena. La luz direccional es útil para simular la luz del sol.
// Estructura para definir una luz direccional struct DirectionalLight { XMFLOAT4 Ambient; XMFLOAT4 Diffuse; XMFLOAT4 Specular; XMFLOAT3 Direction; float Pad; // Padding para alineación }; // Definición de una luz 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.57735f, -0.57735f, 0.57735f); // Normalizado
Luz Puntual
La luz puntual emite luz desde un punto en todas direcciones, similar a una bombilla.
// Estructura para definir una luz puntual struct PointLight { XMFLOAT4 Ambient; XMFLOAT4 Diffuse; XMFLOAT4 Specular; XMFLOAT3 Position; float Range; XMFLOAT3 Att; float Pad; // Padding para alineación }; // Definición de una luz 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, 1.0f, 0.0f); pointLight.Range = 10.0f; pointLight.Att = XMFLOAT3(0.0f, 0.1f, 0.0f); // Atenuación
Configuración de Materiales
Los materiales determinan cómo los objetos reflejan la luz. Aquí configuramos un material básico.
// Estructura para definir un material struct Material { XMFLOAT4 Ambient; XMFLOAT4 Diffuse; XMFLOAT4 Specular; // w = SpecPower XMFLOAT4 Reflect; }; // Definición de 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);
Ejemplo Práctico: Aplicando Iluminación y Materiales
Vamos a combinar la luz direccional y el material en un shader simple.
Vertex Shader
cbuffer cbPerObject { float4x4 gWorldViewProj; float4x4 gWorld; }; 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; vout.PosW = mul(float4(vin.PosL, 1.0f), gWorld).xyz; vout.NormalW = mul(float4(vin.NormalL, 0.0f), gWorld).xyz; vout.PosH = mul(float4(vin.PosL, 1.0f), gWorldViewProj); return vout; }
Pixel Shader
cbuffer cbPerFrame { DirectionalLight gDirLight; float3 gEyePosW; }; cbuffer cbPerObject { Material gMaterial; }; struct VertexOut { float4 PosH : SV_POSITION; float3 PosW : POSITION; float3 NormalW : NORMAL; }; float4 PS(VertexOut pin) : SV_Target { float3 N = normalize(pin.NormalW); float3 L = normalize(gDirLight.Direction); float3 V = normalize(gEyePosW - pin.PosW); float3 R = reflect(-L, N); // Ambient float4 ambient = gMaterial.Ambient * gDirLight.Ambient; // Diffuse float4 diffuse = gMaterial.Diffuse * gDirLight.Diffuse * saturate(dot(N, L)); // Specular float4 spec = gMaterial.Specular * gDirLight.Specular * pow(saturate(dot(R, V)), gMaterial.Specular.w); return ambient + diffuse + spec; }
Ejercicio Práctico
Ejercicio 1: Añadir una Luz Puntual
- Objetivo: Añadir una luz puntual a la escena y ajustar los materiales para ver el efecto.
- Instrucciones:
- Define una estructura
PointLight
en el shader. - Añade una instancia de
PointLight
en el buffer constante. - Modifica el pixel shader para incluir la contribución de la luz puntual.
- Define una estructura
Solución
cbuffer cbPerFrame { DirectionalLight gDirLight; PointLight gPointLight; float3 gEyePosW; }; float4 PS(VertexOut pin) : SV_Target { float3 N = normalize(pin.NormalW); float3 L = normalize(gDirLight.Direction); float3 V = normalize(gEyePosW - pin.PosW); float3 R = reflect(-L, N); // Ambient float4 ambient = gMaterial.Ambient * gDirLight.Ambient; // Diffuse float4 diffuse = gMaterial.Diffuse * gDirLight.Diffuse * saturate(dot(N, L)); // Specular float4 spec = gMaterial.Specular * gDirLight.Specular * pow(saturate(dot(R, V)), gMaterial.Specular.w); // Point Light Contribution float3 P = gPointLight.Position - pin.PosW; float d = length(P); P /= d; // Normalize P float attenuation = 1.0f / (gPointLight.Att.x + gPointLight.Att.y * d + gPointLight.Att.z * d * d); float4 pointDiffuse = gMaterial.Diffuse * gPointLight.Diffuse * saturate(dot(N, P)) * attenuation; float4 pointSpec = gMaterial.Specular * gPointLight.Specular * pow(saturate(dot(reflect(-P, N), V)), gMaterial.Specular.w) * attenuation; return ambient + diffuse + spec + pointDiffuse + pointSpec; }
Conclusión
En esta sección, hemos aprendido sobre los diferentes tipos de luces y cómo configurar materiales en DirectX. Hemos visto cómo aplicar estos conceptos en shaders para crear efectos de iluminación realistas. En el siguiente módulo, exploraremos técnicas avanzadas de iluminación, como el mapeo de sombras, para mejorar aún más la calidad visual de nuestras escenas.
Curso de Programación DirectX
Módulo 1: Introducción a DirectX
- ¿Qué es DirectX?
- Configuración del Entorno de Desarrollo
- Entendiendo la API de DirectX
- Creando Tu Primera Aplicación DirectX
Módulo 2: Conceptos Básicos de Direct3D
- Introducción a Direct3D
- Inicializando Direct3D
- Renderizando un Triángulo
- Manejando el Bucle de Renderizado
Módulo 3: Trabajando con Shaders
- Introducción a los Shaders
- Escribiendo Vertex Shaders
- Escribiendo Pixel Shaders
- Compilando y Usando Shaders
Módulo 4: Técnicas Avanzadas de Renderizado
Módulo 5: Modelos 3D y Animación
Módulo 6: Optimización del Rendimiento
- Perfilado y Depuración
- Optimizando el Rendimiento de Renderizado
- Gestión de Memoria
- Multithreading en DirectX