Unreal Engine的地形系統稱之為Landscape,每個level里面可以存放多個Landscape的Actor(但不能對它們進行連續編輯,也就是說相鄰兩個landscape是不能被同一個brush修改的)。地形被均勻的切割成多個小的地塊,這些地塊名為Landscape Component,每個Component可以持有最多2x2個SubSection。而每一個SubSection是由多個quad組成的,這些quad是地形topology的最小單位。由于地形mesh的頂點信息記錄在heightmap里,也就是頂點紋理中,所以它的分辨率盡量是二的指數冪。因此quad行和列的數量肯定是一個奇數,例如31x31,63x63等,對應的頂點數量為32x32個和64x64個。
相鄰兩個Component的邊界處的頂點信息是一致的,它可以保證在渲染時不會產生crack,當然vertex shader中還有相應的stitch算法能夠消除由于鄰接的patch使用不同lod而導致的t-junction現象。根據地形的視覺誤差計算結果,每個LandscapeComponent會自動的選擇對應的lod,高等級的lod會比低一個等級的lod所對應mesh少一半的quad。所以63x63的quad,只會有6個lod(63x63,31x31,15x15,7x7,3x3,1x1),如果想增加lod的數量,只能去增加subsection的quad數量,換句說每個Component最多只能退化成2x2個quad。這對于比較大的地形來說drawcall數量就可能變得很多,因為地形culling的最小單位是Component,如果是一個subsection的quad數量為63x63,且有2x2個subsection的component,假設一個quad是1m的大小,那么一個component最多可以覆蓋126米的范圍。隨著lod的升高,mesh會越來越稀疏(即三角形數量變少),當使用最高等級的lod時,126米的區域會用4個quad來表示。當前component如果可見,最多會形成4個drawcall(如果這四個subsection的screen size差異不是很大,它會自動合并成一個drawcall)。在視錐內且不沒有被遮擋的Component一旦很多,那么相應的drawcall也會暴漲。通過調高subsection的quad的數量來減少drawcall似乎不是一個好的辦法,因為如果culling粒度太大,會降低culling的效率,導致很多不在視錐內或者被遮擋的三角形依然會被處理。而且由于不同的lod,它對應的mesh的稀疏程度不同,導致drawcall里面處理的頂點數量也不盡相同。
ue4的實現是基于金字塔狀的geometry mipmapping的平鋪結構,而unity的地形是基于quadtree的層級結構,它們各有各的優勢。首先ue4的地形塊之間數據耦合度很小(每個component擁有自己的weightmap和heightmap,這些數據不需要跨component進行讀取),它可以為每個component計算當前幀的lod值,互相比較獨立,完全能夠并行處理,只是收尾階段要獲取四個鄰居的lod值,把它們傳給shader用來做stitch。但是unity的實現需要從根部開始遍歷這顆四叉樹,如果當前的等級滿足要求就不再往下遞歸,直接把當前等級的頂點信息提取出來,應用到一個固定的17x17個頂點的topology上。這樣就保證了每個drawcall處理的頂點數量都是一樣的,只是由于鄰居的lod可能與自身的lod不同,需要選取不同的indexbuffer而已。為了減少topology的模式緩存數量,lod算法要保證相鄰兩個patch之間的lod差不能超過一,否則就會出現crack。而ue4的stitch算法似乎沒有這些顧慮,彈性也因此更大。
由于unity的地形patch是用quadtree管理的,所以為了并行化視錐culling,它需要把quadtree遍歷階段的結果先緩存起來,放入到一個線性數組中,等到后面再與其他的renderer一起處理。反觀ue4的地形,雖然每個component單獨管理一個patch比較靈活,但是drawcall的數量會相對較多,尤其是那些較為平坦的地塊,或者是距離攝像機較遠的地塊,基于quadtree的方法可能就只會使用到一個16x16quads的patch去表達,而ue4的方案如前所述,由于component覆蓋的區域面積是固定的,所以它會生成更多的drawcall,甚至要處理更多的三角形。不僅如此,由于mesh退化程度有限,遠處的mesh在光柵化后可能會出現overshading。
現代的桌面顯卡和圖形api對于drawcall和頂點處理似乎不那么敏感了,但是像素的處理由于量級太大,所以很難忽略它對性能的影響,尤其是紋理的采樣和overdraw。ue4方案利用shader的static permutation的功能,有效的降低了材質中紋理的采樣數量。不過如果unity能早日祭出virtual texture(不需要運行時混合多層的紋理)這一利器就另當別論了。