     } else if (cameraHeight < CLOUD_Y_END) {
         // DEBUG
         if (isInvalidHit(hit1) && isInvalidHit(hit2)) {
-            return vec4(1.0, 1.0, 0.0, 1.0);
+            return vec4(1.0, 1.0, 0.0, 0.0);
         }
         raymarchStartPos = camera.origin;
         totalRayMarchLength = hit1.t < 0.0 ? hit2.t : hit2.t < 0.0 ? hit1.t : min(hit1.t, hit2.t);


    bool useDebugColor = false;

    const int numSteps = 64;
    const int inscatSteps = 6;
    
    float cosTheta = dot(camera.direction, -sunDir);


    // R: Perlin-Worley noise
    // G,B,A: Worley noises at increasing frequencies
    vec4 baseNoises = textureLod(shapeNoise, samplePos, lod);
    float lowFreqFBM = dot(vec3(0.625, 0.25, 0.125), baseNoises.yzw);

    // #todo: baseCloud values are too high
    float baseCloud = baseNoises.x - 0.92;

    vec3 detailNoises = textureLod(erosionNoise, CURLINESS * samplePos2, lod).xyz;

    result.x = saturate(remap(baseCloud, -(1.0 - lowFreqFBM), 1.0, 0.0, 1.0));
    result.y = dot(vec3(0.625, 0.25, 0.125), detailNoises);
    return result;
}

float sampleCloud(vec3 P, float lod) {
    vec4 weatherData = sampleWeather(P);

    float cloudCoverage = weatherData.x;

#if DEBUG_MODE == DEBUG_MODE_NO_NOISE || DEBUG_MODE == DEBUG_MODE_WEATHER
    return cloudCoverage * getDensityForCloud(getHeightFraction(P), 1.0);
    //return cloudCoverage * getCumulusGradient(P);
    //return cloudCoverage;
#endif

    vec2 cloudNoiseSamples = sampleCloudShapeAndErosion(P, lod);

    float baseCloud = cloudNoiseSamples.x;
    float heightFraction = getHeightFraction(P);
