用 Three.js 实现下雨效果
今天我们将使用 Three.js 来实现一个简单的下雨效果。先看一下效果
1. 创建基础场景
我们从一个简单的 Three.js 场景开始,创建一个渲染器、场景和相机。
// 创建场景
const scene = new THREE.Scene();
// 创建相机,参数为视角、纵横比、近裁剪面、远裁剪面
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
2. 创建一个地面
为了让下雨效果更加真实,我们可以添加一个地面(Plane)来接收雨滴的碰撞。
const geometry = new THREE.PlaneGeometry(1000, 1000);
const material = new THREE.MeshBasicMaterial({
color: 0x0088ff,
side: THREE.DoubleSide,
});
const ground = new THREE.Mesh(geometry, material);
ground.rotation.x = -Math.PI / 2; // 将地面旋转为水平
scene.add(ground);
3. 创建雨滴
我们将使用粒子系统来模拟雨滴,创建一个由大量小球组成的雨滴。
// 雨滴的粒子材质
const rainGeometry = new THREE.SphereGeometry(0.1, 8, 8);
const rainMaterial = new THREE.MeshBasicMaterial({ color: 0x88ccff });
// 创建一个数组来存储雨滴
const raindrops = [];
for (let i = 0; i < 1000; i++) {
// 随机位置
const x = Math.random() * 1000 - 500;
const y = Math.random() * 1000 - 500;
const z = Math.random() * 1000 - 500;
// 创建雨滴并设置初始位置
const raindrop = new THREE.Mesh(rainGeometry, rainMaterial);
raindrop.position.set(x, y, z);
// 将雨滴添加到数组中
raindrops.push(raindrop);
scene.add(raindrop);
}
4. 动画渲染雨滴
为了让雨滴看起来是“下落”的,我们需要在每一帧中更新雨滴的位置。这里我们简单地让雨滴的 Y 轴坐标不断减小,模拟下雨的效果。
function animate() {
requestAnimationFrame(animate);
// 更新雨滴位置
raindrops.forEach((raindrop) => {
raindrop.position.y -= 2;
// 如果雨滴掉出场景,则重置位置
if (raindrop.position.y < -500) {
raindrop.position.y = 500;
}
});
// 渲染场景
renderer.render(scene, camera);
}
// 启动动画
animate();
5. 调整相机视角
为了使场景看起来更加生动,可以在适当的位置调整相机,确保我们可以看到下雨的效果。
// 调整相机位置
camera.position.z = 5;
6 添加简单的光源
虽然下雨通常是在阴天,我们可以添加一个简单的光源来提升效果的层次感。
// 创建环境光
const ambientLight = new THREE.AmbientLight(0x404040, 1); // 柔和的光
scene.add(ambientLight);
// 创建一个定向光(模拟太阳)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(0, 1, 1).normalize();
scene.add(directionalLight);
7. 响应窗口大小变化
为了确保当用户调整窗口大小时,场景能自适应,监听窗口尺寸变化并更新相机的宽高比和渲染器的大小。
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
8. 完整代码
将上述代码片段整合在一起,得到一个完整的下雨效果的 Three.js 示例:
import * as THREE from "three";
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建地面
const geometry = new THREE.PlaneGeometry(1000, 1000);
const material = new THREE.MeshBasicMaterial({
color: 0x0088ff,
side: THREE.DoubleSide,
});
const ground = new THREE.Mesh(geometry, material);
ground.rotation.x = -Math.PI / 2;
scene.add(ground);
// 创建雨滴
const rainGeometry = new THREE.SphereGeometry(0.1, 8, 8);
const rainMaterial = new THREE.MeshBasicMaterial({ color: 0x88ccff });
const raindrops = [];
for (let i = 0; i < 5000; i++) {
const x = Math.random() * 1000 - 500;
const y = Math.random() * 1000 - 500;
const z = Math.random() * 1000 - 500;
const raindrop = new THREE.Mesh(rainGeometry, rainMaterial);
raindrop.position.set(x, y, z);
raindrops.push(raindrop);
scene.add(raindrop);
}
// 创建光源
const ambientLight = new THREE.AmbientLight(0x404040, 1);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(0, 1, 1).normalize();
scene.add(directionalLight);
// 调整相机位置
camera.position.z = 5;
// 动画函数
function animate() {
requestAnimationFrame(animate);
// 更新雨滴位置
raindrops.forEach((raindrop) => {
raindrop.position.y -= 2;
// 如果雨滴掉出场景,则重置位置
if (raindrop.position.y < -500) {
raindrop.position.y = 500;
}
});
renderer.render(scene, camera);
}
// 启动动画
animate();
// 监听窗口大小变化
window.addEventListener("resize", () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
9. 总结
我们用 Three.js 创建了一个基本的下雨效果。这个过程包括:
- 设置基础的 Three.js 场景、相机和渲染器。
- 创建一个地面物体来展示雨滴的碰撞。
- 使用粒子系统(小球)模拟雨滴。
- 动态更新雨滴的位置以产生下落效果。
- 添加了简单的光源和响应式设计。