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。