Rain with Splashes
Fast falling raindrops with wind and fog; reset on ground contact.
Key topics: three.js, particles, rain, weather, fog
Game Over
What this code does
- PointsMaterial raindrops fall under constant speed with lateral wind.
- Ground plane creates a visual horizon; fog adds depth in the distance.
- GUI controls: fall speed, wind, and raindrop size.
Continue Learning
JavaScript Implementation
ES6+
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000)
camera.position.set(0, 8, 25)
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(width, height)
document.querySelector('#app').appendChild(renderer.domElement)
// Raindrops as points
const count = 4000
const positions = new Float32Array(count * 3)
const wind = new Float32Array(count * 2)
const fallSpeeds = new Float32Array(count)
const gustPhase = new Float32Array(count)
const gustFreq = new Float32Array(count)
for (let i = 0; i < count; i++) {
const i3 = i * 3
positions[i3] = (Math.random() - 0.5) * 200
positions[i3 + 1] = Math.random() * 120
positions[i3 + 2] = -180 + Math.random() * 220
wind[i * 2] = (Math.random() - 0.5) * 6
wind[i * 2 + 1] = (Math.random() - 0.5) * 6
fallSpeeds[i] = 32 + Math.random() * 45
gustPhase[i] = Math.random() * Math.PI * 2
gustFreq[i] = 0.4 + Math.random()
}
const geo = new THREE.BufferGeometry()
geo.setAttribute('position', new THREE.BufferAttribute(positions, 3))
const mat = new THREE.PointsMaterial({ color: 0x88aaff, size: 2, sizeAttenuation: true, transparent: true })
const rain = new THREE.Points(geo, mat)
scene.add(rain)
function animate () {
requestAnimationFrame(animate)
const dt = 1 / 60
const time = performance.now() * 0.001
for (let i = 0; i < count; i++) {
const i3 = i * 3
const gx = Math.sin(time * gustFreq[i] + gustPhase[i])
const gz = Math.cos(time * gustFreq[i] + gustPhase[i])
positions[i3] += (wind[i * 2] + gx) * dt
positions[i3 + 1] -= fallSpeeds[i] * dt
positions[i3 + 2] += (wind[i * 2 + 1] + gz) * dt
if (positions[i3 + 1] < 0) {
positions[i3] = (Math.random() - 0.5) * 200
positions[i3 + 1] = 120
positions[i3 + 2] = -180 + Math.random() * 220
}
}
geo.attributes.position.needsUpdate = true
renderer.render(scene, camera)
}
animate()