Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Again: How to use Blit with HDRP's CustomPostProcessVolumeComponent?

Discussion in 'High Definition Render Pipeline' started by Brantkings, May 6, 2021.

  1. Brantkings

    Brantkings

    Joined:
    Aug 12, 2013
    Posts:
    3
    Hey! I say again up there because there is a post with the same title, with a solution that left me unsatisfied.

    I am trying to make a custom post processing effect on HDRP that pixelizes the image. I've been successfull in doing this in the past by blitting the source texture into a temporary render texture with a small resolution, and then blitting that one into the destination.

    I plan to treat this image with my shader with a material, but for now without any material this just won't work.

    Before in v2 Post Processing stack this was really easy:

    Code (CSharp):
    1. public override void Render(PostProcessRenderContext context)
    2. {
    3.     RenderTexture temp = RenderTexture.GetTemporary(smallWidth, smallHeight);
    4.     temp.filterMode = FilterMode.Point;
    5.     context.command.Blit(context.source, temp);
    6.     context.command.Blit(temp, context.destination);
    7. }
    This worked OK.

    Now I'm trying to do this on a CustomPostProcessVolumeComponent:

    Code (CSharp):
    1. public override void Render(CommandBuffer cmd, HDCamera camera, RTHandle source, RTHandle destination)
    2. {
    3.     RTHandle rt = RTHandles.Alloc(scaleFactor: Vector2.one * 0.25f, filterMode: FilterMode.Point, wrapMode: TextureWrapMode.Clamp, dimension: TextureDimension.Tex2D);
    4.     HDUtils.BlitCameraTexture(cmd, source, rt);
    5.     HDUtils.BlitCameraTexture(cmd, rt, destination);
    6.     rt.Release();
    7. }
    The other post with the same title established that cmd.Blit() won't work at all in this case and it seems that HDUtils.BlitCameraTexture does the extra leg work you need for to do such thing. Why? What does it do exactly?

    And in the end it gives me a gray screen. Why? BlitCameraTexture()ing directly source to destination works alright. Also making the scale factor as (1,1) does not make a difference. Does the command buffer only accept one blit in this case? Am I using RTHandles correctly? Is there something I'm not seeing?
     
    Last edited: May 6, 2021
  2. antoinel_unity

    antoinel_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    267
    Hello,

    so there are multiple things here.
    In this code snippet, you are actually releasing the RTHandle before using it. That's because the BlitCamera commands you're enqueuing to the command buffer will only be executed at the end of the HDRP render loop, and you release the renderTexture at the end of your function. In that case it's better to allocate the buffer in the Setup() function and release it in Cleanup().

    cmd.Blit is just a command that copies the content of the source buffer to a target buffer and that potentially performs arbitrary scaling, format conversion, or filtering.
    BlitCameraTexture on the other side handles correctly the scaling system we use in RTHandles (we reuse buffers in case there are multiple camera rendering with different resolution), and it also handles VR correctly (use of Texture2DArrays instead of Texture2D).

    This is most likely because of the VR support enabled by default in HDRP. It means that all our buffers are Texture2DArray with a single slice or more in case of VR output, this means that by default the cmd.Blit function doesn't work because it expects a Texture2D in parameter. You can work around that issue with the "destDepthSlice" parameter of the function.

    So I recommend doing something like that:
    Code (CSharp):
    1.     RTHandle rt;
    2.     Material material;
    3.  
    4.     public override void Setup()
    5.     {
    6.         if (Shader.Find(kShaderName) != null)
    7.             material = new Material(Shader.Find(kShaderName));
    8.         else
    9.             Debug.LogError($"Unable to find shader '{kShaderName}'. Post Process Volume TestPP is unable to load.");
    10.  
    11.         rt = RTHandles.Alloc(scaleFactor: Vector2.one * 0.25f, filterMode: FilterMode.Point, wrapMode: TextureWrapMode.Clamp, dimension: TextureDimension.Tex2D);
    12.     }
    13.  
    14.     public override void Render(CommandBuffer cmd, HDCamera camera, RTHandle source, RTHandle destination)
    15.     {
    16.         if (material == null)
    17.             return;
    18.  
    19.         HDUtils.BlitCameraTexture(cmd, source, rt, material, 0);
    20.         cmd.Blit(rt, destination, 0, 0);
    21.     }
    22.  
    23.     public override void Cleanup()
    24.     {
    25.         rt.Release();
    26.         CoreUtils.Destroy(material);
    27.     }
    28.  

    Also note that the material used in `HDUtils.BlitCameraTexture` needs to be compatible, so the input texture should be named "_BlitTexture" in the shader.
     
    Kasperrr and ReformSim like this.