
簡介面向使用Cesium搭建三維地球、又需要在斷網(wǎng)環(huán)境展示地形起伏的開發(fā)者這份資料把DEM高程tif轉(zhuǎn)為Cesium可讀離線terrain瓦片的整套流程打包在一起省去分別尋找Python、GDAL等舊版依賴的麻煩。壓縮包共11個文件約45.9MB以msi與exe安裝程序、py腳本、pdf說明為主另附j(luò)son配置、terrain樣例與txt提示兼顧環(huán)境搭建與轉(zhuǎn)換實操。已有3095人學(xué)習(xí)下載說明該離線地形方案在實際項目中需求穩(wěn)定。其中安裝包覆蓋Python 2.7、GDAL、PIL、NumPy等地理處理基礎(chǔ)組件兩個腳本分別承擔(dān)坐標配準與DEM切片示例DEM數(shù)據(jù)和生成后的tiles結(jié)果可用于對照驗證layer.json便于接入Cesium地形提供者配套PDF與說明文本記錄步驟、參數(shù)與常見報錯處理適合希望一次跑通鏈路并自行調(diào)優(yōu)切片參數(shù)的中級開發(fā)者。1. 從一份 DEM 到能離線加載的地形Cesium terrain 切片到底在切什么Cesium生成離線terrain地形數(shù)據(jù)的核心不是把 GeoTIFF 改個后綴而是把高程柵格重采樣成一顆顆帶索引的 quantized-mesh 瓦片再配一份 layer.json 告訴瀏覽器“哪一級、哪一塊、去哪拿”。我見過不少園區(qū)三維項目底圖能離線模型能離線一到地形就露白根子多在切片網(wǎng)格和 NoData 沒對齊。這套程序適合做內(nèi)網(wǎng)三維地球、離線指揮大屏、無外網(wǎng)環(huán)境地形底座的團隊新手可以按步驟跑通熟手重點看參數(shù)和驗收。它解決的是“沒有在線地形服務(wù)時Cesium 仍能按 LOD 加載本地地形”的問題。2. DEM 預(yù)處理把投影、NoData 和分辨率一次講透2.1 為什么不能直接拿原始 DEM 去切片很多翻車現(xiàn)場從第一步就埋下了。手里拿到的 DEM 可能是 UTM 投影、地方坐標系或者帶偏移的經(jīng)緯度柵格而 Cesium 地形瓦片默認按 WGS84 地理坐標組織瓦片行列號也有一套固定規(guī)則。源數(shù)據(jù)坐標系不統(tǒng)一切片器會按錯誤的范圍算瓦片索引最后在 Cesium 里看到的地形要么整體偏移要么邊緣被裁掉一塊。另一種常見情況是 NoData 值沒處理原始 DEM 用 -9999 表示空洞切片器把它當(dāng)成真實高程生成出來的瓦片就會出現(xiàn)巨大尖刺或黑坑。還有人把 30 米分辨率的 DEM 直接切到 18 級瓦片數(shù)量爆炸瀏覽器加載到高層級就卡死這種問題不是 Cesium 的鍋是層級上限沒跟數(shù)據(jù)分辨率對齊。我一般會先把“源數(shù)據(jù)能不能用”這件事拆成三個檢查項坐標系是不是 WGS84、NoData 值是否明確、像元大小對應(yīng)到 Cesium 的哪一級。三項里有一項含糊后面切出來的地形都像開盲盒。常見做法是先用gdalinfo看元數(shù)據(jù)再用gdalwarp統(tǒng)一投影和 NoData最后用腳本抽查邊界值。不要急著上切片命令預(yù)處理省下來的十分鐘往往能省掉后面兩小時的排查。2.2 用 gdalwarp 統(tǒng)一到 WGS84 與目標瓦片網(wǎng)格下面這條命令是我處理大多數(shù) DEM 的起點。它把源數(shù)據(jù)重投影到 WGS84統(tǒng)一 NoData并寫成帶分塊的 GeoTIFF。分塊和壓縮不是玄學(xué)切片器讀大文件時分塊柵格比條帶柵格少很多隨機 I/O尤其是幾十 GB 的 DEM差距很明顯。# 查看源數(shù)據(jù)基本信息坐標系、尺寸、NoData、像元大小 gdalinfo -stats ./raw_dem.tif # 重投影到 WGS84統(tǒng)一 NoData輸出帶分塊的 GeoTIFF gdalwarp -overwrite \ -t_srs EPSG:4326 \ -r bilinear \ -srcnodata -9999 \ -dstnodata -32768 \ -of GTiff \ -co TILEDYES \ -co COMPRESSLZW \ -co BIGTIFFIF_SAFER \ ./raw_dem.tif ./dem_wgs84.tif-t_srs EPSG:4326是目標坐標系Cesium 地形瓦片按經(jīng)緯度組織這一步不要省。-r bilinear是重采樣方法常規(guī)地形用雙線性比較穩(wěn)陡峭山區(qū)可以試cubic但不要用最近鄰最近鄰會把階地和高程突變放大成臺階。-srcnodata必須跟源數(shù)據(jù)真實 NoData 一致源數(shù)據(jù)沒有 NoData 時不要硬寫否則會把正常高程當(dāng)空洞裁掉。-dstnodata -32768是給后續(xù)切片器一個明確的無效值標記具體值不是重點重點是“源和目標要一致”。-co TILEDYES讓輸出變成分塊柵格COMPRESSLZW是無損壓縮BIGTIFFIF_SAFER是給超大文件留后路。如果源數(shù)據(jù)已經(jīng)是 WGS84只是范圍或分辨率不合適可以把-t_srs保留再加-tr指定目標像元大小。比如要統(tǒng)一到約 1 弧秒可以寫-tr 0.0002777778 0.0002777778。但不要為了“看起來整齊”強行重采樣到高于源數(shù)據(jù)精度的分辨率那只是把 30 米數(shù)據(jù)插值成 10 米文件變大信息量沒增加Cesium 加載時還會多讀一堆無意義的瓦片。2.3 檢查 NoData、邊界和分辨率的三條命令預(yù)處理做完不等于能切。我習(xí)慣用三條檢查把問題攔在切片之前元數(shù)據(jù)、邊界采樣、統(tǒng)計分布。元數(shù)據(jù)看坐標系和 NoData 有沒有寫進去邊界采樣看四角是不是異常值統(tǒng)計分布看最小最大值有沒有離譜。下面這段 Python 用 rasterio 讀一遍輸出比肉眼翻元數(shù)據(jù)更直觀。import rasterio import numpy as np with rasterio.open(dem_wgs84.tif) as ds: print(CRS:, ds.crs) print(SIZE:, ds.width, ds.height) print(NODATA:, ds.nodata) print(TRANSFORM:, ds.transform) # 讀取第一波段maskedTrue 會把 NoData 標成掩膜 arr ds.read(1, maskedTrue) print(MIN/MAX:, arr.min(), arr.max()) print(NODATA_COUNT:, arr.mask.sum()) # 抽查左上、右上、左下、右下四個角 h, w arr.shape corners [arr[0, 0], arr[0, w - 1], arr[h - 1, 0], arr[h - 1, w - 1]] print(CORNERS:, corners)ds.crs應(yīng)該是EPSG:4326不是的話說明gdalwarp沒生效或者讀錯了文件。ds.nodata要和命令里的-dstnodata對上讀出來是None就要回頭檢查。arr.mask.sum()是無效像元數(shù)量太大不一定是壞事說明邊界裁切正常太小則要懷疑 NoData 沒寫進去。四個角的值最容易被忽略如果角上出現(xiàn) -32768 或異常大值切片后就是邊緣黑塊。統(tǒng)計最小最大值時不要只看全圖最好按區(qū)域抽查尤其是跨帶或跨山地的 DEM。2.4 在 Cesium 里看到的“地形空洞”多半是這一步留下的地形空洞在 Cesium 里通常表現(xiàn)成兩種一種是黑色或透明的破洞另一種是突然凹下去的平底坑。前者多是 NoData 沒被切片器識別后者是把 NoData 填成了 0 或某個固定高程。血淚經(jīng)驗是不要用“填 0”解決空洞。0 在海拔里是海平面山區(qū)里填 0 會造出一塊平地視覺上比空洞更難受。正確做法是讓切片器識別無效值并跳過該區(qū)域或者在預(yù)處理階段用鄰域插值補洞但補洞只適合小范圍數(shù)據(jù)缺失大面積缺失應(yīng)該回到數(shù)據(jù)源。還有一種“假空洞”是投影邊緣造成的。源 DEM 范圍是矩形重投影到經(jīng)緯度后四角會變成弧形邊界邊緣像元被重采樣成 NoData。如果直接切片邊緣會出現(xiàn)鋸齒狀缺口。我一般會在gdalwarp時留一點緩沖或者用gdal_fillnodata.py只處理邊緣一圈不要全圖填。填完再檢查一遍統(tǒng)計值確認沒有把大范圍區(qū)域抹平。這個步驟沒有后悔藥切片完成后再發(fā)現(xiàn)空洞只能重新切瓦片數(shù)量多的時候很折磨人。3. 地形切片從 GeoTIFF 到 quantized-mesh 的可執(zhí)行流程3.1 切片工具選型為什么我優(yōu)先選基于 GDAL 的 ctb 路線Cesium 離線地形切片常見有三類路線基于 GDAL 的柵格切片、基于 TIN 簡化的網(wǎng)格生成、以及自己寫腳本把高程柵格轉(zhuǎn)成 quantized-mesh。第一類最適合大多數(shù)項目原因是它直接吃 GeoTIFF能生成 layer.json支持頂點法線和水面掩膜命令行也容易塞進自動化流水線。第二類在地形簡化上更靈活但輸入數(shù)據(jù)往往要先轉(zhuǎn)成點云或 TIN流程更長。第三類適合有明確定制需求的團隊否則維護成本太高。我優(yōu)先選ctb-tile這條路線不是因為它完美而是因為它的邊界清楚輸入是處理好的 WGS84 DEM輸出是z/x/y.terrain加layer.json參數(shù)不多出錯時能對著日志查。它的缺點也要提前知道切片過程對內(nèi)存和磁盤 I/O 比較敏感超大范圍數(shù)據(jù)要分塊切增量更新不如數(shù)據(jù)庫方案靈活水面掩膜需要額外數(shù)據(jù)不是開了參數(shù)就自動有水。選型時先把這些邊界寫進項目計劃比切到一半再換工具強。3.2 一條命令生成 .terrain 瓦片與 layer.json下面這條命令是我常用的基礎(chǔ)版本。它把dem_wgs84.tif切成 0 到 14 級的地形瓦片輸出到terrain_tiles同時生成 layer.json并寫入頂點法線。第一次跑建議先用小范圍 DEM 驗證不要拿全省數(shù)據(jù)直接開刀。# 創(chuàng)建輸出目錄 mkdir -p ./terrain_tiles # 切地形瓦片0-14 級雙線性重采樣生成 layer.json寫入頂點法線 ctb-tile \ -o ./terrain_tiles \ -l terrain \ -f terrain \ -c \ -N \ -s 0 \ -e 14 \ -r bilinear \ -t 8 \ ./dem_wgs84.tif-o是輸出目錄目錄必須可寫磁盤空間要提前算。-l terrain是圖層名會影響 layer.json 里的tiles模板和部分元數(shù)據(jù)不是隨便填也無所謂。-f terrain指定輸出 quantized-mesh 地形格式不要寫成普通高程瓦片格式。-c生成 layer.json缺了它 Cesium 不知道瓦片規(guī)則加載時直接報錯。-N寫入頂點法線開啟后光照更自然但瓦片體積會增大內(nèi)網(wǎng)帶寬足夠時建議開。-s 0和-e 14是起止層級起始層級一般從 0 開始結(jié)束層級要跟 DEM 分辨率匹配。-r bilinear是重采樣方法和預(yù)處理保持一致。-t 8是線程數(shù)按 CPU 核數(shù)一半起步太高會搶內(nèi)存反而變慢。命令跑完后先別急著開 Cesium。先看輸出目錄里有沒有l(wèi)ayer.json再看0/、1/這些層級目錄是否生成。如果layer.json有但瓦片目錄是空的多半是輸入范圍或?qū)蛹墔?shù)不對。如果瓦片目錄有但layer.json缺失檢查-c是否被漏掉。第一次跑可以用--help看當(dāng)前構(gòu)建支持的參數(shù)不同編譯版本會有細微差異不要硬套別人的命令。3.3 參數(shù)表瓦片尺寸、層級范圍、頂點壓縮、法線和水面掩膜參數(shù)常用值作用注意點-s/-e0 / 12-14起止層級結(jié)束層級不要高于數(shù)據(jù)分辨率30 米 DEM 切到 14 級以上收益很低-rbilinear重采樣方法陡峭地形可試 cubic不要用 nearest-N開啟頂點法線光照自然體積增大不開時 Cesium 端不要請求法線-m有水系時開啟水面掩膜需要水體系數(shù)據(jù)參與不是所有 DEM 都自帶-c開啟生成 layer.json缺少時 Cesium 無法識別瓦片規(guī)則-tCPU 核數(shù)一半線程數(shù)過高會搶內(nèi)存低配機器先從 4 開始-l自定義圖層名輸出圖層名不要用中文和空格避免路徑問題層級上限怎么定一個粗略算法是看源數(shù)據(jù)地面分辨率。比如 30 米 DEM在緯度 34 度附近Cesium 第 12 級的像素分辨率大約幾十米切到 12 或 13 級已經(jīng)能表達主要地形切到 15 級以上瓦片數(shù)量按四倍增長內(nèi)容卻多是插值出來的。我一般會先切 0 到 12 級做視覺驗收確認山脊、河谷、邊坡沒有明顯臺階再決定要不要加到 13 或 14。不要一上來切 18 級磁盤和瀏覽器內(nèi)存都會教你做人。水面掩膜要單獨說。-m不是“自動識別水面”它需要額外的水體系數(shù)據(jù)或掩膜輸入。沒有水系數(shù)據(jù)時強行開啟可能生成空掩膜或者直接報錯。Cesium 端requestWaterMask也要和切片參數(shù)對應(yīng)切片沒開水面掩膜前端就不要請求切片開了前端再按需開啟。法線同理-N和requestVertexNormals必須成對出現(xiàn)否則地形要么發(fā)黑要么光照平淡。3.4 切片產(chǎn)物怎么驗收文件樹、瓦片頭與數(shù)量對賬切片完成后我習(xí)慣做三層驗收目錄結(jié)構(gòu)、文件數(shù)量、瓦片頭。目錄結(jié)構(gòu)看z/x/y.terrain是否符合預(yù)期文件數(shù)量看是否和層級范圍大致匹配瓦片頭看文件是不是 gzip 或二進制地形數(shù)據(jù)而不是空文件。下面幾條命令可以直接抄。# 統(tǒng)計地形瓦片數(shù)量 find ./terrain_tiles -type f -name *.terrain | wc -l # 查看前幾層目錄結(jié)構(gòu) find ./terrain_tiles -maxdepth 2 -type d | sort | head -20 # 抽查一個瓦片文件頭1f 8b 表示 gzip xxd -l 16 ./terrain_tiles/12/3376/1560.terrain # 查看 layer.json 的關(guān)鍵字段 python3 -c import json; mjson.load(open(./terrain_tiles/layer.json)); print(m.get(format), m.get(version), m.get(minzoom), m.get(maxzoom))find ... | wc -l是最快的數(shù)量對賬數(shù)量明顯偏少時先查層級范圍是不是寫錯。find -maxdepth 2能看出層級目錄是否連續(xù)如果只有0/沒有1/說明切片在中途失敗。xxd看文件頭1f 8b是 gzip 魔數(shù)Cesium 地形瓦片經(jīng)常是 gzip 壓縮的服務(wù)器返回時要帶正確的Content-Encoding。layer.json里重點看format是否為quantized-mesh-1.0一類的地形格式minzoom和maxzoom是否和命令參數(shù)一致。字段名不同版本可能有差異但核心邏輯不變前端靠這份文件找瓦片字段錯了就 404。4. 本地服務(wù)與 Cesium 加載把 layer.json 接進 Viewer 的最小閉環(huán)4.1 目錄結(jié)構(gòu)與 HTTP 服務(wù)不要直接雙擊 index.html離線地形最常見的第一個坑是直接雙擊 HTML 文件。file://協(xié)議下瀏覽器會攔截跨目錄請求layer.json和.terrain瓦片讀不出來控制臺一片紅。正確做法是起一個本地 HTTP 服務(wù)讓頁面和瓦片同源或者至少讓瓦片服務(wù)帶 CORS 頭。目錄可以這樣組織Cesium 靜態(tài)資源放Cesium/地形瓦片放terrain_tiles/頁面放根目錄。這樣layer.json里的相對路徑和頁面請求路徑容易對齊。# 在項目根目錄啟動本地 HTTP 服務(wù)端口 8080 python3 -m http.server 8080 --bind 127.0.0.1--bind 127.0.0.1只允許本機訪問適合自己調(diào)試要給局域網(wǎng)其他機器看可以改成0.0.0.0但要注意內(nèi)網(wǎng)安全。Python 自帶的 HTTP 服務(wù)不會自動加 CORS 頭如果頁面和瓦片不同源需要換成能配置 CORS 的服務(wù)器或者在反向代理里加Access-Control-Allow-Origin。另外.terrain文件的 MIME 類型不是所有服務(wù)器都認識返回application/octet-stream通常能用關(guān)鍵是不要返回text/html。如果瓦片是 gzip 壓縮的服務(wù)器還要帶Content-Encoding: gzip否則瀏覽器會把壓縮數(shù)據(jù)當(dāng)壞文件。4.2 CesiumTerrainProvider 的關(guān)鍵參數(shù)requestVertexNormals 與 requestWaterMaskCesium 加載本地地形靠CesiumTerrainProviderurl指向包含layer.json的目錄不是指向layer.json文件本身。這一點很容易寫錯寫成.../layer.json后請求路徑會多一層直接 404。requestVertexNormals對應(yīng)切片時的-N切片開了法線前端就設(shè)true地形光照會有立體感切片沒開前端設(shè)true也不會憑空生出法線反而可能報錯或顯示異常。requestWaterMask對應(yīng)-m沒有水面掩膜就設(shè)false不要為了“看起來功能全”硬開。新版本 Cesium 常用CesiumTerrainProvider.fromUrl返回 Promise老版本用構(gòu)造函數(shù)直接 new。寫代碼時看控制臺報錯判斷不要死記一種寫法。fromUrl的好處是能等layer.json加載完再設(shè)置viewer.terrainProvider避免地形還沒就緒就飛相機。如果項目里還用了在線影像或在線地形先把它們關(guān)掉確保請求只打到本地不然排查時分不清是本地瓦片問題還是網(wǎng)絡(luò)問題。4.3 一個最小可運行的加載頁面下面這個頁面只做一件事加載本地地形把相機放到一個指定經(jīng)緯度。它沒有底圖沒有復(fù)雜控件方便先驗證地形本身。實際項目再疊加本地影像或矢量。!DOCTYPE html html langzh-CN head meta charsetutf-8 title離線地形加載/title link relstylesheet href./Cesium/Widgets/widgets.css script src./Cesium/Cesium.js/script style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } /style /head body div idcesiumContainer/div script (async () { const viewer new Cesium.Viewer(cesiumContainer, { imageryProvider: false, // 先關(guān)掉底圖只驗證地形 baseLayerPicker: false, geocoder: false, homeButton: false, sceneModePicker: false, navigationHelpButton: false, animation: false, timeline: false }); // url 指向包含 layer.json 的目錄不是 layer.json 文件 const terrainProvider await Cesium.CesiumTerrainProvider.fromUrl( http://127.0.0.1:8080/terrain_tiles, { requestVertexNormals: true, // 與切片 -N 對應(yīng) requestWaterMask: false // 與切片 -m 對應(yīng) } ); viewer.terrainProvider terrainProvider; // 相機放到地形范圍附近高度先給大一點避免鉆進地下 viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(108.9, 34.2, 20000) }); })(); /script /body /htmlimageryProvider: false是為了排除底圖干擾地形加載失敗時不會誤以為是影像問題。fromUrl的第二個參數(shù)里requestVertexNormals和requestWaterMask必須和切片產(chǎn)物匹配。相機高度先給 20000 米等確認地形范圍后再調(diào)低如果一開始就給 500 米很可能相機在地下或山體里看到的是一片黑。頁面和瓦片同源時url可以寫成相對路徑./terrain_tiles換機器部署時少改一處配置。4.4 離線場景下的跨域、緩存與路徑大小寫內(nèi)網(wǎng)部署時跨域和路徑大小寫是兩把鈍刀子。跨域問題常見于頁面在一個端口、瓦片在另一個端口瀏覽器控制臺會明確提示 CORS。解決方式不是在前端加mode: no-cors那只會讓響應(yīng)變成 opaqueCesium 讀不到內(nèi)容正確做法是讓瓦片服務(wù)返回Access-Control-Allow-Origin或者把頁面和瓦片放到同一個服務(wù)下。路徑大小寫問題多出現(xiàn)在 Linux 服務(wù)器Windows 上Terrain_Tiles和terrain_tiles不區(qū)分傳到 Linux 后 404layer.json里的模板和實際目錄必須完全一致。緩存也要注意。調(diào)試階段瀏覽器會緩存layer.json和失敗的瓦片請求改了切片參數(shù)后頁面沒變化先開無痕窗口或禁用緩存。生產(chǎn)環(huán)境則相反layer.json可以短緩存.terrain瓦片內(nèi)容不變時可以長緩存減少內(nèi)網(wǎng)請求。還有一個小細節(jié)layer.json里的tiles模板如果是{z}/{x}/{y}.terrain實際目錄就必須按這個結(jié)構(gòu)組織不要自作主張改成{z}/{y}/{x}.terrain。Cesium 不會猜你的目錄習(xí)慣模板和文件樹必須一一對應(yīng)。5. 避坑與排查離線地形加載失敗的 5 個現(xiàn)場5.1 地形整體偏移幾百米現(xiàn)象Cesium 里地形和模型、影像對不上整體平移幾百米山脊位置明顯偏。原因源 DEM 不是 WGS84或者gdalwarp的目標坐標系寫錯也可能是經(jīng)緯度軸順序被調(diào)換。解決回到gdalinfo看源 CRS確認-t_srs EPSG:4326生效用gdallocationinfo在已知地物點采樣高程和影像對比如果是軸順序問題檢查是否誤用了-s_srs或數(shù)據(jù)本身帶了非標準元數(shù)據(jù)。偏移問題不要靠前端平移模型去補補得越多后面越亂。5.2 瓦片 404layer.json 能讀到但地形不顯示現(xiàn)象控制臺請求.terrain返回 404layer.json本身 200。原因url指到了layer.json文件而不是目錄layer.json里的tiles模板和實際目錄不一致Linux 下路徑大小寫不匹配服務(wù)器根路徑多了或少了目錄。解決在瀏覽器里直接拼一個瓦片 URL 訪問看能不能下載對照layer.json的模板和find出來的文件樹把url改成目錄并以/結(jié)尾試一次檢查反向代理是否把/terrain_tiles重寫成了別的路徑。5.3 地形發(fā)黑、棱角明顯光照像被壓扁現(xiàn)象地形有起伏但表面發(fā)黑山脊像紙片旋轉(zhuǎn)視角時明暗不自然。原因切片時沒開-N前端卻設(shè)了requestVertexNormals: true或者切片開了法線前端沒請求也有可能是法線數(shù)據(jù)被服務(wù)器 gzip 處理壞了。解決先確認切片命令有沒有-N再確認前端參數(shù)是否一致用xxd看瓦片頭是否正常臨時把requestVertexNormals設(shè)為false對比效果。如果關(guān)掉法線后地形正常問題就在法線鏈路不要繼續(xù)調(diào)光照參數(shù)。5.4 水面沒有效果開了 requestWaterMask 也沒用現(xiàn)象地形加載正常但水面區(qū)域沒有反射或水面掩膜效果。原因切片時沒加-m或者沒有提供水體系數(shù)據(jù)前端requestWaterMask設(shè)了true但瓦片里沒有掩膜。解決先確認切片命令是否帶-m再看輸出瓦片是否包含水面掩膜數(shù)據(jù)沒有水系數(shù)據(jù)時不要硬開前端設(shè)為false如果項目必須顯示水面單獨準備水體系矢量或柵格掩膜再重新切片。水面效果不是前端一個開關(guān)能變出來的數(shù)據(jù)鏈路要完整。5.5 切到高層級后瀏覽器卡死或加載極慢現(xiàn)象低層級正常飛到近處后頁面卡頓內(nèi)存飆升瓦片請求越來越多。原因結(jié)束層級設(shè)得太高瓦片數(shù)量按四倍增長DEM 分辨率不夠高層級全是插值瓦片NoData 區(qū)域也被切片產(chǎn)生大量無效請求。解決把-e降下來30 米 DEM 先切到 12 或 13 級用范圍裁剪只切項目區(qū)域不要全省全國一起切檢查 NoData 區(qū)域是否被跳過瀏覽器端限制maximumScreenSpaceError不要讓 Cesium 無節(jié)制請求最高層級。層級不是越高越好夠用就行。6. 進階把地形切片塞進自動化流水線與驗收腳本切片命令跑通一次不難難的是每次數(shù)據(jù)更新都能穩(wěn)定復(fù)現(xiàn)。我一般會把預(yù)處理、切片、驗收寫成三段腳本中間產(chǎn)物帶日期目錄失敗時保留日志。下面這個 Python 腳本只做驗收讀layer.json統(tǒng)計瓦片數(shù)量檢查關(guān)鍵字段。它不替代人工看地形但能攔住“目錄空了”“層級錯了”“格式不對”這類低級問題。import json import os import glob base ./terrain_tiles layer_path os.path.join(base, layer.json) with open(layer_path, r, encodingutf-8) as f: meta json.load(f) print(format:, meta.get(format)) print(version:, meta.get(version)) print(minzoom:, meta.get(minzoom)) print(maxzoom:, meta.get(maxzoom)) print(tiles_template:, meta.get(tiles)) tiles glob.glob(os.path.join(base, *, *, *.terrain)) print(tile_count:, len(tiles)) # 抽查最大層級目錄是否存在 maxzoom meta.get(maxzoom) if maxzoom is not None: max_dir os.path.join(base, str(maxzoom)) print(maxzoom_dir_exists:, os.path.isdir(max_dir))format應(yīng)該是 quantized-mesh 相關(guān)格式tiles模板要和文件樹對得上tile_count為 0 就直接失敗不用再開瀏覽器。maxzoom_dir_exists能快速判斷切片是否只完成了一半。腳本跑完后我還會抽一個瓦片用xxd看文件頭確認不是空文件。自動化流水線里驗收腳本失敗就不要發(fā)布別把問題留給前端。從那以后我每次切地形都強制走一遍“預(yù)處理檢查、切片參數(shù)對賬、瓦片數(shù)量驗收”不再靠打開頁面看運氣。希望幫到你。本文還有配套的精品資源點擊獲取