用Atlas實現多張貼圖混合的地形及注意事項

常規的地形使用4張diffuse貼圖進行混合,用一張權重圖的rgba通道表示每個diffuse貼圖的權重,實現出來的地形可以有4種不同的地面,4種之前可以過渡。

對於面積很大的地形,4張diffuse圖就使得表現受到局限,顯得單一了。解決方法有2:

1,切分地形為多個小塊,但要能同時編輯多塊地形,處理地形邊界。

2,讓一個地形能混合更多的貼圖。

本文是關於第二種方法的,並且不增加drawcall,shader計算量也沒有太多增加。

思路是把所有要混合的圖做成一張Atals,比如最上面的貼圖,4x4的能有16種。但權重圖仍然只有一張RGBA的話,就得單個通道能區分開4張圖才行。RGBA通道分別表示4x4的一列,R的取值是0-255(color32算的話),可以分成4段:0-63,64-127,128-191,192-255分別表示一列中的某一行,某一段內的取值表示權重,0是0%,63是100%,精度降低到原來的1/4。GBA通道同理。刷地形的工具保證任一點的所有權重加起來是63。

算格子和格子權重的大致代碼如下(shader里顏色是0-1)

tntfloat4 splat_control = tex2D(_Control, IN.tc_Control); //權重圖ntsplat_control = min(splat_control, fixed4(0.999, 0.999, 0.999, 0.999));tt//防止1的出現nthalf4 gridIndex = floor(splat_control * 4);tt//每一個通道表示那一列中從下到上第幾個,[0,3]。nthalf4 gridWeight = floor(splat_control * 256) - gridIndex * 64;tt//每個格子里的權重值,[0,63]。n

把uv還原到一個格子里的演算法

uv0 = frac(IN.uv_Splat0) * float2(0.25, 0.25) + float2(0, gridIndex.r * 0.25);n

下面是效果示例,帶發現光照的。

這個做的是sample4次貼圖,4列之間是可以過渡的,同一列的格子沒法過渡。想過渡的話得sample16次貼圖或者用條件判斷,從性價比上用不到。「2」貼圖之間是很硬的切換,其他之間是有過渡的。

注意事項:

1,diffuse atlas的mipmap

如圖紅色區域部分的瑕疵,原因是使用了錯誤的mipmap層導致的。之前單張diffuse圖的時候,uv是連續的從0到無窮,1.x跟0.x是sample出同樣的內容,1兩邊的值是連續的,但內容是平鋪的。現在變成格子之後uv也得分段去找對應的格子,uv=(0-0.25, 0-0.25)的格子跟uv=(1-1.25, 1-1.25)的格子內容是一樣的,但uv卻不連續了。gpu底層是通過相鄰像素的uv差值來判斷應該用哪個mipmap,差值越小說明越接近應該用最精細的mipmap0,差值越大就用越粗糙的。格子平鋪的時候邊緣uv從0.25到1.0差了0.75,就會用很粗糙的mipmap,而不是邊緣的地方仍然用高精度mipmap,造成了格子邊緣的線。

解決方法是傳入額外的參數調用tex2D告訴它實際的uv插值,ddx和ddy用來做這個

tex2D(_Splat0, uv0, ddx(IN.uv_Splat0), ddy(IN.uv_Splat0))n

函數解釋詳見下面的參考。所有atlas帶mipmap需要平鋪的都要解決這個問題。

2,權重圖的filter mode

Point採樣適合來算格子id,這個不會出什麼錯,別超過最大格就行。

Bilinear適合算格子的權重,過度自然,但是在邊緣可能採樣出超過本格子範圍的值,比如64-127的格子,可以採樣出小於63或大於127的值。所以用一個中間方案,一部分用point一部分用bilinear,point採樣值小於某個格內權重閾值時(比如6)用point的,超過的話用bilinear的,這樣儘管大於6才開始過度,但是過渡是正確的。

unity里的terrain貼圖是它引擎設置的,要想sample2次可以把權重圖copy一份,但是這就有內存代價了,這個圖是不壓縮的,1024x1024的RGBA要多佔5M都內存吧,算上mipmap。

3,在unity里如何改寫terrainInspector刷格子

編輯器代碼是在unityEditor寫的,c#的,可以反編譯出來,仿照著實現一邊是可以的就是代碼多了些。另一種方式是繼承terrainInspector至改寫特定的方法,這樣代碼量就少很多了,把OnSceneGUI里刷貼圖的部分改一下支持刷16格工作量並不大。

參考資料

1,《天下》手游,它的地形是用4x4的atlas,但更複雜還能混合出帶反射的水,並且一個通道表示0-15的格子。細看能看出來有的過渡邊緣比較糙,估計跟點採樣有關。

2,hacksoflife.blogspot.tw

解釋了如何計算使用哪層mipmap的原理

3,cg library里tex2d、ddx、ddy

tex2D


推薦閱讀:

為了忘卻的紀念:析OpenGL史上第二偉大的擴展,DSA
OpenGL+FreeType 模仿黑客帝國數碼雨 V2.0
卡通渲染及其相關技術
神奇的深度圖:複雜的效果,不複雜的原理

TAG:计算机图形学 | 游戏开发 |