Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher

news2024/11/16 11:44:54

接下来我们要来学习下自定义渲染管线中的合批,这一节主要学习SRP Batcher

每一次的Draw Call都需要CPU和GPU之间的通信,如果有大量的数据需要从CPU发送到GPU中,那GPU就可能因为等待数据而浪费时间,而CPU会因为忙于发送数据导致无法做其他的事情,所以这两个问题都会导致帧率的降低。在目前我们的做法有点粗暴,一个物体一个Draw Call,这是非常浪费时间的,只是目前我们发送的整体数据量较少,所以还感受不出问题。

我们可以用示例数字来说明这个问题。
整三十个球,同样颜色,按以前的Unity肯定是能合批的,可是现在需要31个Draw Call,通过合批减少的DrawCall数量(Saved by batching)为0,其实就是天空盒一个,剩下的就是30个球的了。
(为什么Clear的DrawCall没了?哈哈,这就是我们之前做ClearRenderTarget的小优化,对于Skybox的Flag不用进行清理也是可以的,具体可以查看《自定义渲染管线基础学习》-”相机的ClearFlags“这一小节)

在这里插入图片描述

自定义渲染管线的合批

合批是合并Draw Call的过程,减少CPU和GPU之间的通信量。
在自定义管线中最简单的实现方法就是直接开启SRP Batcher,SRP Batcher实际上并不是直接减少Draw Call的数量,而是简化了流程,它将材质属性存储在GPU,所以不用每一次Draw Call都发送数据,这样子既能减少CPU和GPU之间的通信,也能减少CPU每一次Draw Call所要做的数据准备工作。这样也相当于减少了Draw Call的数量。
但是想要SRP Batcher生效,我们的Shader编写必须按照规范的统一结构来。
我们查看Shader的面板可以查看SRP Batcher的使用情况,发现有无法使用的提示,”属性没有定义在叫【UnityPerDraw】的cbuffer中“。cbuffer(constant buffer)。
在这里插入图片描述

想要SRP Batcher生效,我们Shader中的所有材质属性不能像之前那样直接定义,必须放在固定的内存缓存中。
之前SRP Batcher不生效的写法

float4 _BaseColor;

我们查看Unlit的Shader,在上面可以看到提示SRP合批不适用的原因
在这里插入图片描述
标准写法
(但是在一些平台上无法支持cbuffer,比如OpenGL ES 2.0)


//使用cbuffer UnityPerMaterial 包起来才能使SRP Batcher生效
//但是在一些平台上无法支持cbuffer,比如OpenGL ES 2.0
cbuffer UnityPerMaterial  
{
    float4 _BaseColor;  //用于Shader中定义颜色属性,名称需相同
};

由于一些平台无法直接支持cbuffer
Core RP Library中通过CBUFFER_START和CBUFFER_END对此做了处理,因此我们可以使用这个来解决问题
使用需要include Common.hlsl

在这里插入图片描述
在这里插入图片描述

#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"

最终写法


//CBUFFER_START和CBUFFER_END是CORE RP Library中对cbuffer做的处理,解决部分平台无法支持的问题
CBUFFER_START(UnityPerMaterial)
    float4 _BaseColor;
CBUFFER_END

但仍然还有问题
在这里插入图片描述
我们还需要把别的变量也加到这里


CBUFFER_START(UnityPerDraw)
float4x4 unity_ObjectToWorld;  //每一次绘制GPU设置这个值,然后在一次绘制中的顶点片元函数使用期间值不变
float4x4 unity_WorldToObject;
float4 unity_LODFade;
real4 unity_WorldTransformParams;
CBUFFER_END

然后CustomRenderPipeline.cs中开启SRP合批


    public CustomRenderPipeline()
    {
        GraphicsSettings.useScriptableRenderPipelineBatching = true;  //开启SRP合批
    }

终于适用了
在这里插入图片描述
但不知道为什么我的面板还是没有变化
在这里插入图片描述
但是FrameDebuger里面已经可以看到效果了
我们可以看到SRP Batch
但我们可以看到上面显示着,Draw Calls 30,所以实际上SRP Batch并不是真正的合批,仍然会有30次Draw Calls,是减少了发送到GPU的数据量
在这里插入图片描述
到了这里我自己有点懵了
没用SRP之前的有合批么?
除了要勾静态的静态合批外,原来的动态合批是怎么回事?
动态合批需要在PlayerSetting中勾选Dynamic Batch功能,然后也有许多限制
但是它的合批是真的合批
在这里插入图片描述

多种颜色的合批

