GPUInstancing的实现原理2
「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」。
作为一名优秀的开发者,对于技术的探求应该是永无止步的,如何让自己更进步,那就只有不停的学习,不停的充电.而这些都都是说起来容易做起来难,坚持才是难的地方 --蛙哈哈 书接上文 GPUInstancing的实现原理.
在拿到了InstanceID 之后,就要对不同的实例进行个性化的处理.
后面是unity对着三句宏定义的解释
UNITY_INSTANCING_BUFFER_START(Props) // 必须在特殊命名的常量缓冲区中定义每个实例的属性。使用这对宏来包装对每个实例唯一的属性。
UNITY_DEFINE_INSTANCED_PROP(float4, _Color) //用于根据类型和名称定义每个实例着色器的属性。在此示例中,_Color 属性是唯一的。
UNITY_INSTANCING_BUFFER_END(Props) // 必须在特殊命名的常量缓冲区中定义每个实例的属性。使用这对宏来包装对每个实例唯一的属性。
这三个宏定义的内容是:
#define UNITY_INSTANCING_BUFFER_START(buf) UNITY_INSTANCING_CBUFFER_SCOPE_BEGIN(UnityInstancing_##buf) struct {
#define UNITY_DEFINE_INSTANCED_PROP(type, var) type var;
#define UNITY_INSTANCING_BUFFER_END(arr) } arr##Array[UNITY_INSTANCED_ARRAY_SIZE]; UNITY_INSTANCING_CBUFFER_SCOPE_END
那么这三句宏定义在比如Direct3D 11 平台上的展开代码为:
cbuffer UnityInstancingProps{
float4 _Color[500];
}
上面代码使用UNITY_INSTANCING_BUFFER_START宏宣告要使用GPU多例化技术的变量,使用UNITY_DEFINE_INSTANCED_PROP宏声明_Color变量使用技术,使用UNITY_INSTANCING_BUFFER_END宏结束使用技术的宣告。
它定义了一个着色器的常量缓冲区,并定义了要使用的一些变量, 比如_Color, 每个实例都可以设置不同的颜色.
在这个实例真正渲染的时候,着色器根据当前的unity_InstanceID, 去获取到之前存在缓冲区里面的这个id的数据.
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
如何给每一个实例都设置上不同的颜色呢?
private void Start()
{
MaterialPropertyBlock props = new MaterialPropertyBlock();
MeshRenderer renderer;
for (int i = 0; i < 10000; i++)
{
var go = Instantiate(Go);
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));
renderer = go.GetComponent<MeshRenderer>();
renderer.SetPropertyBlock(props);
int x = Random.Range(1, 100);
int y = Random.Range(1, 100);
int z = Random.Range(1, 100);
go.transform.position = new Vector3(x, y, z);
}
// for (int i = 0; i < 10000; i++)
// {
// var go = Instantiate(Go);
// int x = Random.Range(1, 100);
// int y = Random.Range(1, 100);
// int z = Random.Range(1, 100);
// go.transform.position = new Vector3(x, y, z);
// float r = Random.Range(0.0f, 1.0f);
// float g = Random.Range(0.0f, 1.0f);
// float b = Random.Range(0.0f, 1.0f);
// var component = go.GetComponent<MeshRenderer>();
// component.material.color = new Color(r, g, b);
// }
}
直接去修改这个实例上的render的material的color 和去设置renderer的MaterialPropertyBlock是不一样的,后面会再出一节,来分析两者的区别.
最终效果 1万个球, batches只有213.