//Volumetric coulds PS.
#version 450
#extension GL_EXT_nonuniform_qualifier : require

struct SH9
{
    vec3 L[9];
};

struct CloudsInput
{
    vec2 uv0;
};

struct CloudsOutput
{
    vec4 outClouds;
    vec4 outMotion;
};

struct FlrInput
{
    vec2 uv0;
};

struct FlrOutput
{
    vec4 outClouds;
    vec4 outMotion;
};

struct SH9Compressed
{
    uvec4 data0[2];
    uvec4 data1;
};

// Vk3DVision (http://3dsurroundgaming.com/) - Stereo Injection
layout(set = 0, binding = 110, std140) uniform Vk3DParams
{
    vec4 stereo;
    vec4 custom_params;
} vk3d_params;

layout(set = 0, binding = 6, std140) uniform PerView
{
    mat4 invViewProjMatrix;
    vec4 cameraPosWS;
    vec4 frameParameters0;
    vec4 dirLightDirWS;
    vec4 dirLightColorAndIntens;
    SH9Compressed skyModelSH;
    vec4 haltonSamples;
    mat4 viewProjMatrix;
    mat4 prevViewProjMatrix;
    vec4 volCloudsParams0;
    vec4 volCloudsParams1;
    vec4 volCloudsParams2;
    vec4 volCloudsParams3;
    vec4 tornadoWorldPos;
    vec4 viewportSize;
} _663;

layout(set = 0, binding = 100, std430) buffer DebugBuffer
{
    uint debugBuffer[];
} _1387;

layout(set = 2, binding = 0) uniform texture2D globalTextures[];
layout(set = 2, binding = 0) uniform texture3D global3DTextures[];
layout(set = 1, binding = 1) uniform sampler linearRepeatSampler;
layout(set = 0, binding = 4) uniform sampler2D noiseTex;
layout(set = 2, binding = 0) uniform textureCube globalCubeTextures[];
layout(set = 1, binding = 0) uniform sampler linearClampSampler;
layout(set = 1, binding = 2) uniform sampler nearestClampSampler;
layout(set = 1, binding = 3) uniform sampler nearestRepeatSampler;
layout(set = 1, binding = 4) uniform sampler shadowSampler;

layout(location = 0) in vec2 inUV0;
layout(location = 0) out vec4 outColor;
layout(location = 1) out vec4 outMotion;

float _897;

vec3 unproject(vec2 uv0, float depth, mat4 invProjMatrix)
{
    vec4 unprojPos = invProjMatrix * vec4((uv0 * 2.0) - vec2(1.0), depth, 1.0);
    return unprojPos.xyz / unprojPos.www;
}

vec4 unpackUNorm4x8(uint p_PackedValue)
{
    return vec4(float(p_PackedValue & 255u), float((p_PackedValue >> uint(8)) & 255u), float((p_PackedValue >> uint(16)) & 255u), float((p_PackedValue >> uint(24)) & 255u)) * 0.00392160005867481231689453125;
}

SH9 decodeSH9(vec4 data[7])
{
    SH9 result;
    result.L[0] = data[0].xyz;
    result.L[1] = vec3(data[0].w, data[1].xy);
    result.L[2] = vec3(data[1].zw, data[2].x);
    result.L[3] = data[2].yzw;
    result.L[4] = data[3].xyz;
    result.L[5] = vec3(data[3].w, data[4].xy);
    result.L[6] = vec3(data[4].zw, data[5].x);
    result.L[7] = data[5].yzw;
    result.L[8] = data[6].xyz;
    return result;
}

