SamplerState samRef
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap; // or Mirror or Clamp or Border
    AddressV = Wrap; // or Mirror or Clamp or Border
};

float3 CalculateEnvironment(TextureCube cubeEnv, float3 viewDirection, float3 normal, float2 texCoord, float roughness)
{
    float3 reflected = normalize(reflect(viewDirection, normal));
    
    float width, height, mipLevels;
    cubeEnv.GetDimensions(0, width, height, mipLevels);
    
    // 9 lods are generated so use 9
    float3 reflectionCol = cubeEnv.SampleLevel(samRef, reflected, roughness * mipLevels);
	
    return reflectionCol * (1 - roughness);
}

float3 CalculateFresnelFalloff(float3 normal, float3 viewDirection, float3 environmentColor)
{
    float fresnelPrePow = 1 - saturate(abs(dot(normal, viewDirection)));
    float fresnel = pow(fresnelPrePow, 5) * 3;
	
    float fresnelMaskPrePow = 1 - saturate(dot(float3(0, -1, 0), normal));
    float fresnelMask = pow(fresnelMaskPrePow, 1);
	
    return fresnel * fresnelMask * environmentColor;
}

float3 Reflection(TextureCube cubeEnv, float3 normal, float3 view, float2 texCoord, float roughness)
{
    float3 envColor = CalculateEnvironment(cubeEnv, view, normal, texCoord, roughness);
    return CalculateFresnelFalloff(normal, view, envColor);
}
