Implementación de Pantalla Dividida mediante CommandBuffers en Unity

La técnica de pantalla dividida mediante CommandBuffers permite interceptar el flujo de renderizado estándar de Unity para menipular la imagen final. El concepto fundamental consiste en capturar el búfer de imagen actual en una textura de renedrizado (RenderTexture) y, posteriormente, procesarla a través de un shader que distribuya las secciones correspondientes a múltiples salidas.

Lógica del Shader de Procesamiento

Para lograr la división, el shader debe remapear las coordenadas UV. Al escalar el eje horizontal a la mitad y aplicar un desplazamiento dinámico (offset), podemos seleccionar qué parte de la textura original se mostrará en cada segmento de la pantalla.

Shader "Custom/ScreenSplitProcessor"
{
    Properties
    {
        _MainTex ("Source Texture", 2D) = "white" {}
    }

    SubShader
    {
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float _XOffset;

            fixed4 frag (v2f_img i) : SV_Target
            {
                // Ajustamos el muestreo: escalamos el ancho al 50% y desplazamos
                float2 uv_adjusted = i.uv;
                uv_adjusted.x = uv_adjusted.x * 0.5 + _XOffset;
                
                return tex2D(_MainTex, uv_adjusted);
            }
            ENDCG
        }
    }
    Fallback Off
}

Controlador en C# para CommandBuffer

El siguiente script gestiona el ciclo de vida del CommandBuffer. Registra los comandos necesarios para realizar la captura del fotograma actual y enviarlo a las texturas de destino utilizando el material definido anteriormente.

using UnityEngine;
using UnityEngine.Rendering;

[RequireComponent(typeof(Camera))]
public class ScreenSplitterManager : MonoBehaviour
{
    [Header("Texturas de Salida")]
    public RenderTexture sourceCapture;
    public RenderTexture leftViewTarget;
    public RenderTexture rightViewTarget;

    [Header("Recursos de Renderizado")]
    public Shader splitShader;
    private Material _effectMat;
    private CommandBuffer _cb;
    private Camera _cam;

    void OnEnable()
    {
        _cam = GetComponent<Camera>();
        SetupCommandBuffer();
    }

    private void SetupCommandBuffer()
    {
        if (splitShader == null || !splitShader.isSupported) return;

        _effectMat = new Material(splitShader);
        _cb = new CommandBuffer();
        _cb.name = "SplitScreen_Pipeline";

        // 1. Capturar el contenido actual de la cámara
        RenderTargetIdentifier currentActive = BuiltinRenderTextureType.CurrentActive;
        _cb.Blit(currentActive, sourceCapture);

        // 2. Procesar mitad izquierda (offset 0.0)
        _cb.SetGlobalFloat("_XOffset", 0.0f);
        _cb.Blit(sourceCapture, leftViewTarget, _effectMat);

        // 3. Procesar mitad derecha (offset 0.5)
        _cb.SetGlobalFloat("_XOffset", 0.5f);
        _cb.Blit(sourceCapture, rightViewTarget, _effectMat);

        // Inyectar el buffer después de que el renderizado opaco y transparente haya finalizado
        _cam.AddCommandBuffer(CameraEvent.AfterEverything, _cb);
    }

    void OnDisable()
    {
        if (_cb != null)
        {
            _cam.RemoveCommandBuffer(CameraEvent.AfterEverything, _cb);
            _cb.Clear();
            _cb.Dispose();
        }
        
        if (_effectMat != null)
        {
            DestroyImmediate(_effectMat);
        }
    }
}

Funcionamiento del Proceso

  • Captura de Pantalla: Se utiliza BuiltinRenderTextureType.CurrentActive para obtener el frame buffer actual justo antes de que se presente en pantalla.
  • Asignación de Comandos: El CommandBuffer no ejecuta los comandos inmediatamente; los almcaena y los ejecuta de forma secuencial en el evento de cámara especificado (en este caso, AfterEverything).
  • Optimización de UV: El shader realiza una operación aritmética simple en las coordenadas de textura, lo que permite que el proceso sea extremadamente eficiente en términos de GPU.

Etiquetas: Unity CommandBuffer ShaderLab RenderTexture GraphicsPipeline

Publicado el 7-12 20:26