Fog Scattering Playground (r183-inspired)
Atmospheric spotlight demo using exponential fog and additive beam scattering to visualize how light volumetrics react to fog density and penumbra.
Key topics: three.js fog scattering, volumetric spotlight, fogexp2, atmospheric lighting, r183
Game Over
What this code does
- Exponential Fog Base: `THREE.FogExp2` controls atmospheric thickness and distance fade.
- Spotlight Through Media: a `SpotLight` drives a cone-shaped additive beam to approximate forward scattering.
- Beam Texture Gradient: a procedural canvas gradient reduces harsh banding and keeps the shaft readable.
- Penumbra Interaction: changing spotlight penumbra reshapes soft beam falloff against fog.
- Dynamic Sweep: animated target motion demonstrates directional light scattering changes over time.
- Practical Use: useful as a lightweight volumetric look when full volumetric raymarching is unnecessary.
Related Demos
Continue Learning
JavaScript Implementation
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
const scene = new THREE.Scene()
scene.background = new THREE.Color(0x0f1628)
scene.fog = new THREE.FogExp2(0x0f1628, 0.08)
const camera = new THREE.PerspectiveCamera(65, width / height, 0.1, 120)
camera.position.set(0, 2.2, 7)
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(width, height)
document.querySelector('#app').appendChild(renderer.domElement)
const controls = new OrbitControls(camera, renderer.domElement)
controls.target.set(0, 1, 0)
controls.update()
const spot = new THREE.SpotLight(0xbfd8ff, 18, 40, Math.PI / 6, 0.45, 1.2)
spot.position.set(0, 8, 2)
const target = new THREE.Object3D()
target.position.set(0, 0.5, -3)
scene.add(target)
spot.target = target
scene.add(spot)
const beam = new THREE.Mesh(
new THREE.ConeGeometry(1.8, 11, 48, 1, true),
new THREE.MeshBasicMaterial({
color: 0xbad4ff,
transparent: true,
opacity: 0.45,
depthWrite: false,
blending: THREE.AdditiveBlending,
side: THREE.DoubleSide
})
)
beam.position.copy(spot.position)
beam.lookAt(target.position)
scene.add(beam)
function animate () {
requestAnimationFrame(animate)
controls.update()
renderer.render(scene, camera)
}
animate()