SSkilltecabyclaudinhocode
Enviar skill
← Voltar para o catálogo

procedural-clouds

DevOps e Infra

Generate beautiful procedural clouds in Three.js using WebGPU raymarching with WebGL2 billboard/mesh fallbacks. Covers all 10 major cloud genera (cumulus, stratus, cirrus, cumulonimbus, stratocumulus, altocumulus, altostratus, nimbostratus, cirrostratus, cirrocumulus) with physically-inspired lighting including silver linings, god rays, sunset coloring, and Mie/Rayleigh scattering approximation. P

36estrelas
Ver no GitHub ↗Autor: CK42BBLicença: MIT

Procedural Clouds

Generate visually stunning procedural clouds in Three.js with artistic emphasis — volumetric raymarching on WebGPU, billboard/mesh fallbacks on WebGL2.

Architecture Overview

┌──────────────────────────────────────────────────────┐
│                  Cloud Pipeline                       │
│                                                      │
│  Rendering Paths (select by capability + budget):    │
│                                                      │
│  ┌─ VOLUMETRIC (WebGPU) ─────────────────────────┐   │
│  │  Fullscreen quad → raymarching fragment shader │   │
│  │  Noise: 3D worley/perlin compute textures     │   │
│  │  Best quality, most expensive                  │   │
│  └───────────────────────────────────────────────┘   │
│                                                      │
│  ┌─ MESH CLUSTER (WebGL2/WebGPU) ────────────────┐   │
│  │  Instanced soft-particle spheres              │   │
│  │  Per-instance density, color, fade            │   │
│  │  Good quality, moderate cost                   │   │
│  └───────────────────────────────────────────────┘   │
│                                                      │
│  ┌─ BILLBOARD (WebGL2, mobile) ──────────────────┐   │
│  │  Camera-facing quads with noise texture       │   │
│  │  Cheapest, suitable for backgrounds           │   │
│  └───────────────────────────────────────────────┘   │
│                                                      │
│  Shared Systems:                                     │
│  Lighting ─ Drift ─ Time-of-Day ─ Formation         │
└──────────────────────────────────────────────────────┘

Cloud Classification Quick Reference

GenusAltitudeShapeKey Visual
CumulusLow (2km)Puffy moundsFlat base, cauliflower tops
StratusLow (2km)Flat sheetUniform grey blanket
StratocumulusLow (2km)Lumpy rollsPatchy blanket with gaps
CumulonimbusLow→HighTowering anvilMassive vertical, dark base
AltocumulusMid (2-6km)Rippled patches"Mackerel sky" pattern
AltostratusMid (2-6km)Thin veilSun visible as bright spot
NimbostratusMid (2-6km)Thick dark sheetContinuous rain cloud
CirrusHigh (6-12km)Wispy streaksIce crystal hooks and mares' tails
CirrostratusHigh (6-12km)Thin milky hazeHalo around sun
CirrocumulusHigh (6-12km)Tiny ripplesDelicate fish-scale pattern

Full profiles with shader parameters in references/cloud-types.md.

Renderer Setup

import * as THREE from 'three';

async function createRenderer(canvas) {
  let renderer, gpuAvailable = false;
  try {
    const WebGPU = (await import('three/addons/capabilities/WebGPU.js')).default;
    if (WebGPU.isAvailable()) {
      const { default: WebGPURenderer } = await import(
        'three/addons/renderers/webgpu/WebGPURenderer.js'
      );
      renderer = new WebGPURenderer({ canvas, antialias: true });
      await renderer.init();
      gpuAvailable = true;
    }
  } catch (e) { /* fallback */ }
  if (!renderer) {
    renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    renderer.toneMappingExposure = 1.2;
  }
  renderer.setSize(innerWidth, innerHeight);
  renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
  return { renderer, gpuAvailable };
}

3D Noise Foundation

All cloud rendering depends on layered 3D noise. These functions are shared across all three rendering paths.

// GPU-friendly 3D hash (no lookup tables)
// Used in shaders — JavaScript equivalent for CPU cloud mesh placement
function hash3(x, y, z) {
  let h = x * 127.1 + y * 311.7 + z * 74.7;
  return (Math.sin(h) * 43758.5453) % 1;
}

// 3D value noise
function noise3D(x, y, z) {
  const ix = Math.floor(x), iy = Math.floor(y), iz = Math.floor(z);
  const fx = x - ix, fy = y - iy, fz = z - iz;
  const ux = fx * fx * (3 - 2 * fx);
  const uy = fy * fy * (3 - 2 * fy);
  const uz = fz * fz * (3 - 2 * fz);

  const h = (a, b, c) => hash3(ix + a, iy + b, iz + c);
  return lerp(uz,
    lerp(uy, lerp(ux, h(0,0,0), h(1,0,0)), lerp(ux, h(0,1,0), h(1,1,0))),
    lerp(uy, lerp(ux, h(0,0,1), h(1,0,1)), lerp(ux, h(0,1,1), h(1,1,1)))
  );
}
function lerp(t, a, b) { return a + t * (b - a); }

