什么是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
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_EDITOR
PrepareBuffer();
PrepareForSceneWindow();
#endif
if (!Cull()) {
return;
}
Setup();
DrawVisibleGeometry();
#if UNITY_EDITOR
DrawUnsupportedShaders();
DrawGizmos();
#endif
Submit();
}
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();
}
#else
const string SampleName = bufferName;
#endif
}
修改渲染管线配置
右键 -> 新建一个渲染管线asset
菜单 -> Edit -> Project Settings,切换到Quality页签,添加一个品质条目,并关联我们新建的asset
至此,SRP的模板项目搭好了
参考
Custom Render Pipeline
【URP CatlikeCoding学习笔记】1/17 基础渲染管线 - 知乎
Unity自定义SRP(一):构建渲染框架 - 简书
Unity可编程渲染管线(SRP)教程:一、自定义管线 - 知乎