Search code examples
unity-game-engineopenglgraphics3d

How to render a basic GameObject in a custom pass (Unity: ScriptableRenderPass)?


What I'm trying to do: Render GameObject(s) of a specific Layer be rendered in my custom pass. I want to do something more later, but I'm just trying to get it to render exactly as URP would for now.

I'm just learning about ScriptableRenderPass/ScriptableRendererFeature, and so I'm starting basic.

Here's what I want:

Expected

Here's what I'm getting:

Actual Result

This is what my pass's Execute looks like:

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        CommandBuffer cmd = CommandBufferPool.Get("EnemyClearDepthPass"); // Take this outside if you don't need this to change at all.

        foreach (var renderer in _associatedObjects)
        {
            if (renderer.isVisible)
            {
                cmd.DrawRenderer(renderer, renderer.sharedMaterial);
            }
        }

        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }

It looks like it's rotation (thus, its MVP matrix) is correct... but it has no lighting. And I don't know what the 2nd cube of darkness is about. So:

Option #1) Figure out what commands I need to pass to the command buffer in order to apply lighting... and fix whatever the dark square is about... and hope that's it when I start to draw much more complex shaders.

But then I had a thought:

Option #2) Maybe I could use ScriptableRenderContext.DrawRenderers(...) in order to draw it, as I presume then it would work more "out of the box".

Here's what I get, no matter what I try to do with that approach:

Nothingness

(I know I could have just said nothing... but...)

To just get started on that approach, I am just trying to make a pass that draws everything. But I can get it to draw anything. Why?

using System;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class JustDrawSomethingPls : ScriptableRendererFeature
{
    // https://docs.unity3d.com/Packages/[email protected]/manual/containers/create-custom-renderer-feature-1.html
    class DrawEverythingPass : ScriptableRenderPass
    {
        public DrawEverythingPass() { }

        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
            CommandBuffer cmd = CommandBufferPool.Get("DrawEverythingPass");
            // https://docs.unity3d.com/ScriptReference/Rendering.DrawingSettings.html
            DrawingSettings drawingSettings = new DrawingSettings();
            drawingSettings.mainLightIndex = 0;
                SortingSettings sortingSettings = new SortingSettings();
                sortingSettings.criteria = SortingCriteria.None;
            drawingSettings.sortingSettings = sortingSettings;
            // https://docs.unity3d.com/ScriptReference/Rendering.FilteringSettings.html
            FilteringSettings filteringSettings = new FilteringSettings();
            filteringSettings.excludeMotionVectorObjects = false;
            filteringSettings.layerMask = int.MaxValue;
            filteringSettings.renderingLayerMask = uint.MaxValue;
            filteringSettings.renderQueueRange = new RenderQueueRange(0, 5000); // The upper bound must be at least 0 and at most 5000
            filteringSettings.sortingLayerRange = new SortingLayerRange(0, Int16.MaxValue);
            // https://docs.unity3d.com/ScriptReference/Rendering.RenderStateBlock.html
            RenderStateBlock renderStateBlock = new RenderStateBlock(RenderStateMask.Everything);

            context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref filteringSettings, ref renderStateBlock);

            // Execute the command buffer
            context.ExecuteCommandBuffer(cmd);
            CommandBufferPool.Release(cmd);
        }
    }

    private DrawEverythingPass _drawEverythingPass;
    public override void Create()
    {
        _drawEverythingPass = new DrawEverythingPass();
    }
    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        renderer.EnqueuePass(_drawEverythingPass);
    }
}

Solution

  • While I haven't full achieved what I wanted to do via the command buffer, a big step is to not use

    cmd.DrawRenderer(renderer, renderer.sharedMaterial);
    

    as it will draw all shader passes on top of each other, but instead use specific shader pass ("myShaderPass"):

    cmd.DrawRenderer(renderer, renderer.sharedMaterial, 0, myShaderPass);
    

    The main problem in this post was the fact that it was drawing the shadow pass on top of everything else. Note that getting lit shaders to work is going to be more work than getting an unlit shader to work via the command buffer.