Search Unity

LWRP Image Effects - Outline

Discussion in 'Universal Render Pipeline' started by tjmaul, Jun 28, 2019.

  1. tjmaul

    tjmaul

    Joined:
    Aug 29, 2018
    Posts:
    467
    Hello everybody!

    I'm trying to get a better understanding of LWRP and rendering in general and so I'm trying to recreate an outline effect as described in this awesome video by Dan Moran (thanks!) using LWRP. The steps involved are:

    1. Pre-render objects that should glow with an unlit shader (any bright color on a black background)
    2. Blur the resulting image (but keep the original)
    3. Subtract the original image from the blurred one to create the glow outlines
    4. ... let the pipeline do its thing ...
    5. Add glow outlines to the final image (maybe before post processing)

    I already read and programmed along the amazing Catlike Coding tutorials on Rendering and the SRP, watched Introduction to LWRP at GDC 2019 to get a better understanding of the LWRP, fiddled around and tried stuff, but I'm still missing the bigger picture.

    The story so far:
    I started with the LWRP preset (2019.1.8f), upgraded to LWRP and Shader Graph to version 5.16.1. Then I took the Blit ScriptableRendererFeature from LWRP-CustomRendererExamples (Blit.cs and BlitPass.cs), created a scene with some objects, created a Forward Renderer Data with my own Blit Material.
    rendererSettings.png
    The Blit Material Shader takes _MainTex as an input, samples it with the screen UV position and twirls it (just to test). This results in the following image:
    Bildschirmfoto 2019-06-28 um 09.45.44.png
    I now thought I can just render this image to another location by changing the "Destination" from "Color" to texture and then it will be available in another Renderer Feature under the name "_BlitPassTexture", but then there was an error message saying:

    CommandBuffer: temporary render texture _BlitPassTexture not found while executing 
    Twirl Blit (Blit destination)


    I went through the code of Blit.cs:L35 and I can see that a render texture handle is created, but obviously not found.

    tl;dr: My questions:
    1. How can I put the result of a render aside for later use
    2. Where does the magical "_MainTex" come from. What else can I use there? Is there a list?
    3. Where can I find resources about how CPU-side code manages the GPU in general (eg. how does a texture handle interact with the object in the GPU memory, how is resolution of these handled)
    4. How does the CPU set the inputs for a shader program, e.g. _MainTex, so I can understand how to put information aside and use in a later stage of the rendering process

    I just feel a bit frustrated that I assume I already know something about rendering, but its all just fragments and pieces and I'm still missing important parts to put everything together. What is a good resource to get this figured out?

    cheers and sorry for the long post :)
     
  2. tjmaul

    tjmaul

    Joined:
    Aug 29, 2018
    Posts:
    467
    So far, I implemented a ScriptableRendererFeature which adds a ScriptableRenderPass named "CustomGlowPass". The CustomGlowPass class consists of some settings and a RenderTargetHandle rt_unlit, which I initialize in the constructor.

    All that's happening then is that I'm getting a temporaryRT (L.22), setting it as the render target, clearing it, rendering some meshes onto it and setting the temporary texture as a global (L.42).

    My scene consists of a floor plane and two capsules. There is an additional plane in the corner, that renders the global "_GlowUnlit" texture for debugging purposes. The game window looks like this:

    render.png

    Please note that the two capsules are correctly rendered into the render texture, shown in the screen on the left side. The following image shows the frame debugger:

    frameDebug.png

    My questions are:
    1. Why is the first action in the custom glow pass the "RenderTexture.ResolveAA" entry. When selected, I see a copy of the rendered plane and capsules without a skybox.
    2. After the clear has been done and the meshes have been drawn, the Skybox is rendered, but into the render target of the custom glow pass. Obviously, I have to switch back to the previous render target after my pass. How can I get the previous render target?
    3. I suddenly see Messages like "Allocation of 108 bytes at 0x124ab1a90", "Internal: Stack allocator ALLOC_TEMP_THREAD has unfreed allocations, size 88592", "To Debug, enable the define: DEBUG_STACK_LEAK in StackAllocator.h. This will output the callstacks of the leaked allocations". What have I done wrong?


    Here's the code of my ScriptableRenderPass

    Code (CSharp):
    1. namespace UnityEngine.Rendering.LWRP
    2. {
    3.     public class CustomGlowPass : ScriptableRenderPass
    4.     {
    5.         CustomGlow.CustomGlowSettings settings;
    6.         RenderTargetHandle rt_unlit;
    7.  
    8.         public CustomGlowPass(CustomGlow.CustomGlowSettings settings,
    9.                               string name) {
    10.             this.settings = settings;
    11.             rt_unlit.Init("_rt_unlit");
    12.         }
    13.  
    14.         public override void Execute(ScriptableRenderContext context,
    15.                                      ref RenderingData renderingData) {
    16.             Camera camera = renderingData.cameraData.camera;
    17.  
    18.             CommandBuffer cmd = CommandBufferPool.Get("CustomGlowPass");
    19.  
    20.             // Assign a temporary render texture to the rt_unlit handle,
    21.             // set it as the render target and clear depth and color
    22.             cmd.GetTemporaryRT(
    23.                 rt_unlit.id,
    24.                 camera.pixelWidth,
    25.                 camera.pixelHeight,
    26.                 32,
    27.                 FilterMode.Bilinear);
    28.              
    29.             cmd.SetRenderTarget(rt_unlit.Identifier());
    30.             cmd.ClearRenderTarget(true, true, Color.black);
    31.  
    32.             // Draw all renderers in the list
    33.             if (settings.renderers != null)
    34.             {
    35.                 foreach (Renderer renderer in settings.renderers)
    36.                 {
    37.                     cmd.DrawRenderer(renderer, settings.flatMaterial, 0, 0);
    38.                 }
    39.             }
    40.  
    41.             // Make render texture available for other shaders
    42.             cmd.SetGlobalTexture("_GlowUnlit", rt_unlit.Identifier());
    43.  
    44.             context.ExecuteCommandBuffer(cmd);
    45.             CommandBufferPool.Release(cmd);
    46.         }
    47.  
    48.         public override void FrameCleanup(CommandBuffer cmd)
    49.         {
    50.             cmd.ReleaseTemporaryRT(rt_unlit.id);
    51.         }
    52.     }
    53. }
    54.  
     
    Last edited: Jul 2, 2019