想给你的 3D 场景加上随时间变化的动态天空?别再费劲找六面贴图了!Three.js 自带的
Sky
组件,几行代码就能模拟日出日落、晴空雾霭,效果惊艳还省心。
在 Three.js 中,Sky
是一个基于物理大气散射模型(瑞利散射和米氏散射)的组件。它不用传统的六面贴图,而是通过着色器实时计算天空颜色和光照,能动态调整太阳位置、空气浑浊度等参数,轻松模拟从万里晴空到黄昏暮色的各种效果。比静态天空盒更灵活、更真实。
核心优势:
// 引入 Sky 组件
import * as THREE from 'three';
import { Sky } from 'three/examples/jsm/objects/Sky.js';
// 创建天空实例并添加到场景
javascript
const scene = new THREE.Scene();
const sky = new Sky();
sky.scale.setScalar(100000); // 把天空撑大,包裹整个场景
scene.add(sky);
// 设置 10 万以上,避免相机移动时穿帮。
// 调整关键参数
// Sky 通过 uniforms 参数控制效果。
// 以下是必调参数及典型值:
const skyUniforms = sky.material.uniforms;
// 常用参数配置
skyUniforms['turbidity'].value = 5; // 空气浑浊度 (2-20)
skyUniforms['rayleigh'].value = 2; // 瑞利散射 (控制蓝天强度)
skyUniforms['mieCoefficient'].value = 0.005; // 米氏散射系数 (影响光晕)
skyUniforms['mieDirectionalG'].value = 0.8; // 光晕方向性 (0-1)
太阳位置决定光照方向和天空颜色分布:
const sun = new THREE.Vector3();
// 设置太阳在 3D 空间中的位置 (x, y, z)
sun.set(0.3, -0.038, -0.95); // 示例:夕阳位置
skyUniforms['sunPosition'].value.copy(sun);
//别忘了同步更新场景其他光源,若场景中有模拟阳光的 `DirectionalLight`,需同步其位置:
directionalLight.position.copy(sun);
参数 | 物理原理 | 效果 | 典型值 |
---|---|---|---|
turbidity |
空气中悬浮颗粒密度 | 值越高越浑浊(雾霾天) | 2(清澈)~ 20(雾霾) |
rayleigh |
瑞利散射(短波蓝光散射) | 值越高天空越蓝 | 3(晴天)~ 0.5(暮色) |
mieCoefficient |
米氏散射(大颗粒散射) | 值越高雾感/光晕越强 | 0.005(晴)~ 0.1(雾) |
mieDirectionalG |
米氏散射方向性 | 值越高太阳光晕越集中 | 0.8(标准)~ 0.95(强光晕) |
常用天气配方参考:
// 晴天配方
turbidity: 2, rayleigh: 3, mieCoefficient: 0.005
// 黄昏配方
turbidity: 10, rayleigh: 2, mieCoefficient: 0.08
// 雾霾配方
turbidity: 20, rayleigh: 1, mieCoefficient: 0.1
通过动画循环更新太阳位置,模拟太阳轨迹:
function animate() {
requestAnimationFrame(animate);
// 随时间改变太阳高度/角度
const time = Date.now() * 0.0005;
sun.set(Math.sin(time) 100, Math.cos(time) 50, -50);
skyUniforms['sunPosition'].value.copy(sun);
// 别忘了同步光源!
directionalLight.position.copy(sun);
renderer.render(scene, camera);
}
技巧:当 sun.y < 0
(地平线下)时,可结合星空贴图实现夜空!
用 PMREMGenerator
将天空转为环境贴图,让物体反射天空光:
const pmremGenerator = new THREE.PMREMGenerator(renderer);
const envMap = pmremGenerator.fromScene(sky).texture;
scene.environment = envMap; // 全局环境光
scene.background = envMap; // 背景天空
天空全黑或者颜色出现异常?
rayleigh
是否过低(建议 ≥1)sunPosition
已正确设置并同步光源控制台报错 uniforms undefined
?
sky
实例已成功加入 scene
后再访问 material
太阳光晕不够逼真显得太假?
mieCoefficient
(0.005~0.01)mieDirectionalG
(0.8~0.95)