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. Dismiss Notice

Question Render Feature does not work. Any coding help?

Discussion in 'Universal Render Pipeline' started by Maimai, Dec 2, 2020.

  1. Maimai

    Maimai

    Joined:
    Dec 24, 2017
    Posts:
    10
    I want to render a monochrome image of a character's hair and use that later to calculate the shadow of hair.
    I set the render order to "BeforeRenderingOpaques" and set the layer to search for the hair that I want to render. The editor does not show any errors, but in the frame debugger I can't find the rendered image that I want. As it's illustrated in the screenshot, I can see the RenderTarget is set to "_HairSolidColor", but it is not rendered and the rendering then goes to Render Opaques. (The custom image should be rendered before RenderingOpqques)
    upload_2020-12-2_12-10-10.png
    I am very new to render features. The code is from a guideline and I failed to make it work. Any help will be appreciated!

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Rendering;
    3. using UnityEngine.Rendering.Universal;
    4.  
    5. public class HairShadow : ScriptableRendererFeature
    6. {
    7.     [System.Serializable]
    8.     public class Setting
    9.     {
    10.         public LayerMask hairLayer;
    11.         public LayerMask faceLayer;
    12.  
    13.         [Range(1000, 5000)]
    14.         public int queueMin = 2000;
    15.         [Range(1000, 5000)]
    16.         public int queueMax = 3000;
    17.  
    18.         public Material material;
    19.     }
    20.     public Setting setting = new Setting();
    21.  
    22.     class CustomRenderPass : ScriptableRenderPass
    23.     {
    24.         public int soildColorID = 0;
    25.         public ShaderTagId shaderTag = new ShaderTagId("UniversalForward");
    26.         public Setting setting;
    27.  
    28.         FilteringSettings filtering;
    29.         FilteringSettings filtering2;
    30.  
    31.         public CustomRenderPass(Setting setting)
    32.         {
    33.             this.setting = setting;
    34.  
    35.             RenderQueueRange queue = new RenderQueueRange();
    36.             queue.lowerBound = Mathf.Min(setting.queueMax, setting.queueMin);
    37.             queue.upperBound = Mathf.Max(setting.queueMax, setting.queueMin);
    38.  
    39.             filtering = new FilteringSettings(queue, setting.faceLayer);
    40.             filtering2 = new FilteringSettings(queue, setting.hairLayer);
    41.         }
    42.  
    43.  
    44.         // This method is called before executing the render pass.
    45.         // It can be used to configure render targets and their clear state. Also to create temporary render target textures.
    46.         // When empty this render pass will render to the active camera render target.
    47.         // You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
    48.         // The render pipeline will ensure target setup and clearing happens in an performance manner.
    49.         public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
    50.         {
    51.             int temp = Shader.PropertyToID("_HairSoildColor");
    52.  
    53.             RenderTextureDescriptor desc = cameraTextureDescriptor;
    54.             cmd.GetTemporaryRT(temp, desc);
    55.             soildColorID = temp;
    56.             ConfigureTarget(temp);
    57.             ConfigureClear(ClearFlag.All, Color.black);
    58.  
    59.         }
    60.  
    61.         public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    62.         {
    63.  
    64.             var draw1 = CreateDrawingSettings(shaderTag, ref renderingData, renderingData.cameraData.defaultOpaqueSortFlags);
    65.             draw1.overrideMaterial = setting.material;
    66.             draw1.overrideMaterialPassIndex = 0;
    67.             context.DrawRenderers(renderingData.cullResults, ref draw1, ref filtering);
    68.  
    69.             var draw2 = CreateDrawingSettings(shaderTag, ref renderingData, renderingData.cameraData.defaultOpaqueSortFlags);
    70.             draw2.overrideMaterial = setting.material;
    71.             draw2.overrideMaterialPassIndex = 1;
    72.             context.DrawRenderers(renderingData.cullResults, ref draw2, ref filtering2);
    73.  
    74.         }
    75.  
    76.         /// Cleanup any allocated resources that were created during the execution of this render pass.
    77.         public override void FrameCleanup(CommandBuffer cmd)
    78.         {
    79.         }
    80.     }
    81.  
    82.     CustomRenderPass m_ScriptablePass;
    83.  
    84.     public override void Create()
    85.     {
    86.         m_ScriptablePass = new CustomRenderPass(setting);
    87.  
    88.         // Configures where the render pass should be injected.
    89.         m_ScriptablePass.renderPassEvent = RenderPassEvent.BeforeRenderingOpaques;
    90.     }
    91.  
    92.     // Here you can inject one or multiple render passes in the renderer.
    93.     // This method is called when setting up the renderer once per-camera.
    94.     public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    95.     {
    96.         renderer.EnqueuePass(m_ScriptablePass);
    97.     }
    98. }
    99.  
    100.  
    101.  
     
  2. weiping-toh

    weiping-toh

    Joined:
    Sep 8, 2015
    Posts:
    186
    I am confused as to what you are trying to accomplish but the fact that SetRenderTarget succeeds and yet nothing gets drawn, indicates that your culling settings have culled away everything and there is nothing to draw, So you might want to check your culling settings and what is it that you are trying to render.
     
  3. Maimai

    Maimai

    Joined:
    Dec 24, 2017
    Posts:
    10
    Thanks for the response!
    I want to render a pure color image like this. So I just want to render the hair and filter out face and all unrelated stuff. That's why I set two layers.
    As for the culling settings, are you refering to the culling setting in shader or in the editor? Do you mean that the render feature coding I've uploaded itself is fine? (I'm not confident about that)

    upload_2020-12-2_20-24-14.png
     
    tmonestudio likes this.
  4. weiping-toh

    weiping-toh

    Joined:
    Sep 8, 2015
    Posts:
    186
    The context.DrawRenderers just enqueues the drawing of objects into current context but it does not execute until the context is being submitted.
    You might want to take reference to the DrawObjectsPass for the proper execution of the render pass

    Code (CSharp):
    1.         public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    2.         {
    3.             CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag);
    4.             using (new ProfilingScope(cmd, m_ProfilingSampler))
    5.             {
    6.                 context.ExecuteCommandBuffer(cmd);
    7.                 cmd.Clear();
    8.  
    9.                 Camera camera = renderingData.cameraData.camera;
    10.                 var sortFlags = (m_IsOpaque) ? renderingData.cameraData.defaultOpaqueSortFlags : SortingCriteria.CommonTransparent;
    11.                 var drawSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, sortFlags);
    12.                 context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref m_FilteringSettings, ref m_RenderStateBlock);
    13.  
    14.                 // Render objects that did not match any shader pass with error shader
    15.                 RenderingUtils.RenderObjectsWithError(context, ref renderingData.cullResults, camera, m_FilteringSettings, SortingCriteria.None);
    16.             }
    17.             context.ExecuteCommandBuffer(cmd);
    18.             CommandBufferPool.Release(cmd);
    19.         }
    https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.DrawRenderers.html
     
  5. weiping-toh

    weiping-toh

    Joined:
    Sep 8, 2015
    Posts:
    186
    The first ExecuteCommandBuffer in the ProfilingScope forces/flushes a context submission, signaling a start of a new queue.
    The Execute at the end just submits the current queue for drawing.
     
  6. Maimai

    Maimai

    Joined:
    Dec 24, 2017
    Posts:
    10
    Hi, I rewrite the code and add the ExecuteCommandBuff in my render feature, but it still does not work... (nothing shows in Frame Debugger)

    Code (CSharp):
    1.         public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    2.         {
    3.             CommandBuffer cmd = CommandBufferPool.Get("_HairSoildColor");
    4.             context.ExecuteCommandBuffer(cmd);
    5.             cmd.Clear();
    6.  
    7.             var draw1 = CreateDrawingSettings(shaderTag, ref renderingData, renderingData.cameraData.defaultOpaqueSortFlags);
    8.             draw1.overrideMaterial = setting.material;
    9.             draw1.overrideMaterialPassIndex = 0;
    10.             context.DrawRenderers(renderingData.cullResults, ref draw1, ref filtering);
    11.  
    12.             var draw2 = CreateDrawingSettings(shaderTag, ref renderingData, renderingData.cameraData.defaultOpaqueSortFlags);
    13.             draw2.overrideMaterial = setting.material;
    14.             draw2.overrideMaterialPassIndex = 1;
    15.             context.DrawRenderers(renderingData.cullResults, ref draw2, ref filtering2);
    16.  
    17.             context.ExecuteCommandBuffer(cmd);
    18.             CommandBufferPool.Release(cmd);
    19.  
    20.         }
     
  7. weiping-toh

    weiping-toh

    Joined:
    Sep 8, 2015
    Posts:
    186
  8. Maimai

    Maimai

    Joined:
    Dec 24, 2017
    Posts:
    10
    I feel sorry that I couldn't catch up. After I set the viewMatrix, the game view is filled with pink.
    upload_2020-12-5_14-24-38.png

    Do I need to calculate the viewMatrix independently? I didn't see any stuff about viewMatrix in the original tutorial. Is there something else in my code that is wrong? Here is my latest code for the render feature

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Rendering;
    3. using UnityEngine.Rendering.Universal;
    4.  
    5. public class CelHairShadow_Test : ScriptableRendererFeature
    6. {
    7.     [System.Serializable]
    8.     public class Setting
    9.     {
    10.         public LayerMask hairLayer;
    11.         public LayerMask faceLayer;
    12.  
    13.         [Range(1000, 5000)]
    14.         public int queueMin = 2000;
    15.         [Range(1000, 5000)]
    16.         public int queueMax = 3000;
    17.  
    18.         public Material material;
    19.     }
    20.     public Setting setting = new Setting();
    21.  
    22.  
    23.     class CustomRenderPass : ScriptableRenderPass
    24.     {
    25.         public int soildColorID = 0;
    26.         public ShaderTagId shaderTag = new ShaderTagId("UniversalForward");
    27.         public Setting setting;
    28.  
    29.         FilteringSettings filtering;
    30.         FilteringSettings filtering2;
    31.         Matrix4x4 myViewMatrix = Matrix4x4.Scale(new Vector3(2f, 2f, 2f));
    32.  
    33.         public CustomRenderPass(Setting setting)
    34.         {
    35.             this.setting = setting;
    36.             RenderQueueRange queue = new RenderQueueRange();
    37.             queue.lowerBound = Mathf.Min(setting.queueMax, setting.queueMin);
    38.             queue.upperBound = Mathf.Max(setting.queueMax, setting.queueMin);
    39.  
    40.             filtering = new FilteringSettings(queue, setting.faceLayer);
    41.             filtering2 = new FilteringSettings(queue, setting.hairLayer);
    42.         }
    43.  
    44.  
    45.         // This method is called before executing the render pass.
    46.         // It can be used to configure render targets and their clear state. Also to create temporary render target textures.
    47.         // When empty this render pass will render to the active camera render target.
    48.         // You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
    49.         // The render pipeline will ensure target setup and clearing happens in an performance manner.
    50.         public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
    51.         {
    52.             int temp = Shader.PropertyToID("_HairSoildColor");
    53.             RenderTextureDescriptor desc = cameraTextureDescriptor;
    54.             cmd.GetTemporaryRT(temp, desc);
    55.             soildColorID = temp;
    56.             ConfigureTarget(temp);
    57.             ConfigureClear(ClearFlag.All, Color.black);
    58.  
    59.         }
    60.  
    61.         public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    62.         {
    63.             CommandBuffer cmd = CommandBufferPool.Get("_HairSoildColor");
    64.             cmd.SetViewMatrix(myViewMatrix);
    65.             context.ExecuteCommandBuffer(cmd);
    66.  
    67.             cmd.Clear();
    68.  
    69.             var draw1 = CreateDrawingSettings(shaderTag, ref renderingData, renderingData.cameraData.defaultOpaqueSortFlags);
    70.             draw1.overrideMaterial = setting.material;
    71.             draw1.overrideMaterialPassIndex = 0;
    72.             context.DrawRenderers(renderingData.cullResults, ref draw1, ref filtering);
    73.  
    74.             var draw2 = CreateDrawingSettings(shaderTag, ref renderingData, renderingData.cameraData.defaultOpaqueSortFlags);
    75.             draw2.overrideMaterial = setting.material;
    76.             draw2.overrideMaterialPassIndex = 1;
    77.             context.DrawRenderers(renderingData.cullResults, ref draw2, ref filtering2);
    78.  
    79.             context.ExecuteCommandBuffer(cmd);
    80.             CommandBufferPool.Release(cmd);
    81.  
    82.         }
    83.  
    84.         /// Cleanup any allocated resources that were created during the execution of this render pass.
    85.         public override void FrameCleanup(CommandBuffer cmd)
    86.         {
    87.         }
    88.     }
    89.  
    90.     CustomRenderPass m_ScriptablePass;
    91.  
    92.     public override void Create()
    93.     {
    94.         m_ScriptablePass = new CustomRenderPass(setting);
    95.  
    96.         // Configures where the render pass should be injected.
    97.         m_ScriptablePass.renderPassEvent = RenderPassEvent.BeforeRenderingOpaques;
    98.     }
    99.  
    100.     // Here you can inject one or multiple render passes in the renderer.
    101.     // This method is called when setting up the renderer once per-camera.
    102.     public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    103.     {
    104.         renderer.EnqueuePass(m_ScriptablePass);
    105.     }
    106. }
    107.  
    108.  
    109.  
     
  9. weiping-toh

    weiping-toh

    Joined:
    Sep 8, 2015
    Posts:
    186
    You can obtain the View and Projection matrices from the camera.
    Code (CSharp):
    1.  
    2.             command.SetViewProjectionMatrices(camera.worldToCameraMatrix, camera.projectionMatrix);