Unity3D学习笔记8——GPU实例化(3)
文章目录
- 1. 概述
- 2. 详论
- 2.1. 自动实例化
- 2.2. MaterialPropertyBlock
- 3. 参考
1. 概述
在前两篇文章《Unity3D学习笔记6——GPU实例化(1)》《Unity3D学习笔记6——GPU实例化(2)》分别介绍了通过简单的顶点着色器+片元着色器,以及通过表面着色器实现GPU实例化的过程。而在Unity的官方文档Creating shaders that support GPU instancing里,也提供了一个GPU实例化的案例,这里就详细论述一下。
2. 详论
2.1. 自动实例化
一个有意思的地方在于,Unity提供的标准材质支持自动实例化,而不用像《Unity3D学习笔记6——GPU实例化(1)》《Unity3D学习笔记6——GPU实例化(2)》那样额外编写脚本和Shader。并且,会自动将transform,也就是模型矩阵作为每个实例的属性。
照例,还是编写一个脚本挂到一个空的GameObject对象上:
using UnityEngine;public class Note8Main : MonoBehaviour
{public Mesh mesh;public Material material;public int instanceCount = 5000;// Start is called before the first frame updatevoid Start(){MaterialPropertyBlock props = new MaterialPropertyBlock();for (int i = 0; i < instanceCount; i++){GameObject go = new GameObject();go.name = i.ToString();MeshFilter mf = go.AddComponent<MeshFilter>();mf.mesh = mesh;MeshRenderer mr = go.AddComponent<MeshRenderer>();mr.material = material;go.transform.position = Random.insideUnitSphere * 5;go.transform.eulerAngles = new Vector3(Random.Range(0.0f, 90.0f), Random.Range(0.0f, 90.0f), Random.Range(0.0f, 90.0f));float s = Random.value;go.transform.localScale = new Vector3(s, s, s);go.transform.parent = gameObject.transform;}}// Update is called once per framevoid Update(){}
}
这个脚本的意思是,给挂接的GameObject下新建很多GameObject,它们使用我们传入的Mesh和Material,但是位置、姿态和大小是随机的。传入的Mesh使用Unity自带的胶囊体,Material使用Unity的标准材质。运行结果如下:
这个时候Unity还没有自动实例化,打开Frame Debug就可以看到:
这个时候我们可以在使用的材质上勾选打开实例化的选项:
再次运行,就会在Frame Debug看到Unity实现了自动实例化,绘制的批次明显减少,并且性能会有所提升:
可以看到确实是自动进行实例化绘制了,但是这种方式却似乎存在实例化个数的上限,所有的实例化数据还是分成了好几个批次进行绘制。与《Unity3D学习笔记6——GPU实例化(1)》《Unity3D学习笔记6——GPU实例化(2)》提到的通过底层接口Graphic进行实例化绘制相比,效率还是要低一些。
2.2. MaterialPropertyBlock
自动实例化只能将transform,也就是模型矩阵作为每个实例的属性。如果需要增加自己的实例属性,就需要使用MaterialPropertyBlock,也就是材质属性块。
修改上面的脚本:
using UnityEngine;public class Note8Main : MonoBehaviour
{public Mesh mesh;public Material material;public int instanceCount = 5000;// Start is called before the first frame updatevoid Start(){MaterialPropertyBlock props = new MaterialPropertyBlock();for (int i = 0; i < instanceCount; i++){GameObject go = new GameObject();go.name = i.ToString();MeshFilter mf = go.AddComponent<MeshFilter>();mf.mesh = mesh;MeshRenderer mr = go.AddComponent<MeshRenderer>();mr.material = material;float r = Random.Range(0.0f, 1.0f);float g = Random.Range(0.0f, 1.0f);float b = Random.Range(0.0f, 1.0f);props.SetColor("_Color", new Color(r, g, b));mr.SetPropertyBlock(props);go.transform.position = Random.insideUnitSphere * 5;go.transform.eulerAngles = new Vector3(Random.Range(0.0f, 90.0f), Random.Range(0.0f, 90.0f), Random.Range(0.0f, 90.0f));float s = Random.value;go.transform.localScale = new Vector3(s, s, s);go.transform.parent = gameObject.transform;}}// Update is called once per framevoid Update(){}
}
脚本使用的材质,其使用的Shader如下,可以直接在Standard Surface Shader的基础上改:
Shader "Custom/HiddenSurfaceIntanceShader"
{Properties{_Color ("Color", Color) = (1,1,1,1)_MainTex ("Albedo (RGB)", 2D) = "white" {}_Glossiness ("Smoothness", Range(0,1)) = 0.5_Metallic ("Metallic", Range(0,1)) = 0.0}SubShader{Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM// Physically based Standard lighting model, and enable shadows on all light types#pragma surface surf Standard fullforwardshadows// Use shader model 3.0 target, to get nicer looking lighting#pragma target 3.0sampler2D _MainTex;struct Input{float2 uv_MainTex;};half _Glossiness;half _Metallic;//fixed4 _Color;// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.// #pragma instancing_options assumeuniformscalingUNITY_INSTANCING_BUFFER_START(Props)// put more per-instance properties hereUNITY_DEFINE_INSTANCED_PROP(fixed4, _Color)UNITY_INSTANCING_BUFFER_END(Props)void surf (Input IN, inout SurfaceOutputStandard o){// Albedo comes from a texture tinted by color//fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * UNITY_ACCESS_INSTANCED_PROP(Props, _Color);o.Albedo = c.rgb;// Metallic and smoothness come from slider variableso.Metallic = _Metallic;o.Smoothness = _Glossiness;o.Alpha = c.a;}ENDCG}FallBack "Diffuse"
}
关键的代码在于Unity内置宏UNITY_INSTANCING_BUFFER_START和UNITY_INSTANCING_BUFFER_END、UNITY_DEFINE_INSTANCED_PROP定义了实例化属性,在着色器中,通过内置宏UNITY_ACCESS_INSTANCED_PROP来获取这个属性值。这个实例化属性也就是脚本代码中MaterialPropertyBlock传入的颜色值。
查看Unity Shader源代码,这四个用于实例化的宏封装的是一个cbuffer数组,cbuffer就是hlsl的常量缓冲区:
#define UNITY_INSTANCING_CBUFFER_SCOPE_BEGIN(name) cbuffer name {#define UNITY_INSTANCING_CBUFFER_SCOPE_END }#define UNITY_INSTANCING_BUFFER_START(buf) UNITY_INSTANCING_CBUFFER_SCOPE_BEGIN(UnityInstancing_##buf) struct {#define UNITY_INSTANCING_BUFFER_END(arr) } arr##Array[UNITY_INSTANCED_ARRAY_SIZE]; UNITY_INSTANCING_CBUFFER_SCOPE_END
#define UNITY_DEFINE_INSTANCED_PROP(type, var) type var;
#define UNITY_ACCESS_INSTANCED_PROP(arr, var) arr##Array[unity_InstanceID].var
运行的结果如下:
可以看到除了纹理,每一个胶囊体还获取了随机赋予给材质的颜色,也就是我们设置的颜色成为了实例化属性数据。MaterialPropertyBlock主要由Graphics.DrawMesh和Renderer.SetPropertyBlock使用,在希望绘制具有相同材质,但属性略有不同的多个对象时可使用它。
个人认为使用MaterialPropertyBlock自动实例化性能比不上使用Graphics.DrawMeshInstancedIndirect(),但是它有个优点是实例化的要求没那么高,Graphics.DrawMeshInstancedIndirect()要求使用同一mesh,同一贴图;但是MaterialPropertyBlock没这个要求,只要是同一材质,任何属性不一样都可以用,在减少绘制批次的同时还能减少材质的个数。
3. 参考
- 《Unity3D学习笔记6——GPU实例化(1)》
- 《Unity3D学习笔记6——GPU实例化(2)》
- Creating shaders that support GPU instancing
- MaterialPropertyBlock
具体实现代码
Unity3D学习笔记8——GPU实例化(3)相关推荐
- Unity3D学习笔记6——GPU实例化(1)
文章目录 1. 概述 2. 详论 3. 参考 1. 概述 在之前的文章中说到,一种材质对应一次绘制调用的指令.即使是这种情况,两个三维物体使用同一种材质,但它们使用的材质参数不一样,那么最终仍然会造成 ...
- Unity3D 学习笔记3——了解U3D引擎的操作面板和各种工具
Unity3D 学习笔记3--了解U3D引擎的操作面板和各种工具 在完成了Unity的安装破解之后,我们接下来要做的当前是启动这个引擎,然后学会如何去使用它为我们提供的各种工具,这也是上手任何一个软件 ...
- Unity3D 学习笔记4 —— UGUI+uLua游戏框架
Unity3D 学习笔记4 -- UGUI+uLua游戏框架 使用到的资料下载地址以及基础知识 框架讲解 拓展热更过程 在这里我们使用的是uLua/cstolua技术空间所以提供的UGUI+uLua的 ...
- unity3d 学习笔记四 skybox(天空盒) light(光源) halo(光晕)
Unity3D学习笔记(四)天空.光晕和迷雾 六年前第一次接触<魔兽世界>的时候,被其绚丽的画面所折服,一个叫做贫瘠之地的地方,深深印在我的脑海里.当时在艾泽拉斯大陆还不能使用飞行坐骑,试 ...
- Unity3D学习笔记:粒子特效参数
Unity3D学习笔记:粒子特效参数含义 转载 https://blog.csdn.net/asd237241291/article/details/8433534 粒子特效 粒子系统检视面板 初始化 ...
- Unity3D学习笔记12——渲染纹理
文章目录 1. 概述 2. 详论 3. 问题 1. 概述 在文章<Unity3D学习笔记11--后处理>中论述了后处理是帧缓存(Framebuffer)技术实现之一:而另外一个帧缓存技术实 ...
- Unity3D学习笔记(二、小球滚动吃金币)
源码:键盘方向键操作小球滚动吃金币Unity3D源码 下篇:Unity3D学习笔记(三.小球跑酷) 一.颜色材质球创建 二.Plane平板创建 三.围墙 同理二,新建Cube,并调整属性,设立围墙 ...
- Unity3D学习笔记3——Unity Shader的初步使用
文章目录 1. 概述 2. 详论 2.1. 创建材质 2.2. 着色器 2.2.1. 名称 2.2.2. 属性 2.2.3. SubShader 2.2.3.1. 标签(Tags) 2.2.3.2. ...
- Unity3D学习笔记之九为场景添加细节(二)
上节为场景中添加了第一块带有碰撞器的石头,本节我们来利用Prefab,将场景细节都添加进去,并且做的更完善. 这一系列教程以及素材均参考自人人素材翻译组出品的翻 ...
最新文章
- 【转】WebApi 身份认证解决方案:Basic基础认证
- python中random库_python标准库之random模块
- android卫星菜单中间,Android卫星菜单:android-satellite-menu
- SMT32H743+CubeMX-配置MPU后,在Keil上的程序卡死
- 数据类型oracle,oracle的数据类型
- 淄博计算机文化基础试卷,我校顺利举办省高校计算机文化基础考试并获佳绩
- 日志的log中如何输出变量_如何在kubernetes中优雅的输出日志
- /dev/null脚本中作用
- Android将库导入到build.gradle
- 洛谷P4012 深海机器人问题(费用流)
- php数组中去掉空格,php数组如何去除空格
- 下载蓝盒插件_chrome迅雷下载插件-迅雷下载支持插件下载 v3.1官方版--pc6下载站...
- 使用daemontools监控zookeeper,storm等进程
- 【通俗理解】显著性检验,T-test,P-value
- 电驱系列:直流无刷马达(不用芯片,独立元器件搭建)
- 【MySql】mysql之用户管理
- 不改一行代码,将微信小程序转成商业App?
- 春风桃李花开夜,秋雨梧桐叶落时——python面向对象三大特征(封装、继承、多态)
- 【OpenCV+Python实现医学影像拼接(一)】
- Duang! 工商银行也要做电商?