Search Unity

Question How to inject a custom render pass after rendering transparents in URP?

Discussion in 'Universal Render Pipeline' started by Maimai, Nov 23, 2020.

  1. Maimai

    Maimai

    Joined:
    Dec 24, 2017
    Posts:
    11
    Currently I have a distortion effect that works fine in URP, using _CameraOpaqueTexture. As a result, the distortion won't be applied to any transparent objects or particle effects. Is there a way to fix it so that the distortion can affect both opaque objects and transparent objects?

    I know that I can define a custom Render Pass to solve that, but how can I make that happen exactly after the transparent pass? It seems that 'IAfterTransparent' is gone in URP. Is there any instructions or examples on how to make such a render texture to include all transparent objects & effects? (to replace the _CameraOpaqueTexture)

    Any hints will be appreciated!
     
  2. Maimai

    Maimai

    Joined:
    Dec 24, 2017
    Posts:
    11
    Hi Yuta,

    Thank you so much for your reference! I figured out how it works and got the render texture finally.

    However, the distortion effect is still not working properly. The distortion shader I made is using the transparent render pass and it is attached to a plane so that the plane can work as a mask and makes all the stuff behind it distorted. The new problem is that the plane itself will be also rendered into the render texture(coz it's also transparent), and the scene will go recursively in the distorted area. It also causes a new problem that the plane will only show the render texture of the last frame (The plane is rendered during the transparent pass, but the render texture that the plane is using will only be rendered after the transparent pass).

    Is there a way to avoid rendering that plane?
     
  3. Maimai

    Maimai

    Joined:
    Dec 24, 2017
    Posts:
    11
    Sure! The general idea is to output certain part of the camera image behind the mask and then add some distortion effects. The _CameraOpaqueTexture works fine but it does not include transparent stuff, so I need another Render Texture to capture all the opaque stuff and transparent stuff.

    Shader:
    The core idea is to capture the screen image and output it so I only paste the core part:

    float3 CaptureSceneColor(float2 uv)
    {
    // Return custom Render Texture
    return tex2D(_GrabPassTransparent, uv);

    // Return _CameraOpaqueTexture
    //return SAMPLE_TEXTURE2D_X(_CameraOpaqueTexture, sampler_CameraOpaqueTexture, UnityStereoTransformScreenSpaceTex(uv)).rgb;
    }


    The Render Feature and Render Pass:
    I found it on github:
    https://gist.github.com/Refsa/54da34a9e2fc8e45472286572216ad17
    It just capture the screen image after rendering transparents

    When I return: _CameraOpaqueTexture, the distortion works perfect but the transparent cube is not rendered
    upload_2020-11-24_21-39-55.png

    When I return: _GrabPassTransparent RenderTexture, the transparent cube appears but the RT also capture the plane itself, so it will render itself recursively
    upload_2020-11-24_21-41-13.png

    Is there a way to avoid the plane (distortion mask) being rendered so that it won't render recursively? Or any other ideas to solve that?
     
  4. Maimai

    Maimai

    Joined:
    Dec 24, 2017
    Posts:
    11
    Thank you so much!!
    I used the Render Objects method. I set a specific layer for my distortion mask, make the default renderer ignore that layer and render it later using Render Objects. It works perfect! The recursive image is gone and the effects looks awesome. The only problem is that the distortion mask won't show up in the scene anymore. Is there any way to ensure that it can also work in the scene view?
     
  5. Maimai

    Maimai

    Joined:
    Dec 24, 2017
    Posts:
    11
    I do. But the distortion mask just disappear from my scene view once I filter out its layer from the rendering layer mask. It seems that things that are only rendered by Render Objects won't show up in scene view.
     
  6. weiping-toh

    weiping-toh

    Joined:
    Sep 8, 2015
    Posts:
    192
    From what I have researched, the SceneView rendering reads from the depth attachment. So you probably need to write make sure that the Render Objects also renders to the depth texture too while rendering.

    Code (CSharp):
    1. #if UNITY_EDITOR
    2.             if (isSceneViewCamera)
    3.             {
    4.                 // Scene view camera should always resolve target (not stacked)
    5.                 Assertions.Assert.IsTrue(lastCameraInTheStack, "Editor camera must resolve target upon finish rendering.");
    6.                 m_SceneViewDepthCopyPass.Setup(m_DepthTexture);
    7.                 EnqueuePass(m_SceneViewDepthCopyPass);
    8.             }
    9. #endif
    This sneaky little snippet...