我们增加不同颜色的材质赋予这些球,但是我们发现实际上SRP的Batch并不会增加,因为数据缓存在了GPU上,每一次DrawCall只需要包含内存位置的偏移数据就好了。
对于SRP的使用有一个限制是每个材质的memory layout(内存布局?)必须是一样的,因此在这里所有的球我们都使用了同一个Shader,而这些材质都只包含了一个颜色属性。Unity不会去详细的比较的材质的memory layout,而是简单的根据相同的Shader变体去合并Draw Calls。
在这里插入图片描述

在上面的例子中,为了有5种颜色,我们创建了5个材质球,但如果要十几种颜色或者更多,我们总不能去创建那么多的材质球。如果我们能直接设置每个对象的颜色,那就会方便很多。
我们通过MaterialPropertyBlock实现这个功能。


using UnityEngine;
[DisallowMultipleComponent]
public class PerObjectMaterialProperties : MonoBehaviour
{
    static int baseColorId = Shader.PropertyToID("_BaseColor"); //使用Id的方式去设置属性会更高效
    static MaterialPropertyBlock block;
    [SerializeField]
    Color baseColor = Color.white;
    void Awake()
    {
        OnValidate();  //OnValidate只在编辑器下会被调用,打包后我们得自己调用
    }
    //OnValidate在编辑器下,在组件加载和组件修改时会被调用
    void OnValidate()
    {
        if (block == null)
        {
            block = new MaterialPropertyBlock();
        }
        block.SetColor(baseColorId, baseColor);
        GetComponent<Renderer>().SetPropertyBlock(block);
    }
}

我们可以看到虽然我们对这些球只使用了一个材质球,但是颜色却是不一样的,是通过组件修改单个对象的颜色
在这里插入图片描述
但是,我们看到SRP Batcher不生效了,这样子虽然方便了,但是性能不行了
在这里插入图片描述

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

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

相关文章

第五章:Windows server加域

加入AD域&#xff1a;教学视频&#xff1a;https://www.bilibili.com/video/BV1xM4y1D7oL/?spm_id_from333.999.0.0首先我们选择一个干净的&#xff0c;也就是新建的没动过的Windows server虚拟机。我们将DNS改成域的ip地址&#xff0c;还要保证它们之间能ping的通&#xff0c…

详细解读ChatGPT:如何调用ChatGPT的API接口到官方例子的说明以及GitHub上的源码应用

文章目录1. 解读ChatGPT1.1 词语解释1.2 功能解读2. GitHub上ChatGPT的应用源码3. 调用ChatGPT的API4. 官方例子说明5. 集成ChatGPT自ChatGPT出来到如今&#xff0c;始终走在火热的道路上&#xff0c;如今日活用户破亿&#xff0c;他为何有如此大的魅力&#xff0c;深受广大用户…

opencv保存图片

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…

SIGIR22:User-controllable Recommendation Against Filter Bubbles

User-controllable Recommendation Against Filter Bubbles 摘要 推荐系统经常面临过滤气泡的问题&#xff1a;过度推荐基于用户特征以及历史交互的同质化项目。过滤气泡将会随着反馈循环增长&#xff0c;缩小了用户兴趣。现有的工作通常通过纳入诸如多样性和公平性等准确性之…

AcWing、第 90 场周赛:4806. 首字母大写、4807. 找数字、4808. 构造字符串(C++)

目录 4806. 首字母大写 题目描述&#xff1a; 实现代码&#xff1a; 4807. 找数字 题目描述&#xff1a; 实现代码&#xff1a; 回溯&#xff08;超时&#xff09;&#xff1a; 原理思路&#xff1a; 贪心&#xff1a; 原理思路&#xff1a; 4808. 构造字符串 问题…

53. 最大子数组和

文章目录题目描述暴力法动态规划法分治法参考文献题目描述 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 1&#xff1a; 输入&…

JavaScript中数组常用的方法

文章目录前言常用数组方法1、 join( )2、push&#xff08;&#xff09;与 pop&#xff08;&#xff09;3、shift&#xff08;&#xff09;与 unshift&#xff08;&#xff09;4、sort&#xff08;&#xff09;5、reverse&#xff08;&#xff09;6、slice&#xff08;&#xff…

代码随想录算法训练营第二十七天 | 93.复原IP地址,78.子集,90.子集II

一、参考资料复原IP地址题目链接/文章讲解&#xff1a;https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html 视频讲解&#xff1a;https://www.bilibili.com/video/BV1XP4y1U73i/子集题目链接/文章讲解&#xff1a;https://programmercarl.com/0078.…

乐观锁、雪花算法、MyBatis-Plus多数据源

