博客 / 詳情

返回

MapV-Three實現擬真的天氣效果,比想象中簡單

MapV-Three實現擬真的天氣效果,比想象中簡單

做三維地圖可視化的時候,如果場景裏總是晴空萬里,看久了難免有點單調。加上點天氣效果——下點雨、飄點雪、來點霧——整個場景立馬生動起來。

以前實現這些效果得自己寫粒子系統、調光照參數,費時費力還不一定效果好。好在MapV-Three框架已經把這些封裝好了,就兩個組件:DynamicSky(動態天空)和 DynamicWeather(動態天氣),配合使用就能搞定。

今天就來聊聊怎麼用這兩個組件實現各種天氣效果。

一、核心組件介紹

DynamicSky - 動態天空

這是天氣效果的"舞台"。它能模擬真實的大氣散射、日出日落、日夜交替,還支持體積雲(就是那種看起來很真實的雲層)。

核心能力

  • 根據時間自動調整光照(早中晚不同)
  • 大氣散射效果(地平線那種漸變)
  • 體積雲渲染
  • 環境光實時捕獲(讓場景中的物體也受天空光照影響)

DynamicWeather - 動態天氣

這是"演員"。基於DynamicSky,它能模擬各種天氣現象。

支持的天氣類型

  • clear - 晴天
  • partlyCloudy - 多雲
  • cloudy - 陰天
  • overcast - 陰沉
  • foggy - 霧天
  • rainy - 雨天
  • snowy - 雪天

重點:DynamicWeather必須配合DynamicSky使用,單獨用是不行的。

二、快速上手:實現雨天效果

先來看一個完整的例子,實現雨天場景。

完整代碼

import {useRef} from 'react';
import {Engine, DynamicSky, DynamicWeather, BingImageryTileProvider} from '@baidu/mapv-three';
import {Mesh, SphereGeometry, MeshStandardMaterial} from 'three'

const ref = useRef();
const center = [105.9151758905, 29.32990056012];

async function callback(engine) {
    const sky = engine.add(new DynamicSky());

    const weather = engine.add(new DynamicWeather(sky));
    weather.weather = 'rainy'; // clear | partlyCloudy | cloudy | overcast | foggy | rainy | snowy

    const sphere = new SphereGeometry(100, 32, 32);
    const material = new MeshStandardMaterial({
        color: 0xffff00,
        metalness: 0.8,
        roughness: 0.5,
    })
    const mesh = engine.add(new Mesh(sphere, material));
    const position = engine.map.projectArrayCoordinate(center);
    mesh.position.set(position[0], position[1], position[2]);
    
    return engine;
}

<App ref={ref} initConfig={{
    map: {
        provider: new BingImageryTileProvider(),
        center: center,
        heading: 90,
        pitch: 80,
        range: 1000,
        projection: 'EPSG:3857',
    },
    rendering: {
        sky: null,
        enableAnimationLoop: true,
    },
    clock: {
        currentTime: new Date('2025-05-15 14:30:00'),
    }
}} callback={callback} />

代碼解析

第一步:創建動態天空

const sky = engine.add(new DynamicSky());

這是基礎,所有天氣效果都依賴它。

第二步:創建天氣實例

const weather = engine.add(new DynamicWeather(sky));
weather.weather = 'rainy';

注意要把 sky 傳進去。然後通過 weather.weather 屬性設置天氣類型。這裏設置為 'rainy',就會出現下雨效果。

第三步:添加測試物體(可選)

代碼里加了一個黃色球體,目的是看天氣對場景物體的光照影響。下雨時,光線會變暗,球體顏色也會跟着變。

關鍵配置

  • enableAnimationLoop: true:必須開啓動畫循環,不然雨滴不會動
  • sky: null:初始化時不設置天空,因為我們要在callback裏手動添加DynamicSky
  • currentTime:設置初始時間,影響光照效果。下午2點半光照比較充足

運行效果

跑起來之後,你會看到:

  1. 天空是灰濛濛的(陰雨天的感覺)
  2. 畫面上有雨滴飄落(粒子效果)
  3. 場景整體光線偏暗
  4. 球體表面有明顯的光照變化

三、切換不同天氣

天氣切換非常簡單,就改一個屬性值。

七種天氣效果

// 晴天 - 陽光明媚
weather.weather = 'clear';

// 多雲 - 有云但不影響光照
weather.weather = 'partlyCloudy';

// 陰天 - 雲層較厚,光線減弱
weather.weather = 'cloudy';

// 陰沉 - 更暗,像要下雨的樣子
weather.weather = 'overcast';

// 霧天 - 能見度降低,有霧氣效果
weather.weather = 'foggy';

// 雨天 - 下雨,天空灰暗
weather.weather = 'rainy';

