动态合批、静态合批与 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次批处理

  1. 默认情况下,UNITY_INSTANCED_ARRAY_SIZE 定义为 500,可以使用 #pragma instancing_options maxcount 编译器指令覆盖它
  2. 尽管台式机的最大容量为 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 实例化相关推荐

  1. Unity3D学习笔记6——GPU实例化(1)

    文章目录 1. 概述 2. 详论 3. 参考 1. 概述 在之前的文章中说到,一种材质对应一次绘制调用的指令.即使是这种情况,两个三维物体使用同一种材质,但它们使用的材质参数不一样,那么最终仍然会造成 ...

  2. Unity3D学习笔记8——GPU实例化(3)

    文章目录 1. 概述 2. 详论 2.1. 自动实例化 2.2. MaterialPropertyBlock 3. 参考 1. 概述 在前两篇文章<Unity3D学习笔记6--GPU实例化(1) ...

  3. echart 实例显示位置_技术分享:如何在Unity中使用实例化渲染?

    编者按 在日常开发中,通常说到优化.提高帧率时,总是会提到批量渲染.之前简单总结了静态合批(点此查看全文)以及动态合批(点此查看全文),这次作者将和大家聊聊实例化渲染. 作者:枸杞忧天 (本文内容由公 ...

  4. U3D 文档 GPU INSTANCING

    https://docs.unity3d.com/Manual/GPUInstancing.html 归纳总结: 一,快速使用U3D 的GPU 实例化功能 1,选择一个shader,勾选 enable ...

  5. Unity中的静态合批、动态合批、GPU Instance 以及SRP Batching

    文章目录 Unity中的静态合批.动态合批.GPU Instance 以及SRP Batching 四种合批简介 GPU instancing static Batching Dynamic batc ...

  6. Unity GPU Instance踩坑记录

    Unity GPU Instance踩坑记录 Unity中GPUInstance主要有两种:一种是unity自动进行的,或者调用Graphics.DrawMeshInstancedIndirect等A ...

  7. 由浅到浅入门批量渲染(三)

    上回简单总结了一下动态合批,这次我们继续说说实例化渲染. | 实例化渲染 当我们想要呈现这样的场景:一片茂密的森林.广阔的草原或崎岖的山路时,会发现在这些场景中存在大量重复性元素:树木.草和岩石. 仙 ...

  8. 技术分享 |《原神》部分渲染效果分析

    一.光与影 游戏中的影子大致可以区分为以下几类: 1.场景的静态烘焙阴影 游戏中的场景应该主要还是基于lightmap实现的静态阴影.对于植被并没有计算lightmap,其实我感觉可以在草等植被的下方 ...

  9. Unity 2018.3地形功能更新介绍

    Unity 2018.3将更新地形系统,此次更新涉及改进的工具和利用GPU实现的更高性能.它还添加了HDRP高清晰渲染管线和LWRP轻量级渲染管线的支持,同时兼容内置渲染管线和现有Unity地形系统. ...

最新文章

  1. keras 的 example 文件 imdb_bidirectional_lstm.py 解析
  2. 年中盘点:2021年最炙手可热的10家AI初创公司
  3. 五个角度解释深度学习中 Batch Normalization为什么效果好?
  4. AlphaFold证明人工智能可以解决基本的科学问题
  5. 二极管7种应用电路详解之二
  6. python超级计算机_Python高性能计算库——Numba
  7. php如何压缩txt文件怎么打开,PHP-压缩txt文件,同时保持文件扩展名
  8. ISP运营商实验室测试机架拓扑搭建经验分享
  9. LaneAF | 利用Affinity Field聚类进行车道线实例分割
  10. IIS部署VUE刷新404问题如何解决?
  11. nagios监控服务短信报警开发及部署细节
  12. 安装python3-dev_ubuntu16.04安装python3.7
  13. 树形DP Codeforces Round #135 (Div. 2) D. Choosing Capital for Treeland
  14. LGame-0 3 Android与JavaSE游戏引擎 正式发布,新增SRPG制作模块
  15. 动态表情与超链接制作
  16. 2021年ABAQUS仿真技术竞赛获奖作品集来啦
  17. Unity中GPUInstance详解
  18. ajax向数据库中添加数据,用jqueryajax在数据库中插入数据
  19. OpenJDK8维护暂停?272迟迟不发布
  20. 二级计算机等级证水平高吗,全国计算机水平一级高还是二级高

热门文章

  1. python基础知识-python基础知识总结
  2. python是什么课程-吐血整理!程序员喜爱的13个免费Python课程
  3. 55岁自学python编程-热门专业三年一换?奥鹏教育解析编程还能火多久
  4. python新手入门代码-新手必看:手把手教你入门 Python
  5. python怎么读取excel-python怎么读取excel中的数值
  6. createbitmap 旋转90度_如何旋转的位图90度
  7. win102004优化_windows 10新版2004和1909该如何选择
  8. Redis基础学习(2)
  9. 【Redis笔记】数据结构和对象:字典
  10. 卸载linux grub rescue,Grub Rescue 修复方法