// FBM for cloud density
function cloudFBM(x, y, z, octaves = 5, lac = 2.0, gain = 0.5) {
  let sum = 0, amp = 1, freq = 1, max = 0;
  for (let i = 0; i < octaves; i++) {
    sum += noise3D(x * freq, y * freq, z * freq) * amp;
    max += amp; amp *= gain; freq *= lac;
  }
  return sum / max;
}

Path 1: Volumetric Raymarching (WebGPU)

The highest-quality path renders clouds by marching rays through a density field defined by 3D noise. Implemented as a fullscreen post-process pass.

Cloud Density Field

The density function defines cloud shape, coverage, and type:

// GLSL-style pseudocode for the density function (full GLSL in references)
float cloudDensity(vec3 p, float time) {
  // Altitude shaping — confine to cloud layer
  float altFade = smoothstep(cloudBase, cloudBase + 200.0, p.y)
                * smoothstep(cloudTop, cloudTop - 200.0, p.y);

  // Large-scale shape (coverage map)
  float shape = fbm3D(p * 0.0003 + wind * time, 3);
  shape = remap(shape, coverageThreshold, 1.0, 0.0, 1.0); // coverage control

  // Detail erosion (carves edges)
  float detail = fbm3D(p * 0.003 + wind * time * 2.0, 5);
  float density = shape - detail * detailStrength;

  return max(density * altFade, 0.0);
}

Raymarching Loop

// Core raymarching pattern (see references/cloud-shaders.md for full GLSL)
vec4 raymarchClouds(vec3 ro, vec3 rd) {
  float t = intersectCloudLayer(ro, rd); // Ray-slab intersection
  vec4 result = vec4(0.0);

  for (int i = 0; i < MAX_STEPS; i++) {
    if (result.a > 0.99 || t > maxDist) break;

    vec3 p = ro + rd * t;
    float density = cloudDensity(p, time);

    if (density > 0.001) {
      // Light marching — secondary ray toward sun
      float lightEnergy = lightMarch(p);

      // Phase function (Henyey-Greenstein)
      float phase = henyeyGreenstein(dot(rd, sunDir), 0.3)
                  + henyeyGreenstein(dot(rd, sunDir), 0.8) * 0.5;

      // Color from scattering
      vec3 cloudColor = sunColor * lightEnergy * phase + ambientSky * 0.15;

      // Silver lining — bright edge when sun is behind cloud
      float rim = pow(1.0 - abs(dot(rd, sunDir)), 4.0);
      cloudColor += sunColor * rim * 0.3 * lightEnergy;

      // Beer-Lambert absorption
      float alpha = 1.0 - exp(-density * stepSize * absorptionCoeff);
      result.rgb += cloudColor * alpha * (1.0 - result.a);
      result.a += alpha * (1.0 - result.a);
    }

    t += stepSize;
  }
  return result;
}

Fullscreen Cloud Pass Setup

function createVolumetricCloudPass(camera, scene) {
  const cloudMaterial = new THREE.ShaderMaterial({
    uniforms: {
      tDepth:           { value: null },       // Scene depth texture
      cameraPos:        { value: new THREE.Vector3() },
      invProjection:    { value: new THREE.Matrix4() },
      invView:          { value: new THREE.Matrix4() },
      sunDir:           { value: new THREE.Vector3(0.3, 0.8, 0.5).normalize() },
      sunColor:         { value: new THREE.Color(0xfff8e7) },
      ambientSky:       { value: new THREE.Color(0x6699cc) },
      time:             { value: 0 },
      cloudBase:        { value: 1500 },       // meters
      cloudTop:         { value: 3500 },
      coverage:         { value: 0.45 },       // 0-1, controls cloud amount
      detailStrength:   { value: 0.35 },
      windDirection:    { value: new THREE.Vector2(1, 0.3).normalize() },
      windSpeed:        { value: 15 },
      absorptionCoeff:  { value: 0.04 },
    },
    vertexShader: FULLSCREEN_VERT,    // See references/cloud-shaders.md
    fragmentShader: VOLUMETRIC_FRAG,  // See refere

Como adicionar

/plugin marketplace add CK42BB/procedural-clouds-threejs

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Comentários · Nenhum comentário

Entre para comentar. Entrar

  • Ainda não há comentários. Seja o primeiro.