vanCopper bio photo

vanCopper

Try Your Best.

Email Github

创建 RenderPipeline 类

使用自定义SRP首先需要自定义一个RenderPipeline类,用来组织管理渲染流程:

public class DevRenderPipeline: RenderPipeline
{
	 public override void Render(ScriptableRenderContext renderContext, Camera[] cameras)
     {
            base.Render(renderContext, cameras);
     }
}
  • ScriptableRenderContext 用于设置渲染用各种状态,以及提交CommandBuffer等
  • Camera[] 需要渲染处理的相机数组

设置当前渲染使用的管线

Unity提供了RenderPipelineAsset来创建并存放自定义管线的配置。

using System;
using UnityEngine.Experimental.Rendering;

#if UNITY_EDITOR

using UnityEditor;
using UnityEditor.ProjectWindowCallback;

#endif

namespace SRPTest_01
{
    public class DevRenderPipelineAsset : RenderPipelineAsset
    {

#if UNITY_EDITOR
        [MenuItem("Assets/Create/Render Pipeline/SRPTest_01/Pipeline Asset")]
        static void CreateSRPTestPipeline()
        {
            ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, CreateInstance<CreateSRPTest_01_PipelineAsset>(), "SRPTest_01 Pipeline.asset", null, null);
        }

        class CreateSRPTest_01_PipelineAsset : EndNameEditAction{

            public override void Action(int instanceId, string pathName, string resourceFile)
            {
                var instance = CreateInstance<DevRenderPipelineAsset>();
                AssetDatabase.CreateAsset(instance, pathName);
            }

        }

#endif

        protected override IRenderPipeline InternalCreatePipeline()
        {
            return new DevRenderPipeline();
        }
    }
}

接下来可通过菜单创建管线资源并在Edit–>Settings–>Graphics中,将Scriptable Render Pipeline Settings设置为刚刚创建的资源。

此时所有渲染都会通过我们自定的管线来进行处理。

使用CommandBuffer

CommandBuffer不是SRP中出现的新概念,CommandBuffer本是用来扩展Unity的固定管线,在SRP中仍需使用CommandBuffer来做一些设置工作,下面的代码使用CommandBuffer将缓冲区填充为黄色。

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

            BeginFrameRendering(cameras);

            var clearCmd = new CommandBuffer { name = "Clear(SRP-CommandBuffer)" };
            clearCmd.ClearRenderTarget(true, true, Color.yellow);
            renderContext.ExecuteCommandBuffer(clearCmd);
            renderContext.Submit();
}

Culling

在渲染之前,我们需要先进行Culling(剔除),即找出需要渲染的物件。Unity提供两种剔除方式:

  • Frustum culling(视锥剔除): 通过视锥的远截面(far)和近截面(near)来最终确定需渲染的物件 详细参考
  • Occlusion culling(遮挡剔除):通过物件的遮挡关系来最终确定需要渲染的物件 详细参考

在SRP中我们可以通过Camera来获取剔除后的渲染列表:

ScriptableCullingParameters cullingParameters;
if (!CullResults.GetCullingParameters(camera, out cullingParameters))
    continue;
CullResults cullResults = new CullResults();
CullResults.Cull(ref cullingParameters, renderContext, ref cullResults);

// 剔除后需要渲染的物件列表
cullResults.visibleRenderers

Filter

使用SRP执行渲染时,还需要指定该次渲染的渲染队列,即SubShaderQueue标签所指定的队列分类。Unity定义了5种队列,其中队列索引号越小表示越早被渲染。我们在自己的管线中也应该尽量遵守该规则。

名称 队列索引
Background 1000
Geometry 2000
AlphaTest 2450
Transparent 3000
Overlay 4000
var filterSettings = new FilterRenderersSettings(true);
//不透明物体 SubShader使用 Geometry表情 Filter使用 RenderQueueRange.opaque 队列
filterSettings.renderQueueRange = RenderQueueRange.opaque;

Draw Settings

最后使用DrawRendererSettings指定该次渲染使用的Shader Pass

// ShaderPassName的参数即 Shader中的LightMode标签
var drawSettings = new DrawRendererSettings(camera, new ShaderPassName("BasicLightMode"));

DrawRenderers

using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;
namespace SRPTest_01
{
    public class DevRenderPipeline : RenderPipeline
    {

        public override void Dispose()
        {
            base.Dispose();
        }

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

            BeginFrameRendering(cameras);

            var clearCmd = new CommandBuffer { name = "Clear(SRP-CommandBuffer)" };
            clearCmd.ClearRenderTarget(true, true, Color.yellow);
            renderContext.ExecuteCommandBuffer(clearCmd);
            clearCmd.Release();//dispose
            //renderContext.Submit();
            foreach (var camera in cameras){

                BeginCameraRendering(camera);
                ScriptableCullingParameters cullingParameters;
                if (!CullResults.GetCullingParameters(camera, out cullingParameters))
                    continue;
                CullResults cullResults = new CullResults();
                CullResults.Cull(ref cullingParameters, renderContext, ref cullResults);

                renderContext.SetupCameraProperties(camera);


                var filterSettings = new FilterRenderersSettings(true);
                var drawSettings = new DrawRendererSettings(camera, new ShaderPassName("BasicLightMode"));
                drawSettings.rendererConfiguration = RendererConfiguration.PerObjectLightProbe | RendererConfiguration.PerObjectLightmaps;


                // 不透明物件
                filterSettings.renderQueueRange = RenderQueueRange.opaque;
                drawSettings.sorting.flags = SortFlags.CommonOpaque;
                renderContext.DrawRenderers(cullResults.visibleRenderers, ref drawSettings, filterSettings);

                // skybox
                if( camera.clearFlags == CameraClearFlags.Skybox){
                    renderContext.DrawSkybox(camera);
                }

                // 透明物件
                filterSettings.renderQueueRange = RenderQueueRange.transparent;
                drawSettings.sorting.flags = SortFlags.CommonTransparent;
                renderContext.DrawRenderers(cullResults.visibleRenderers, ref drawSettings, filterSettings);

                renderContext.Submit();

            }
        }
    }
}

分别绘制了不透明物件,透明物件。

完整代码访问:

Github: https://github.com/vanCopper/Unity_SRP_Test


扫码分享该文