Unity 3D之自定义SRP(可编程渲染管线)教程3

自定义渲染管线

前言

本文从内容上是继承自Unity的官方说明文档。添加了部分自己对SRP的认识。

最简单的custom SRP

srp的基本组成 srp asset

srp asset是srp在编辑器下的一种序列后的资源文件。类似的,我们在导入lwrp之后,可以在project文件下创建一个lwrp的资源文件,选中后在inspector中会出现如下界面:
Unity 3D之自定义SRP(可编程渲染管线)教程3_第1张图片
这里创建的就是srp asset。而srp asset所对应的对象就是srp instance。Asset的作用可以看成是srp的设置界面,其设置的参数将会传入到srp instance。但是这里并不是传入那么简单,其实是重新创建了一个新的instance。

srp的基本组成 srp instance

srp asset修改的是srp instance的参数,那对应srp instance是什么?
从名字既可知道,srp instance是srp的一种实例,是srp的逻辑的实现对象。我们在srp asset中设置的参数将会输入我们设置的接口,并且按照参数生产新的instance。
在srp instance中我们需要声明自定义渲染管线的逻辑,从而实现自定义效果。在其中可实现:

  • 清理帧缓存
  • 处理场景剔除
  • 渲染对象
  • 帧缓存的传递
  • 渲染阴影
  • 实现后期特效

创建最简单的srp asset

srp asset与其他unity asset资源等同,可通过AssetDatabase.CreateAsset接口创建。其实也就是去序列化一个类的对象。
下面给出最简srp脚本:

[ExecuteInEditMode]
public class BasicAssetPipe : RenderPipelineAsset
{
    public Color clearColor = Color.green;

#if UNITY_EDITOR
    // Call to create a simple pipeline
    [UnityEditor.MenuItem("SRP-Demo/01 - Create Basic Asset Pipeline")]
    static void CreateBasicAssetPipeline()
    {
        var instance = ScriptableObject.CreateInstance<BasicAssetPipe>();
        UnityEditor.AssetDatabase.CreateAsset(instance, "Assets/BasicAssetPipe.asset");
    }
#endif

    // Function to return an instance of this pipeline
    protected override IRenderPipeline InternalCreatePipeline()
    {
        return new BasicPipeInstance(clearColor);
    }
}

其中,InternalCreatePipeline是重写自接口RenderPipelineAsset[ExecuteInEditMode]保证更新函数能够在编辑器模式下执行。该函数会在每次对srp asset进行修改后,创建出新的srp instance。这里返回的是自定义的BasicPipeInstance对象。

创建最简单的SRP Instance


internal class BasicPipeInstance : RenderPipeline
{
    private Color screenColor;
    private bool stereoEnable = false;

    public BasicPipeInstance(Color screenColor)
    {
        this.screenColor = screenColor;
    }
    public override void Render(ScriptableRenderContext renderContext, Camera[] cameras)
    {
        base.Render(renderContext, cameras);
        //command
        var cmd = new CommandBuffer();
        //cmd.DrawRenderer(renderContext, new Material());
        cmd.ClearRenderTarget(true, true, screenColor);//1
        renderContext.ExecuteCommandBuffer(cmd);//2
        cmd.Release();
        //clear screen
        //end command
        renderContext.Submit();
        }
    }
}

类中只是简单实现了清屏效果,在创建asset之后,屏幕会跟随设置的颜色进行变化。这里就体现了srp与传统rp之间的区别。传统rp是一个黑盒,我们只能通过shader去处理物体的渲染效果,而srp能够通过unity给出的接口自定义渲染流程和处理渲染的效果。相当于开了底层的接口,我们能够更好的实现我们想要的效果,而不受rp的限制。

实现不透明SRP

  public override void Render(ScriptableRenderContext renderContext, Camera[] cameras)
    {
       base.Render(renderContext, cameras);
       // clear depth buffer

       //context才是渲染管线的本体
       foreach (var camera in cameras)
       {

           // Culling
           ScriptableCullingParameters cullingParams;
           if (!CullResults.GetCullingParameters(camera, out cullingParams))
               continue;

           CullResults cull = CullResults.Cull(ref cullingParams, renderContext);

           // Setup camera for rendering (sets render target, view/projection matrices and other
           // per-camera built-in shader variables).
           renderContext.SetupCameraProperties(camera);
           var cmd = new CommandBuffer();
           cmd.ClearRenderTarget(true, false, screenColor);
           renderContext.ExecuteCommandBuffer(cmd);
           cmd.Release();


           // Draw opaque objects using BasicPass shader pass
           var settings = new DrawRendererSettings(camera, new ShaderPassName("BasicPass"));
           settings.sorting.flags = SortFlags.CommonOpaque;

           var filterSettings = new FilterRenderersSettings(true) { renderQueueRange = RenderQueueRange.opaque };
           renderContext.DrawRenderers(cull.visibleRenderers, ref settings, filterSettings);

           // Draw skybox
           renderContext.DrawSkybox(camera);

           renderContext.Submit();
       }
    }

在官方文档中没有提及摄像机遍历部分。对于srp会将场景和编辑器下的每个相机都会输出(除了game场景还有scene窗口),因此srp的编写也会影响到scene窗口。

在渲染中首先会根据相机和3d对象进行剔除,获取到剔除后需要渲染的对象

           // Culling
           ScriptableCullingParameters cullingParams;
           if (!CullResults.GetCullingParameters(camera, out cullingParams))
               continue;

           CullResults cull = CullResults.Cull(ref cullingParams, renderContext);

具体剔除规则后面更新
然后对渲染方式进行设置,并渲染结果

           var settings = new DrawRendererSettings(camera, new ShaderPassName("BasicPass"));
           settings.sorting.flags = SortFlags.CommonOpaque;

           var filterSettings = new FilterRenderersSettings(true) { renderQueueRange = RenderQueueRange.opaque };
           renderContext.DrawRenderers(cull.visibleRenderers, ref settings, filterSettings);

这里会使用到new ShaderPassName("BasicPass"));语句,注意这里的参数BasicPass需要填写shader中的lightmode对应的值,而不是pass的name。

测试工程链接在这里

你可能感兴趣的:(游戏开发,Unity-Shader,Unity-进阶)