IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> UnityShader33:GPU 实例化 -> 正文阅读

[游戏开发]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次批处理

  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;
}

搞定!

参考文章:

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 14:32:32  更:2021-07-22 14:35:03 
 
开发: 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年5日历 -2024/5/20 15:50:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码