几种合批
SRP Batcher
a) 优化原理
通过ConstantBuffer将对象的基本信息存储在GPU上,减少CPU和GPU频繁的数据交互带来的性能损失。
b) 限制
- 需要使用可编程渲染管线,不支持内置渲染管线。
- 需要shader兼容。
c) 写法参考
Shader "Xxxx" { Properties { _BaseMap("Texture", 2D) = "white" {} //主贴图 _BaseColor("Tint Color", Color) = (1, 1, 1, 1) //混合颜色 _Specular("Specular", Color) = (1, 1, 1, 1) //高光反射颜色 } SubShader { //..... HLSLINCLUDE #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; float4 _BaseColor; float4 _Specular; CBUFFER_END ENDHLSL //..... Pass { //..... } } }
Dynamic Batcher
a) 优化原理
将不同物体上的Mesh合并成一个大的Mesh,由CPU作为一个批次提交给GPU,即由原来多个drawcall变成了一个drawcall。
b) 限制
- 参与合批的物体需要使用相同的材质(同一个材质的clone对象也不行)
- 单个Mesh不能超过225个顶点
- shader不能有多个pass
- 参与合批的对象只能受一个光照影响
- 收集合批时会有一定的cpu消耗
c) 建议
如果场景中的物体共享材质的情况比较少,建议关闭动态合批,这样可以减少cpu每帧检查哪些物体可以动态合批的消耗。
GPU Instance
a) 优化原理
不同物体的Mesh相同时,可以由CPU作为一个批次提交给GPU,由原来多个drawcall变成了一个drawcall,减少CPU和GPU之间的通信开销。
不同的物体变换矩阵,颜色,纹理等可以不同。
b) 限制
- 物体的Mesh要相同,且使用相同的材质
- shader要支持GPU Instancing
c) 写法参考
Shader "My/URP_GPUInst" { SubShader { Tags { "RenderPipeline" = "UniversalPipeline" "Queue" = "Geometry" //URP中不再决定渲染顺序 "RenderType" = "Opaque" } HLSLINCLUDE #pragma multi_compile_instancing //编译指令: 添加GPU实例化开关 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl" #define UNITY_MATRIX_M unity_ObjectToWorld //GPU实例化: 不同物体的变换矩阵, 使用索引访问 UNITY_INSTANCING_BUFFER_START(PerInstance) //GPU实例化: 不同物体的颜色, 使用索引访问 UNITY_DEFINE_INSTANCED_PROP(float4, _Color) UNITY_INSTANCING_BUFFER_END(PerInstance) ENDHLSL Pass { Tags { "LightMode" = "UniversalForward" } //渲染pass HLSLPROGRAM #pragma vertex vert #pragma fragment frag struct Attributes { //程序传入顶点着色器的数据 float4 positionOS : POSITION; //用模型空间顶点坐标填充该变量 UNITY_VERTEX_INPUT_INSTANCE_ID //每个物体都会分配一个索引 }; struct Varings { //顶点着色器传入片元着色器的数据 float4 positionCS : SV_POSITION; //该变量存放了裁剪空间的顶点坐标 UNITY_VERTEX_INPUT_INSTANCE_ID //GPU实例化会用到的索引 }; Varings vert(Attributes IN) { //顶点着色器 Varings OUT; UNITY_SETUP_INSTANCE_ID(IN); //GPU实例化分配索引 UNITY_TRANSFER_INSTANCE_ID(IN, OUT); VertexPositionInputs positionInputs = GetVertexPositionInputs(IN.positionOS.xyz); //顶点坐标从模型空间转其他空间 OUT.positionCS = positionInputs.positionCS; return OUT; } float4 frag(Varings IN) : SV_Target { //片元着色器(逐像素) UNITY_SETUP_INSTANCE_ID(IN); float4 c = UNITY_ACCESS_INSTANCED_PROP(PerInstance, _Color); return c; } ENDHLSL } } }
public class InstancedColor : MonoBehaviour { static int colorID = Shader.PropertyToID("_Color"); static MaterialPropertyBlock propertyBlock; [SerializeField] private Color color = Color.white; void Awake() { OnValidate(); } void OnValidate() { if (propertyBlock == null) propertyBlock = new MaterialPropertyBlock(); propertyBlock.SetColor(colorID, color); GetComponent<MeshRenderer>().SetPropertyBlock(propertyBlock); } }
优先级
SRP Batcher > GPU Instancing > Dynamic Batching
参考
【Unity Shader】在URP里写Shader(一):介绍-从Built-In到URP - 知乎
关于Unity四种合批技术详解_unity 合批-CSDN博客
Unity可编程渲染管线(SRP)教程:二、自定义着色器 - 知乎
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
2023-12-19 cpp环境搭建 - vs2017编译CMakeLists项目(Box2dLite)