Unity SRP 管线【第一讲:自定义渲染管线】

news2024/12/26 22:32:46

来源:

https://edu.uwa4d.com/lesson-detail/282/1308/0?isPreview=false
在这里插入图片描述

文章目录

  • 来源:
  • 自定义渲染管线
    • 前置工作
    • 渲染管线资产
    • 渲染管线实例
  • 正式渲染
    • CommandBuffer
    • 清除渲染目标
    • 剔除(Culling)
    • 绘制
      • 绘制集合体
    • 透明和不透明物体分开绘制
  • 编辑器优化
    • 绘制SRP不支持的着色器类型
      • 使用Unity的ErrorShader来绘制不支持的着色器
    • 将Unity编辑器中使用的代码单独放在一个局部类中管理
    • 绘制辅助线框
    • UI绘制(在Scene视图中把UI绘制出来)
  • 多摄像机
    • 多个摄像机渲染不同类型的物体Culling Mask
    • 多个摄像机渲染结果的混合Clear Flags

自定义渲染管线

前置工作

下载 Core RP Library 库。SRP、URP、HDRP都是依据该包进行拓展的,它是Unity开放出来供我们使用调用的C#接口,通过调用更底层的C++提供的渲染接口。包中还包括一些基本的着色器文件。

渲染管线资产

using UnityEngine.Rendering;

继承RenderPipelineAsset,即可成为一个资产管理资源文件的定义文件
继承后需要重写CreatePipeline()函数,返回一个RenderPipeline 【渲染管线实例】

    protected override RenderPipeline CreatePipeline()
    {
        return new CustomRenderPipeline();
    }

记得将资产管理资源添加到菜单栏

//该类作为一个管线资产,可通过如下菜单创建
[CreateAssetMenu(menuName = "Rendering/CreateCustomRenderPipeline")]

之后在unity中创建该资源文件,并将该资源文件添加到Editor->Project Setting->Graphics->Scriptable Render Pipeline Setting中即可创建成功。

渲染管线实例

新建渲染管线脚本文件,继承RenderPipeline,实现方法Render。

public class CustomRenderPipeline : RenderPipeline
{

    CameraRenderer renderer = new CameraRenderer();
    /// <summary>
    /// Unity每帧都会调用CustomRenderPipeline实例的Render()方法进行画面渲染
    /// 是SRP的入口
    /// </summary>
    /// <param name="context"> 传入的当前上下文 </param>
    /// <param name="cameras"> 参与这一帧渲染的所有对象 </param>
    protected override void Render(ScriptableRenderContext context, Camera[] cameras)
    {
        foreach (var camera in cameras)
        {
            renderer.Render(context, camera);
        }
    }
}

在渲染管线资产中中返回该渲染管线实例类的一个实例即可。

Unity每帧都会调用实例的Render方法进行画面渲染,Render()方法是SRP的入口,进行渲染时底层接口会调用它并传递两个参数,一个是ScriptableRenderContext渲染上下文,一个是Camera[]对象,储存了参与这一帧渲染的所有相机对象

正式渲染

调用ScriptableRenderContext.DrawSkybox来绘制一个天空盒
因为通过context发送的渲染命令都是缓存,所以需要通过调用Submit()方法来正式提交渲染命令。

        // 设置相机view属性
        context.SetupCameraProperties(camera);
        context.DrawSkybox(camera);
        context.Submit();

CommandBuffer

控制Unity渲染流程的一种手段。一些命令需要单独的命令缓冲区简介发出,CommandBuffer是一个容器,保存了这些将要执行的渲染命令。

新建CommanfBuffer

    const string bufferName = "Render Camera";
    CommandBuffer commandBuffer = new CommandBuffer//是一个容器,保存将要执行的渲染命令
    {
        //给缓冲区起个名字,用于在Frame Debugger中识别他
        name = bufferName
    };

开启采样过程,这样就可以在Frame Debugger中显示,通常放在整个渲染过程的开始和结束。

commandBuffer.BeginSample(bufferName);
context.ExecuteCommandBuffer(commandBuffer);//执行缓存区命令
commandBuffer.Clear();

渲染设置...
渲染命令...

commandBuffer.EndSample(bufferName);
context.ExecuteCommandBuffer(commandBuffer);
commandBuffer.Clear();

命令提交...

清除渲染目标

buffer.BeginSample();

