Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Resolved Custom Pass into Render Texture into Custom AOV

Discussion in 'High Definition Render Pipeline' started by JM_CG, Jul 26, 2021.

  1. JM_CG

    JM_CG

    Joined:
    Apr 20, 2017
    Posts:
    32
    Hi,
    Im doing a custom ID pass which seems to work in the frame debugger, but I cannot seem to blit the rt into a render texture successfully. I've tried mutiple approaches as in similar threads on the forums - using - Blit, CopyTexture - using ctx.customColorBuffer.Value in two successive custom passes.

    @antoinel_unity hope you can help.

    ID Custom Pass

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Rendering.HighDefinition;
    3. using UnityEngine.Rendering;
    4. using UnityEngine.Experimental.Rendering;
    5.  
    6. public class CustomPassID : CustomPass
    7. {
    8.     RTHandle idBuffer;
    9.     RTHandle idDepthBuffer;
    10.  
    11.     [SerializeField, HideInInspector]
    12.     Shader idShader;
    13.     Material idMaterial;
    14.    
    15.  
    16.     protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
    17.     {
    18.         idShader = Shader.Find("CustomPassID");
    19.         idMaterial = CoreUtils.CreateEngineMaterial(idShader);
    20.  
    21.         idBuffer = RTHandles.Alloc(
    22.         Vector2.one, TextureXR.slices, dimension: TextureXR.dimension,
    23.         colorFormat: GraphicsFormat.R32G32B32A32_SFloat, enableRandomWrite: false, autoGenerateMips: false, filterMode: FilterMode.Point, useDynamicScale: false, name: "ID Color Buffer", enableMSAA: false, useMipMap: false);
    24.  
    25.         idDepthBuffer = RTHandles.Alloc(
    26.                 Vector2.one, TextureXR.slices, dimension: TextureXR.dimension,
    27.                 colorFormat: GraphicsFormat.R32_SInt, useDynamicScale: false,
    28.                 name: "ID Depth Buffer", depthBufferBits: DepthBits.Depth32);
    29.  
    30.     }
    31.  
    32.     protected override void Execute(CustomPassContext ctx)
    33.     {
    34.         ShaderTagId[] litForwardTags = { HDShaderPassNames.s_ForwardOnlyName, HDShaderPassNames.s_ForwardName, HDShaderPassNames.s_SRPDefaultUnlitName };
    35.         var renderListDesc = new RendererListDesc(litForwardTags, ctx.cullingResults, ctx.hdCamera.camera)
    36.         {
    37.             rendererConfiguration = PerObjectData.None,
    38.             renderQueueRange = RenderQueueRange.all,
    39.             sortingCriteria = SortingCriteria.BackToFront,
    40.             excludeObjectMotionVectors = false,
    41.             overrideMaterial = idMaterial,
    42.             overrideMaterialPassIndex = 0,
    43.             stateBlock = new RenderStateBlock(RenderStateMask.Depth) { depthState = new DepthState(true, CompareFunction.LessEqual) }
    44.         };
    45.  
    46.             CoreUtils.SetRenderTarget(ctx.cmd, idBuffer, idDepthBuffer, ClearFlag.All);
    47.             CoreUtils.DrawRendererList(ctx.renderContext, ctx.cmd, RendererList.Create(renderListDesc));
    48.          
    49.     }
    50.  
    51.     protected override void Cleanup()
    52.     {
    53.         CoreUtils.Destroy(idMaterial);
    54.         idBuffer.Release();
    55.         idDepthBuffer.Release();
    56.     }
    57. }
    58.  
    Copy Pass

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Rendering;
    3. using UnityEngine.Rendering.HighDefinition;
    4. using UnityEngine.Experimental.Rendering;
    5. public class CopyPass : CustomPass
    6. {
    7.  
    8.     protected override bool executeInSceneView => true;
    9.  
    10.     protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
    11.     {
    12.         var go_mc = GameObject.Find("Main Camera");
    13.         go_mc.GetComponent<FFmpegOut.CameraCapture>().idTexture = new RenderTexture(640, 360, 0, GraphicsFormat.R32G32B32A32_SFloat, 0);
    14.         go_mc.GetComponent<FFmpegOut.CameraCapture>().idTexture.Create();
    15.     }
    16.  
    17.     protected override void Execute(CustomPassContext ctx)
    18.     {
    19.         var go_mc = GameObject.Find("Main Camera");
    20.         var scale = RTHandles.rtHandleProperties.rtHandleScale;
    21.         RTHandle source = ctx.customColorBuffer.Value;
    22.         ctx.cmd.Blit(source, go_mc.GetComponent<FFmpegOut.CameraCapture>().idTexture, new Vector2(scale.x, scale.y), Vector2.zero, 0, 0);      
    23.     }
    24. }
    25.  
     
  2. antoinel_unity

    antoinel_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    237
    Hello,

    Something I don't see in your code is how the `customColorBuffer` you use in the source for the Blit() could contain correct data because it's not used in the ID Custom Pass.

    Otherwise, your copy code seems correct, as you can see in this Copy pass example it's similar: https://github.com/alelievr/HDRP-Cu.../Assets/CustomPasses/CopyPass/CopyPass.cs#L67

    You can also take a look at this implementation of the ID custom pass: https://github.com/Unity-Technologies/Graphics/pull/5209/files?file-filters[]=.cs (it will be included in HDRP 12.0)
     
    _geo__ and JM_CG like this.
  3. JM_CG

    JM_CG

    Joined:
    Apr 20, 2017
    Posts:
    32
    Thanks for taking a look.

    How do I pass the idBuffer from the first custom pass into the second pass? For some reason I thought it inherited the ''custom" output from the previous custom pass.
     
  4. antoinel_unity

    antoinel_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    237
    I guess you can use directly the customColorBuffer instead of allocating a new texture, except if you really need the graphics format to be 32bit per channel, in that case, you'll need something else to share the render texture between the two passes (a static or singleton object, ect.)
     
  5. JM_CG

    JM_CG

    Joined:
    Apr 20, 2017
    Posts:
    32
    I've tried using customColorBuffer along with a static/singleton object but the blit does not seem to set a RenderTarget, looking in the Frame Debug.

    NoWorky.png
     
  6. JM_CG

    JM_CG

    Joined:
    Apr 20, 2017
    Posts:
    32
    So I can blit in into a sharedRenderTexture and write this image out to disk.

    However, it only works if I set the ClearFlag to None, but then I get accumulation betwen frames.

    Code (CSharp):
    1.  
    2. CoreUtils.SetRenderTarget(ctx.cmd, SharedBuffers.Get.sharedRTHandleColor, SharedBuffers.Get.sharedRTHandleDepth, ClearFlag.None);
    I think the issue is that the texture clear is occuring at an unexpected time, which seems to work against writing out the texture end of frame.

    Should have stated earlier - my goal is write these out to a movie and I'm doing it this way as the CustomPassAOVs code does not seem to work.

    NoWorky2.png
     
  7. JM_CG

    JM_CG

    Joined:
    Apr 20, 2017
    Posts:
    32
    Ok after much pain I finally got this working. Here is the code so I can save you from it.

    The customAOV code seems only to work with the custom color buffer (ctx.customColorBuffer.Value) and not a user defined one at this point in time, which is what I was missing. I've seen some pull requests in the github that might change this in future so you can use a different target format for the custom texture - not sure if operational yet.

    Hence for the custom pass
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Rendering.HighDefinition;
    4. using UnityEngine.Rendering;
    5. using UnityEngine.Experimental.Rendering;
    6. public class CustomPassID : CustomPass
    7. {
    8.     [SerializeField, HideInInspector]
    9.     Shader idShader;
    10.     Material idMaterial;
    11.  
    12.     protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
    13.     {
    14.         idShader = Shader.Find("CustomPassID");
    15.         idMaterial = CoreUtils.CreateEngineMaterial(idShader);
    16.     }
    17.     protected override void Execute(CustomPassContext ctx)
    18.     {
    19.         ShaderTagId[] litForwardTags = { HDShaderPassNames.s_ForwardOnlyName, HDShaderPassNames.s_ForwardName, HDShaderPassNames.s_SRPDefaultUnlitName };
    20.         var renderListDesc = new RendererListDesc(litForwardTags, ctx.cullingResults, ctx.hdCamera.camera)
    21.         {
    22.             rendererConfiguration = PerObjectData.None,
    23.             renderQueueRange = RenderQueueRange.all,
    24.             sortingCriteria = SortingCriteria.BackToFront,
    25.             excludeObjectMotionVectors = false,
    26.             overrideMaterial = idMaterial,
    27.             overrideMaterialPassIndex = 0,
    28.             stateBlock = new RenderStateBlock(RenderStateMask.Depth) { depthState = new DepthState(true, CompareFunction.LessEqual) }
    29.         };
    30.             CoreUtils.SetRenderTarget(ctx.cmd, ctx.customColorBuffer.Value, ctx.customDepthBuffer.Value, ClearFlag.All);
    31.             CoreUtils.DrawRendererList(ctx.renderContext, ctx.cmd, RendererList.Create(renderListDesc));
    32.        
    33.     }
    34.     protected override void Cleanup()
    35.     {
    36.         CoreUtils.Destroy(idMaterial);
    37.     }
    38. }
    And for the custom AOV read

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using UnityEngine.Rendering;
    4. using UnityEngine.Rendering.HighDefinition;
    5. using UnityEngine.Experimental.Rendering;
    6.  
    7. public class CustomAOV : MonoBehaviour
    8. {
    9.     Texture2D m_ReadBackIDTexture;
    10.     RTHandle m_TmpRTID;            // The RTHandle used to render the AOV
    11.     Material _material;
    12.  
    13.     public bool writeIDpng;
    14.  
    15.     IEnumerator Start()
    16.     {
    17.  
    18.         int m_Frames = 0;
    19.         var camera = gameObject.GetComponent<Camera>();
    20.         if (camera != null)
    21.         {
    22.             var hdAdditionalCameraData = gameObject.GetComponent<HDAdditionalCameraData>();
    23.             if (hdAdditionalCameraData != null)
    24.             {
    25.                 int camPixelWidth = camera.pixelWidth;
    26.                 int camPixelHeight = camera.pixelHeight;
    27.  
    28.                 var aovRequestBuilder = new AOVRequestBuilder();
    29.  
    30.                 var aovIDRequest = AOVRequest.NewDefault();
    31.                 AOVBuffers[] aovBuffers = null;
    32.                 CustomPassAOVBuffers[] customPassAovBuffers = null;
    33.                 customPassAovBuffers = new[] { new CustomPassAOVBuffers(CustomPassInjectionPoint.AfterPostProcess, CustomPassAOVBuffers.OutputType.CustomPassBuffer) };
    34.  
    35.                 m_TmpRTID = RTHandles.Alloc(camPixelWidth, camPixelHeight);
    36.  
    37.                 aovRequestBuilder.Add(
    38.                     aovIDRequest,
    39.                     bufferId => m_TmpRTID,
    40.                     null,
    41.                     aovBuffers,
    42.                     customPassAovBuffers,
    43.                      bufferId => m_TmpRTID,
    44.                     (cmd, buffers, customBuffers, properties) =>
    45.                     {
    46.                         if (customBuffers.Count > 0)
    47.                         {
    48.                             if (writeIDpng)
    49.                             {
    50.                                 m_ReadBackIDTexture = m_ReadBackIDTexture ?? new Texture2D(camPixelWidth, camPixelHeight, TextureFormat.RGBAFloat, false);
    51.                                 RenderTexture.active = customBuffers[0].rt;
    52.                                 m_ReadBackIDTexture.ReadPixels(new Rect(0, 0, camPixelWidth, camPixelHeight), 0, 0, false);
    53.                                 m_ReadBackIDTexture.Apply();
    54.                                 RenderTexture.active = null;
    55.                                 byte[] bytesID = m_ReadBackIDTexture.EncodeToPNG();
    56.                                 System.IO.File.WriteAllBytes($"output_{m_Frames++}_ID.png", bytesID);
    57.                                 Debug.Log("CustomAOV() : Writing ID png");
    58.                             }
    59.  
    60.                             //Texture is customBuffers[0].rt
    61.                             //Blit it accordingly to your target texture
    62.                         }
    63.                     }
    64.                 );
    65.                 var aovRequestDataCollection = aovRequestBuilder.Build();
    66.                 hdAdditionalCameraData.SetAOVRequests(aovRequestDataCollection);
    67.             }
    68.         }
    69.         for (var eof = new WaitForEndOfFrame(); ;)
    70.         {
    71.             yield return eof;
    72.         }
    73.     }
    74. }
    PushCustomPassTexture.png


    .
     
    antoinel_unity likes this.