SH9 decodeSH9(uvec4 data0[2], uvec4 data1)
{
    uint param = data0[0].x;
    vec4 tempCoeff = (unpackUNorm4x8(param) * 2.0) - vec4(1.0);
    float tempCoeffLen = unpackHalf2x16(data1.x & 65535u).x;
    vec4 coeffs[7];
    coeffs[0] = tempCoeff * tempCoeffLen;
    uint param_1 = data0[0].y;
    tempCoeff = (unpackUNorm4x8(param_1) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16((data1.x >> uint(16)) & 65535u).x;
    coeffs[1] = tempCoeff * tempCoeffLen;
    uint param_2 = data0[0].z;
    tempCoeff = (unpackUNorm4x8(param_2) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16(data1.y & 65535u).x;
    coeffs[2] = tempCoeff * tempCoeffLen;
    uint param_3 = data0[0].w;
    tempCoeff = (unpackUNorm4x8(param_3) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16((data1.y >> uint(16)) & 65535u).x;
    coeffs[3] = tempCoeff * tempCoeffLen;
    uint param_4 = data0[1].x;
    tempCoeff = (unpackUNorm4x8(param_4) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16(data1.z & 65535u).x;
    coeffs[4] = tempCoeff * tempCoeffLen;
    uint param_5 = data0[1].y;
    tempCoeff = (unpackUNorm4x8(param_5) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16((data1.z >> uint(16)) & 65535u).x;
    coeffs[5] = tempCoeff * tempCoeffLen;
    uint param_6 = data0[1].z;
    tempCoeff = (unpackUNorm4x8(param_6) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16(data1.w & 65535u).x;
    coeffs[6] = tempCoeff * tempCoeffLen;
    vec4 param_7[7] = coeffs;
    return decodeSH9(param_7);
}

SH9 projectOntoSH9(vec3 n)
{
    SH9 sh;
    sh.L[0] = vec3(0.88622760772705078125);
    vec3 a1 = n.yzx * 0.48860299587249755859375;
    sh.L[1] = vec3(2.094399929046630859375) * a1.x;
    sh.L[2] = vec3(2.094399929046630859375) * a1.y;
    sh.L[3] = vec3(2.094399929046630859375) * a1.z;
    sh.L[4] = vec3(0.785398006439208984375) * ((1.09254801273345947265625 * n.x) * n.y);
    sh.L[5] = vec3(0.785398006439208984375) * ((1.09254801273345947265625 * n.y) * n.z);
    sh.L[6] = vec3(0.785398006439208984375) * (0.3153919875621795654296875 * (((3.0 * n.z) * n.z) - 1.0));
    sh.L[7] = vec3(0.785398006439208984375) * ((1.09254801273345947265625 * n.x) * n.z);
    sh.L[8] = vec3(0.785398006439208984375) * (0.546274006366729736328125 * ((n.x * n.x) - (n.y * n.y)));
    return sh;
}

vec3 shDotProduct(SH9 a, SH9 b)
{
    vec3 result = a.L[0] * b.L[0];
    result += (a.L[1] * b.L[1]);
    result += (a.L[2] * b.L[2]);
    result += (a.L[3] * b.L[3]);
    result += (a.L[4] * b.L[4]);
    result += (a.L[5] * b.L[5]);
    result += (a.L[6] * b.L[6]);
    result += (a.L[7] * b.L[7]);
    result += (a.L[8] * b.L[8]);
    return result;
}

vec3 sampleSH(uvec4 data0[2], uvec4 data1, vec3 dir)
{
    uvec4 param[2] = data0;
    uvec4 param_1 = data1;
    SH9 sh = decodeSH9(param, param_1);
    vec3 param_2 = dir;
    SH9 dirSH = projectOntoSH9(param_2);
    SH9 param_3 = dirSH;
    SH9 param_4 = sh;
    return max(shDotProduct(param_3, param_4), vec3(0.0));
}

vec3 intersectRaySphere(float sphereRadius, vec3 origin, vec3 direction)
{
    float a0 = (sphereRadius * sphereRadius) - dot(origin, origin);
    float a1 = dot(origin, direction);
    float result = sqrt((a1 * a1) + a0) - a1;
    return origin + (direction * result);
}

float cloudCoverage(vec3 pos)
{
    return smoothstep(0.125, 0.5, pos.y);
}

vec4 flrSampleLevelBindless(sampler samplerState, vec2 uv, float lod, uint textureIdx)
{
    return textureLod(sampler2D(globalTextures[nonuniformEXT(textureIdx)], samplerState), uv, lod);
}

vec4 flrSampleLevelBindless3D(sampler samplerState, vec3 uvw, float lod, uint textureIdx)
{
    return textureLod(sampler3D(global3DTextures[nonuniformEXT(textureIdx)], samplerState), uvw, lod);
}

float smoothThreshold(float value, float threshold, float edgeSize)
{
    return smoothstep(threshold, threshold + edgeSize, value);
}

float cloudNoise(inout vec3 pos, inout vec3 rayPosWS, float coverage, float tornadoDistNorm, vec3 tornadoDir)
{
    pos = (pos * 2.0) - vec3(1.0);
    rayPosWS = rayPosWS;
    vec2 param = (pos.xy * 0.100000001490116119384765625) * 2.0;
    float param_1 = 0.0;
    uint param_2 = floatBitsToUint(_663.volCloudsParams0.y);
    vec3 curl = (flrSampleLevelBindless(linearRepeatSampler, param, param_1, param_2).xyz * 2.0) - vec3(1.0);
    pos += (curl * 0.00999999977648258209228515625);
    float noiseOffset = 0.0;
    vec4 flowUvOffset = vec4(0.0);
    float flowLayerBlendFactor = 0.0;
    float flowTime = _663.frameParameters0.x;
    vec2 flow = vec2(0.0);
    vec4 _node11 = vec4(_663.frameParameters0.x);
    vec4 _node12 = _node11 * vec4(0.0500000007450580596923828125);
    flowTime = _node12.x;
    vec4 _node14 = tornadoDir.xyzx;
    vec4 _node23 = curl.xyzx;
    vec4 _node26 = _node23 * vec4(0.0500000007450580596923828125);
    vec4 _node28 = _node14 + _node26;
    vec4 _node24 = _node28;
    vec4 _node22 = vec4(0.0);
    _node22.x = _node24.x;
    _node22.y = _node24.z;
    vec4 _node15 = _node22 * vec4(10.0);
    vec4 _node19 = vec4(tornadoDistNorm);
    vec4 _node21 = vec4(1.0) - _node19;
    vec4 _node17 = max(_node21, vec4(0.25));
    vec4 _node25 = _node15 * _node17;
    flow = _node25.xy;
    float time = mod(flowTime, 1.0);
    vec2 scale = vec2(time, mod(time + 0.5, 1.0));
    flowLayerBlendFactor = 2.0 * abs(time - 0.5);
    flowUvOffset = flow.xyxy * scale.xxyy;
    vec4 _node10 = vec4(tornadoDistNorm);
    vec4 _node6 = smoothstep(vec4(1.0), vec4(0.100000001490116119384765625), _node10);
    vec4 _node1 = _node6 * vec4(0.100000001490116119384765625);
    noiseOffset = _node1.x;
    vec4 _node29 = vec4(_663.frameParameters0.x);
    vec4 _node31 = _node29 * vec4(0.0500000007450580596923828125, 0.0, 0.0, 0.0);
    pos += _node31.xyz;
    vec3 param_3 = (pos + vec3(flowUvOffset.x, 0.0, flowUvOffset.y)) * 0.100000001490116119384765625;
    float param_4 = 0.0;
    uint param_5 = floatBitsToUint(_663.volCloudsParams0.x);
    float baseNoise0 = flrSampleLevelBindless3D(linearRepeatSampler, param_3, param_4, param_5).x + noiseOffset;
    vec3 param_6 = (pos + vec3(flowUvOffset.z, 0.0, flowUvOffset.w)) * 0.100000001490116119384765625;
    float param_7 = 0.0;
    uint param_8 = floatBitsToUint(_663.volCloudsParams0.x);
    float baseNoise1 = flrSampleLevelBindless3D(linearRepeatSampler, param_6, param_7, param_8).x + noiseOffset;
    float baseNoise = mix(baseNoise0, baseNoise1, flowLayerBlendFactor);
    float param_9 = baseNoise;
    float param_10 = 0.5;
    float param_11 = 0.800000011920928955078125;
    float base = clamp(smoothThreshold(param_9, param_10, param_11), 0.0, 1.0);
    base = clamp(base - 0.0500000007450580596923828125, 0.0, 1.0);
    base *= coverage;
    vec3 param_12 = pos * 1.2000000476837158203125;
    float param_13 = 0.0;
    uint param_14 = floatBitsToUint(_663.volCloudsParams0.z);
    float detail = 1.0 - flrSampleLevelBindless3D(linearRepeatSampler, param_12, param_13, param_14).x;
    detail *= smoothstep(1.0, 0.0, base);
    detail *= 1.5;
    return clamp(base - detail, 0.0, 1.0) * 5.0;
}

float cloudSample(vec3 rayPosNorm, vec3 rayPosWS, float tornadoDistNorm, vec3 tornadoDir)
{
    vec3 param = rayPosNorm;
    float coverage = cloudCoverage(param);
    if (coverage < 9.9999999392252902907785028219223e-09)
    {
        return 0.0;
    }
    else
    {
        vec3 param_1 = rayPosNorm;
        vec3 param_2 = rayPosWS;
        float param_3 = coverage;
        float param_4 = tornadoDistNorm;
        vec3 param_5 = tornadoDir;
        float _895 = cloudNoise(param_1, param_2, param_3, param_4, param_5);
        return _895;
    }
}

float lightSample(vec3 rayPosWS, float tornadoDistNorm, vec3 tornadoDir)
{
    float light = 0.0;
    float currentStep = 62.5;
    for (uint i = 1u; float(i) < 5.0; i++)
    {
        vec3 samplePosWS = rayPosWS + (_663.dirLightDirWS.xyz * currentStep);
        vec3 param = samplePosWS / vec3(22500.0);
        vec3 param_1 = samplePosWS;
        float param_2 = tornadoDistNorm;
        vec3 param_3 = tornadoDir;
        light += cloudSample(param, param_1, param_2, param_3);
        currentStep += (currentStep * 8.0);
    }
    return light;
}

float hgPhase(float cosAngle, float g)
{
    float g2 = g * g;
    return (1.0 - g2) / pow(abs((1.0 + g2) - ((2.0 * g) * cosAngle)), 1.5);
}

float powderTerm(float densityAtSample, float cosTheta)
{
    float powder = 1.0 - exp(((-0.4000000059604644775390625) * densityAtSample) * 2.0);
    powder = clamp((powder * 10.0) * 2.0, 0.0, 1.0);
    return mix(1.0, powder, smoothstep(0.5, -0.5, cosTheta));
}

float beerTerm(float densityAtSample)
{
    return exp((-0.4000000059604644775390625) * densityAtSample);
}

void volumetricClouds(CloudsInput cloudsInput, inout CloudsOutput cloudsOutput)
{
    
    vec2 param = cloudsInput.uv0;
    float param_1 = 0.0;
    mat4 param_2 = _663.invViewProjMatrix;
    
    
    
    vec3 posWS = unproject(param, param_1, param_2);
    uvec2 wh = uvec2(480u, 270u);
    ivec2 size = textureSize(noiseTex, 0);
    vec2 noiseWh;
    noiseWh.x = float(size.x);
    noiseWh.y = float(size.y);
    vec2 noiseScale = noiseWh / vec2(wh);
    vec3 rayWS = normalize(posWS - _663.cameraPosWS.xyz);
    uvec4 param_3[2];
    param_3[0] = _663.skyModelSH.data0[0];
    param_3[1] = _663.skyModelSH.data0[1];
    uvec4 param_4 = _663.skyModelSH.data1;
    vec3 param_5 = vec3(0.0, 1.0, 0.0);
    vec3 ambientLightingTop = (sampleSH(param_3, param_4, param_5) * 1.0) / vec3(3.1415927410125732421875);
    uvec4 param_6[2];
    param_6[0] = _663.skyModelSH.data0[0];
    param_6[1] = _663.skyModelSH.data0[1];
    uvec4 param_7 = _663.skyModelSH.data1;
    vec3 param_8 = vec3(0.0, -1.0, 0.0);
    vec3 ambientLightingBottom = (sampleSH(param_6, param_7, param_8) * 1.0) / vec3(3.1415927410125732421875);
    float tornadoSize = 1.0;
    tornadoSize = 26000.0;
    vec3 tornadoDir = normalize(_663.tornadoWorldPos.xyz - _663.cameraPosWS.xyz);
    float param_9 = 20000.0;
    vec3 param_10 = vec3(0.0);
    vec3 param_11 = tornadoDir;
    vec3 tornadoPos = intersectRaySphere(param_9, param_10, param_11);
    float param_12 = 22500.0;
    vec3 param_13 = vec3(0.0);
    vec3 param_14 = rayWS;
    vec3 rayEndPosWS = intersectRaySphere(param_12, param_13, param_14);
    float param_15 = 20000.0;
    vec3 param_16 = vec3(0.0);
    vec3 param_17 = rayWS;
    vec3 rayStartPosWS = intersectRaySphere(param_15, param_16, param_17);
    float stepSize = distance(rayEndPosWS, rayStartPosWS) / 4.0;
    float jitter = textureLod(noiseTex, (cloudsInput.uv0 / noiseScale) + vec2((_663.haltonSamples.x * 2.0) - 1.0), 0.0).x;
    float currentStep = jitter * stepSize;
    vec4 result = vec4(0.0, 0.0, 0.0, 1.0);
    vec3 meanRayPos = rayEndPosWS;
    for (uint i = 0u; i < 3u; i++)
    {
        if (result.w < 9.9999999392252902907785028219223e-09)
        {
            break;
        }
        vec3 rayPosWS = rayStartPosWS + (rayWS * currentStep);
        vec3 rayPosNorm = rayPosWS / vec3(22500.0);
        vec3 tornadoFromRay = tornadoPos - rayPosWS;
        float tornadoFromRayLen = length(tornadoFromRay);
        vec3 tornadoRayDir = tornadoFromRay / vec3(tornadoFromRayLen);
        float tornadoDistNorm = clamp(tornadoFromRayLen / tornadoSize, 0.0, 1.0);
        vec3 colorModulator = vec3(1.0);
        vec4 _node7 = vec4(tornadoDistNorm);
        vec4 _node8 = mix(vec4(0.15687815845012664794921875, 0.460269153118133544921875, 0.85653221607208251953125, 1.0), vec4(1.0), vec4(_node7.x));
        colorModulator = _node8.xyz;
        vec3 param_18 = rayPosNorm;
        vec3 param_19 = rayPosWS;
        float param_20 = tornadoDistNorm;
        vec3 param_21 = tornadoRayDir;
        float density = cloudSample(param_18, param_19, param_20, param_21);
        vec3 param_22 = rayPosWS;
        float param_23 = tornadoDistNorm;
        vec3 param_24 = tornadoRayDir;
        float light = lightSample(param_22, param_23, param_24);
        float cosAngle = dot(rayWS, -_663.dirLightDirWS.xyz);
        float param_25 = cosAngle;
        float param_26 = 0.800000011920928955078125;
        float forwardScattering = hgPhase(param_25, param_26);
        float param_27 = cosAngle;
        float param_28 = -0.5;
        float backwardScattering = hgPhase(param_27, param_28);
        float phase = (forwardScattering + backwardScattering) * 0.5;
        vec3 ambient = mix(ambientLightingBottom, ambientLightingTop, vec3(rayPosNorm.y));
        float param_29 = density;
        float param_30 = cosAngle;
        float param_31 = light;
        vec3 lum = (((_663.dirLightColorAndIntens.xyz * (powderTerm(param_29, param_30) * beerTerm(param_31))) * _663.dirLightColorAndIntens.w) * phase) + ambient;
        uint param_32 = floatBitsToUint(_663.volCloudsParams1.z);
        vec3 sigmaS = ((colorModulator * 0.100000001490116119384765625) * unpackUNorm4x8(param_32).xyz) * density;
        float sigmaE = max(0.300000011920928955078125 * density, 9.9999999392252902907785028219223e-09);
        float stepSizeInMeters = stepSize * 0.00999999977648258209228515625;
        float t = exp((-sigmaE) * stepSizeInMeters);
        vec3 s = lum * sigmaS;
        vec3 si = (s - (s * t)) / vec3(sigmaE);
        vec3 _1280 = result.xyz + (si * result.w);
        result = vec4(_1280.x, _1280.y, _1280.z, result.w);
        result.w *= t;
        currentStep += stepSize;
    }
    vec4 currentRayPos = _663.viewProjMatrix * vec4(meanRayPos, 0.0);
    
    //Fix here.
    currentRayPos.x += vk3d_params.stereo.x * (currentRayPos.w+vk3d_params.stereo.y*currentRayPos.z*0.2) * 1;
    
    
    vec3 _1306 = currentRayPos.xyz / currentRayPos.www;
    currentRayPos = vec4(_1306.x, _1306.y, _1306.z, currentRayPos.w);
    vec4 prevRayPos = _663.prevViewProjMatrix * vec4(meanRayPos, 0.0);
    
    prevRayPos.x -= vk3d_params.stereo.x * (prevRayPos.w+vk3d_params.stereo.y*prevRayPos.z*0.2) * 1;
    
    vec3 _1322 = prevRayPos.xyz / prevRayPos.www;
    prevRayPos = vec4(_1322.x, _1322.y, _1322.z, prevRayPos.w);
    
    
    
    cloudsOutput.outMotion = vec4(((currentRayPos.xy * 0.5) + vec2(0.5)) - ((prevRayPos.xy * 0.5) + vec2(0.5)), 0.0, 0.0);
    cloudsOutput.outClouds = result;
}

void flrMain(FlrInput flrInput, inout FlrOutput flrOutput)
{
    CloudsInput cloudsInput;
    cloudsInput.uv0 = flrInput.uv0;
    CloudsInput param = cloudsInput;
    CloudsOutput param_1;
    volumetricClouds(param, param_1);
    CloudsOutput cloudsOutput = param_1;
    flrOutput.outClouds = cloudsOutput.outClouds;
    flrOutput.outMotion = cloudsOutput.outMotion;
}

void main()
{
    FlrInput flrInput;
    flrInput.uv0 = inUV0;
    FlrInput param = flrInput;
    FlrOutput param_1;
    flrMain(param, param_1);
    FlrOutput flrOutput = param_1;
    outColor = flrOutput.outClouds;
    outMotion = flrOutput.outMotion;
}