//*************************************
//buffer.ClearRenderTarget(是否清除深度,是否清除颜色,清除颜色数据的颜色);
buffer.ClearRenderTarget(true,true,Color.clear);
//*************************************

context.ExecuteCommandBuffer(commandBuffer);
commandBuffer.Clear();
......

ClearRenderTarget操作会自动包裹在一个使用命名缓冲区名字的样本条目中,因此一般不包含在其他命名缓冲区之内。

上段代码修改为

//*************************************
buffer.ClearRenderTarget(true,true,Color.clear);
//*************************************

buffer.BeginSample();
context.ExecuteCommandBuffer(commandBuffer);
commandBuffer.Clear();
......

然而,在帧调试中,Clear操作显示为Draw GL条目,而不是Clear。原因是我们需要提前设置Camera的属性,才能让Unity知道要调用Clear的硬件方法,而不是Hidden/InternalClear,SubShader #0着色器。

在这里插入图片描述

剔除(Culling)

剔除在相机渲染 Render() 最开始执行。

通过camera.TryGetCullingParameters(out p)得到需要进行剔除检查的所有物体,正式的剔除通过context.Cull()实现,最后会返回一个CullingResults结构,里面存储了我们相机剔除后所有视野内可见的物体的数据信息。

CullingResults cullingResults;
bool Cull(){
	ScriptableCullingParameters p;
	if(camera.TryGetCullingParameters(out p)){
		cullingResults = context.Cull.cull(ref p);
		return true;
	}
	return false;
}

绘制

当剔除完毕后,我们就知道需要渲染那些可见物体了。
正是渲染需要调用context.DrawRenderers方法实现。

绘制集合体

   static ShaderTagId unlitShaderTagID = new ShaderTagId("SRPDefaultUnlit");//渲染使用的Shader
   private void DrawVisibleGeometry()
   {
       // 设置绘制顺序和指定渲染相机
       var sortingSettings = new SortingSettings(camera)
       {
           criteria = SortingCriteria.CommonOpaque//不透明对象的典型排序模式
       };
       // 设置渲染的 Shader Pass 和排序模式
       var drawingSettings = new DrawingSettings(unlitShaderTagID,sortingSettings);//使用哪个ShaderID,以什么一定顺序渲染的设定
       // 设置哪些类型的渲染队列可以被绘制
       var filteringSettig = new FilteringSettings(RenderQueueRange.all);//过滤给定的渲染对象,这里使用all渲染所有对象
       //图像绘制
       context.DrawRenderers(cullingResults,ref drawingSettings,ref filteringSettig);

       context.DrawSkybox(camera);
   }

在这里插入图片描述

透明和不透明物体分开绘制

先绘制不透明物体,首先将过滤设置设置为Opaque,渲染不透明物体。
在渲染天空盒
最后渲染透明物体

    private void DrawVisibleGeometry()
    {
        // 设置绘制顺序和指定渲染相机
        var sortingSettings = new SortingSettings(camera)
        {
            criteria = SortingCriteria.CommonOpaque//不透明对象的典型排序模式
        };
        // 设置渲染的 Shader Pass 和排序模式
        var drawingSettings = new DrawingSettings(unlitShaderTagID,sortingSettings);//使用哪个ShaderID,以什么一定顺序渲染的设定
        // 设置哪些类型的渲染队列可以被绘制
        //var filteringSettig = new FilteringSettings(RenderQueueRange.all);//过滤给定的渲染对象,这里使用all渲染所有对象
        var filteringSetting = new FilteringSettings(RenderQueueRange.opaque);//过滤出不透明物体
        //图像绘制(不透明物体)
        context.DrawRenderers(cullingResults,ref drawingSettings,ref filteringSetting);

        context.DrawSkybox(camera);

        // 绘制透明物体
        sortingSettings.criteria = SortingCriteria.CommonTransparent; //透明对象的典型排序模式
        drawingSettings.sortingSettings = sortingSettings;
        // 过滤出透明物体
        filteringSetting.renderQueueRange = RenderQueueRange.transparent;
        // 绘制
        context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSetting);

    }

渲染透明物体要注意渲染顺序,这里设置渲染顺序为SortingCriteria.CommonTransparent

编辑器优化

绘制SRP不支持的着色器类型

SRP不支持的着色器类型

static ShaderTagId[] legacyShaderTagId = 
{
	new ShaderTagId("Always"),
	new ShaderTagId("ForwardBase"),
	new ShaderTagId("PrepassBase"),
	new ShaderTagId("Vertex"),
	new ShaderTagId("VertexMRGBM"),
	new ShaderTagId("VertexLM"),
};

