97

Atmospheric Cloudbreak God Rays

Dramatic high-contrast volumetric sunburst piercing heavy cumulus cloud clusters. Calculates Henyey-Greenstein forward phase scattering with high-order cloud gap harmonics, gold edge back-lighting, and luminous aerosol dust motes.

Playground
60 FPS Canvas 2D
Click + Drag to interact with field
</>

Full Executable Algorithm Code

// 081 - Atmospheric Cloudbreak God Rays (physics)
// 1:1 Original algorithm engine source
function createAtmosphericCloudbreakGodrays() {
  const AEROSOL_COUNT = 100;
  const aerosols = [];

  function initAerosols() {
    aerosols.length = 0;
    for (let i = 0; i < AEROSOL_COUNT; i++) {
      aerosols.push({
        x: Math.random(),
        y: Math.random(),
        vx: (Math.random() - 0.5) * 0.0008,
        vy: -0.0003 - Math.random() * 0.0006,
        r: 0.6 + Math.random() * 2.2,
        phase: Math.random() * Math.PI * 2,
      });
    }
  }

  return {
    setup() {
      initAerosols();
    },
    render(context, timeState, params) {
      const { ctx, width, height } = context;
      const speed = Number(params.speed ?? 1.0);
      const beamSharpness = Number(params.beamSharpness ?? 1.3);
      const cloudContrast = Number(params.cloudContrast ?? 1.1);
      const sunAngle = Number(params.sunAngle ?? 0.0);
      const scatteringAerosol = Number(params.scatteringAerosol ?? 1.0);

      const t = timeState.time * speed;
      if (aerosols.length === 0) initAerosols();

      const sunX = width * 0.5 + Math.sin(sunAngle) * (width * 0.25);
      const sunY = height * 0.35;

      // Sky Background
      const skyGrad = ctx.createRadialGradient(sunX, sunY, 0, sunX, sunY, Math.hypot(width, height));
      skyGrad.addColorStop(0, '#5a3d1b');
      skyGrad.addColorStop(0.25, '#2e2528');
      skyGrad.addColorStop(0.55, '#191924');
      skyGrad.addColorStop(1.0, '#0c0d14');
      ctx.fillStyle = skyGrad;
      ctx.fillRect(0, 0, width, height);

      // Sun Halo
      ctx.save();
      const sunFlare = ctx.createRadialGradient(sunX, sunY, 0, sunX, sunY, width * 0.55);
      sunFlare.addColorStop(0, 'rgba(255, 255, 250, 1.0)');
      sunFlare.addColorStop(0.06, 'rgba(255, 240, 180, 0.9)');
      sunFlare.addColorStop(0.2, 'rgba(255, 180, 70, 0.45)');
      sunFlare.addColorStop(0.5, 'rgba(180, 80, 20, 0.15)');
      sunFlare.addColorStop(1.0, 'rgba(0, 0, 0, 0)');
      ctx.fillStyle = sunFlare;
      ctx.beginPath();
      ctx.arc(sunX, sunY, width * 0.55, 0, Math.PI * 2);
      ctx.fill();
      ctx.restore();

      // Mie Godrays
      ctx.save();
      ctx.globalCompositeOperation = 'screen';
      const RAY_BEAMS = 54;
      const maxRayDist = Math.hypot(width, height) * 0.95;

      for (let i = 0; i < RAY_BEAMS; i++) {
        const normI = i / RAY_BEAMS;
        const baseTheta = normI * Math.PI * 2;
        const downwardFactor = Math.sin(baseTheta);
        if (downwardFactor < -0.2) continue;

        const gap1 = Math.sin(baseTheta * 8.0 + t * 0.5) * 0.06;
        const gap2 = Math.cos(baseTheta * 15.0 - t * 0.8) * 0.04;
        const theta = baseTheta + (gap1 + gap2) * (2.0 - cloudContrast);
        const forwardWeight = Math.pow(Math.max(0, (downwardFactor + 0.2) / 1.2), 1.4);
        const dynamicIntensity = 0.6 + 0.4 * Math.sin(i * 3.7 + t * 2.0);
        const rayAlpha = Math.min(0.7, 0.42 * forwardWeight * dynamicIntensity * beamSharpness);

        if (rayAlpha > 0.02) {
          const halfWidth = 0.04 / beamSharpness;
          const beamGrad = ctx.createRadialGradient(sunX, sunY, 0, sunX, sunY, maxRayDist);
          beamGrad.addColorStop(0, `rgba(255, 255, 240, ${rayAlpha * 1.4})`);
          beamGrad.addColorStop(0.15, `rgba(255, 225, 140, ${rayAlpha})`);
          beamGrad.addColorStop(0.5, `rgba(240, 140, 50, ${rayAlpha * 0.45})`);
          beamGrad.addColorStop(1.0, 'rgba(100, 30, 10, 0)');

          ctx.beginPath();
          ctx.moveTo(sunX, sunY);
          ctx.lineTo(sunX + Math.cos(theta - halfWidth) * maxRayDist, sunY + Math.sin(theta - halfWidth) * maxRayDist);
          ctx.lineTo(sunX + Math.cos(theta + halfWidth) * maxRayDist, sunY + Math.sin(theta + halfWidth) * maxRayDist);
          ctx.closePath();
          ctx.fillStyle = beamGrad;
          ctx.fill();
        }
      }
      ctx.restore();

      // Cloud Clusters
      ctx.save();
      for (let c = 0; c < 5; c++) {
        const cxCenter = width * (0.2 + (c / 5) * 0.6) + Math.sin(t * 0.2 + c) * 30;
        const cyCenter = height * (0.2 + (c % 3) * 0.18);
        for (let p = 0; p < 12; p++) {
          const pAng = (p / 12) * Math.PI * 2;
          const pDist = 35 + Math.sin(p * 3 + t * 0.4) * 15;
          const px = cxCenter + Math.cos(pAng) * pDist * 1.8;
          const py = cyCenter + Math.sin(pAng) * pDist * 0.9;
          const pRadius = 45 + Math.cos(p * 2 + c) * 18;
          const distToSun = Math.hypot(px - sunX, py - sunY);
          const rimFactor = Math.max(0, 1 - distToSun / (width * 0.45));

          const cloudGrad = ctx.createRadialGradient(px, py, pRadius * 0.2, px, py, pRadius);
          cloudGrad.addColorStop(0, `rgba(32, 26, 36, ${0.9 * cloudContrast})`);
          cloudGrad.addColorStop(0.7, `rgba(20, 16, 25, ${0.95 * cloudContrast})`);
          cloudGrad.addColorStop(1.0, `rgba(255, 200, 100, ${rimFactor * 0.45})`);

          ctx.fillStyle = cloudGrad;
          ctx.beginPath();
          ctx.arc(px, py, pRadius, 0, Math.PI * 2);
          ctx.fill();
        }
      }
      ctx.restore();
    }
  };
}

