Understanding Temporary RT and custom capture in URP

Hi,
I’m trying to make a fluid simulation in URP, but I’m not sure how / what is the right way to setup the render targets / blit in URP.

General idea of what I want to achieve is:

  • Create an orthographic top down camera.
  • Create two temporary render texture, one for previous frame, one to capture current frame
  • Blit previous frame “physical RT” in temporary render texture.
  • Assign a temporary render texture to that camera’s output texture to capture the fluid’s input.
  • Blit that input to a physical render texture with a material.

Right now I’m trying to use RenderPipelineManager.beginCameraRendering

So first issue I have, is that OnBeginCameraRendering is being called for each camera and I cannot find a reliable way to execute it only for my “capture camera”.
For example, doing this works in game view, but not in scene view

    void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
    {
        if (camera != _CaptureCamera)
        {
            return;
        }
    }

Then I cannot figure out what is the right way to create temporary render texture un URP.
Is it using RenderingUtils.ReAllocateIfNeeded ?

RenderTextureDescriptor texDesc = new RenderTextureDescriptor();
texDesc.width = 1024;
texDesc.height = 1024;
texDesc.colorFormat = RenderTextureFormat.ARGBFloat;
texDesc.dimension = TextureDimension.Tex2D;
texDesc.autoGenerateMips = false;
texDesc.depthBufferBits = 0;
texDesc.msaaSample = 1;
        
RenderingUtils.ReAllocateIfNeeded(ref _CaptureHandle, texDesc);

Lastly for the Blit I was thinking to use something like this:

CommandBuffer cmd = CommandBufferPool.Get();
Blitter.BlitCameraTexture(cmd, _CaptureHandle, _SimulationRT, material, pass);

but Blitter seems to take only RTHandle, how can you blit an RTHandle to a physical texture?

Thanks!

Ok I got this almost working, but there is some weird things going on.

  • In the editor it updates only if I move the captured object despite having [ExecuteAlways] and [ExecuteInEditMode] on the script
  • In play mode it works as I want in the scene view, but the Game View it’s rendering all over the place

Relevant Code



    void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
    {

        var cameraType = camera.cameraType;

        if (cameraType == CameraType.Reflection || cameraType == CameraType.Preview)
        {
            return;
        }

        var cameraData = camera.GetUniversalAdditionalCameraData();

        if (cameraData.renderType != CameraRenderType.Base)
        {
            return;
        }

        if (camera != _DynamicEffectsCamera)
        {
            return;
        }
        

        Simulate(context);
    }


    private void Simulate(ScriptableRenderContext context)
    {
        if(_CopyMaterial == null)
        { 
            return;
        }

        RenderTextureDescriptor texDesc = new RenderTextureDescriptor();
        texDesc.width = 1024;
        texDesc.height = 1024;
        texDesc.colorFormat = RenderTextureFormat.ARGBFloat;
        texDesc.dimension = TextureDimension.Tex2D;
        texDesc.autoGenerateMips = false;
        texDesc.depthBufferBits = 0;
        texDesc.msaaSamples = 1;
    
        RenderingUtils.ReAllocateIfNeeded(ref _CaptureHandle, texDesc, FilterMode.Bilinear, name:"Capture");
        RenderingUtils.ReAllocateIfNeeded(ref _PreviousHandle, texDesc, FilterMode.Bilinear, name: "Previous");
        CommandBuffer cmd = CommandBufferPool.Get();

        // Current Frame
        _DynamicEffectsCamera.targetTexture = _CaptureHandle;

        // Copy Previous Frame
        _CopyMaterial.SetTexture("_MainTex", _SimulationRT);
        Blitter.BlitTexture(cmd, _SimulationRT, _PreviousHandle, _CopyMaterial, 0);

        // Simulation
        _SimulationMaterial.SetTexture("_CaptureTex", _CaptureHandle);
        _SimulationMaterial.SetTexture("_PreviousTex", _PreviousHandle);
        Blitter.BlitTexture(cmd, _CaptureHandle, _SimulationRT, _SimulationMaterial, 0);
   

        context.ExecuteCommandBuffer(cmd);
        cmd.Clear();
        CommandBufferPool.Release(cmd);
    }

I believe the issue is coming from OnBeginCameraRendering
Since I cannot find a way to execute this only for my Capture camera it executes the simulation once PER camera and causes the trouble.

removing this from OnBeginCameraRendering makes it work correctly in the scene view

       if (camera != _DynamicEffectsCamera)
        {
            return;
        }

but in the game view, it’s kinda rendered twice.

Issue also occurs if I have game view active at the same time as the scene view

Darn it, it was a but with unity apparently. Updated to Unity 6 / URP 17 and it worked right away…

The result:

1 Like