private void DrawUnsupportedShaders()
{
    var drawingSettings = new DrawingSettings(legacyShaderTagId[0], new SortingSettings(camera));
    for (int i = 1; i < legacyShaderTagId.Length; i++)
    {
        drawingSettings.SetShaderPassName(i, legacyShaderTagId[i]);
    }

    var filteringSettings = FilteringSettings.defaultValue;
    context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);
}

使用函数DrawUnsupportedShaders();绘制不支持的材质渲染

public void Render(ScriptableRenderContext context, Camera camera)
{
	...
	
    SetUp();
    DrawVisibleGeometry();
    DrawUnsupportedShaders();
	
	...
}

使用Unity的ErrorShader来绘制不支持的着色器

static Material errorMaterial;
void DrawUnsupportedShaders(){
	if(errorMaterial == null)
	{
		errorMaterial = new Material(Shader.Find("Hidden/InternalErrorShader"));
	}
	
	var drawingSettings = new DrawingSettings(legacyShaderTagIds[0], new SortingSettings(camera))
	{
		overrideMaterial = errorMaterial
	};
}

将Unity编辑器中使用的代码单独放在一个局部类中管理

一些代码只适合调试时使用,但不会在发行版中运行,因此使用 动静代码分离:局部类 将代码进行分离管理。

使用partial分离class,将编辑器部分分离出来。

using UnityEngine;
using UnityEngine.Rendering;

public partial class CameraRenderer
{
    partial void DrawUnsupportedShaders();

// build and run 时 不运行这部分
#if UNITY_EDITOR
    static ShaderTagId[] legacyShaderTagIds =
    {
        new ShaderTagId("Always"),
        new ShaderTagId("ForwardBase"),
        new ShaderTagId("PrepassBase"),
        new ShaderTagId("Vertex"),
        new ShaderTagId("VertexMRGBM"),
        new ShaderTagId("VertexLM"),
    };

    static Material errorMaterial;
    /// <summary>
    /// 使用Unity内置ErrorShader。
    /// </summary>
    partial 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);
    }
#endif
}

对编辑器内使用的函数代码,使用#if UNITY_EDITOR #endif将其包入其中。注意,若将函数定义在宏编译内,在编译条件不通过时,该函数如果在其他函数内调用,则会报错。使用partial添加函数定义,即可。
如:partial void DrawUnsupportedShaders();

绘制辅助线框

未绘制辅助线框
在这里插入图片描述
绘制辅助线框
在这里插入图片描述
绘制辅助线框代码

#if UNITY_EDITOR
	...
	
    partial void DrawGizmos()
    {
        if (Handles.ShouldRenderGizmos())
        {
            context.DrawGizmos(camera, GizmoSubset.PreImageEffects);
            context.DrawGizmos(camera, GizmoSubset.PostImageEffects);
        }
        
    }
#endif

UI绘制(在Scene视图中把UI绘制出来)

如果将 CanvasRenderMode 设置为 ScreenSpace Overlay
在这里插入图片描述
UI不是由我们管线进行绘制的,而是单独绘制的。

如果我们将 CanvasRenderMode 设置为 ScreenSpace Camera
UI绘制由我们管线管理。

调用如下函数,即可将Games视图下的UI绘制到Scene视图下。

partial void PrepareForSceneWindow()
{
    if (camera.cameraType == CameraType.SceneView)
    {
        ScriptableRenderContext.EmitWorldGeometryForSceneView(camera);
    }
}

注意:调用PrepareForSceneWindow函数需要在剔除之前,因为UI会在场景中添加几何体,这个集合体可能会被剔除操作剔除。

多摄像机

多摄像机绘制。绘制顺序按照深度递增渲染。【先绘制小数,再绘制大数】。
在这里插入图片描述

多个摄像机渲染不同类型的物体Culling Mask

需要使用Layer将物体进行分类。使用摄像机的Culling Mask剔除不需要渲染的可见物。

多个摄像机渲染结果的混合Clear Flags

将第二个 Camera 的 clearFlag 设置为Depth Only,然后根据该设置写代码:
在这里插入图片描述