乐观锁、雪花算法、MyBatis-Plus多数据源e>雪花算法2、乐观锁a>场景b>乐观锁与悲观锁c>模拟修改冲突d>乐观锁实现流程e>Mybatis-Plus实现乐观锁七、通用枚举a>数据库表添加字段sexb>创建通用枚举类型c>配置扫描通用枚举d>测试九、多数据源1、创建…

电子学会2022年12月青少年软件编程(图形化)等级考试试卷(二级)答案解析

青少年软件编程&#xff08;图形化&#xff09;等级考试试卷&#xff08;二级&#xff09; 一、单选题(共25题&#xff0c;共50分) 1. 一个骰子&#xff0c;从3个不同角度看过去的点数如图所示&#xff0c;请问5的对面是什么点数&#xff1f;&#xff08; &#xff09; …

数据库(单表查询)

素材&#xff1a; 表名&#xff1a;worker-- 表中字段均为中文&#xff0c;比如 部门号 工资 职工号 参加工作 等 CREATE TABLE worker ( 部门号 int(11) NOT NULL, 职工号 int(11) NOT NULL, 工作时间 date NOT NULL, 工资 float(8,2) NOT NULL, 政治面貌 varchar(10) NOT NUL…

【C语言技能树】程序环境和预处理

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

一文掌握,单机Redis、哨兵和Redis Cluster的搭建,建议收藏

本篇文章讲述了 Redis 单机环境、主备、哨兵 Sentinel 模式以及 Redis Cluster 集群模式下的操作步骤&#xff0c;关于这些操作我们没必要死记硬背&#xff0c;只需要总结下来&#xff0c;下次使用直接拿出来就好。建议当作操作手册收藏。安装单实例 Redis编译Redis1.下载Redis…

小白都能学会的红帽(RedHat8)RHEL8系统安装实战

文章目录前言一. 实验环境二. 安装虚拟机三. 安装操作系统四. 系统安装成功后的操作总结前言 本文是应一位大佬的提议&#xff0c;建议我写写红帽系列&#xff0c;centos8已经不维护了&#xff0c;centos7 维护到2024年6月30日&#xff0c; 也就是明年的事情了&#xff0c;所以…

【Flutter入门到进阶】Dart基础篇---基于对比Java学习Dart

1 Dart语言特性 1.1 简介 1.1.1 说明 2011年10月&#xff0c;在丹麦召开的 GOTO 大会上&#xff0c;Google 发布了一种新的编程语言 Dart 。如同 Kotlin 和 Swift 的出现&#xff0c;分别是为了解决 Java 和 Objective-C 在编写应用程序的一些实际问题一样&#xff0c;Dart 的…

算法笔记(二)—— 认识N(logN)的排序算法

递归行为的时间复杂度估算 整个递归过程是一棵多叉树&#xff0c;递归过程相当于利用栈做了一次后序遍历。 对于master公式&#xff0c;T(N)表明母问题的规模为N&#xff0c;T(N/b)表明每次子问题的规模&#xff0c;a为调用次数&#xff0c;加号后面表明&#xff0c;除去调用之…

八股初始:RocketMQ

一、消息队列介绍 消息队列是什么 对于 MQ 来说&#xff0c;其实不管是 RocketMQ、Kafka 还是其他消息队列&#xff0c;它们的本质都是&#xff1a;一发一存一消费。 将 MQ 掰开了揉碎了来看&#xff0c;都是「一发一存一消费」&#xff0c;再直白点就是一个「转发器」。生产…

记一次上环境获取资源失败的案例

代码结构以及资源位置 测试代码 RestController RequestMapping("/json") public class JsonController {GetMapping("/user/1")public String queryUserInfo() throws Exception {// 如果使用全路径, 必须使用/开头String path JsonController.class.ge…

《计算机组成与设计》03. 计算机的算术运算

文章目录整数运算加法与减法乘法普通十进制乘法硬件中实现步骤例子乘法器的设计除法普通十进制除法硬件中实现步骤例子除法器的设计浮点数运算科学计数法、规格化数浮点表示单精度浮点数双精度浮点数移码表示法IEEE 754指数偏移值&#xff08;exponent bias&#xff09;规格化的…

计算机网络4:计算机网络体系结构

目录计算机网络体系结构1.网络模型2.每一层的代表含义2.1 OSI7层模型2.2 五层协议2.3 TCP/IP 四层协议3.数据在各层之间的传输过程4.为什么要进行分层计算机网络体系结构 1.网络模型 2.每一层的代表含义 2.1 OSI7层模型 &#xff08;1&#xff09;物理层&#xff1a;比特流–…