建全流程解析:從數(shù)據(jù)準備到性能優(yōu)化)
從第一次接觸三維地形構(gòu)建到現(xiàn)在我最大的感受是這項技術(shù)最迷人的地方恰恰也是最容易讓人翻車的地方。很多朋友看了幾篇教程興沖沖地打開引擎拖一個地形插件調(diào)一堆噪聲參數(shù)截了張很唬人的圖發(fā)朋友圈結(jié)果一導(dǎo)入項目就露餡——要么山體稀稀拉拉不像貌要么貼圖糊成一團要么走兩步幀率掉一半。原因其實很簡單地形不是一張貼在平面上的紋理它是由數(shù)據(jù)、網(wǎng)格、材質(zhì)和渲染策略組合出來的完整系統(tǒng)任何一環(huán)掉鏈子最終畫面都會把錢花在臉上。這期我結(jié)合自己做寫實場景和開放世界原型的經(jīng)驗把三維地形構(gòu)建從數(shù)據(jù)準備、程序化生成、網(wǎng)格處理、貼圖混合到性能優(yōu)化這套流程完整拆開講一遍內(nèi)容是實打?qū)嵏蛇^活之后沉淀下來的東西適合剛?cè)腴T的同學(xué)也適合已經(jīng)踩過一些坑的同行作為查漏補缺的參考。1. 先把地形當(dāng)數(shù)據(jù)而不是當(dāng)風(fēng)景數(shù)據(jù)源與初始參數(shù)的決定性影響1.1 三種主要數(shù)據(jù)來源和它們的“脾氣”很多人上來就問“用什么算法生成地形”實際上在動手之前有一件事更值得先花時間想清楚這片地形的數(shù)據(jù)到底從哪來。我總結(jié)下來無非三條路各有各的脾氣選錯了后面至少多返工兩周。第一條路是拿真實世界的高程數(shù)據(jù)。像SRTM、ASTER GDEM、ALOS這樣的衛(wèi)星遙感數(shù)據(jù)或者更高精度的LiDAR點云都是可以直接拾取的素材。它們的優(yōu)點不言而喻真實、可信、自帶地理特征適合做數(shù)字孿生、飛行模擬、歷史遺址復(fù)現(xiàn)這類對“像不像”有要求的項目。缺點也明顯——投影坐標、坐標系轉(zhuǎn)換、大范圍數(shù)據(jù)的裁剪拼接這些預(yù)處理工作一點不輕松。你拿到一份GeoTIFF可能它用的是經(jīng)緯度坐標你還要把經(jīng)緯度換算成引擎里的世界坐標再處理缺失區(qū)域的插值光這一步如果沒有GIS基礎(chǔ)就容易卡殼。第二條路是純程序化生成。噪聲函數(shù)、侵蝕模擬、分形疊加所有地形都由算法算出來。這條路的優(yōu)勢在于完全可控想要峽谷就有峽谷想要環(huán)形山就有環(huán)形山而且還自帶無限擴展性適合做游戲地圖、影視預(yù)演、概念場景。問題在于程序化噪聲生成的東西很容易“一眼假”山體千篇一律、溝壑分布均勻得像流水線產(chǎn)品缺了真地形里那種“隨機但有因果”的質(zhì)感所以后期還得靠侵蝕模擬和手工修飾去補救。第三條路是手工雕刻。像ZBrush、Unity的Terrain Tools、World Machine里都有筆刷式的雕刻工具你可以像捏泥巴一樣把高地壓下去、把河谷拉出來。手雕的好處是精細、可控適合做關(guān)鍵地標、主城區(qū)域或敘事場景的核心地塊代價也非常直觀——大場景純手工雕能把你雕到懷疑人生隨便一張2048分辨率的區(qū)域圖刷子刷完一遍幾小時就沒了。我把三種來源常用數(shù)據(jù)的取舍整理了一下方便對照數(shù)據(jù)來源優(yōu)勢代價典型場景真實高程數(shù)據(jù)可信度高、天然具備地理邏輯坐標系處理繁瑣、分辨率受來源限制數(shù)字孿生、航拍類項目程序化生成速度快、覆蓋范圍大、參數(shù)可控特征容易重復(fù)、缺乏自然隨機性游戲大地圖、概念場景手工雕刻可控性最強、藝術(shù)表達直接耗時巨大、難以鋪滿大范圍關(guān)卡核心區(qū)域、近距離交互地面1.2 開工前先確定網(wǎng)格尺度別等貼圖做完才發(fā)現(xiàn)采不了樣不管選哪條路有一件事必須在管線啟動前拍板那就是地形范圍、高度圖分辨率和頂點間距。這三者是互相鎖死的假設(shè)你要做一塊4096米乘4096米的地圖高度圖用1024乘1024那每個頂點間距就是4米這意味著小于4米的地形起伏根本表現(xiàn)不出來——不是算法不行是采樣率不支持。很多新手把高度圖分辨率拍腦袋設(shè)成512貼圖卻狂堆8K結(jié)果地形起伏粗糙得跟砂紙一樣再高清的貼圖也救不回來。我的經(jīng)驗是先定“最小地形特征尺寸”再反推分辨率。比如游戲里角色身高1.7米他要能在山坡上自然行走這個坡度變化至少在2到3米級別才有感覺那頂點間距最好控制在2米以內(nèi)。如果地圖總大小兩公里那高度圖至少得1024出頭的分辨率才夠用。還有一個坑是高度圖位深。項目剛開始我圖省事用了8位PNG導(dǎo)出后山體梯度斷層非常嚴重斜坡上能看到一圈圈像等高線一樣的色階。后來全部換成16位灰度圖或EXR問題直接消失。只要項目允許高度圖一律用16位起步8位只配做預(yù)覽縮略圖。2. 從噪聲圖到起伏地表程序化地形里那套“塑形”手法2.1 噪聲不是越復(fù)雜越好先理解Perlin、Simplex和Voronoi的分工程序化地形繞不開噪聲但很多教程把噪聲講得太玄了。我換個方式說不同的噪聲函數(shù)本質(zhì)上是不同風(fēng)格的“隨機數(shù)畫筆”。Perlin噪聲畫出來的是柔和連續(xù)的山丘起伏頻率穩(wěn)定適合做大面積丘陵和緩坡Simplex噪聲和Perlin類似但均勻性更好網(wǎng)格扭曲更少適合做需要更自然分布的地表而Voronoi噪聲天生自帶多邊形分割感拿來生成懸崖、斷壁、裂谷特別合適——只要把Voronoi圖里的距離值取反或者做閾值處理就能得到一個個形狀清晰的石柱和壁面。真正讓地形像回事的很少只靠單層噪聲通常用的是分形布朗運動簡單理解就是把多層不同頻率、不同振幅的噪聲疊在一起低頻率決定大山脈骨架高頻率負責(zé)表面碎石和崎嶇感。公式大概是float fbm(vec2 p) { float value 0.0; float amplitude 0.5; float frequency 1.0; for (int i 0; i 6; i) { value amplitude * noise(p * frequency); frequency * 2.0; amplitude * 0.5; } return value; }疊個五六層就夠了再往上疊收益會明顯衰減反而增加性能開銷。還有一個特別實用的小技巧叫域扭曲——在對位置做噪聲采樣前先把坐標本身塞進另一個噪聲函數(shù)里扭曲一遍。效果就是山脊被“揉”出了自然的曲線而不是直愣愣的等高線這在做山脈地形時幾乎是標配。2.2 用海拔重映射把噪聲“捏”成地貌特征有了基礎(chǔ)噪聲值還不能直接當(dāng)高度因為那樣出來的地形只有起起伏伏的波浪沒有平原、海岸、高原這種分明的層次。這里需要做一件事叫海拔重映射。說白了就是拿一條曲線或一個函數(shù)把噪聲值重新分配到各個海拔區(qū)間。我想做一個海島地形時大概的處理邏輯是這樣的底部0附近是淺海大陸架所以0到0.15這一段要壓平拉緩讓海底平緩延伸0.15到0.35是沙灘和低地坡度可以稍微有點變化但不要陡0.35到0.7是丘陵腹地這一段保留噪聲的大部分起伏超過0.7以后逐漸向山峰收攏再加一點冪函數(shù)讓山體更尖銳。用代碼表達式寫就是用smoothstep、clamp、pow組合出一段分段函數(shù)或者直接在高程曲線上拉控制點。這一步幾乎決定了地形的“性格”比起調(diào)噪聲參數(shù)改重映射曲線的反饋更直觀。做完基礎(chǔ)高度之后我強烈建議再做一步簡單的水力侵蝕模擬。不需要很復(fù)雜的粒子系統(tǒng)只要用地形領(lǐng)域常用的那種“雨滴從高處滾落沿坡度帶走泥沙在低洼處沉積”的簡化算法跑上幾十次迭代就能看到山坡上出現(xiàn)細碎的沖溝、山谷底部出現(xiàn)扇狀堆積原本生硬的山體瞬間多了歲月感。我在Houdini里用Heightfield自帶的水力侵蝕節(jié)點或者用開源的侵蝕算法庫效果差別都不大關(guān)鍵是這一步真的能讓“程序化”三個字變得不那么程序化。3. 網(wǎng)格不能只拉高度還要接得住細節(jié)地形網(wǎng)格生成與分塊思路3.1 從高度圖到網(wǎng)格拓撲選擇決定后續(xù)所有編輯的余地高度圖本質(zhì)上是一個矩形數(shù)組每個格子存一個高度值要變成可渲染的幾何體就要把數(shù)組轉(zhuǎn)換成網(wǎng)格。最簡單的辦法是按順序生成頂點網(wǎng)格每行每列各留一個頂點間隔就是上面算好的步長然后按相鄰四個頂點組成兩個三角形。這種矩形網(wǎng)格看起來簡單但它的問題在三角形形狀上如果山體某處起伏特別夸張瘦長的三角形會出現(xiàn)非常明顯的棱線和鋸齒光照看著特別臟。所以我后來在做要求高的場景時會更偏向用細分算法給網(wǎng)格提前做一輪優(yōu)化或者在地形編輯器里設(shè)更高的網(wǎng)格密度密度再通過減面算法把平坦區(qū)域的頂點降下來。你可以理解成把頂點預(yù)算優(yōu)先分配給地形特征最豐富的地方而不是平均灑在整個地圖上。這個過程類似攝影里的“對焦區(qū)域”焦點在主體上背景虛化掉畫面才好看。同理地形網(wǎng)格要重點照顧山谷、崖壁、河流切割面這些細節(jié)密集區(qū)大平地上稀疏一點完全不影響觀感還能省下大量渲染資源。3.2 大地圖必須分塊分塊就要處理接縫接縫是地形項目里最經(jīng)典的坑當(dāng)你的地圖大到超出單個網(wǎng)格能承載的精度時不可避免地要把它切成若干個區(qū)塊。大多數(shù)引擎和工具也是這么干的比如Unity的Terrain分塊、Unreal的Landscape分成多個Component。區(qū)塊化帶來的直接后果就是接縫問題兩個相鄰區(qū)塊如果網(wǎng)格密度不同、頂點法線不同、甚至紋理坐標在邊界上各走各的中間就會出現(xiàn)一條肉眼可見的線。處理接縫有幾種常見思路。一種是做裙邊skirt也就是在區(qū)塊每個邊緣額外生成一圈向下延伸的窄三角帶把縫隙蓋住雖然技術(shù)上有取巧嫌疑但成本很低很多實時渲染方案都在用。一種是讓相鄰區(qū)塊在共享邊界上用完全相同的網(wǎng)格細分規(guī)則這要求LOD切換時邊界頂點位置必須一致復(fù)雜度高一些但效果最干凈。還有一種是在紋理采樣上解決把高度圖做幾個像素的外擴連紋理都不暴露缺口。我的建議是如果你用的是成熟引擎優(yōu)先用引擎自帶的地形系統(tǒng)處理接縫不要自己手寫網(wǎng)格拼塊。自己寫的網(wǎng)格拼接代碼在小的原型里看著沒問題一旦地圖規(guī)模上來邊界鋸齒、頂點法線跳變、陰影接縫這些妖魔鬼怪會一起找你算賬。把精力留給地形生成算法本身渲染層面的接縫交給經(jīng)過大量用戶驗證的引擎機制去兜底。4. 地表貼皮的質(zhì)感密碼三平面映射、坡度遮罩與紋理混合的實操配方4.1 陡坡貼圖拉伸是常態(tài)三平面映射是根治法地形高度起伏之后貼圖遇到的頭號問題是拉伸畸變。一張草地貼圖平鋪在平整地面時挺正常一旦貼到垂直的崖壁上紋理立刻被拉成一道道長條。原因很簡單普通UV投影是從上往下蓋在地表上的斜坡越接近90度單位面積上能分到的紋素就越多紋理自然被拉長。站得住腳的做法是三平面映射。思路非常直接分別按X軸、Y軸、Z軸三個方向?qū)δP妥鲆淮渭y理投影然后根據(jù)表面法線的方向計算出三種投影的混合權(quán)重。比如地面朝向接近垂直的Y軸那Y方向投影權(quán)重最大水平投影基本不影響如果是崖壁法線指向橫向那么對應(yīng)軸向的投影接管權(quán)重。這樣無論坡多陡紋理都能以正視角覆蓋表面不再拉伸。在主流引擎里Unity的Terrain有自動三平面選項Unreal的Material函數(shù)庫里也有現(xiàn)成節(jié)點用起來不復(fù)雜效果卻立竿見影。4.2 材質(zhì)混合不是畫漸變而是用坡度、曲率和噪聲做“做舊”做好了基礎(chǔ)映射接下來是地表材質(zhì)的混合。一個真實地形場景很少只有一張草地貼圖通常要混上泥土、巖石、砂礫、積雪甚至濕地。很多新手做混合時直接畫一張splatmap權(quán)重圖用畫筆在哪兒抹一下巖石就在哪兒出現(xiàn)。這樣做出來的結(jié)果材質(zhì)邊界干凈得像用圓規(guī)畫的假得不行。真實山體上材質(zhì)分布是有自然邏輯的平地長草陡坡露巖山脊因風(fēng)吹日曬更容易裸出碎石凹地容易積水所以顏色更深。把這些邏輯寫成算法混合效果比自己手刷好得多坡度遮罩法線方向越接近水平草地權(quán)重越高越陡峭巖石權(quán)重越高。曲率遮罩地形凸起的地方山脊、巖棱更容易露土凹進去的溝谷更容易長植被。噪聲擾動在遮罩計算之后疊一層低頻噪聲把硬邊界打散讓兩種材質(zhì)之間有犬牙交錯的過渡這才是“做舊”的關(guān)鍵。我做過一個小實驗同一段山體一半用純手繪splatmap一半用坡度加曲率遮罩加噪聲自動生成遠看差別不大鏡頭一拉近、陽光一斜自動生成的那一半明顯更像真山。因為它保留了材質(zhì)之間隨機但符合物理直覺的過渡而手繪很容易陷入“這涂一塊那涂一塊”的布面感。4.3 細節(jié)貼圖與高度混合解決遠景糊、近景平的雙重困境地形材質(zhì)還有個兩難問題遠景需要大面積重復(fù)。都好說近景又需要足夠多的石頭紋路、草根泥土這些細節(jié)。單一貼圖分辨率再高也沒法同時滿足。我的做法是拆兩層一層是大尺度顏色層負責(zé)草地、巖石、積雪的基本色塊分布分辨率可以低一些另一層是重復(fù)細節(jié)貼圖鋪在地表上面用三平面映射疊加一個小尺度噪聲紋理讓近看時表面有顆粒感。兩層之間再靠高度混合來過渡——細節(jié)貼圖越靠近高海拔地區(qū)越明顯越往濕地越低下去這樣就避免了近景一片光滑的“塑料感”。前面說了三種高度貼圖合數(shù)我們結(jié)合來看無人機。5. 大型地形的性能賬本LOD、剔除和相機原點這些繞不開的事5.1 LOD不是用來省顯存的是用來避免“地形一望無際幀率直接見底”的地形面積一大就算網(wǎng)格再優(yōu)化頂點數(shù)也會爆炸式增長。一塊2公里乘2公里的地形如果頂點間距2米那么將近一百萬個頂點而且這些頂點全都在同一幀里需要處理任何顯卡都扛不住。所以大型地形系統(tǒng)幾乎無一例外地要上LOD多層次細節(jié)。核心思路很簡單離相機近的地方用高密度網(wǎng)格離相機遠的地方用低密度網(wǎng)格你看不清的地方就不需要那么多三角形去堆。常見的方案有好幾種。一種是四叉樹分塊LOD把地形切成方形區(qū)塊每個區(qū)塊根據(jù)離相機的距離選擇不同細分級別越遠越粗糙一種是Clipmap以相機為中心生成一圈圈環(huán)形的LOD層像等高線一樣套在周邊這種做法實現(xiàn)起來性能最好但邊界處理更麻煩還有一種是基于GPU tessellation的動態(tài)細分讓顯卡實時決定三角形密度最省頂點但編寫難度最高。我不建議新手從底層自己擼LOD系統(tǒng)。殺雞用牛刀而且容易引入各種邊緣裂縫、LOD彈出、陰影接縫。直接用引擎地形系統(tǒng)自帶的LOD或者用Unity的Terrain LOD、Unreal Landscape預(yù)設(shè)體驗會舒服非常多。等到你對這套機制實在了解透了再考慮自己定制那時候你已經(jīng)知道哪些參數(shù)會影響彈出感、哪些會在遠處閃動了。5.2 大世界坐標漂移和浮點精度流失比LOD更隱蔽當(dāng)你的地圖大到十公里級別另一個隱藏殺手就出現(xiàn)了浮點精度流失。游戲引擎常用的32位浮點數(shù)精度在小數(shù)值區(qū)間表現(xiàn)很好但一旦坐標數(shù)值變大比如角色走到離世界原點幾千上萬米的地方浮點數(shù)能表達的最小步長會越來越大結(jié)果就是你眼睜睜看著地形和角色開始抖動、穿模模型邊緣出現(xiàn)肉眼可見的“咯咯”感。這跟地形構(gòu)建沒有直接關(guān)系但它會在你地形做到一定規(guī)模后突然冒出來打你個措手不及。行業(yè)通行解決方案是浮動原點floating origin或者世界原點重定位讓相機保持在世界坐標原點附近當(dāng)?shù)貓D內(nèi)容相對相機偏移時把整個場景整體做平移而不是移動相機到遠處。這樣做相機坐標數(shù)值永遠保持在游戲引擎精度較高的范圍。很多開放世界項目都靠這套機制避免抖動。如果你做的是衛(wèi)星級大地圖還要考慮用雙精度存儲地形塊的位置數(shù)據(jù)渲染階段再轉(zhuǎn)成相機空間的相對坐標。5.3 剔除策略不是所有地方都值得畫判斷“看不見”才是真優(yōu)化靜態(tài)地形本身其實不太需要復(fù)雜的剔除優(yōu)化因為它沒有骨骼動畫、不涉及蒙皮。但地形是場景里最大的幾何體之一而且會遮擋后面一大片內(nèi)容。如果你不把地形按區(qū)塊組織成獨立的剔除單元那么站在山腳下時相機測不到山背后很大一片天空和建筑沒必要的繪制開銷全都白白支付了。所以做地形性能優(yōu)化第一件事就是確保地形區(qū)塊參與視錐剔除和遮擋剔除。引擎會自動處理一部分視錐剔除但遮擋剔除的表現(xiàn)就看地形切塊的方式了。我習(xí)慣把地形區(qū)塊切得跟場景的Multiplayer空間一致這樣遮擋查詢的效率最高。另外地形上的植被、石頭這類實例物體也盡量用GPU實例化批量繪制別一棵樹一個Draw Call。你每天呼叫獨立進程地形本身跑得再快也架不住成千上萬個物體一起拖后腿。6. 程序化快但別讓它“地球統(tǒng)一”程序化結(jié)果與手工雕刻的協(xié)作流程6.1 從程序基底到人工收尾的三段式工作流程序化生成最大的優(yōu)勢是快最大的劣勢是“千篇一律”。同一個噪聲種子生成出來兩張地圖只要參數(shù)差不多看半天愣是分辨不出區(qū)別山的形狀、谷的位置、河流的走向全都像是同一個模子倒出來的。真實世界的地貌充滿偶然性而這種偶然性恰好是程序化算法最難提供的。我打磨過一套組合工作流效果比較穩(wěn)叫“程序打底、手工修型、程序收尾”三段式程序打底先用噪聲、侵蝕、海拔重映射生成整個地形的基礎(chǔ)骨架這一步要保證大格局正確山脈在哪、盆地在哪、海岸線基本輪廓如何。手工修型在關(guān)鍵區(qū)域用手工筆刷調(diào)整。比如把主城所在的高地鏟平一點、把河流入??谕貙挕涯匙鶚酥拘陨椒宓妮喞酶怃J。這個階段工具選擇很重要World Machine里可以配合Mask單獨修改局部區(qū)域Unity和Unreal的筆刷做局部推拉也很直觀。程序收尾修型之后重新跑一遍細節(jié)噪聲、材質(zhì)混合、植被分布的自動化流程。這樣手工的調(diào)整能無縫嵌回整個系統(tǒng)材質(zhì)過渡、植被密度這些又會自動匹配新的形狀。這套流程的核心邏輯是程序化負責(zé)宏觀效率和全圖一致性手工負責(zé)敘事需要和視覺焦點程序化再負責(zé)把手工的痕跡融合進全圖。三個環(huán)節(jié)缺一個結(jié)果都不完美。6.2 分層數(shù)據(jù)管理高度圖、權(quán)重圖、生物群系遮罩分開存儲為了保證上面這套工作流能在項目的生命周期里持續(xù)修改而不崩潰地形數(shù)據(jù)一定要分圖層管理。我見過太多項目把所有地形信息塞進一張高度圖加一張灰度圖美其名曰“管線簡單”結(jié)果美術(shù)想調(diào)整森林分布時只能在石頭權(quán)重圖上面抹來抹去稍不注意就把山體輪廓也改了一發(fā)牽全身項目不到一半就亂套了。我建議至少分成這幾層高度圖層只存地形幾何數(shù)據(jù)。材質(zhì)遮罩層草地、巖石、沙地、積雪的權(quán)重分布。生物群系層記錄區(qū)域類型比如森林區(qū)、荒漠區(qū)、濕地、城市區(qū)域。地表屬性層硬度、濕度、坡度這些會影響后續(xù)植被擺放和物理交互的數(shù)據(jù)。這樣每一層都能獨立修改、獨立重算。改完高度圖材質(zhì)層會自動重采樣改完生物群系層植被分布程序可以跟著變化。配合版本管理工具時每個圖層也最好單獨提交避免一個二進制大文件的所有修改都堆在一個提交里讓同事沒法Review。6.3 程序化地形的“靈感隨機化”技巧用種子管理而不是手動硬調(diào)最后再分享一個我常用的效率技巧地形種子seed管理。在做早期探索時我會寫一套參數(shù)化腳本把所有關(guān)鍵的地形生成參數(shù)——噪聲頻率、振幅、侵蝕迭代次數(shù)、海拔曲線控制點、濕度權(quán)重——全部暴露成可調(diào)參數(shù)然后用種子值驅(qū)動一次完整生成。每次只需要換一個種子數(shù)字就能得到一種新的地形方案把幾種方案并排放一起截圖對比比手動拖動滑桿來回調(diào)快得多。有段時間我探索開放世界地圖概念階段用這套方法一個下午生成了幾十種地形概念方案最后挑了三個特別有潛力的交給美術(shù)做手工深化。相比從零手雕這種“算法先出幾十個草圖、人再從中選優(yōu)”的做法更像是地形版的“靈感板”非常出活。7. 我在三維地形項目里踩過的三個坑附排查思路7.1 坑一高度圖導(dǎo)出格式不對山體梯田化嚴重第一次做寫實地形時我把高度圖導(dǎo)出成8位PNG加載進引擎后整個山體像被刀切過一層層臺階尤其在緩坡地帶特別明顯。我一開始以為是噪聲分辨率不夠把噪聲層的細節(jié)加到遠超過需求的地步還是不見好。后來靜下來排查把生成好的高度圖在圖像工具里單獨拉出來看才發(fā)現(xiàn)數(shù)據(jù)本身的連續(xù)性是完好無損的問題出在導(dǎo)出時被壓縮成了8位離散值256級灰階根本不夠描述細膩的高度變化相鄰兩個高度值之間的落差直接被量化成了可見的臺階。排查思路提煉一下先分辨問題出在“生成”還是“存取”。把中間數(shù)據(jù)單獨導(dǎo)出、單獨放大檢查就能區(qū)分是算法的問題還是格式的鍋。解決方式是換成16位PNG或EXR高度圖數(shù)據(jù)量雖然翻倍了但換來的是完全沒有梯度斷層的地形表面值。7.2 坑二貼圖接縫在遠處看不出來近處燈光一打就現(xiàn)形另一個讓我頭疼很久的問題是地形區(qū)塊貼圖接縫。白天在頭頂陽光環(huán)境下看著還正常一旦夕陽西下低角度的光斜著打過來接縫處就出現(xiàn)一條細細的暗線怎么調(diào)LOD都壓不掉。排查過程比較曲折我先懷疑是法線問題重新計算了一遍法線貼圖又懷疑是陰影貼圖分辨率提到4096還是沒解決最后偶然把兩個D外紋理的邊框像素展開對比發(fā)現(xiàn)兩個相鄰區(qū)塊在同一樣紋理坐標上采到了不同的紋素值——因為我在導(dǎo)出貼圖時每個區(qū)塊都單獨處理了邊緣像素沒有做紋理外擴導(dǎo)致邊緣采樣出現(xiàn)半個像素的偏差。解決辦法其實很簡單導(dǎo)出地形貼圖時在區(qū)塊邊界做4到8像素的外擴填充也就是讓每個塊邊緣多存一段鄰居區(qū)塊的紋理信息這樣采樣時邊緣不會缺數(shù)據(jù)。踩過這個坑之后我后續(xù)所有分塊紋理導(dǎo)出都默認帶上邊緣外擴再也沒被這種細如發(fā)絲的暗線折磨過。7.3 坑三法線方向算反了整個地形表面看起來像“倒?!边€有一次特別尷尬我生成的地形整體光照感覺不對山體向陽面和背陽面的明暗關(guān)系完全反了看起來像把模具的內(nèi)外翻了個面。我檢查燈光方向覺得沒問題檢查材質(zhì)參數(shù)也覺得沒問題最后一籌莫展時把網(wǎng)格法線可視化出來才發(fā)現(xiàn)大量頂點的法線指向反方向——問題出在我用的高度圖是按“越亮越高”的約定生成的但網(wǎng)格生成代碼里讀取灰度值后做的高度換算公式少了個符號導(dǎo)致地形整體被壓成了鏡像的負空間。這件事給我的教訓(xùn)是法線方向這種事不要靠猜更不要靠肉眼調(diào)燈光來找補直接把法線可視化出來看一眼就全明白了??梢暬€網(wǎng)、法線、UV這些Debug手段看起來土但永遠是排查三維渲染問題最直接的路。如果只讓我留一條建議給正在學(xué)地形構(gòu)建的朋友那就是把地形當(dāng)作一套完整的數(shù)據(jù)系統(tǒng)去對待高度、材質(zhì)、光照、遮擋每一環(huán)都要單獨驗證別等串起來之后才回頭找問題。地形是所有場景資產(chǎn)里最不直觀的一個但也是當(dāng)你把光影、貼圖、起伏、細節(jié)全部對齊之后最有成就感的一個。這期的內(nèi)容都是我一次次生成、導(dǎo)出、渲染、返工之后換來的實際操作經(jīng)驗希望能幫你在三維地形構(gòu)建這條路上少掉幾次頭發(fā)。