【libgdx】2D地圖塊(tileset)地圖出現縫隙(gap / bleeding)的問題

最近按官方wiki寫地圖塊代碼時遇到此問題:在Tiled裏畫好地圖,一切都按wiki步驟來,當把地圖顯示出來,相機在地圖上移動時,會發現地圖塊之間偶爾會出現縫隙(或者是黑線、白線,根據clear用的填充色不同而不同),用英文來描述,就是tiles之間有gap或white/black line,更專業一點的叫法就是tile bleeding。
借用一下別人的圖
這裏寫圖片描述
於是google了一頓,終於找到算是OK的解決辦法了。
據說此問題是libgdx論壇的日經問題,每隔幾天就會有人問,因爲一直也沒有十分優雅的解決方案,目前唯一據說比較實用的解決辦法其原理也是囧得不行,聽起來就讓人脫力,而給出解答的人往往也都是三言兩語,說的都是那種“說起來容易做起來巨麻煩”的話,讓人摸不到頭腦。於是仍然一直有人在問,惡性循環。。。
然後我終於看到了一篇博客,給出了簡單詳細的解決辦法:http://thekemiren.blogspot.jp/2014/07/tile-bleeding-in-libgdx-using-tiled.html
(注意得翻牆)

我把自己搜到的相關知識總結一下:
首先這個問題讓人想到的就是filter方案的問題,是不是誤用了linear,而其實應該換成nearest。用過unity3D或者熟習openGL的人估計首先都會想到這個。但是可惜不是,據說libgdx裏的OrthogonalTiledMapRenderer渲染器默認用的就是nearest,還有一說這個也不是特別好改(或是改了之後效果不好?感覺論壇上的人都各執一詞),總之此路不通。
解決方案二,考慮到之所以出現這種問題,是因爲相機(camera)在移動的時候,移動值的類型是float,精度十分高,所以當恰好移動到某一小精度時,可能會導致某兩個相鄰圖塊的渲染出現了1象素的位置偏差(比如左邊的圖塊x座標舍了點,右邊的圖塊x座標入了點,於是他倆之間出現了一個1象素的縱向的縫)。綜上所述,想到的解決辦法就是,不讓相機的移動有如此高的精度,比如可以讓移動的最小單位是0.2,不足0.2的可以補上或者舍掉,這樣移動的時候就不會產生縫隙了。更極端的做法是乾脆讓相機按int精度移動。
這種解決方案在修改相冊移動的同時必須也修改畫面上物體的移動,不然會覺得物體在畫面上各種抖動。而且更糟糕的是,它或許不能完全解決問題。比如我上面說的0.2精度,在原大畫面時看起來很完美,但是如果畫面被放大或縮小,那麼這問題可能會再次出現,只能再不斷降低精度。降成int就能百分百解決問題了麼?似乎並沒有人能給出這樣的保證。而且把物體的移動精度降成int的同時也削弱了我們遊戲的靈敏平滑程度,這也並不是我們所期望的。
第三種解決方案,也就是最終解決方案了,同時也是最麻煩最讓人無語但是卻又不得不承認是最有效的一個。做法就是:給一大張tileset裏的每一個小圖塊(tile),都加上1個象素的勾邊(gutter)。這裏特別強調這個gutter,用的不是常見的padding也不是spacing也更不是margin什麼的(媽個幣的這幾個破詞我特麼糾結好久,論壇上的老外們也是經常分不清楚地瞎叫),雖然挺多人聲稱那個勾邊叫padding,但是這叫法很誤導人,我覺得最準確還是應該叫gutter。至於區別,gutter跟padding/spacing最大的區別是,它增加的這一個象素的勾邊,不是透明的,也不是填充某種單色(比如黑色、白色),而是根據圖塊而產生的一個色的延伸。比如某圖塊的左邊緣一縱列象素都是深綠色,那麼相應在左邊產生的勾邊也是深綠色,如果要是一縱列從紅到藍的漸變色,那麼產生的勾邊也應該是一個象素列從上到下的漸變色。如下圖:
原圖:尺寸32x32
這裏寫圖片描述

1象素的透明邊(padding/spacing)尺寸34x34
這裏寫圖片描述

1象素的色邊(gutter)尺寸34x34
這裏寫圖片描述

到這裏,大家應該明白這種解法的原理了。假如我用的是32x32的地圖塊,加了gutter之後就相當於用的是帶1象素邊緣的34x34圖塊,但是那多出的一個象素是彼此重疊放置的(在Tiled地圖編輯器裏可以這樣設置),所以看起來仍然是32x32的圖塊。那麼當再因爲相機移動而產生1個象素的縫隙時,原本相互重疊的那一個象素就會露出來,但是因爲已經勾上邊了,所以就算露出來也很難用肉眼看出來這一破綻…………
聽起來真是超級囧,非常有悖於大部分程序員一直追求的“優雅”。而且這種解法還導致了一個效能的問題……你的素材可能因此而尺寸不再是2的冪數值了。比如我的256x1024的tileset圖片勾了邊之後就變成272x1088……雖然libgdx也能hold得住這種尺寸的圖片,但是這完全跟官方wiki中口口聲聲說的“儘量使用2的冪作爲圖片的尺寸”這一good practice法則相矛盾,但是很遺憾,這確實是官方論壇上目前給出的最有效解決方案,所以也難怪此問題會成爲官方論壇上的日經問題了。
而且說到給圖片加gutter這件事,如果不是拼好的素材,而是自己用texturepacker現從一個文件夾打包成atlas的素材那還好,直接改改配置再重新打包就好了。但是如果你只有一張完整的tilset素材,由許多張tile圖片拼成(比如直接從RPG Maker的RTP素材裏copy過來的那種)。這尼瑪一個個加起來豈不是要了人命?打開PS,把圖片拆成一塊一塊,然後再擴大畫布,給每一塊圖片一象素一象素地勾上一個邊,臥槽,光聽就想死了。程序員們肯定想馬上寫個程序來幫忙做此事了。事實上貌似確實已經有些這樣的現成程序了,我在google code上看到一個,但是不知道怎麼搞,所以沒試。我試了另一種,使用一款名叫GIMP的免費圖片編輯軟件,它有一個小插件可以幫忙完成此事。http://registry.gimp.org/node/26044
使用時需要這樣配置參數:(我懶得自己截圖了,用的上面我給的那個博客裏的圖)
這裏寫圖片描述
就可以完成勾邊。而在Tiled裏,也一定要設置好margin和spacing(按上面截圖勾出來的tileset的話,應該margin是1,spacing是2),才能正常地畫地圖。
然後直接用到程序裏,不用特地爲它們寫什麼,最終效果就非常OK了。不使勁看根本看不出來(對不明真相的玩家來說,使勁看都看不出來)

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