Catlike Coding Custom SRP笔记 - SRP项目搭建

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 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的模板项目搭好了

参考

Custom Render Pipeline

【URP CatlikeCoding学习笔记】1/17 基础渲染管线 - 知乎

Unity自定义SRP(一):构建渲染框架 - 简书

Unity可编程渲染管线(SRP)教程:一、自定义管线 - 知乎

🔍 相关推荐