Variable volumetricCloudFragmentShaderConst
volumetricCloudFragmentShader: "\n #define PI 3.14159265359\n \n uniform float uTime;\n uniform float uCoverage;\n uniform float uDensity;\n uniform float uCloudBase;\n uniform float uCloudHeight;\n uniform vec3 uCloudColor;\n uniform vec3 uShadowColor;\n uniform vec2 uWindDirection;\n uniform float uWindSpeed;\n uniform float uSunIntensity;\n uniform float uSunAngle;\n uniform vec3 uSunColor;\n uniform int uSteps;\n uniform int uLightSteps;\n \n varying vec3 vWorldPosition;\n varying vec3 vViewDirection;\n \n float hash3D(vec3 p) {\n return fract(sin(dot(p, vec3(127.1, 311.7, 74.7))) * 43758.5453);\n }\n \n float noise3D(vec3 p) {\n vec3 i = floor(p);\n vec3 f = fract(p);\n f = f * f * (3.0 - 2.0 * f);\n \n float n000 = hash3D(i);\n float n100 = hash3D(i + vec3(1.0, 0.0, 0.0));\n float n010 = hash3D(i + vec3(0.0, 1.0, 0.0));\n float n110 = hash3D(i + vec3(1.0, 1.0, 0.0));\n float n001 = hash3D(i + vec3(0.0, 0.0, 1.0));\n float n101 = hash3D(i + vec3(1.0, 0.0, 1.0));\n float n011 = hash3D(i + vec3(0.0, 1.0, 1.0));\n float n111 = hash3D(i + vec3(1.0, 1.0, 1.0));\n \n return mix(\n mix(mix(n000, n100, f.x), mix(n010, n110, f.x), f.y),\n mix(mix(n001, n101, f.x), mix(n011, n111, f.x), f.y),\n f.z\n );\n }\n \n float fbm3D(vec3 p, int octaves) {\n float value = 0.0;\n float amplitude = 0.5;\n float frequency = 1.0;\n float maxValue = 0.0;\n \n for (int i = 0; i < 8; i++) {\n if (i >= octaves) break;\n value += amplitude * noise3D(p * frequency);\n maxValue += amplitude;\n amplitude *= 0.5;\n frequency *= 2.0;\n }\n \n return maxValue > 0.0 ? value / maxValue : 0.0;\n }\n \n float sampleCloudDensity(vec3 pos) {\n float heightFactor = (pos.y - uCloudBase) / uCloudHeight;\n if (heightFactor < 0.0 || heightFactor > 1.0) return 0.0;\n \n float heightShape = 4.0 * heightFactor * (1.0 - heightFactor);\n \n vec3 windOffset = vec3(uWindDirection.x, 0.0, uWindDirection.y) * uWindSpeed * uTime;\n vec3 samplePos = (pos + windOffset) * 0.01;\n \n float baseCloud = fbm3D(samplePos, 5);\n float detail = fbm3D(samplePos * 4.0 + 50.0, 3) * 0.3;\n float cloud = baseCloud + detail;\n \n float threshold = 1.0 - uCoverage;\n cloud = smoothstep(threshold, threshold + 0.3, cloud);\n \n return cloud * heightShape * uDensity;\n }\n \n float lightMarch(vec3 pos) {\n float sunHeight = sin(uSunAngle * PI / 180.0);\n vec3 lightDir = normalize(vec3(0.3, max(0.1, sunHeight), 0.3));\n float stepSize = uCloudHeight / max(float(uLightSteps), 1.0);\n float totalDensity = 0.0;\n \n for (int i = 0; i < 16; i++) {\n if (i >= uLightSteps) break;\n pos += lightDir * stepSize;\n totalDensity += sampleCloudDensity(pos) * stepSize;\n }\n \n return exp(-totalDensity * 0.5);\n }\n \n void main() {\n vec3 rayDir = normalize(-vViewDirection);\n \n // Handle near-horizontal rays to prevent division by zero\n if (abs(rayDir.y) < 0.0001) {\n gl_FragColor = vec4(0.0);\n return;\n }\n \n float tMin = (uCloudBase - vWorldPosition.y) / rayDir.y;\n float tMax = (uCloudBase + uCloudHeight - vWorldPosition.y) / rayDir.y;\n \n if (tMin > tMax) {\n float temp = tMin;\n tMin = tMax;\n tMax = temp;\n }\n \n tMin = max(0.0, tMin);\n tMax = max(0.0, tMax);\n \n if (tMin >= tMax) {\n gl_FragColor = vec4(0.0);\n return;\n }\n \n float stepSize = (tMax - tMin) / max(float(uSteps), 1.0);\n vec3 pos = vWorldPosition + rayDir * tMin;\n \n vec4 accumulatedColor = vec4(0.0);\n float accumulatedAlpha = 0.0;\n \n for (int i = 0; i < 64; i++) {\n if (i >= uSteps) break;\n if (accumulatedAlpha > 0.95) break;\n \n float density = sampleCloudDensity(pos);\n \n if (density > 0.01) {\n float lightTransmittance = lightMarch(pos);\n vec3 cloudCol = mix(uShadowColor, uCloudColor, lightTransmittance);\n cloudCol += uSunColor * uSunIntensity * lightTransmittance * 0.3;\n \n float alpha = density * stepSize * 2.0;\n alpha = 1.0 - exp(-alpha);\n \n accumulatedColor.rgb += cloudCol * alpha * (1.0 - accumulatedAlpha);\n accumulatedAlpha += alpha * (1.0 - accumulatedAlpha);\n }\n \n pos += rayDir * stepSize;\n }\n \n gl_FragColor = vec4(accumulatedColor.rgb, accumulatedAlpha);\n }\n" = ...