GPU Instancing原理:
GPU Instancing条件:①使用相同材质②使用相同Mesh③正在视野中
GPU Instancing的适用范围:①大规模小物件渲染,同时有需要表现物件间的异样性,如花草
GPU Instancing能优化性能的原因:
①降低DrawCall
②降低SetPass calls
GPU Instancing的缺点:
①比起静态/动态合批,GPU Instancing可以规避合并Mesh导致的内存与性能上升的问题,但是由于场景中所有符合该合批条件的渲染物体的信息每帧都要被重新创建,并放入"统一/常量缓冲区"中,而碍于缓存区的大小限制,每一个Constant Buffer的大小要严格限制(不得大于64k)
GPU Instancing失败的情况:
①缩放为负值
②代码动态改动材质变量
③受限于常量缓冲区在不同设备上的大小的上限
④只支持一盏实时光,要在多个光源的情况下使用实例化,只能切换到延迟渲染路径,为了能够让这套机制运作起来,请将所需的编译器指令添加到我们着色器的延迟渲染通道中
GPU Instancing中断的情况:
①位置不相邻且中间夹杂着不同材质的其他物体
②一个批次超过1023个物体
③优先静态批处理,然后才到GPU Instancing
下面是GPU Instancing的实操
①先创建一个Material,并勾选"Enable GPU Instancing"
②搭建一个简单的场景,如下图
③脚本Spawner的代码内容如下
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class ObjData
{
public Vector3 pos;
public Vector3 scale;
public Quaternion rot;
public Color clr;
public Material mtrl;
public Matrix4x4 matrix
{
get
{
return Matrix4x4.TRS(pos, rot, scale);
}
}
}
public static class Extensions
{
public static Vector4 ToVector4(this Color obj)
{
return new Vector4(obj.r, obj.g, obj.b, obj.a);
}
}
public class Spawner : MonoBehaviour
{
public Material mtrlBatched;//材质
public Mesh mesh;//网格
public int count;//生成的实例数量
public Vector3 maxPos;//生成位置的范围
private List batch = new List();//用来存要生成的实例的数据
// Start is called before the first frame update
void Start()
{
for (int i = 0; i < count; i++)
{
var obj = new ObjData()
{
pos = new Vector3(
UnityEngine.Random.Range(-maxPos.x, maxPos.x),
UnityEngine.Random.Range(-maxPos.y, maxPos.y),
UnityEngine.Random.Range(-maxPos.z, maxPos.z)
),
rot = Quaternion.identity,
scale = Vector3.one * 2,
clr = UnityEngine.Random.ColorHSV(),
};
obj.mtrl = Instantiate(mtrlBatched);
obj.mtrl.SetColor("_Color", obj.clr);
batch.Add(obj);
}
}
List curBatch = new List();
private void DrawInstancedBatched()
{
for (int i = 0; i < batch.Count; i++)
{
var obj = batch[i];
curBatch.Add(obj);
if (curBatch.Count == 1023 || i == batch.Count - 1)
{
MaterialPropertyBlock props = new MaterialPropertyBlock();
props.SetVectorArray("_Color",curBatch.Select(x=>x.clr.ToVector4()).ToList());
Graphics.DrawMeshInstanced(mesh, 0, mtrlBatched, curBatch.Select(x => x.matrix).ToList(), props);
curBatch.Clear();
}
}
}
// Update is called once per frame
void Update()
{
DrawInstancedBatched();
}
}
④点击运行可以看到Stats界面中,Batches为148,Saved by batching为49854,SetPass calls为3,优化效果非常不错