private void SetUp()
{
    // 设置相机属性
    context.SetupCameraProperties(camera);
    // 得到Camera的CameraClearFlags对象
    CameraClearFlags flags = camera.clearFlags;
    //设置相机清除状态
    commandBuffer.ClearRenderTarget(flags <= CameraClearFlags.Depth,//Skybox,Color,Depth 无论哪一个都要清理深度缓存
                                    flags == CameraClearFlags.Color,
                                    flags == CameraClearFlags.Color ? camera.backgroundColor.linear : Color.clear);
}

根据camera的Clear Flags修改帧缓存的深度缓存,颜色缓存是否重置。

  • 若设置为Depth Only,则只重置深度,颜色不变,这样就可以将上一个摄像机的渲染作为这个摄像机的背景。
  • 若设置为Don't Clear,则深度,颜色都不重置,这样相当于在原有帧数据的基础上继续渲染【只修改了摄像机数据】。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1098582.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL学习(二)——MySQL内置函数

文章目录 1. 函数1.1 字符串函数1.2 数值函数1.3 日期函数1.4 流程函数 2. 约束2.1 概述2.2 外键约束2.2.1 外键使用2.2.2 删除/更新行为 1. 函数 和其他编程语言一样&#xff0c;MySQL也有函数的定义。函数 是指一段可以直接被另一段程序调用的程序或代码。 也就意味着&#…

jmeter接口测试实战:接口加密、接口解密、签名sign接口实战详解

在接口测试中&#xff0c;签名&#xff08;sign&#xff09;是一种重要的加密方式&#xff0c;用于保障数据传输的安全性和完整性。在这篇文章中&#xff0c;我们将通过一个具体的案例来学习如何使用 JMeter 进行签名接口的测试&#xff0c;并用 Python 代码进行实战演示。 比…

集成友盟qq互联分享,导出风险问题处理

处理方案&#xff1a;移除 android:exported"true"即可。 注意友盟SDK QQ share 里默认配置是android:exported"true"&#xff0c;所以要覆盖即可。

为什么CDN能创造这么利益

互联网的快速发展带来了更多的在线内容和应用&#xff0c;但同时也引发了对网站性能的高要求。用户对快速加载的期望越来越高&#xff0c;这就需要采用高效的内容分发解决方案。在这方面&#xff0c;CDN&#xff08;内容分发网络&#xff09;扮演了关键角色&#xff0c;通过其分…

uniapp(uncloud) 使用生态开发接口详情2(使用 schema创建数据, schema2code创建页面, iconfont 引入项目)

上一篇介绍如何创建项目,接下来该是如何使用 在项目中pages 目录下,新建界面 项目运行,浏览器中用账号密码登录, 新建一级和二级页面 2.1 系统管理 > 菜单管理 (新增一级界面) 2.2 找到刚刚创建的菜单, 操作行有 子菜单(点击) 用DB Schema创建页面, 3.1 在uniCloud > d…

大规模语言模型人类反馈对齐--RLHF

大规模语言模型在进行监督微调后&#xff0c; 模型具备了遵循指令和多轮对话的能力&#xff0c; 具备了初步与用户进行对话 的能力。然而&#xff0c; 大规模语言模由于庞大的参数量和训练语料&#xff0c; 其复杂性往往难以理解和预测。当这些模型被部署 时&#xff0c; 它们可…

经济不景气时,企业如何通过反向竞价节省成本?

在经济不景气时期&#xff0c;企业往往被迫寻找创新方法来削减成本&#xff0c;争取提高盈利。其中一种越来越受欢迎的方法就是使用反向竞价。 反向竞价是一种采购策略&#xff0c;它颠覆了传统的采购流程&#xff0c;允许供应商竞争买方的业务。这种方法可以节省大量成本&…

退税政策线上VR互动科普展厅为税收工作带来了强大活力

缴税纳税是每个公民应尽的义务和责任&#xff0c;由于很多人缺乏专业的缴税纳税操作专业知识和经验&#xff0c;因此为了提高大家的缴税纳税办事效率和好感度&#xff0c;越来越多地区税务局开始引进VR虚拟现实、web3d开发和多媒体等技术手段&#xff0c;基于线上为广大公民提供…

C# Winform编程(2)常用控件

C# Winform编程&#xff08;2&#xff09;常用控件 常用控件 常用控件 标签&#xff0c;文本&#xff0c;按钮&#xff0c;列表框&#xff0c;组合框等的使用 Program.cs using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks…

Python-pyecharts和pandas库

