作為一個剛開始學習 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. 只在需要的時候開啓
    1. 參數不要調太大
    1. 不是所有物體都要發光,只對關鍵元素用 畢竟效果再好,卡成幻燈片也不行啊!

第十步:踩過的坑

作為一個初學者,我踩了不少坑,記錄下來避免再犯:

坑 1:開啓了 Bloom 但沒效果

原因:只開啓了 Bloom,但物體的顏色值沒有超出 RGB 範圍。

解決:要麼用超大顏色值,要麼用 PBR 材質配合光照,要麼用自發光屬性。

坑 2:效果太強刺眼

原因strength 參數調太大了。

解決:慢慢調,找到合適的值,一般 0.1-0.5 比較舒服。

坑 3:太多地方發光,看起來很亂

原因threshold 值太小了。

解決:提高 threshold,讓只有真正亮的地方才發光。

坑 4:用 MeshBasicMaterial 但沒光照

原因MeshBasicMaterial 不參與光照計算,必須直接用超大顏色值。

解決:要麼改用 MeshStandardMaterial,要麼直接用超大顏色值。

我的學習總結

經過這一天的學習,我掌握了:

  1. 如何開啓 Bloom:在配置里加 enabled: true 就行
    1. 三種產生泛光的方法
    • 超大顏色值(最簡單直接)
    • PBR 材質 + 光照(更自然)
    • 自發光屬性(適合光源)
    1. 參數調整strengththresholdradius 要慢慢調
    1. 性能考慮:注意開銷,合理使用 我的感受:Bloom 效果真的很酷!雖然剛開始有點懵,但是看到效果的那一刻,感覺所有的努力都值了!現在我的場景也能發光發亮了!

下一步計劃:我想試試在城市夜景場景裏用 Bloom,讓整個城市亮起來!想想就興奮!


學習筆記就到這裏啦!作為一個初學者,我覺得 Bloom 效果雖然概念有點複雜,但是用起來其實不難。關鍵是多試、多調、多看效果。希望我的筆記能幫到其他初學者!大家一起加油!