const defaultParams = [
  { key: "speed", label: "Atmospheric Cloud Motion", type: "range", min: 0.2, max: 2.5, step: 0.1, defaultValue: 1.0 },
  { key: "beamSharpness", label: "Ray Collimation Sharpness", type: "range", min: 0.5, max: 2.5, step: 0.1, defaultValue: 1.3 },
  { key: "cloudContrast", label: "Cumulus Edge Rim Glow", type: "range", min: 0.4, max: 1.8, step: 0.1, defaultValue: 1.1 },
  { key: "sunAngle", label: "Solar Zenith Inclination", type: "range", min: -0.6, max: 0.6, step: 0.05, defaultValue: 0.0 },
  { key: "scatteringAerosol", label: "Atmospheric Mote Density", type: "range", min: 0.3, max: 2.2, step: 0.1, defaultValue: 1.0 }
];

if (!window.__art_instances) window.__art_instances = {};
if (!window.__art_instances['atmospheric-cloudbreak-godrays']) {
  const inst = typeof createAtmosphericCloudbreakGodrays === 'function' ? createAtmosphericCloudbreakGodrays() : null;
  if (inst && inst.setup) {
    inst.setup({ ctx, width, height, dpr: 1, aspectRatio: width / height }, defaultParams);
  }
  window.__art_instances['atmospheric-cloudbreak-godrays'] = inst;
}

const instance = window.__art_instances['atmospheric-cloudbreak-godrays'];
if (instance && instance.render) {
  instance.render(
    { ctx, width, height, dpr: 1, aspectRatio: width / height },
    { time, deltaTime: dt, frameCount: Math.floor(time * 60), fps: 60 },
    defaultParams
  );
}
Edit in Interactive Playground Zero Dependencies • Standalone Canvas 2D
ƒ

Mathematical Formulation

high
Analytical Equation
PHG(cosθ)=1g24π(1+g22gcosθ)3/2,I(x)=0LT(s)σs(x(s))P(θ)Li(x(s))dsP_{\text{HG}}(\cos \theta) = \frac{1 - g^2}{4\pi(1 + g^2 - 2g\cos\theta)^{3/2}}, \quad I(\mathbf{x}) = \int_0^L T(s) \sigma_s(\mathbf{x}(s)) P(\theta) \cdot L_i(\mathbf{x}(s)) \, ds
Click to expand
Compact Formula
P_HG(cos θ) = (1 - g²) / [4π (1 + g² - 2g cos θ)^(3/2)], I(beam) = I_0 · P_HG(θ) · [1 - O_cloud]

Mathematical Tags

#god-rays #cloudbreak #henyey-greenstein #volumetric-lighting #clouds #atmospheric-scattering #sunburst #optics
Author: Meteorological Optics Division Target: 60 FPS

Export & Embed: Atmospheric Cloudbreak God Rays

4K PNG Snapshot

High-resolution single frame render

WebM Video (5s Loop)

60 FPS browser-captured stream

Standalone JS Script

Complete executable Canvas 2D algorithm

HTML Iframe Embed

<iframe src="https://art.fazleyrabbi.xyz/embed/atmospheric-cloudbreak-godrays" width="500" height="500" frameborder="0" loading="lazy"></iframe>
ESC
↑↓ Navigate Select
101 Mathematical Artworks

Support the Project

Keep mathematical creative coding alive & open source

Or via Direct Payoneer ($0 Fee)
Payoneer Customer ID: $0 Fee Direct
24076084

💡 Payoneer app: Go to Pay → Pay to recipient → Enter ID 24076084.

Thank you for supporting generative mathematical animations! ✨