目录 pyecharts库 pandas库 示例1 示例2 pyecharts库 pyecharts是一个基于Python的交互式数据可视化库&#xff0c;旨在帮助用户轻松地创建各种类型的图表和可视化效果。该库是在Echarts开源项目的基础上开发的&#xff0c;Echarts是一款由百度开发的优秀的数据可视化工具。…

静力触探数据智能预处理(3)

静力触探数据智能预处理&#xff08;3&#xff09; 前言 将钻探、物探、静力触探三种数据放在一起对比分析&#xff0c;三种方法间存在尚不明确的物性联系。利用某规范进行土的分类&#xff0c;得出了全是砂土的错误结论&#xff0c;非专业编写&#xff0c;仅供参考。 1、对…

Xilinx IP 10G Ethernet PCS/PMA IP Core

Vivado 10G Ethernet PCS/PMA介绍 1介绍 完整的10G以太网接口如下图,分为10G PHY和10G MAC两部分。 这篇文章重点讲 10G Ethernet PCS/PMA。 2 IP的基本介绍 10G以太网物理编码子层/物理介质连接(PCS/PMA)核心在Xilinx 10G以太网介质访问控制器(MAC)核心和具有10Gb/s…

并发数的计算

一 常用平均并发数计算公式 1.1 普通计算方法 计算公式&#xff1a; TPS总请求数/总时间按照需求所示&#xff0c;第32周有4.13万的浏览量&#xff0c;那么总请求数估算为4.13万 总请求数4.13完请求数41300请求数 总时间1天24小时24*3600秒 TPS41300请求数/24*3600秒0.48请求数…

2.1 初探大数据

文章目录 零、学习目标一、导入新课二、新课讲解&#xff08;一&#xff09;什么是大数据&#xff08;二&#xff09;大数据的特征1、Volume - 数据量大2、Variety - 数据多样3、Velocity - 数据增速快4、Value - 数据价值低5、Veracity - 数据真实性 &#xff08;三&#xff0…

Cpolar和极简主义文件管理器:为用户提供高效稳定的个人云存储服务

文章目录 1. 前言2.Tiny File Manager网站搭建2.1.Tiny file manager下载和安装2.2 Tiny file manager网页测试2.2 Tiny file manager网页测试3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试总结 1. 前言 文件共享和查阅是现在网络最常见的应用场景&am…

基于ssm的图书商城

功能如下图所示 摘要 今天&#xff0c;我们生活在一个充满活力的时代&#xff0c;其中网购已经成为一种主要购物方式。传统实体书店的客流量日益减少&#xff0c;而实体书籍的销售量也逐年下滑&#xff0c;这不可避免地导致了在线图书商城的崛起。在线商城具有众多优势。首先&a…

谷歌、AMD、英特尔加入挑战,英伟达AI解决方案还能继续“遥遥领先”吗?

夕小瑶科技说 原创 编译 | 谢年年 要问世界范围内人工智能解决方案谁最“遥遥领先”&#xff1f; 那肯定是英伟达&#xff01; 然鹅这一情况很有可能会发生变动。 谷歌正在构建自己的人工智能基础设施&#xff01; 除了谷歌&#xff0c;在软件方面&#xff0c;Meta的PyTor…

华为云云耀云服务器L实例评测|CentOS系统盘迁移到数据盘教程讲解

华为云云耀云服务器L实例评测&#xff5c;CentOS系统盘迁移到数据盘教程讲解 在华为云网购买华为云云耀云服务器L实例的Centos系统机器&#xff0c;可能会出现没有在挂载数据盘直接安装在系统盘情况,又或者系统初始化自动挂载在其他目录上。建议大家都把数据存放在数据盘下 …

CICD:Circle CI 实现CICD

持续集成解决什么问题 提高软件质量效率迭代便捷部署快速交付、便于管理 持续集成&#xff08;CI&#xff09; 集成&#xff0c;就是一些孤立的事物或元素通过某种方式集中在一起&#xff0c;产生联系&#xff0c;从而构建一个有机整体的过程。 持续&#xff0c;就是指长期…

如何养好一个微信新号?

最近听到一句话&#xff0c;“微信是个完整的互联网”。 你还真别说&#xff0c;真是。如果你还觉得微信只是个聊天视频打电话的工具&#xff0c;那可就有信息差了。 微信有各种各样的小程序&#xff0c;有打车的&#xff0c;有交话费的&#xff0c;有游戏&#xff0c;可以说&a…