Catlike Coding Custom SRP笔记 - SRP项目搭建
什么是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_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的模板项目搭好了
参考
【URP CatlikeCoding学习笔记】1/17 基础渲染管线 - 知乎
Unity可编程渲染管线(SRP)教程:一、自定义管线 - 知乎
分类:
shader / SRP
, shader
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!