gpuinstance修改屬性

現代基於光柵化的批處理技術一般有動態批處理,靜態批處理,gpuinstance,srpbatch等。

其中我要說的是gpuinstance,gpuinstance可以讓同一個mesh,同一個material,來傳遞多個統一的數據結構到buff中。進行後面的着色等處理。

其中數據結構是我們所關心的,因爲我們可能需要創建不同的位置,旋轉或物體顏色,法線等信息。

gpuinstance使用比較簡單,就是在shader中有#pragma multi_compile_instancing就好,那麼在unity中就會在對應的材質下出現

通常來說只要同一mesh,同一material就能合併到一個drawcall。

修改gpuinstance下的材質的屬性有兩種方式

第一種是直接修改位置和旋轉信息,這兩塊不會引起gpuinstance的切換。但是縮放會,如果縮放不一樣的話會放到另一個drawcall裏。這是因爲縮放會改變頂點間的距離,所以mesh自然就不一樣了。另外我們還要注意如果多個material,一定要排序好,讓相同的material在同一個render queue。這樣才能讓相同的material在同一個隊列下合併。不然會打亂合併順序。

下面給出unity的排序的先後順序

 

第二種是修改材質的顏色等內部屬性。這塊如果直接用material.setcolor等方式去做是不生效的,要不就新創建了一個material讓他到了另一個drawcall,要不就是sharedmaterial讓全部相同的material都修改了。

但我們的目的不是這個,我們的目的是每個不同的物體,能修改他們的顏色等信息但又能合併一個drawcall。

這時就要用到MaterialPropertyBlock,他是材質修改屬性的工具,不會產生新的材質。

MaterialPropertyBlock props = new MaterialPropertyBlock();
props.SetColor("_BaseColor", new Color(0,0,0,1));
GameObject.Find("Cube").GetComponent<MeshRenderer>().SetPropertyBlock(props);

但是如果我們直接這樣修改,也不會生效,這時會出現一個錯誤

non-instanced properties set for instanced shader

這是因爲instance不識別我們的屬性,我們需要把他包入一個UNITY_INSTANCING_BUFFER_START中,然後用UNITY_DEFINE_INSTANCED_PROP來定義這個屬性。當然我們還是需要在頂點和片元着色器中定義instance的idUNITY_SETUP_INSTANCE_ID(input);

這裏有好幾個宏,這些宏都可以再UnityInstancing.hlsl中找到定義。

下面給出解釋:

#pragma multi_compile_instancing
“multi_compile_instancing”會使你的Shader生成兩個Variant,其中一個定義了Shader關鍵字INSTANCING_ON,另外一個沒有定義此關鍵字。 除了這個#pragma指令,下面所列其他的修改都是使用了在UnityInstancing.cginc裏定義的宏(此cginc文件位於Unity_Install_Dir\Editor\Data\CGIncludes)。取決於關鍵字INSTANCING_ON是否被定義,這些宏將展開爲不同的代碼。 

UNITY_INSTANCE_ID
用於在Vertex Shader輸入 / 輸出結構中定義一個語義爲SV_InstanceID的元素。 UNITY_INSTANCING_CBUFFER_START(name) /

UNITY_INSTANCING_CBUFFER_END
每個Instance獨有的屬性必須定義在一個遵循特殊命名規則的Constant Buffer中。使用這對宏來定義這些Constant Buffer。“name”參數可以是任意字符串。

UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
定義一個具有特定類型和名字的每個Instance獨有的Shader屬性。這個宏實際會定義一個Uniform數組。 

UNITY_SETUP_INSTANCE_ID(v)
這個宏必須在Vertex Shader的最開始調用,如果你需要在Fragment Shader裏訪問Instanced屬性,則需要在Fragment Shader的開始也用一下。這個宏的目的在於讓Instance ID在Shader函數裏也能夠被訪問到。 UNITY_TRANSFER_INSTANCE_ID(v, o)
在Vertex Shader中把Instance ID從輸入結構拷貝至輸出結構中。只有當你需要在Fragment Shader中訪問每個Instance獨有的屬性時才需要寫這個宏。 

UNITY_ACCESS_INSTANCED_PROP(_Color)
訪問每個Instance獨有的屬性。這個宏會使用Instance ID作爲索引到Uniform數組中去取當前Instance對應的數據。

 

如果要訪問對應的屬性就需要在定義屬性的時候加類似下面的定義

UNITY_INSTANCING_BUFFER_START(STTest)

        UNITY_DEFINE_INSTANCED_PROP(float4, _BaseColor)

    UNITY_INSTANCING_BUFFER_END(STTest)

STTest是結構體名字,float4是屬性類型,_BaseColor是具體的屬性名。

然後在使用的地方

float4 newColor = UNITY_ACCESS_INSTANCED_PROP(STTest, _BaseColor);

這樣定義後就直接用newColor 代替_BaseColor。這樣就能讓instance識別到具體的屬性了,也就能合併批次了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章