您的位置:首页 > 移动开发 > Unity3D

[Unity3D]降低向Shader中传值的开销

2015-06-05 01:29 399 查看

摘要

Unity3D中提供了很多API用于向shader传值,这篇文章对比测试了两类不同的使用方法的性能。

正文

Unity3D中,通过C#代码向shader传值有两种方式。

一种是面向具体的material,另一种是面向所有的material。

以上两种方式分别对应下面两类API:

Material.SetXXX();

Shader.SetGlobalXXX();

例如,现在的需求是,需要每帧向shader传递一个offset、一个scale、和一个alpha。

普通的做法是:

在shader中添加:

float _Offset;
float _Scale;
float _Alpha;


在C#中通过以下方式进行传值:

Shader.SetGlobalFloat("_Offset", offset);
Shader.SetGlobalFloat("_Scale", scale);
Shader.SetGlobalFloat("_Alpha", alpha);


以上写法可以正常工作,但是更好的方法是下面这种:

Shader中:

float4 _Parameter;


C#中:

Vector4 parameter = new Vector4(offset, scale, alpha, 0);
Shader.SetGlobalVector("_Parameter", parameter );


第二种方法在GPU寄存器的使用方面会优于第一种方法,因为不论是SetFloat还是SetVector,都会占用一个寄存器。CPU和GPU通信次数越少性能开销也就越少。

用下面的方法做一下测试,可以发现两种方式在CPU方面开销变化很明显,在我的电脑上,万次循环一帧大约可以节省2ms左右。

void Update()
{
for (int i = 0; i < 10000; i++)
{
if (_switcher)
{
Shader.SetGlobalVector("_Parameter", new Vector4(1, 0, 0, 1));
}
else
{
Shader.SetGlobalFloat("_R", 0);
Shader.SetGlobalFloat("_G", 1);
Shader.SetGlobalFloat("_B", 1);
Shader.SetGlobalFloat("_A", 1);
}
}
}


最后

其实这个技巧也不仅仅局限于Unity3d,在dx和gl中也应该是这样,思想是通用的,如果谁能分享一些不是非常难的结合代码的GPU和CPU通信的学习资料大普通将be very appreciate。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息