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

 

参考

Custom Render Pipeline

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

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

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

 

posted @   yanghui01  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示