作為一個剛開始學習 mapvthree 的小白,今天要學習渲染系統了!聽説這個系統可以控制場景的渲染方式,還能開啓動畫循環、配置渲染特效等!想想就激動!
第一次聽説渲染系統
今天在文檔裏看到了 engine.rendering 這個詞,一開始我還以為是用來畫圖的,結果查了一下才知道,原來這是用來控制場景渲染的模塊!
文檔説渲染系統可以:
- 控制動畫循環
- 配置渲染特效(如 Bloom、抗鋸齒等)
- 監聽渲染事件
- 監控渲染性能
- 控制渲染質量
我的理解:簡單説就是控制"怎麼渲染場景",比如要不要每幀都渲染、用什麼特效、怎麼優化性能等!
第一步:發現引擎的渲染屬性
作為一個初學者,我習慣先看看引擎有哪些屬性。文檔説 engine.rendering 就是渲染管理器!
我的發現:原來引擎創建後,就自動有了一個渲染管理器對象!不需要手動創建,直接用就行!
import * as mapvthree from '@baidumap/mapv-three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container);
// 渲染管理器已經自動創建了!
console.log(engine.rendering); // 可以訪問渲染管理器
我的理解:engine.rendering 就是渲染系統的入口,所有渲染相關的操作都通過它來完成。
第二步:開啓循環渲染
文檔説可以通過 engine.rendering.enableAnimationLoop 來開啓循環渲染。我試了試:
// 開啓循環渲染
engine.rendering.enableAnimationLoop = true;
我的疑問:什麼是循環渲染?為什麼要開啓?
看了文檔才知道,默認情況下,引擎只在需要時渲染(比如拖動地圖時)。開啓循環渲染後,引擎會每幀都渲染,適合有動畫的場景。
我的嘗試:我寫了個簡單的測試:
import * as mapvthree from '@baidumap/mapv-three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container, {
map: {
center: [116.404, 39.915],
range: 1000,
},
rendering: {
enableAnimationLoop: true, // 開啓循環渲染
},
});
我的發現:開啓後,如果有動畫效果(比如飛線、粒子等),會持續播放!
我的理解:
- 默認關閉:只在需要時渲染,節省性能
- 開啓後:每幀都渲染,適合有動畫的場景
我的注意:如果場景沒有動畫,建議不要開啓,可以節省性能!
第三步:設置幀率
看到循環渲染後,我開始好奇:能不能控制渲染的幀率?
文檔説可以通過 engine.rendering.animationLoopFrameTime 來設置幀時間間隔!
// 設置幀時間間隔為 16 毫秒(約 60 FPS)
engine.rendering.animationLoopFrameTime = 16;
我的理解:animationLoopFrameTime 是每幀之間的時間間隔(毫秒),默認是 16 毫秒,約等於 60 FPS。
我的嘗試:
// 60 FPS(默認)
engine.rendering.animationLoopFrameTime = 16;
// 30 FPS
engine.rendering.animationLoopFrameTime = 33;
// 120 FPS(更快,但更耗性能)
engine.rendering.animationLoopFrameTime = 8;
我的發現:
16:約 60 FPS,流暢33:約 30 FPS,稍慢但省性能8:約 120 FPS,很快但耗性能
我的想法:如果做性能優化,可以降低幀率來節省性能!
第四步:監聽渲染事件
看到循環渲染後,我想:能不能在渲染時執行一些操作?
文檔説可以用 engine.rendering.addPrepareRenderListener() 來監聽渲染事件!
engine.rendering.addPrepareRenderListener((engine, renderState) => {
// 每幀渲染前都會執行這裏的代碼
console.log('正在渲染...');
});
我的理解:addPrepareRenderListener() 會在每幀渲染前調用,可以在這裏執行一些操作。
我的嘗試:
// 監聽渲染事件
engine.rendering.addPrepareRenderListener((engine, renderState) => {
// 獲取當前視野距離
const range = engine.map.getRange();
// 根據視野距離控制模型的顯示隱藏
if (range > 1000) {
// 視野太遠,隱藏模型
mesh.visible = false;
} else {
// 視野較近,顯示模型
mesh.visible = true;
}
});
我的發現:可以在渲染時根據場景狀態動態調整物體!
我的想法:如果做性能優化,可以用這個方法來根據視野距離控制模型的顯示!
檢查視野是否變化
文檔説可以用 renderState.viewChanged 來判斷視野是否變化!
engine.rendering.addPrepareRenderListener((engine, renderState) => {
if (renderState.viewChanged) {
// 只有視野變化時才執行
console.log('視野變化了!');
}
});
我的理解:viewChanged 可以判斷視野是否變化,避免不必要的操作。
我的發現:配合 viewChanged 使用,可以減少無效的回調調用,提升性能!
我的建議:使用 addPrepareRenderListener 時,建議配合 viewChanged 檢查,避免無效回調!
第五步:瞭解渲染特性
看到渲染監聽後,我開始好奇:什麼是渲染特性?
文檔説可以通過 engine.rendering.features 來配置渲染特性,比如抗鋸齒、Bloom 等!
開啓抗鋸齒
// 開啓抗鋸齒
engine.rendering.features.antialias.enabled = true;
engine.rendering.features.antialias.method = 'smaa';
我的理解:抗鋸齒可以讓畫面更平滑,減少鋸齒感。
我的發現:默認是開啓的,所以一般不需要手動設置。
開啓 Bloom 泛光
// 開啓 Bloom 泛光
engine.rendering.features.bloom.enabled = true;
engine.rendering.features.bloom.strength = 0.1;
engine.rendering.features.bloom.threshold = 1;
engine.rendering.features.bloom.radius = 0;
我的理解:Bloom 可以讓亮的地方更亮,產生泛光效果。
我的發現:這個功能我在之前的 Bloom 學習筆記裏學過,這裏可以統一配置!
第六步:設置像素比
看到渲染特性後,我想:能不能控制渲染的分辨率?
文檔説可以通過 engine.rendering.pixelRatio 來設置設備像素比!
// 設置像素比
engine.rendering.pixelRatio = 1.0;
我的理解:pixelRatio 控制渲染的分辨率,默認是 window.devicePixelRatio。
我的嘗試:
// 正常分辨率(默認)
engine.rendering.pixelRatio = window.devicePixelRatio;
// 降低分辨率(節省性能)
engine.rendering.pixelRatio = 1.0;
// 提高分辨率(更清晰,但更耗性能)
engine.rendering.pixelRatio = 2.0;
我的發現:
1.0:標準分辨率,性能好2.0:高分辨率,更清晰但耗性能window.devicePixelRatio:根據設備自動調整(默認)
我的想法:如果做性能優化,可以降低像素比來提升性能!
第七步:使用高質量緩衝區
看到像素比後,我開始好奇:什麼是高質量緩衝區?
文檔説可以通過 engine.rendering.useHighPrecisionBuffer 來開啓高質量緩衝區!
// 開啓高質量緩衝區
engine.rendering.useHighPrecisionBuffer = true;
我的理解:高質量緩衝區可以提升畫面質量,但會增加性能開銷。
我的發現:
- 默認是
false,使用低質量緩衝區 - 開啓後使用高質量緩衝區,畫面更清晰
- 某些渲染特性(如 Bloom、反射)會自動開啓
我的嘗試:
// 開啓高質量緩衝區
engine.rendering.useHighPrecisionBuffer = true;
我的發現:開啓後,畫面質量確實提升了,但是性能也下降了。
我的建議:只有在需要高質量畫面或使用高級渲染特性時才開啓!
第八步:使用調試模式
看到高質量緩衝區後,我想:有沒有調試模式?
文檔説可以用 engine.rendering.debugMode 來開啓調試模式!
// 開啓調試模式
engine.rendering.debugMode = 1; // DEBUG_MODE_MESH
我的理解:調試模式可以顯示渲染的詳細信息,方便調試。
我的發現:
0:無調試模式(默認)1:網格調試模式2:材質調試模式3:物體調試模式
我的嘗試:
// 開啓網格調試模式
engine.rendering.debugMode = 1;
我的發現:開啓後,可以看到網格的詳細信息,方便調試!
我的注意:調試模式主要用於開發,生產環境建議關閉!
第九步:凍結更新
看到調試模式後,我想:能不能暫停渲染更新?
文檔説可以用 engine.rendering.freezeUpdate 來凍結更新!
// 凍結更新
engine.rendering.freezeUpdate = true;
// 恢復更新
engine.rendering.freezeUpdate = false;
我的理解:凍結更新後,場景不會更新,但可以繼續交互。
我的嘗試:
// 凍結更新
engine.rendering.freezeUpdate = true;
// 做一些操作...
// 恢復更新
engine.rendering.freezeUpdate = false;
我的發現:凍結後,場景會停止更新,適合做批量操作!
我的想法:如果做批量更新,可以先凍結,更新完再恢復,可以提升性能!
第十步:獲取渲染對象
看到這麼多屬性後,我想:能不能直接訪問底層的渲染對象?
文檔説可以通過 engine.rendering.renderer、engine.rendering.scene、engine.rendering.camera 來訪問底層對象!
// 獲取渲染器
const renderer = engine.rendering.renderer;
// 獲取場景
const scene = engine.rendering.scene;
// 獲取相機
const camera = engine.rendering.camera;
我的理解:這些是 Three.js 的底層對象,可以直接操作。
我的發現:可以直接訪問 Three.js 對象,可以做更底層的操作!
我的注意:直接操作底層對象需要了解 Three.js,建議謹慎使用!
獲取渲染分辨率
文檔説可以用 engine.rendering.resolution 來獲取渲染分辨率!
// 獲取渲染分辨率
const resolution = engine.rendering.resolution;
console.log(resolution); // 分辨率信息
我的發現:可以獲取當前渲染的分辨率,方便做適配!
獲取動畫管理器
文檔説可以用 engine.rendering.animation 來獲取動畫管理器!
// 獲取動畫管理器
const animation = engine.rendering.animation;
我的理解:動畫管理器可以用來控制場景中的動畫效果。
我的發現:可以通過動畫管理器來統一管理場景中的動畫!
獲取標籤實例
文檔説可以用 engine.rendering.label 來獲取標籤實例!
// 獲取標籤實例
const label = engine.rendering.label;
我的理解:標籤實例可以用來管理場景中的標籤。
我的發現:可以通過標籤實例來統一管理場景中的標籤!
獲取拾取器實例
文檔説可以用 engine.rendering.picking 來獲取拾取器實例!
// 獲取拾取器實例
const picking = engine.rendering.picking;
我的理解:拾取器可以用來檢測鼠標點擊的對象。
我的發現:可以通過拾取器來實現點擊交互功能!
獲取天氣實例
文檔説可以用 engine.rendering.weather 來獲取天氣實例!
// 獲取天氣實例
const weather = engine.rendering.weather;
我的理解:如果場景中有天氣效果,可以通過這個屬性訪問。
我的發現:可以獲取天氣實例,然後控制天氣效果!
獲取天空實例
文檔説可以用 engine.rendering.sky 來獲取天空實例!
// 獲取天空實例
const sky = engine.rendering.sky;
我的理解:如果場景中有天空,可以通過這個屬性訪問。
我的發現:可以獲取天空實例,然後控制天空效果!
第十一步:獲取渲染狀態
看到底層對象後,我想:能不能獲取渲染狀態?
文檔説可以用 engine.rendering.renderState 來獲取渲染狀態!
// 獲取渲染狀態
const renderState = engine.rendering.renderState;
// 檢查視野是否變化
if (renderState.viewChanged) {
console.log('視野變化了!');
}
我的理解:renderState 保存了渲染狀態信息,比如視野變化、相機位置等。
我的發現:可以在渲染監聽中使用 renderState 來獲取狀態信息!
第十二步:自動偏移相機和場景
看到渲染狀態後,我想:什麼是自動偏移?
文檔説可以通過 engine.rendering.autoOffsetRelativeCenter 來設置自動偏移!
// 開啓自動偏移
engine.rendering.autoOffsetRelativeCenter = true;
我的理解:自動偏移可以讓相機和場景自動偏移,使 worldMatrix 偏移量較小,提升精度。
我的發現:開啓後,可以提升座標精度,適合大範圍場景!
我的注意:這個功能主要用於大範圍場景,一般場景不需要開啓!
第十三步:保留繪圖緩衝區
看到自動偏移後,我想:什麼是保留繪圖緩衝區?
文檔説可以通過 contextParameters.preserveDrawingBuffer 來設置保留繪圖緩衝區!
const engine = new mapvthree.Engine(container, {
rendering: {
contextParameters: {
preserveDrawingBuffer: true, // 開啓保留繪圖緩衝區
},
},
});
我的理解:保留繪圖緩衝區可以讓截圖功能正常工作。
我的發現:如果要做截圖功能,需要開啓這個選項!
我的嘗試:
const engine = new mapvthree.Engine(container, {
rendering: {
contextParameters: {
preserveDrawingBuffer: true, // 開啓截圖功能
},
},
});
// 截圖
const dataURL = engine.rendering.renderer.domElement.toDataURL();
我的發現:開啓後,可以正常截圖了!
我的注意:開啓後會稍微影響性能,只在需要截圖時開啓!
第十四步:初始化時配置渲染
看到這麼多屬性後,我想:能不能在創建引擎時就配置渲染?
文檔説可以在引擎初始化時通過 rendering 配置項來設置渲染參數!
const engine = new mapvthree.Engine(container, {
map: {
center: [116.404, 39.915],
range: 1000,
},
rendering: {
enableAnimationLoop: true,
animationLoopFrameTime: 16,
pixelRatio: 1.0,
features: {
antialias: {
enabled: true,
method: 'smaa',
},
bloom: {
enabled: true,
strength: 0.1,
threshold: 1,
radius: 0,
},
},
},
});
我的發現:可以在初始化時一次性配置所有渲染參數,更方便!
我的理解:
enableAnimationLoop:是否開啓循環渲染animationLoopFrameTime:幀時間間隔pixelRatio:像素比features:渲染特性配置
我的嘗試:
const engine = new mapvthree.Engine(container, {
map: {
center: [116.404, 39.915],
range: 1000,
},
rendering: {
enableAnimationLoop: true,
animationLoopFrameTime: 16,
features: {
bloom: {
enabled: true,
},
},
},
});
我的發現:初始化時就配置好了,代碼更簡潔!
第十五步:實際應用場景
學到這裏,我開始想:渲染系統能用在什麼地方呢?
場景 1:動畫場景
如果場景中有動畫效果(如飛線、粒子等),需要開啓循環渲染:
engine.rendering.enableAnimationLoop = true;
我的想法:這樣動畫才能持續播放!
場景 2:性能優化
如果場景性能不好,可以優化渲染設置:
// 降低幀率
engine.rendering.animationLoopFrameTime = 33;
// 降低像素比
engine.rendering.pixelRatio = 1.0;
// 關閉不必要的特效
engine.rendering.features.bloom.enabled = false;
我的想法:這樣可以提升性能,讓場景更流暢!
場景 3:根據視野控制顯示
如果場景中有很多模型,可以根據視野距離控制顯示:
engine.rendering.addPrepareRenderListener((engine, renderState) => {
if (renderState.viewChanged) {
const range = engine.map.getRange();
// 根據視野距離控制模型顯示
models.forEach(model => {
model.visible = range < 5000;
});
}
});
我的想法:這樣可以根據視野距離動態控制模型,提升性能!
第十六步:做一個完整的示例
我想寫一個完整的示例,把學到的都用上:
import * as mapvthree from '@baidumap/mapv-three';
import {Mesh, BoxGeometry, MeshStandardMaterial, Color} from 'three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container, {
map: {
center: [116.404, 39.915],
range: 1000,
pitch: 60,
},
rendering: {
enableAnimationLoop: true,
animationLoopFrameTime: 16,
pixelRatio: 1.0,
features: {
bloom: {
enabled: true,
strength: 0.1,
},
},
},
});
// 創建一個模型
const geometry = new BoxGeometry(50, 50, 50);
const material = new MeshStandardMaterial({
color: new Color(2, 2, 0),
});
const mesh = new Mesh(geometry, material);
engine.add(mesh);
const position = engine.map.projectArrayCoordinate([116.404, 39.915]);
mesh.position.set(position[0], position[1], 0);
// 監聽視野變化,控制模型顯示
engine.rendering.addPrepareRenderListener((engine, renderState) => {
if (renderState.viewChanged) {
const range = engine.map.getRange();
// 視野太遠時隱藏模型
if (range > 1000) {
mesh.visible = false;
} else {
mesh.visible = true;
}
}
});
我的感受:寫一個完整的示例,把學到的都用上,感覺很有成就感!
我的發現:
- 可以控制渲染循環
- 可以配置渲染特性
- 可以監聽渲染事件
- 可以監控渲染性能
雖然代碼還很簡單,但是已經能做出一個基本的渲染控制系統了!
第十七步:踩過的坑
作為一個初學者,我踩了不少坑,記錄下來避免再犯:
坑 1:動畫不播放
原因:沒有開啓循環渲染。
解決:設置 engine.rendering.enableAnimationLoop = true。
坑 2:性能不好
原因:開啓了循環渲染但沒有動畫,或者像素比太高。
解決:
- 如果沒有動畫,不要開啓循環渲染
- 降低像素比
- 降低幀率
坑 3:修改數據後場景不更新
原因:沒有開啓循環渲染,或者需要手動請求渲染。
解決:
- 開啓循環渲染(如果有動畫)
- 或者調用
engine.requestRender()手動請求渲染
坑 4:渲染監聽回調執行太頻繁
原因:沒有檢查 viewChanged,導致每次渲染都執行。
解決:配合 renderState.viewChanged 檢查,只在視野變化時執行。
坑 5:高質量緩衝區影響性能
原因:開啓了高質量緩衝區但沒有必要。
解決:只有在需要高質量畫面或使用高級渲染特性時才開啓。
坑 6:截圖功能不工作
原因:沒有開啓 preserveDrawingBuffer。
解決:在初始化時設置 contextParameters.preserveDrawingBuffer = true。
坑 7:渲染監聽回調執行太頻繁
原因:沒有檢查 viewChanged,導致每次渲染都執行。
解決:配合 renderState.viewChanged 檢查,只在視野變化時執行。
我的學習總結
經過這一天的學習,我掌握了:
- 渲染系統的作用:控制場景的渲染方式、動畫循環、渲染特效等
- 如何開啓循環渲染:通過
enableAnimationLoop開啓 - 如何設置幀率:通過
animationLoopFrameTime設置 - 如何監聽渲染事件:通過
addPrepareRenderListener監聽 - 如何配置渲染特性:通過
features配置 Bloom、抗鋸齒等 - 如何優化性能:通過調整像素比、幀率、關閉不必要的特效等
- 如何開啓截圖功能:通過
contextParameters.preserveDrawingBuffer開啓 - 如何獲取渲染對象:通過
renderer、scene、camera等屬性訪問 - 如何獲取渲染狀態:通過
renderState獲取渲染狀態信息
我的感受:渲染系統真的很強大!雖然功能很多,但是用起來其實不難。關鍵是要理解每個功能的作用,然後根據需求合理配置!
下一步計劃:
- 學習更多渲染特性的配置
- 嘗試做性能優化
- 做一個完整的渲染控制項目
學習筆記就到這裏啦!作為一個初學者,我覺得渲染系統雖然功能很多,但是用起來其實不難。關鍵是要理解每個功能的作用,然後根據需求合理配置!希望我的筆記能幫到其他初學者!大家一起加油!