作為一個剛開始學習 mapvthree 的小白,今天我要學習一個超酷的效果——Bloom(泛光)!聽説這個效果能讓場景裏的物體發光,就像遊戲裏的特效一樣,想想就激動!
第一次聽説 Bloom
今天在文檔裏看到了 Bloom 這個詞,查了一下才知道,原來這就是那種讓物體周圍有一圈光暈的效果!就像看太陽的時候,眼睛周圍會有那種"溢出"的光暈一樣。
文檔説 Bloom 可以讓:
- 場景更有層次感(聽起來很專業)
-
- 氛圍更好(這個我懂!)
-
- 高亮區域更真實(比如太陽、燈光)
-
- 重要元素更突出(這個實用!) 我的理解:簡單説就是讓亮的東西更亮,而且會"發光"!就像給物體加了個光環特效!
第一步:先看看怎麼開啓
作為一個初學者,我習慣先看最簡單的例子。文檔説可以通過 engine.rendering.features.bloom 來控制。
嘗試 1:初始化時就開啓
我照着文檔寫了個最簡單的例子:
import * as mapvthree from '@baidumap/mapv-three';
// 先獲取容器(這個我熟悉)
const container = document.getElementById('container');
// 創建引擎,順便把 Bloom 打開
const engine = new mapvthree.Engine(container, {
map: {
center: [116.414, 39.915],
range: 500,
heading: 225,
pitch: 70,
},
rendering: {
enableAnimationLoop: true,
features: {
bloom: {
enabled: true, // 就這一行!開啓 Bloom!
},
},
},
});
我的想法:看起來很簡單嘛!就是在配置里加個 enabled: true。但是...我運行了代碼,怎麼什麼都沒發生?
嘗試 2:運行時開啓
文檔説也可以在創建引擎後再開啓,我試試:
// 先創建引擎(不開啓 Bloom)
const engine = new mapvthree.Engine(container, {
// ... 其他配置
});
// 然後手動開啓
engine.rendering.features.bloom.enabled = true;
我的發現:原來可以動態控制!這樣我就可以做個開關按鈕了,想想就興奮!
第二步:為什麼沒效果?
我開啓了 Bloom,但是場景裏什麼都沒變化...我開始懷疑是不是我理解錯了。
看了文檔才知道,開啓 Bloom 只是第一步,還要讓物體"足夠亮"才會有效果!
文檔説顏色值要超出 RGB 範圍(0-1),比如顏色值可以是 10、20 這樣的大數字!這刷新了我的認知,原來顏色值不一定是 0-1 啊!
第三步:第一次看到泛光效果!
我照着文檔寫了個測試代碼:
import * as mapvthree from '@baidumap/mapv-three';
import {Mesh, MeshBasicMaterial, IcosahedronGeometry, Color} from 'three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container, {
map: {
provider: null,
center: [0, 0],
heading: 0,
pitch: 85,
range: 50,
},
rendering: {
sky: null,
enableAnimationLoop: true,
features: {
bloom: {
enabled: true,
},
},
},
});
// 創建一個超亮的紅色球體(顏色值是 10!)
const glowingBox = engine.add(new Mesh(
new IcosahedronGeometry(5, 15),
new MeshBasicMaterial({
color: new Color(10, 0, 0), // 紅色值 10,超出正常範圍!
})
));
glowingBox.position.set(-10, 0, 0);
// 再創建一個正常顏色的球體(對比用)
const normalBox = engine.add(new Mesh(
new IcosahedronGeometry(5, 15),
new MeshBasicMaterial({
color: new Color(0.5, 0, 0), // 正常顏色值
})
));
normalBox.position.set(0, 0, 0);
我的反應:哇!真的發光了!那個紅色的球體周圍有一圈紅色的光暈!太酷了!
對比一下,正常顏色的球體就沒有光暈,只有超亮的那個才有。我終於理解了!
第四步:探索參數
看到效果後,我開始好奇:能不能調整光暈的強度?能不能控制哪些區域發光?
文檔説有三個參數可以調:
strength:泛光強度(默認 0.1)-
threshold:泛光閾值(默認 1)
-
radius:泛光半徑(默認 0)
嘗試調整 strength
我試着把強度調大:
engine.rendering.features.bloom.strength = 0.5; // 從 0.1 調到 0.5
我的發現:光暈變強了!但是太強了有點刺眼...我又調回 0.2,感覺剛剛好。看來參數要慢慢調,找到合適的值。
嘗試調整 threshold
文檔説這個值控制"多亮才會發光"。我試了試:
engine.rendering.features.bloom.threshold = 0.5; // 降低閾值
我的發現:降低閾值後,更多區域開始發光了!但是有些不太亮的地方也開始發光,感覺有點亂。我又調回 1.0,感覺這樣只有真正亮的地方才發光,更自然。
嘗試調整 radius
engine.rendering.features.bloom.radius = 0.5; // 增加半徑
我的發現:光暈擴散得更大了!看起來更柔和,但是也模糊了一些。我試了幾個值,發現 0.2-0.3 之間比較舒服。
我的總結:調參數就像調音效一樣,要慢慢試,找到自己覺得舒服的值!
第五步:發現新方法——PBR 材質!
我以為只有用超大的顏色值才能發光,結果文檔説還有另一種方法:用 PBR 材質配合光照!
我試了試:
import * as mapvthree from '@baidumap/mapv-three';
import {Mesh, MeshStandardMaterial, IcosahedronGeometry, Color} from 'three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container, {
map: {
provider: null,
center: [0, 0],
heading: 0,
pitch: 85,
range: 50,
},
rendering: {
sky: null,
enableAnimationLoop: true,
features: {
bloom: {
enabled: true,
},
},
},
});
// 添加動態天空(提供光照)
const sky = engine.add(new mapvthree.DynamicSky());
// 設置時間(這個我查了文檔才知道怎麼用)
engine.clock.currentTime = new Date('2025-05-15 10:00:00');
engine.clock.tickMode = engine.clock.TICK_NORMAL;
// 創建一個鏡面反射的球體
const reflectiveBox = engine.add(new Mesh(
new IcosahedronGeometry(5, 15),
new MeshStandardMaterial({
color: new Color(1, 0, 0), // 正常顏色值
roughness: 0, // 完全光滑(像鏡子)
metalness: 0.9, // 高金屬度
})
));
reflectiveBox.position.set(10, 0, 0);
我的驚喜:哇!這個球體也發光了!雖然顏色值是正常的 1,但是因為它是鏡面的,反射的光經過計算後超出了 RGB 範圍,所以也產生了泛光!
這太神奇了!原來不一定要手動設置超大顏色值,通過材質屬性也能實現!
第六步:發現第三種方法——自發光!
文檔還説可以用 emissive(自發光)屬性,我趕緊試試:
import * as mapvthree from '@baidumap/mapv-three';
import {Mesh, MeshStandardMaterial, SphereGeometry, Color} from 'three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container, {
map: {
center: [116.414, 39.915],
range: 500,
},
rendering: {
enableAnimationLoop: true,
features: {
bloom: {
enabled: true,
},
},
},
});
// 創建一個自發光的球體
const emissiveSphere = engine.add(new Mesh(
new SphereGeometry(10, 32, 32),
new MeshStandardMaterial({
color: new Color(0xffffff),
emissive: new Color(0x00ffff), // 青色自發光
emissiveIntensity: 1.5, // 強度超過 1
})
));
const position = engine.map.projectArrayCoordinate([116.414, 39.915]);
emissiveSphere.position.set(position[0], position[1], 10);
我的感受:這個球體看起來就像個發光的燈泡!emissive 屬性讓物體自己發光,配合 Bloom 效果,看起來特別真實!
第七步:做一個完整的對比測試
我想看看三種方法的效果對比,就寫了個完整的測試:
import * as mapvthree from '@baidumap/mapv-three';
import {Mesh, MeshBasicMaterial, MeshStandardMaterial, IcosahedronGeometry, Color} from 'three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container, {
map: {
provider: null,
center: [0, 0],
heading: 0,
pitch: 85,
range: 50,
},
rendering: {
sky: null,
enableAnimationLoop: true,
features: {
bloom: {
enabled: true,
strength: 0.1,
threshold: 1,
radius: 0,
},
},
},
});
// 添加動態天空
const sky = engine.add(new mapvthree.DynamicSky());
engine.clock.currentTime = new Date('2025-05-15 10:00:00');
engine.clock.tickMode = engine.clock.TICK_NORMAL;
// 方法一:超大顏色值
const box1 = engine.add(new Mesh(
new IcosahedronGeometry(5, 15),
new MeshBasicMaterial({
color: new Color(10, 0, 0), // 直接設置超大值
})
));
box1.position.set(-10, 0, 0);
// 方法二:正常顏色值(對比)
const box2 = engine.add(new Mesh(
new IcosahedronGeometry(5, 15),
new MeshBasicMaterial({
color: new Color(0.5, 0, 0), // 正常值,不會發光
})
));
box2.position.set(0, 0, 0);
// 方法三:PBR 材質 + 光照
const box3 = engine.add(new Mesh(
new IcosahedronGeometry(5, 15),
new MeshStandardMaterial({
color: new Color(1, 0, 0),
roughness: 0, // 鏡面
metalness: 0.9, // 金屬
})
));
box3.position.set(10, 0, 0);
我的觀察:
- box1:直接發光,很亮很顯眼
-
- box2:不發光,就是普通的紅色
-
- box3:也發光,但是是反射光,看起來更自然 三種方法各有特點,看場景需求選擇!
第八步:實際應用場景
學到這裏,我開始想:這個效果能用在什麼地方呢?
場景 1:城市夜景
我想做個夜景場景,讓路燈發光:
import {Mesh, SphereGeometry, MeshStandardMaterial, Color} from 'three';
// 路燈
const streetLight = engine.add(new Mesh(
new SphereGeometry(2, 16, 16),
new MeshStandardMaterial({
color: new Color(0xffffaa),
emissive: new Color(0xffffaa),
emissiveIntensity: 2.0, // 高強度的自發光
})
));
我的想法:這樣路燈看起來就像真的在發光一樣!如果做城市夜景,肯定很漂亮!
場景 2:數據可視化
我想突出顯示重要的數據點:
import {Mesh, SphereGeometry, MeshBasicMaterial, Color} from 'three';
// 高亮數據點
const dataPoint = engine.add(new Mesh(
new SphereGeometry(5, 32, 32),
new MeshBasicMaterial({
color: new Color(5, 2, 0), // 強烈的橙紅色泛光
})
));
我的想法:這樣重要的數據點會特別顯眼,用户一眼就能看到!
場景 3:鏡面反射
我想做個鏡面效果:
import {Mesh, PlaneGeometry, MeshStandardMaterial, Color} from 'three';
// 鏡面
const mirror = engine.add(new Mesh(
new PlaneGeometry(20, 20),
new MeshStandardMaterial({
color: new Color(0.8, 0.8, 0.9),
roughness: 0, // 完全光滑
metalness: 1.0, // 完全金屬
})
));
我的想法:這樣看起來就像真的鏡子,反射的光也會有泛光效果!
第九步:性能注意事項
學得差不多了,我開始擔心性能問題。文檔説開啓 Bloom 會增加性能開銷,因為要用更高精度的類型存儲顏色。
我的理解:
- 內存佔用會增加
-
- GPU 計算負擔會增加
-
- 低端設備可能會卡 我的策略:
- 只在需要的時候開啓
-
- 參數不要調太大
-
- 不是所有物體都要發光,只對關鍵元素用 畢竟效果再好,卡成幻燈片也不行啊!
第十步:踩過的坑
作為一個初學者,我踩了不少坑,記錄下來避免再犯:
坑 1:開啓了 Bloom 但沒效果
原因:只開啓了 Bloom,但物體的顏色值沒有超出 RGB 範圍。
解決:要麼用超大顏色值,要麼用 PBR 材質配合光照,要麼用自發光屬性。
坑 2:效果太強刺眼
原因:strength 參數調太大了。
解決:慢慢調,找到合適的值,一般 0.1-0.5 比較舒服。
坑 3:太多地方發光,看起來很亂
原因:threshold 值太小了。
解決:提高 threshold,讓只有真正亮的地方才發光。
坑 4:用 MeshBasicMaterial 但沒光照
原因:MeshBasicMaterial 不參與光照計算,必須直接用超大顏色值。
解決:要麼改用 MeshStandardMaterial,要麼直接用超大顏色值。
我的學習總結
經過這一天的學習,我掌握了:
- 如何開啓 Bloom:在配置里加
enabled: true就行 -
- 三種產生泛光的方法:
-
- 超大顏色值(最簡單直接)
-
- PBR 材質 + 光照(更自然)
-
- 自發光屬性(適合光源)
-
- 參數調整:
strength、threshold、radius要慢慢調
- 參數調整:
-
- 性能考慮:注意開銷,合理使用 我的感受:Bloom 效果真的很酷!雖然剛開始有點懵,但是看到效果的那一刻,感覺所有的努力都值了!現在我的場景也能發光發亮了!
下一步計劃:我想試試在城市夜景場景裏用 Bloom,讓整個城市亮起來!想想就興奮!
學習筆記就到這裏啦!作為一個初學者,我覺得 Bloom 效果雖然概念有點複雜,但是用起來其實不難。關鍵是多試、多調、多看效果。希望我的筆記能幫到其他初學者!大家一起加油!