UnityShader33:GPU 实例化
动态合批、静态合批与 GPU 实例化(GPU Instancing)的本质都是通过减少 CPU 对 GPU 绘制请求(Draw Call)的次数,以达到提高性能的目的
对相于合批,GPU 实例化是相对独立的一个功能,之前有一篇 OpenGL 的文档可以参考,这篇主要记录 Unity 下如何去实现 GPU 实例化
一、再提 GPU 实例化
GPU 实例化只提交一个模型网格,然后绘制多次,每次绘制的网格属性都可以不一样:包括缩放、位置、颜色等等,即材质球虽然相同但属性可以各有各的区别
如果想要自己的 Shader 支持 GPU 实例化,需要先在对应的自定义 Shader GUI 中添加开关:
void Instancing()
{m_MaterialEditor.EnableInstancingField();
}
之后就和 UnityStandard 一样,可以勾选材质的 Enable GPU Instancing 属性
1.1 自定义 Shader
需要添加预编译指令:
#pragma multi_compile_instancing
之后在顶点数据和片段数据中添加实例化 ID:
struct appdata_img
{//……UNITY_VERTEX_INPUT_INSTANCE_ID
};struct v2f_img
{//……UNITY_VERTEX_INPUT_INSTANCE_ID
};
和绘制单个对象不同的是,GPU Instancing 顶点着色器中不再只有单一的 unity_ObjectToWorld 矩阵,而是一个 unity_ObjectToWorld 矩阵数组,毕竟每个对象的位置属性必然不会一样
宏 UNITY_SETUP_INSTANCE_ID(v) 帮我们做了很多事情,其中就有拿矩阵数据去替代掉 unity_ObjectToWorld 的操作,因此在顶点着色器中要引用它,并把它放到最前面:
v2f vert(appdata v)
{UNITY_SETUP_INSTANCE_ID(v)v2f o;//……return o;
}
好了,到此为止就可以在 Game 视图中看到效果了:绘制 10000 个相同材质的简单物体只有 25 个 Batchs,这可以类比 DrawCall
然而也可以看出:5000 个物体,25个 Batches,去除天空盒之后也并不是一批渲染所有的物体:这取决于 GPU 内存缓冲区(在 Direct3D 中称为常量缓冲区)的容量限制
假设台式机 GPU 每个缓冲区的大小限制为 64KB,一个矩阵 16 x 4 = 64 个字节,算上法线转换矩阵共128字节,受于内存的2进制计量,可以得出最大批处理大小为 64000/128 = 500,渲染5000个物体需要10次批处理
- 默认情况下,UNITY_INSTANCED_ARRAY_SIZE 定义为 500,可以使用 #pragma instancing_options maxcount 编译器指令覆盖它
- 尽管台式机的最大容量为 64KB,但大多数移动设备的最大容量仅为 16KB,Unity 通过在针对 OpenGL ES 3,OpenGL Core 或 Metal 时将最大值除以四来解决此问题
上面的流程,对于每个 PASS 都是一样的,例如 Shadow Pass
1.2 混合材质与材质属性块
如果想要支持每个物体的材质属性都不同,就需要用到材质属性块:
MaterialPropertyBlock properties = new MaterialPropertyBlock();
properties.SetColor("_Color", new Color(Random.value, Random.value, Random.value)
);
t.GetComponent<MeshRenderer>().SetPropertyBlock(properties);
接下来是 Shader:需要了解下面几个关键宏:
- UNITY_TRANSFER_INSTANCE_ID(v, o):当需要在在片段着色器中访问每个 Instance 独有的属性时,用于在顶点着色器中将 Instance ID 从输入结构拷贝至输出结构中
- UNITY_SETUP_INSTANCE_ID(v):目的是让 Instance ID 在 Shader 函数里也能够被访问到,并且重载正确的矩阵数据(通过内部的 UnitySetupCompoundMatrices() 方法),需要在着色器的最前面调用
- UNITY_INSTANCING_CBUFFER_START(name) / UNITY_INSTANCING_CBUFFER_END(name):用于定义 Constant Buffer,每个 Instance 独有的属性必须定义在一个遵循特殊命名规则的 Constant Buffer 中
UNITY_DEFINE_INSTANCED_PROP(type, name):第一个参数为属性类型,第二个参数为属性名字,该宏会定义一个 Uniform 数组
UNITY_ACCESS_INSTANCED_PROP(bufferName, name):第一个参数为属性所在缓冲区名字,第二个参数为属性名字,该宏会使用 Instance ID 作为索引到 Uniform 数组中去取当前Instance 对应的数据
关于 UNITY_INSTANCING_CBUFFER_START,还有一个宏是 CBUFFER_START,Direct3D 11后所有着色器变量都位于 Constant Buffers(在 openGL 中是 UBO),对于 Unity 大部分的内置变量已经分组,我们自己的着色器变量也可以放在单独的 Constant Buffers 中
以颜色这个属性为例,对应的 Shader 修改如下:
1. 定义颜色属性:
UNITY_INSTANCING_BUFFER_START(TestColor)
UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
UNITY_INSTANCING_BUFFER_END(TestColor)
2. 顶点着色器:
v2f vert(appdata v)
{UNITY_SETUP_INSTANCE_ID(v)v2f o;UNITY_INITIALIZE_OUTPUT(v2f, o); //将v2f变量数据初始化为零UNITY_TRANSFER_INSTANCE_ID(v, o); //将 Instance ID 从输入结构拷贝至输出结构中//……
}
3. 修改使用到属性的地方:
float3 GetAlbedo(v2f i)
{float3 albedo = tex2D(_MainTex, i.uv.xy).rgb * UNITY_ACCESS_INSTANCED_PROP(TestColor, _Color).rgb;return albedo;
}
float GetAlpha(v2f i)
{float alpha = tex2D(_MainTex, i.uv.xy).a * UNITY_ACCESS_INSTANCED_PROP(TestColor, _Color).a;return alpha;
}
搞定!
参考文章:
- https://zhuanlan.zhihu.com/p/356211912
- https://catlikecoding.com/unity/tutorials/rendering/part-19/
- https://zhuanlan.zhihu.com/p/34499251
- https://docs.unity3d.com/Manual/SL-BuiltinMacros.html
- https://zhuanlan.zhihu.com/p/106234207
UnityShader33:GPU 实例化相关推荐
- Unity3D学习笔记6——GPU实例化(1)
文章目录 1. 概述 2. 详论 3. 参考 1. 概述 在之前的文章中说到,一种材质对应一次绘制调用的指令.即使是这种情况,两个三维物体使用同一种材质,但它们使用的材质参数不一样,那么最终仍然会造成 ...
- Unity3D学习笔记8——GPU实例化(3)
文章目录 1. 概述 2. 详论 2.1. 自动实例化 2.2. MaterialPropertyBlock 3. 参考 1. 概述 在前两篇文章<Unity3D学习笔记6--GPU实例化(1) ...
- echart 实例显示位置_技术分享:如何在Unity中使用实例化渲染?
编者按 在日常开发中,通常说到优化.提高帧率时,总是会提到批量渲染.之前简单总结了静态合批(点此查看全文)以及动态合批(点此查看全文),这次作者将和大家聊聊实例化渲染. 作者:枸杞忧天 (本文内容由公 ...
- U3D 文档 GPU INSTANCING
https://docs.unity3d.com/Manual/GPUInstancing.html 归纳总结: 一,快速使用U3D 的GPU 实例化功能 1,选择一个shader,勾选 enable ...
- Unity中的静态合批、动态合批、GPU Instance 以及SRP Batching
文章目录 Unity中的静态合批.动态合批.GPU Instance 以及SRP Batching 四种合批简介 GPU instancing static Batching Dynamic batc ...
- Unity GPU Instance踩坑记录
Unity GPU Instance踩坑记录 Unity中GPUInstance主要有两种:一种是unity自动进行的,或者调用Graphics.DrawMeshInstancedIndirect等A ...
- 由浅到浅入门批量渲染(三)
上回简单总结了一下动态合批,这次我们继续说说实例化渲染. | 实例化渲染 当我们想要呈现这样的场景:一片茂密的森林.广阔的草原或崎岖的山路时,会发现在这些场景中存在大量重复性元素:树木.草和岩石. 仙 ...
- 技术分享 |《原神》部分渲染效果分析
一.光与影 游戏中的影子大致可以区分为以下几类: 1.场景的静态烘焙阴影 游戏中的场景应该主要还是基于lightmap实现的静态阴影.对于植被并没有计算lightmap,其实我感觉可以在草等植被的下方 ...
- Unity 2018.3地形功能更新介绍
Unity 2018.3将更新地形系统,此次更新涉及改进的工具和利用GPU实现的更高性能.它还添加了HDRP高清晰渲染管线和LWRP轻量级渲染管线的支持,同时兼容内置渲染管线和现有Unity地形系统. ...
最新文章
- keras 的 example 文件 imdb_bidirectional_lstm.py 解析
- 年中盘点:2021年最炙手可热的10家AI初创公司
- 五个角度解释深度学习中 Batch Normalization为什么效果好?
- AlphaFold证明人工智能可以解决基本的科学问题
- 二极管7种应用电路详解之二
- python超级计算机_Python高性能计算库——Numba
- php如何压缩txt文件怎么打开,PHP-压缩txt文件,同时保持文件扩展名
- ISP运营商实验室测试机架拓扑搭建经验分享
- LaneAF | 利用Affinity Field聚类进行车道线实例分割
- IIS部署VUE刷新404问题如何解决?
- nagios监控服务短信报警开发及部署细节
- 安装python3-dev_ubuntu16.04安装python3.7
- 树形DP Codeforces Round #135 (Div. 2) D. Choosing Capital for Treeland
- LGame-0 3 Android与JavaSE游戏引擎 正式发布,新增SRPG制作模块
- 动态表情与超链接制作
- 2021年ABAQUS仿真技术竞赛获奖作品集来啦
- Unity中GPUInstance详解
- ajax向数据库中添加数据,用jqueryajax在数据库中插入数据
- OpenJDK8维护暂停?272迟迟不发布
- 二级计算机等级证水平高吗,全国计算机水平一级高还是二级高
热门文章
- python基础知识-python基础知识总结
- python是什么课程-吐血整理!程序员喜爱的13个免费Python课程
- 55岁自学python编程-热门专业三年一换?奥鹏教育解析编程还能火多久
- python新手入门代码-新手必看:手把手教你入门 Python
- python怎么读取excel-python怎么读取excel中的数值
- createbitmap 旋转90度_如何旋转的位图90度
- win102004优化_windows 10新版2004和1909该如何选择
- Redis基础学习(2)
- 【Redis笔记】数据结构和对象:字典
- 卸载linux grub rescue,Grub Rescue 修复方法