// 雪天 - 下雪,比雨天更冷的感覺
weather.weather = 'snowy';

實時切換

如果想做一個天氣切換功能,可以這樣:

// 假設有個下拉框讓用户選擇天氣
const weatherSelect = document.querySelector('#weather-select');

weatherSelect.addEventListener('change', (e) => {
    weather.weather = e.target.value;
});

就這麼簡單,用户選什麼天氣,場景就立即切換。

四、理解DynamicSky的作用

為什麼DynamicWeather一定要配合DynamicSky使用?因為DynamicSky提供了幾個關鍵能力:

1. 光照系統

DynamicSky會根據時間自動調整太陽光、環境光的強度和顏色。

比如:

  • 早晨6點:太陽剛升起,光線偏橙紅色
  • 中午12點:陽光最強,白色光
  • 傍晚18點:夕陽西下,偏金黃色
  • 晚上22點:只有微弱的環境光

這些光照變化會直接影響天氣效果的真實感。

2. 大氣散射

這是那種"地平線處天空泛藍,頭頂深藍"的效果。真實的大氣散射能讓整個場景更有層次感。

3. 體積雲

普通的天空盒用的是貼圖,看起來像一張平面照片。DynamicSky的體積雲是3D的,有厚度、有光影,看起來就是真的雲。

4. 環境光捕獲

這個比較厲害。DynamicSky會實時提取天空顏色,作為環境光影響場景中的物體。

舉個例子:

  • 晴天時,天空是藍色的,場景物體表面也會帶點藍色反光
  • 雨天時,天空是灰色的,物體也會顯得灰暗

這種細節讓整個場景的色調統一,看起來更協調。

五、初始化時直接設置天空

前面的例子是在callback裏手動添加DynamicSky,其實也可以在初始化時直接設置:

const initConfig = {
    map: {
        provider: new BingImageryTileProvider(),
        center: center,
        pitch: 88,
        range: 1000,
    },
    rendering: {
        sky: new DynamicSky(), // 直接在這裏設置
        enableAnimationLoop: true,
    }
};

async function callback(engine) {
    // 從引擎獲取天空實例
    const sky = engine.rendering.sky;
    
    // 創建天氣
    const weather = engine.add(new DynamicWeather(sky));
    weather.weather = 'snowy';

    return engine;
}

兩種方式都可以,看個人習慣。

六、常見問題與注意事項

問題1:看不到天氣效果

排查清單

  1. 是否開啓了 enableAnimationLoop
  2. DynamicWeather是否傳入了DynamicSky實例?
  3. 相機視角是否合適?(太低或太高可能看不清)
  4. 天氣類型是否拼寫正確?

問題2:時間設置的作用

clock.currentTime 設置的是場景初始時間,它會影響光照效果。

  • 設置白天時間(如14:00):光照充足
  • 設置夜晚時間(如22:00):光照很暗

如果你想看雨天效果,建議設置在白天或傍晚,太暗的話雨滴看不清。

七、實用場景

場景1:天氣預報可視化

實時顯示某個地區的天氣狀況:

// 根據API獲取天氣數據
fetch('/api/weather').then(res => res.json()).then(data => {
    // 假設API返回 {condition: 'rainy', temperature: 18}
    weather.weather = data.condition;
});

場景2:場景氛圍烘托

遊戲或展示類項目中,用天氣烘托氛圍。比如懸疑場景用霧天,悲傷場景用雨天。

場景3:時間與天氣聯動

模擬真實的晝夜和天氣變化:

// 設置時間自動更新
sky.timeAnimation = true;
sky.timeAnimationSpeed = 240; // 加速播放

// 根據時間段自動調整天氣
setInterval(() => {
    const hour = engine.clock.currentTime.getHours();
    
    if (hour >= 6 && hour < 12) {
        weather.weather = 'clear'; // 早晨晴天
    } else if (hour >= 12 && hour < 18) {
        weather.weather = 'partlyCloudy'; // 下午多雲
    } else {
        weather.weather = 'foggy'; // 晚上起霧
    }
}, 5000);

八、總結

MapV-Three的天氣系統就兩個組件:

DynamicSky:提供動態光照、大氣散射、體積雲等基礎能力
DynamicWeather:基於DynamicSky,實現各種天氣效果

使用步驟

  1. 創建DynamicSky實例
  2. 創建DynamicWeather實例,傳入sky
  3. 設置 weather.weather 屬性切換天氣
  4. 記得開啓 enableAnimationLoop

七種天氣:clear、partlyCloudy、cloudy、overcast、foggy、rainy、snowy

代碼簡單,效果真實,性價比很高。如果你的項目需要天氣效果,不妨試試這個方案。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.