| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 游戏开发 -> URP下SRPBatcher,GPUInstancing,动态合批,静态合批 -> 正文阅读 |
|
[游戏开发]URP下SRPBatcher,GPUInstancing,动态合批,静态合批 |
SRPBatcher:适用前提:????????需要是同一个shader,可以是不同的材质球,Shader代码必须兼容SRP Batcher。 ????????但是不支持用材质球属性块(MaterialPropertyBlock) ? ? ? ??渲染的物体必须是一个mesh或者skinned?mesh。不能是粒子。 效果:? ? ? ? 可以有效降低SetPassCall的数目,用于CPU性能优化 优化原理:????????1.在过去的渲染架构中,Unity采取对一个材质分配一个CBuffer(or 一个Pass,这不是重点),这个CBuffer 包括shader里的显性的参数(你自己定义的uniform参数)和隐性的参数(unity固定的uniform modelMatrix,modelviewMatrix之类。),所以每一次drawcall,要更新这个CBuffer ????????2.在SRP渲染架构中,Unity采取的策略是对一个材质分配一个半CBuffer,为什么是一个半呢?首先shader的显性参数分配到一个CBuffer里,shader的隐性参数则是N个物体共享一个CBuffer。比如一个shader 对应 10个物体,在SRP渲染架构中,一共分配了11个CBuffer,其中10个分别存这10个物体材质中定义的显性参数。然后分配一个大的共享CBuffer,把这10个物体的modelMatrix这类隐性参数都放在一起。 ????????乍一看这不是负优化吗?老架构更新10个CBuffer,你现在更新11个。 ????????这个策略叫做动静分离,材质的显性参数大部分都是低频更新的(你总不能一个游戏所有的材质参数每桢都改变吧),所以在理想情况下,这10个放显性参数的CBuffer就基本不修改。而modelMatrix之类的隐性参数是高频更新的,很多模型会动来动去。他们被批量放在一个CBuffer里,一次更新可以更新一片。 如下图:大型的共享CBuffer和每个材质自己的CBuffer都有各自专门的代码进行更新,大部分情况只需要更新大型共享CBuffer,从而降低了一帧内SetPassCall的数目 ?标准流程和SRPBatcher流程的区别: ?以上,据Unity官方宣传 SRP Batcher 可以取得 1.2~4 倍的 CPU渲染时间提升(仅提升CPU部分,不是渲染耗时提升这么多,还得看cpu瓶颈占多大比重) 如何让Shader支持SRPBatcher:1、必须声明所有内建引擎properties?在一个名为"UnityPerDraw"的CBUFFER里。
(URP内置的UnityInput.hlsl里自带更全面的代码。也就是说,如果你的代码有引用或间接引用UnityInput.hlsl,那就不用做这一步了。) 2、必须声明所有材质properties在一个名为"UnityPerMaterial"的CBUFFER里。
若需要配合GPUInstancing则需要改写为
GPUInstancing:适用前提:
效果:
原理:Unity会在运行时对于正在视野中的符合要求的所有对象,将其位置、缩放、uv偏移、lightmapindex等相关信息放到CBuffer(Constant Buffer)中,然后统一保存在显存中的“统一/常量缓冲器”中,当一个对象作为实例送入渲染流程时,在执行DrawCall操作后,根据传入的InstanceID从显存中取出当前实例对应的部分共享信息与从GPU常量缓冲器中取出对应对象的相关信息一并传递到下一渲染阶段,与此同时,不同的着色器阶段都可以从缓存区中直接获取到需要的常量,不用设置两次常量。总的来说就是一次性存入所有对象的公共信息到CBuffer,后续根据id来取,不用每次都发数据到GPU。 流程图: 如何使用GUPInstancing:
当需要创建海量mesh的时候,一般不要用实例化游戏物体的方式,这样会比较消耗性能,推荐使用Graphics.DrawMeshInstanced来创建。 例子:
Graphics.DrawMeshInstanced()这方法还有两问题 1.一次最多画1023个元素,如果超出就会报错,所以需要将草进行分类管理。 2.它不提供裁切的功能,也就是说摄像机看不到的地方,这些草是不会被剔除掉的,依然会被渲染。 解决这个问题,为了避免运行时暴力的for循环来判断是否在视野内,我采取的方法是预先将场景分成20X20若干个格子(可根据游戏的可视范围而定)根据玩家的位置,始终只渲染周围9个格子内的草元素,这样将大幅度减少运行时for循环的次数。 如果每个草的顶点色是不一样的怎么办呢?可以用MaterialPropertyBlock来让同一个材质求有不同的属性 未完待续。。。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/27 18:32:27- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |