什么是SRP?
可编程渲染管线 (Scriptable Render Pipeline) 是 Unity 内置渲染管线的替代方案。 使用 SRP 可以通过 C# 脚本控制和定制渲染流程
URP和SRP的区别?
URP是基于SRP实现的一套渲染管线(由Unity官方实现,并以模板项目的方式提供给开发者使用)
LWRP又是啥?
轻量级渲染管线(Lightweight Render Pipeline), 其实就是URP的前身,Unity2020版本开始更名为URP。
创建SRP项目
这边使用Unity2021
空的SRP项目
代码部分
自定义渲染管线主要实现RenderPipelineAsset和RenderPipeline
1) RenderPipelineAsset子类,用于创建并返回自定义的RenderPipleline
CustomRenderPipelineAsset.cs
[CreateAssetMenu(menuName = "Rendering/Custom Render Pipeline")] public class CustomRenderPipelineAsset : RenderPipelineAsset {
protected override RenderPipeline CreatePipeline () {return new CustomRenderPipeline();}
}
2) RenderPipeline子类,用于定制渲染
CustomRenderPipeline.cs
public class CustomRenderPipeline : RenderPipeline {CameraRenderer renderer = new CameraRenderer();protected override void Render(ScriptableRenderContext context, Camera[] cameras) {}protected override void Render(ScriptableRenderContext context, List<Camera> cameras) {for (int i = 0; i < cameras.Count; i++) {renderer.Render(context, cameras[i]);}}}
CameraRenderer.cs
public partial class CameraRenderer {const string bufferName = "Render Camera";static ShaderTagId unlitShaderTagId = new ShaderTagId("SRPDefaultUnlit");CommandBuffer buffer = new CommandBuffer {name = bufferName};ScriptableRenderContext context;Camera camera;CullingResults cullingResults;public void Render(ScriptableRenderContext context, Camera camera) {this.context = context;this.camera = camera;#if UNITY_EDITORPrepareBuffer();PrepareForSceneWindow(); #endifif (!Cull()) {return;}Setup();DrawVisibleGeometry(); #if UNITY_EDITORDrawUnsupportedShaders();DrawGizmos(); #endifSubmit();}bool Cull() {if (camera.TryGetCullingParameters(out ScriptableCullingParameters p)) {cullingResults = context.Cull(ref p);return true;}return false;}void Setup() {context.SetupCameraProperties(camera);CameraClearFlags flags = camera.clearFlags;buffer.ClearRenderTarget(flags <= CameraClearFlags.Depth,flags <= CameraClearFlags.Color,(flags == CameraClearFlags.Color) ? camera.backgroundColor.linear : Color.clear);buffer.BeginSample(SampleName);ExecuteBuffer();}void Submit() {buffer.EndSample(SampleName);ExecuteBuffer();context.Submit();}void ExecuteBuffer() {context.ExecuteCommandBuffer(buffer);buffer.Clear();}void DrawVisibleGeometry() {//先渲染不透明物体var sortingSettings = new SortingSettings(camera) {criteria = SortingCriteria.CommonOpaque};var drawingSettings = new DrawingSettings(unlitShaderTagId, sortingSettings);var filteringSettings = new FilteringSettings(RenderQueueRange.opaque);context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);//再渲染天空盒 context.DrawSkybox(camera);//再渲染半透明物体sortingSettings.criteria = SortingCriteria.CommonTransparent;drawingSettings.sortingSettings = sortingSettings;filteringSettings.renderQueueRange = RenderQueueRange.transparent;context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);}}
CameraRenderer.Editor.cs
partial class CameraRenderer {#if UNITY_EDITOR//内置渲染管线的tag标识static ShaderTagId[] legacyShaderTagIds = {new ShaderTagId("Always"),new ShaderTagId("ForwardBase"),new ShaderTagId("PrepassBase"),new ShaderTagId("Vertex"),new ShaderTagId("VertexLMRGBM"),new ShaderTagId("VertexLM")};static Material errorMaterial;string SampleName { get; set; }void DrawGizmos() {if (Handles.ShouldRenderGizmos()) {context.DrawGizmos(camera, GizmoSubset.PreImageEffects);context.DrawGizmos(camera, GizmoSubset.PostImageEffects);}}//shader错误时, 显示为粉红void DrawUnsupportedShaders() {if (errorMaterial == null) {errorMaterial = new Material(Shader.Find("Hidden/InternalErrorShader"));}var drawingSettings = new DrawingSettings(legacyShaderTagIds[0], new SortingSettings(camera)) {overrideMaterial = errorMaterial};for(int i = 1; i < legacyShaderTagIds.Length; i++) {drawingSettings.SetShaderPassName(i, legacyShaderTagIds[i]);}var filteringSettings = FilteringSettings.defaultValue;context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);}void PrepareForSceneWindow() {if (camera.cameraType == CameraType.SceneView) {ScriptableRenderContext.EmitWorldGeometryForSceneView(camera); //渲染ugui的几何图形 }}void PrepareBuffer() {Profiler.BeginSample("Editor Only"); //Window -> Analysis -> Profile -> CPU Usage:Hierarchy中会显示buffer.name = SampleName = camera.name; //编辑器下BeginSample使用相机名字, Player下使用固定名字(Render Camera) Profiler.EndSample();}#elseconst string SampleName = bufferName; #endif}
修改渲染管线配置
右键 -> 新建一个渲染管线asset
菜单 -> Edit -> Project Settings,切换到Quality页签,添加一个品质条目,并关联我们新建的asset
至此,SRP的模板项目搭好了
参考
Custom Render Pipeline
【URP CatlikeCoding学习笔记】1/17 基础渲染管线 - 知乎
Unity自定义SRP(一):构建渲染框架 - 简书
Unity可编程渲染管线(SRP)教程:一、自定义管线 - 知乎