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

代码简单,效果真实,性价比很高。如果你的项目需要天气效果,不妨试试这个方案。

posted @ 2025-12-24 19:15  beyondma  阅读(3)  评论(0)    收藏  举报