在定義Draw Call是什麼之前,先淺談一下Unity的Batching原理會比較好理解。 Unity Batching分為靜態(static)與動態(dynamic)兩種。在處理渲染之前,會透過Batching的動作盡可能將同個材質的物件之網格合併成一個大的網格資料,如此減少Draw call。(若不合併,則一個mesh就會自己吃掉一個Draw call)
可以在inspector看到Static選項,藉此預先設為Static Batching物件,Unity在渲染時就會將同個材質球的物件網格結合成一個大的網格資料,也因此會增加記憶體的需求。
使用起來算是簡單,(除非參數有改,否則buffer設定一次即可)。
UpdateBuffers用於填入所需資料進ComputeBuffer 與材質buffer
其中參數比較難理解的是argsBuffer
定義:The GPU buffer containing the arguments for how many instances of this mesh to draw.
內容:Buffer with arguments, bufferWithArgs, has to have five integer numbers at given argsOffset offset: index count per instance, instance count, start index location, base vertex location, start instance location.
必須為長度5的陣列,內容分別為 三角形數量 , instance數量 , 三角形起始index , 頂點索引的偏移 , instance初始位置
通常這樣設定即可:
同理,草地僅是將position的y軸高度設為較小的範圍,使草貼齊地面。
100k面草 100fps,更好的做法是再搭配視錐剔除[5]( 又是個大坑...)。
以上我們透過DrawMeshInstancedIndirect解決了第一個限制的問題,接下來要將移動邏輯交給GPU去解決。
在Compute Shader處理移動
由於我這個是用深度貼圖進行移動判斷,該作法成效不好且也不太正確,但有助於初學Compute Shader。
流程圖
(為求簡化,所以假設Buffer只須設定一次)
主要的Loop邏輯如下:
這裡使用兩種shader,一個是compute shader叫做pointOffsetCS,專門用來算粒子位移;另一個un-lit shader用來製作渲染用的材質球。
由於球體會一直生成,所以得持續做buffer更新
簡單的直線掉落:
材質shader:
透過buffer資料直接改變vertex的世界位置,再投影到viewport空間。跟以往差別在於一個是從object-> view;一個是從world->view空間。
Compute shader做深度判斷
先取得screen的uv,並採樣周遭的深度
使用point的世界座標反推在畫面上的座標:
移動規則簡單檢查哪個方位可以移動,就往那個方向去。