在實際項目中,我們經常需要加載大規模的三維場景數據,比如城市建築模型、地形數據等。3D Tiles 是 Cesium 提出的開放標準,用於高效地流式傳輸和渲染大量 3D 內容。今天就來學習一下如何在 mapvthree 中使用 3D Tiles。
瞭解 3D Tiles
3D Tiles 是一種用於流式傳輸和渲染大量 3D 內容的開放標準,具有以下特點:
- 層次化結構:使用空間層次結構組織數據,支持細節層次(LOD)
- 流式傳輸:按需加載,只加載視野內的數據
- 高性能:通過剔除、LOD 等技術優化渲染性能
- 標準化:開放標準,支持多種數據格式
我的理解:3D Tiles 就像是一個智能的三維場景管理系統,能夠根據相機位置和視角,自動決定加載哪些數據,以及加載到哪個細節層次。
第一步:從 URL 加載 3D Tiles
最簡單的方式是從 URL 加載 3D Tiles 數據。
基本使用
import * as mapvthree from '@baidumap/mapv-three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container, {
map: {
center: [105.931, 29.349, 280],
range: 2000,
pitch: 75,
provider: null,
},
});
// 從 URL 加載 3D Tiles
const tileset = engine.add(new mapvthree.Default3DTiles({
url: 'data/3dtiles/tileset.json',
}));
我的發現:只需要提供 tileset.json 的 URL,引擎會自動加載整個 3D Tiles 數據集。
我的理解:
tileset.json是 3D Tiles 的入口文件,定義了整個數據集的層次結構- 引擎會根據相機位置自動加載需要的瓦片
- 支持多種 3D Tiles 格式(b3dm、i3dm、pnts 等)
第二步:從 Cesium Ion 加載
如果數據存儲在 Cesium Ion 上,可以使用 asset ID 加載。
使用 fromAssetId
// 從 Cesium Ion asset ID 加載
const tileset = await mapvthree.Default3DTiles.fromAssetId('assetId', {
errorTarget: 16,
});
engine.add(tileset);
我的發現:fromAssetId 是靜態方法,返回一個 Promise,需要等待加載完成。
我的理解:
- 需要先配置 Cesium Ion AccessToken
- asset ID 是 Cesium Ion 中資源的唯一標識
- 可以使用配置參數來優化加載和渲染
第三步:性能優化配置
3D Tiles 提供了很多性能優化參數,合理配置可以顯著提升渲染性能。
errorTarget:屏幕空間誤差
errorTarget 控制屏幕空間誤差目標值,影響 LOD 的切換時機。
const tileset = engine.add(new mapvthree.Default3DTiles({
url: 'data/3dtiles/tileset.json',
errorTarget: 16, // 默認值,數值越小,細節越多,性能開銷越大
}));
我的理解:
- 數值越小,顯示的細節越多,但性能開銷越大
- 數值越大,顯示的細節越少,但性能更好
- 需要根據場景和性能要求調整
cullRequestsWhileMoving:移動時剔除
cullRequestsWhileMoving 控制相機移動時是否剔除請求,可以提升移動時的性能。
const tileset = engine.add(new mapvthree.Default3DTiles({
url: 'data/3dtiles/tileset.json',
cullRequestsWhileMoving: true, // 移動時剔除請求,提升性能
}));
我的發現:開啓後,相機快速移動時不會加載新瓦片,等移動停止後再加載,可以避免不必要的網絡請求。
cullWithChildrenBounds:使用子節點邊界剔除
cullWithChildrenBounds 控制是否使用子節點邊界進行剔除,可以更精確地判斷是否需要加載子節點。
const tileset = engine.add(new mapvthree.Default3DTiles({
url: 'data/3dtiles/tileset.json',
cullWithChildrenBounds: true, // 使用子節點邊界進行剔除
}));
我的理解:開啓後,會使用子節點的邊界框來判斷是否需要加載,可以更精確地剔除不可見的節點。
loadSiblings:加載兄弟節點
loadSiblings 控制是否加載兄弟節點,可以預加載相鄰的瓦片。
const tileset = engine.add(new mapvthree.Default3DTiles({
url: 'data/3dtiles/tileset.json',
loadSiblings: true, // 加載兄弟節點,預加載相鄰瓦片
}));
我的發現:開啓後,會預加載相鄰的瓦片,當相機移動到相鄰區域時,數據已經準備好了,可以提升用户體驗。
其他性能參數
還有一些高級性能參數:
const tileset = engine.add(new mapvthree.Default3DTiles({
url: 'data/3dtiles/tileset.json',
// 緩存配置
cacheBytes: 512 * 1024 * 1024, // 緩存大小(字節)
// 動態屏幕空間誤差
dynamicScreenSpaceError: true,
dynamicScreenSpaceErrorDensity: 0.00278,
dynamicScreenSpaceErrorHeightFalloff: 0.25,
// 注視點渲染(Foveated Rendering)
foveatedScreenSpaceError: true,
foveatedConeSize: 0.1,
foveatedMinimumScreenSpaceErrorRelaxation: 2.0,
// 其他配置
forceUnlit: false, // 強制無光照模式
progressiveResolutionHeightFraction: 0.3,
}));
我的理解:這些參數主要用於高級優化,一般使用默認值即可,除非有特殊的性能需求。
第四步:運行時調整參數
可以在運行時動態調整參數,實時優化性能。
const tileset = engine.add(new mapvthree.Default3DTiles({
url: 'data/3dtiles/tileset.json',
errorTarget: 16,
}));
// 運行時調整參數
tileset.errorTarget = 8; // 提高細節
tileset.cullRequestsWhileMoving = true; // 開啓移動剔除
tileset.loadSiblings = true; // 開啓兄弟節點加載
我的發現:可以根據場景需求動態調整參數,比如在性能不足時降低 errorTarget,在需要流暢移動時開啓 cullRequestsWhileMoving。
第五步:完整示例
我想寫一個完整的示例,把學到的都用上:
import * as mapvthree from '@baidumap/mapv-three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container, {
map: {
center: [105.931, 29.349, 280],
range: 2000,
pitch: 75,
provider: null,
},
});
// 從 URL 加載 3D Tiles,配置性能參數
const tileset = engine.add(new mapvthree.Default3DTiles({
url: 'data/3dtiles/tileset.json',
errorTarget: 16,
cullRequestsWhileMoving: true,
cullWithChildrenBounds: true,
loadSiblings: true,
}));
我的感受:掌握了這些配置,就可以根據實際需求優化 3D Tiles 的加載和渲染性能了!
第六步:踩過的坑
作為一個初學者,我踩了不少坑,記錄下來避免再犯:
坑 1:3D Tiles 不顯示
原因:URL 路徑錯誤,或者 tileset.json 文件不存在。
解決:
- 檢查 URL 路徑是否正確
- 確認 tileset.json 文件存在且可訪問
- 檢查瀏覽器控制枱是否有錯誤信息
坑 2:加載很慢
原因:數據量大,或者網絡慢,或者性能參數配置不當。
解決:
- 檢查網絡連接
- 調整
errorTarget參數,降低細節要求 - 開啓
cullRequestsWhileMoving優化移動性能 - 檢查數據是否過大,考慮使用 LOD 優化
坑 3:內存佔用過高
原因:緩存設置過大,或者加載了太多瓦片。
解決:
- 調整
cacheBytes參數,限制緩存大小 - 降低
errorTarget,減少加載的瓦片數量 - 開啓
cullWithChildrenBounds精確剔除
坑 4:相機移動卡頓
原因:移動時加載了太多新瓦片,或者性能參數配置不當。
解決:
- 開啓
cullRequestsWhileMoving,移動時暫停加載 - 開啓
loadSiblings,預加載相鄰瓦片 - 調整
errorTarget,降低細節要求
坑 5:Cesium Ion 加載失敗
原因:沒有配置 Cesium Ion AccessToken,或者 asset ID 錯誤。
解決:
- 確保配置了 Cesium Ion AccessToken
- 檢查 asset ID 是否正確
- 確認 asset ID 對應的資源存在且有訪問權限
我的學習總結
經過這一天的學習,我掌握了:
- 從 URL 加載:使用
new Default3DTiles({ url })從 URL 加載 - 從 Cesium Ion 加載:使用
Default3DTiles.fromAssetId()從 Cesium Ion 加載 - 性能優化:理解
errorTarget、cullRequestsWhileMoving等參數的作用 - 運行時調整:可以在運行時動態調整參數
我的感受:3D Tiles 功能很強大,但配置參數也比較多。關鍵是要理解每個參數的作用,然後根據實際需求進行優化。性能優化是一個平衡的過程,需要在細節和性能之間找到平衡點!
下一步計劃:
- 學習更多 3D Tiles 的高級功能
- 嘗試創建自定義的 3D Tiles 數據
- 做一個完整的大規模場景展示項目
學習筆記就到這裏啦!作為一個初學者,我覺得 3D Tiles 功能很強大,但配置參數也比較多。關鍵是要理解每個參數的作用,然後根據實際需求進行優化。希望我的筆記能幫到其他初學者!大家一起加油!