Los efectos de post-procesamiento son técnicas aplicadas a la imagen renderizada final para mejorar su calidad visual o añadir efectos especiales. Estos efectos se aplican después de que la escena ha sido completamente renderizada, de ahí el término "post-procesamiento". En este módulo, aprenderemos sobre algunos de los efectos de post-procesamiento más comunes y cómo implementarlos en DirectX.

Conceptos Clave

  1. Render Target: Un buffer donde se almacena la imagen renderizada antes de ser presentada en la pantalla.
  2. Shader de Post-Procesamiento: Un shader que se aplica a la imagen renderizada para modificar su apariencia.
  3. Framebuffer: Un conjunto de buffers que incluye el color, la profundidad y otros datos necesarios para renderizar una escena.

Efectos Comunes de Post-Procesamiento

  1. Bloom: Añade un resplandor a las áreas brillantes de la imagen.
  2. Depth of Field: Simula el efecto de enfoque y desenfoque de una cámara.
  3. Motion Blur: Añade un efecto de desenfoque a los objetos en movimiento.
  4. Color Correction: Ajusta los colores de la imagen para mejorar su apariencia.

Implementación de Efectos de Post-Procesamiento

Paso 1: Configuración del Render Target

Primero, necesitamos configurar un render target donde almacenaremos la imagen renderizada antes de aplicar los efectos de post-procesamiento.

// Crear un render target
ID3D11Texture2D* pRenderTargetTexture = nullptr;
D3D11_TEXTURE2D_DESC textureDesc = {};
textureDesc.Width = width;
textureDesc.Height = height;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;

HRESULT hr = device->CreateTexture2D(&textureDesc, nullptr, &pRenderTargetTexture);
if (FAILED(hr)) {
    // Manejar error
}

// Crear un render target view
ID3D11RenderTargetView* pRenderTargetView = nullptr;
hr = device->CreateRenderTargetView(pRenderTargetTexture, nullptr, &pRenderTargetView);
if (FAILED(hr)) {
    // Manejar error
}

Paso 2: Renderizar la Escena al Render Target

Renderizamos la escena al render target en lugar de directamente a la pantalla.

// Establecer el render target
context->OMSetRenderTargets(1, &pRenderTargetView, nullptr);

// Renderizar la escena
RenderScene();

Paso 3: Aplicar el Shader de Post-Procesamiento

Después de renderizar la escena, aplicamos el shader de post-procesamiento. Aquí hay un ejemplo de un shader simple que aplica un efecto de inversión de color.

Vertex Shader (PostProcessVS.hlsl)

struct VS_OUTPUT {
    float4 Pos : SV_POSITION;
    float2 TexCoord : TEXCOORD0;
};

VS_OUTPUT main(float4 pos : POSITION, float2 texCoord : TEXCOORD0) {
    VS_OUTPUT output;
    output.Pos = pos;
    output.TexCoord = texCoord;
    return output;
}

Pixel Shader (PostProcessPS.hlsl)

Texture2D sceneTexture : register(t0);
SamplerState samplerState : register(s0);

float4 main(float2 texCoord : TEXCOORD0) : SV_TARGET {
    float4 color = sceneTexture.Sample(samplerState, texCoord);
    // Invertir colores
    color.rgb = 1.0 - color.rgb;
    return color;
}

Paso 4: Configurar y Ejecutar el Shader

Configuramos y ejecutamos el shader de post-procesamiento.

// Establecer el shader de post-procesamiento
context->VSSetShader(pPostProcessVertexShader, nullptr, 0);
context->PSSetShader(pPostProcessPixelShader, nullptr, 0);

// Establecer el render target original (pantalla)
context->OMSetRenderTargets(1, &pOriginalRenderTargetView, nullptr);

// Dibujar un quad de pantalla completa
context->Draw(6, 0);

Ejercicio Práctico

Ejercicio 1: Implementar un Efecto de Desenfoque Gaussiano

  1. Objetivo: Implementar un efecto de desenfoque gaussiano en la imagen renderizada.
  2. Instrucciones:
    • Configura un render target.
    • Renderiza la escena al render target.
    • Aplica un shader de post-procesamiento que implemente un desenfoque gaussiano.
    • Renderiza la imagen procesada a la pantalla.

Pista: Un desenfoque gaussiano se puede implementar mediante la convolución de la imagen con un kernel gaussiano.

Solución

Pixel Shader (GaussianBlurPS.hlsl)

Texture2D sceneTexture : register(t0);
SamplerState samplerState : register(s0);

float4 main(float2 texCoord : TEXCOORD0) : SV_TARGET {
    float4 color = float4(0, 0, 0, 1);
    float2 offsets[9] = {
        float2(-1, -1), float2(0, -1), float2(1, -1),
        float2(-1,  0), float2(0,  0), float2(1,  0),
        float2(-1,  1), float2(0,  1), float2(1,  1)
    };
    float kernel[9] = {
        1.0 / 16, 2.0 / 16, 1.0 / 16,
        2.0 / 16, 4.0 / 16, 2.0 / 16,
        1.0 / 16, 2.0 / 16, 1.0 / 16
    };

    for (int i = 0; i < 9; i++) {
        color += sceneTexture.Sample(samplerState, texCoord + offsets[i] * 0.005) * kernel[i];
    }

    return color;
}

Conclusión

En esta sección, hemos aprendido sobre los efectos de post-procesamiento y cómo implementarlos en DirectX. Hemos cubierto la configuración de render targets, la aplicación de shaders de post-procesamiento y hemos implementado un efecto de inversión de color. Además, hemos proporcionado un ejercicio práctico para implementar un desenfoque gaussiano. Con estos conocimientos, estarás preparado para explorar y crear tus propios efectos de post-procesamiento avanzados.

© Copyright 2024. Todos los derechos reservados