Daniel Gray

Thoughts, Notes, Ideas, Projects

Contact

Atmospheric Effects and Fog Systems

The mist system uses custom shader materials with per-particle attributes to create an atmospheric fog effect reminiscent of Chinese landscape paintings. Each mist particle has a random size, uses GPU-based animation for optimal performance, clusters organically through random positioning, and animates with gentle floating motion using sine waves.

Interactive Shader Demo

Here's a simplified fragment shader that demonstrates the core concepts of particle-based fog effects using procedural generation:

<GLSLIDE width="800" height="500" showCodeEditor="true" defaultView="split" code="void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = fragCoord / iResolution.xy; uv.x *= iResolution.x / iResolution.y;

vec3 color = vec3(0.05, 0.05, 0.1);

// Procedural particle generation
float particleCount = 50.0;
float fogIntensity = 0.0;

for (float i = 0.0; i < particleCount; i += 1.0) {
    // Generate particle position using hash
    float seed = i * 100.0;
    vec2 particlePos = vec2(
        fract(sin(seed * 12.9898)),
        fract(sin(seed * 78.233))
    );
    
    // Animate particle using sine waves (GPU-based animation)
    particlePos.y += sin(iTime * 0.5 + particlePos.x * 0.1) * 0.1;
    particlePos.x += sin(iTime * 0.3 + particlePos.y * 0.1) * 0.05;
    
    // Calculate distance from current pixel
    float d = length(uv - particlePos);
    
    // Particle size and intensity
    float size = 0.01 + fract(sin(seed * 43.758)) * 0.02;
    // Fixed: smoothstep needs 3 arguments (edge0, edge1, x) where edge0 < edge1
    // We want high intensity when close (d small), low when far (d large)
    float intensity = 1.0 - smoothstep(0.0, size * 0.5, d);
    
    // Additive blending for fog effect
    fogIntensity += intensity * 0.2;
}

// Apply fog color with additive blending
// Fixed: mix(vec3, vec3, float) - both colors must be vec3
color = mix(color, vec3(1.0, 1.0, 1.0), fogIntensity);

// Fixed: vec4 constructor takes 4 arguments (x, y, z, w)
fragColor = vec4(color, 1.0);

}" />

This simplified demo shows procedural particle generation and GPU-based animation using sine waves, similar to the fog system. The particles animate entirely in the fragment shader, demonstrating the performance benefits of GPU-based particle systems.

The visualization above demonstrates the fog particle system. Adjust particle count, animation speed, and particle size to see how these parameters affect the atmospheric effect. Click and drag to rotate the camera, or scroll to zoom.

Technical Implementation

The fog system uses GPU-based animation for optimal performance, moving all calculations to the vertex shader:


// Create mist particles

const mistGeometry = new THREE.BufferGeometry();

const particleCount = 200;

const positions = new Float32Array(particleCount * 3);

const sizes = new Float32Array(particleCount);

  

for (let i = 0; i < particleCount; i++) {

const i3 = i * 3;

positions[i3] = (Math.random() - 0.5) * 20;

positions[i3 + 1] = Math.random() * 5;

positions[i3 + 2] = (Math.random() - 0.5) * 20;

sizes[i] = 0.5 + Math.random() * 1.5;

}

  

mistGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));

mistGeometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));

  

// GPU-based shader material

const mistMaterial = new THREE.ShaderMaterial({

uniforms: { time: { value: 0 } },

vertexShader: `

attribute float size;

uniform float time;

void main() {

vec3 pos = position;

// Animate on GPU - no CPU updates needed!

pos.y += sin(time + position.x * 0.1 + position.z * 0.1) * 0.1;

vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0);

gl_PointSize = size * (300.0 / -mvPosition.z);

gl_Position = projectionMatrix * mvPosition;

}

`,

fragmentShader: `

void main() {

float dist = length(gl_PointCoord - vec2(0.5));

float alpha = 1.0 - smoothstep(0.0, 0.5, dist);

gl_FragColor = vec4(1.0, 1.0, 1.0, alpha * 0.3);

}

`,

transparent: true,

blending: THREE.AdditiveBlending,

depthWrite: false,

});

GPU-Based Animation

All animation happens in the vertex shader, which means:

  • No CPU overhead: No JavaScript updates needed each frame

  • Highly efficient: GPU processes all particles in parallel

  • Smooth performance: Can handle hundreds of particles without frame drops

The animation uses sine waves with different phases for each particle, creating organic, floating motion:


pos.y += sin(time + position.x * 0.1 + position.z * 0.1) * 0.1;

Each particle moves based on its position and the current time, creating varied motion patterns.

Visual Aesthetic

The fog system creates an atmospheric effect that:

  • Clusters organically through random positioning

  • Floats gently with sine wave animation

  • Adds depth to the scene with atmospheric perspective

  • Matches the aesthetic of Chinese landscape paintings

The particles use additive blending to create a soft, glowing effect that enhances the minimalist, stylized look of the background.

Performance Optimization

The fog system is optimized for performance:

  • GPU-based animation (no CPU updates)

  • Efficient point sprite rendering

  • Configurable particle count (typically 200-400 particles)

  • IntersectionObserver pauses rendering when not visible

References

Related Articles

Sub-Topics

Explore specific atmospheric effects:

Explore Categories

Related Content

The 3D Background

The 3D Background The animated 3D background is a procedurally generated landscape that creates an infinite, dynamically rendered terrain with fractal trees, atmospheric effects, and interactive camer...

Cell Shading and Non-Photorealistic Rendering

Cell Shading and Non-Photorealistic Rendering Both terrain and trees use custom shader modifications via Three.js's `onBeforeCompile` hook. This allows us to modify the shader code at runtime, injecti...

Performance Optimization for 3D Background

Performance Optimization for 3D Background Performance was critical: this needs to run smoothly in a variety of environments, from high-end desktops to mobile devices. This article covers the key opti...

Fog Visualization

Fog Visualization Fog visualization is a key component of atmospheric effects in 3D scenes. This page explores the techniques and implementations used to create realistic and stylized fog effects. Ove...

Rain Visualization

Rain Visualization Rain effects add dynamic weather elements to 3D scenes. This page explores techniques for creating realistic and performant rain visualizations. Overview Rain visualization involves...

Snow Visualization

Snow Visualization Snow effects create winter atmospheres in 3D scenes. This page explores techniques for rendering snowflakes and snow accumulation. Overview Snow visualization involves creating part...