El mapatge d'ombres és una tècnica avançada de renderització que permet crear ombres realistes en una escena 3D. Aquesta tècnica és àmpliament utilitzada en motors de jocs i aplicacions gràfiques per millorar la percepció de profunditat i realisme.
Conceptes Clau
- Shadow Map (Mapa d'Ombres): Una textura que emmagatzema la informació de profunditat des de la perspectiva de la font de llum.
- Passada de Profunditat: La primera passada de renderització on es genera el shadow map.
- Passada de Renderització: La segona passada on es compara la profunditat dels píxels amb el shadow map per determinar si un píxel està a l'ombra.
Passos per Implementar el Mapatge d'Ombres
- Crear el Shadow Map
Primer, hem de crear una textura que servirà com a shadow map. Aquesta textura emmagatzemarà la informació de profunditat des de la perspectiva de la font de llum.
// Crear una textura per al shadow map D3D11_TEXTURE2D_DESC shadowMapDesc = {}; shadowMapDesc.Width = SHADOW_MAP_WIDTH; shadowMapDesc.Height = SHADOW_MAP_HEIGHT; shadowMapDesc.MipLevels = 1; shadowMapDesc.ArraySize = 1; shadowMapDesc.Format = DXGI_FORMAT_R24G8_TYPELESS; shadowMapDesc.SampleDesc.Count = 1; shadowMapDesc.Usage = D3D11_USAGE_DEFAULT; shadowMapDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; ID3D11Texture2D* shadowMapTexture; device->CreateTexture2D(&shadowMapDesc, nullptr, &shadowMapTexture);
- Configurar la Vista de la Font de Llum
Hem de configurar una matriu de vista i projecció des de la perspectiva de la font de llum.
// Configurar la matriu de vista de la font de llum XMVECTOR lightPosition = XMVectorSet(0.0f, 10.0f, 0.0f, 1.0f); XMVECTOR lightTarget = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f); XMVECTOR lightUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); XMMATRIX lightViewMatrix = XMMatrixLookAtLH(lightPosition, lightTarget, lightUp); // Configurar la matriu de projecció de la font de llum XMMATRIX lightProjectionMatrix = XMMatrixOrthographicLH(20.0f, 20.0f, 1.0f, 100.0f);
- Renderitzar la Passada de Profunditat
Renderitzem la escena des de la perspectiva de la font de llum per generar el shadow map.
// Configurar el render target per al shadow map context->OMSetRenderTargets(0, nullptr, shadowMapDepthStencilView); context->ClearDepthStencilView(shadowMapDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0); // Configurar les matrius de vista i projecció de la font de llum cbLightViewProjection.lightView = XMMatrixTranspose(lightViewMatrix); cbLightViewProjection.lightProjection = XMMatrixTranspose(lightProjectionMatrix); context->UpdateSubresource(lightViewProjectionBuffer, 0, nullptr, &cbLightViewProjection, 0, 0); // Renderitzar la escena per generar el shadow map RenderScene(context, shadowMapShader);
- Aplicar el Shadow Map en la Passada de Renderització
En la passada de renderització, utilitzem el shadow map per determinar si un píxel està a l'ombra.
// Configurar el shader resource view del shadow map context->PSSetShaderResources(1, 1, &shadowMapSRV); // Configurar les matrius de vista i projecció de la càmera cbCameraViewProjection.cameraView = XMMatrixTranspose(cameraViewMatrix); cbCameraViewProjection.cameraProjection = XMMatrixTranspose(cameraProjectionMatrix); context->UpdateSubresource(cameraViewProjectionBuffer, 0, nullptr, &cbCameraViewProjection, 0, 0); // Renderitzar la escena amb el shadow map RenderScene(context, mainShader);
Exercici Pràctic
Objectiu
Implementar el mapatge d'ombres en una escena 3D simple amb una font de llum direccional.
Passos
- Crear el Shadow Map: Seguint els passos descrits anteriorment, crea una textura per al shadow map.
- Configurar la Vista de la Font de Llum: Configura les matrius de vista i projecció des de la perspectiva de la font de llum.
- Renderitzar la Passada de Profunditat: Renderitza la escena des de la perspectiva de la font de llum per generar el shadow map.
- Aplicar el Shadow Map: Utilitza el shadow map en la passada de renderització per determinar si els píxels estan a l'ombra.
Solució
// Pas 1: Crear el Shadow Map D3D11_TEXTURE2D_DESC shadowMapDesc = {}; shadowMapDesc.Width = SHADOW_MAP_WIDTH; shadowMapDesc.Height = SHADOW_MAP_HEIGHT; shadowMapDesc.MipLevels = 1; shadowMapDesc.ArraySize = 1; shadowMapDesc.Format = DXGI_FORMAT_R24G8_TYPELESS; shadowMapDesc.SampleDesc.Count = 1; shadowMapDesc.Usage = D3D11_USAGE_DEFAULT; shadowMapDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; ID3D11Texture2D* shadowMapTexture; device->CreateTexture2D(&shadowMapDesc, nullptr, &shadowMapTexture); // Pas 2: Configurar la Vista de la Font de Llum XMVECTOR lightPosition = XMVectorSet(0.0f, 10.0f, 0.0f, 1.0f); XMVECTOR lightTarget = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f); XMVECTOR lightUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); XMMATRIX lightViewMatrix = XMMatrixLookAtLH(lightPosition, lightTarget, lightUp); XMMATRIX lightProjectionMatrix = XMMatrixOrthographicLH(20.0f, 20.0f, 1.0f, 100.0f); // Pas 3: Renderitzar la Passada de Profunditat context->OMSetRenderTargets(0, nullptr, shadowMapDepthStencilView); context->ClearDepthStencilView(shadowMapDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0); cbLightViewProjection.lightView = XMMatrixTranspose(lightViewMatrix); cbLightViewProjection.lightProjection = XMMatrixTranspose(lightProjectionMatrix); context->UpdateSubresource(lightViewProjectionBuffer, 0, nullptr, &cbLightViewProjection, 0, 0); RenderScene(context, shadowMapShader); // Pas 4: Aplicar el Shadow Map context->PSSetShaderResources(1, 1, &shadowMapSRV); cbCameraViewProjection.cameraView = XMMatrixTranspose(cameraViewMatrix); cbCameraViewProjection.cameraProjection = XMMatrixTranspose(cameraProjectionMatrix); context->UpdateSubresource(cameraViewProjectionBuffer, 0, nullptr, &cbCameraViewProjection, 0, 0); RenderScene(context, mainShader);
Errors Comuns i Consells
- Resolució del Shadow Map: Una resolució massa baixa pot causar artefactes d'ombres. Ajusta la resolució segons les necessitats de la teva aplicació.
- Bias de Profunditat: Un bias inadequat pot causar ombres incorrectes. Experimenta amb diferents valors de bias per trobar el més adequat.
- Aliasing: Utilitza tècniques com el PCF (Percentage Closer Filtering) per suavitzar les ombres i reduir l'aliasing.
Conclusió
El mapatge d'ombres és una tècnica poderosa per afegir realisme a les escenes 3D. Comprendre i implementar aquesta tècnica és essencial per a qualsevol desenvolupador que treballi amb gràfics 3D avançats. Amb la pràctica, podràs crear ombres realistes i millorar significativament la qualitat visual de les teves aplicacions.
Curs de Programació DirectX
Mòdul 1: Introducció a DirectX
- Què és DirectX?
- Configuració de l'Entorn de Desenvolupament
- Comprendre l'API de DirectX
- Crear la Teva Primera Aplicació DirectX
Mòdul 2: Conceptes Bàsics de Direct3D
- Introducció a Direct3D
- Inicialitzar Direct3D
- Renderitzar un Triangle
- Gestionar el Bucle de Renderització
Mòdul 3: Treballar amb Shaders
Mòdul 4: Tècniques Avançades de Renderització
Mòdul 5: Models 3D i Animació
Mòdul 6: Optimització del Rendiment
- Perfilat i Depuració
- Optimitzar el Rendiment de la Renderització
- Gestió de Memòria
- Multifil en DirectX