Threejs案例
Cloud

使用 Three.js 创建逼真的暴风雨场景

本文将详细介绍如何使用 Three.js 构建一个视觉效果强烈的暴风雨场景。

通过结合粒子系统、纹理加载以及光照控制,我们能创建出带有云层、闪电、雨滴以及雾气效果的逼真动态场景。

一、功能概述

  • 云层效果:利用透明的纹理图片实现云层。

  • 降雨效果:利用粒子系统生成大量雨滴。

  • 闪电效果:通过随机控制点光源实现闪电瞬间的亮光闪烁。

  • 雾化效果:场景中启用指数雾效,增加场景真实感和景深感。

二、初始化场景和相机设置

在这一部分,我们初始化了 Three.js 必备的基础元素:场景、相机和渲染器。这三个元素分别负责管理所有物体、观察视角以及画面呈现。相机参数经过精心调整,以产生独特的视角效果。

  • 场景:用于包含所有的图像、光线和环境效果。
  • 相机:使用透视相机,并且通过特定的旋转来模拟观看天空的角度。
  • 渲染器:负责将场景渲染到画布上,并启用雾效背景。

代码实现及详解

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
// 设置相机位置和旋转角度,以模拟向天空仰视的效果
camera.position.set(0, 0, 1);
camera.rotation.set(1.16, -0.12, 0.27);
 
renderer = new THREE.WebGLRenderer();
scene.fog = new THREE.FogExp2(0x11111f, 0.002); // 指数型雾效,模拟雨雾中的视距衰减
renderer.setClearColor(scene.fog.color);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

我们使用指数雾效(FogExp2)实现真实的景深感,使远处的物体逐渐被雾气遮挡而变得模糊。

三、光源设置与闪电效果

为了模拟暴风雨中特殊的闪电效果,我们组合使用了环境光、方向光以及点光源。特别是点光源(PointLight)用于模拟闪电,通过随机闪烁的位置和强度实现真实感。

代码实现及详解

ambient = new THREE.AmbientLight(0x555555); // 环境光提供基础照明,避免场景过暗
scene.add(ambient);
 
directionalLight = new THREE.DirectionalLight(0xffeedd); // 模拟方向性的微弱光照,增强立体感
directionalLight.position.set(0, 0, 1);
scene.add(directionalLight);
 
flash = new THREE.PointLight(0x062d89, 30, 500, 1.7); // 闪电点光源
flash.position.set(200, 300, 100);
scene.add(flash);

点光源强度随机变化的逻辑放在动画循环中,通过随机概率实现闪电忽明忽暗的自然效果。

四、雨滴粒子系统的创建与控制

降雨效果通过Three.js的粒子系统实现。我们定义了大量随机位置的粒子,这些粒子将模拟雨滴从天空坠落的效果。

代码实现及详解

rainGeo = new THREE.BufferGeometry();
let positions = [];
for (let i = 0; i < rainCount; i++) {
	positions.push(
		Math.random() * 400 - 200,
		Math.random() * 500 - 250,
		Math.random() * 400 - 200
	);
}
rainGeo.setAttribute('position', new THREE.BufferAttribute(new Float32Array(positions), 3));
rainMaterial = new THREE.PointsMaterial({
	color: 0xaaaaaa,
	size: 0.1,
	transparent: true
});
rain = new THREE.Points(rainGeo, rainMaterial);
scene.add(rain);

此处我们使用了BufferGeometry来高效处理大量粒子,性能更好,渲染更快。

五、云层纹理加载与位置摆放

云层采用透明纹理,通过TextureLoader加载外部图片

并创建多个平面网格(Mesh)组成云层场景,每个云层都随机旋转以增加真实感。

代码实现及详解

let loader = new THREE.TextureLoader();
loader.load(
	'YOUR_CLOUD_TEXTURE_URL', // 云纹理URL
	function(texture) {
		cloudGeo = new THREE.PlaneBufferGeometry(500, 500);
		cloudMaterial = new THREE.MeshLambertMaterial({ map: texture, transparent: true });
 
		for (let p = 0; p < 25; p++) {
			let cloud = new THREE.Mesh(cloudGeo, cloudMaterial);
			cloud.position.set(Math.random() * 800 - 400, 500, Math.random() * 500 - 450);
			cloud.rotation.set(1.16, -0.12, Math.random() * Math.PI * 2);
			cloud.material.opacity = 0.6;
			cloudParticles.push(cloud);
			scene.add(cloud);
		}
		animate();
		window.addEventListener('resize', onWindowResize);
	}
);

云层透明度控制在0.6,以实现较真实的透光效果。

六、动画与动态效果实现

通过动画循环控制云层的缓慢旋转、雨滴位置的动态调整以及闪电随机效果,使整个场景更具动态感和真实感。

代码实现及详解

function animate() {
	cloudParticles.forEach((p) => {
		p.rotation.z -= 0.002; // 缓慢旋转云层
	});
 
	// 雨滴下落效果
	rain.position.z -= 0.222;
	if (rain.position.z < -200) rain.position.z = 0;
 
	// 闪电随机闪烁
	if (Math.random() > 0.93 || flash.power > 100) {
		if (flash.power < 100)
			flash.position.set(Math.random() * 400, 300 + Math.random() * 200, 100);
		flash.power = 50 + Math.random() * 500;
	}
 
	renderer.render(scene, camera);
	requestAnimationFrame(animate);
}

动画循环通过requestAnimationFrame保证流畅的帧率和性能。

七、窗口自适应

场景随着窗口尺寸的变化自动调整画布和相机视野,保证显示效果的一致性。

代码实现及详解

function onWindowResize() {
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize(window.innerWidth, window.innerHeight);
}

八、总结

通过组合运用粒子系统、纹理加载、光照和动态动画,我们成功打造了一个真实的暴风雨场景。

这些技术不仅适用于天气效果模拟,还可以扩展到其他动态特效场景的实现。希望本文能帮你理解 Three.js 中各种技术细节的结合运用,并激发你的更多创作灵感。