//This file is automatically rebuilt by the Cesium build process.
export default "vec3 lambertianDiffuse(vec3 diffuseColor)\n\
{\n\
    return diffuseColor / czm_pi;\n\
}\n\
\n\
vec3 fresnelSchlick2(vec3 f0, vec3 f90, float VdotH)\n\
{\n\
    float versine = 1.0 - VdotH;\n\
    // pow(versine, 5.0) is slow. See https://stackoverflow.com/a/68793086/10082269\n\
    float versineSquared = versine * versine;\n\
    return f0 + (f90 - f0) * versineSquared * versineSquared * versine;\n\
}\n\
\n\
#ifdef USE_ANISOTROPY\n\
/**\n\
 * @param {float} bitangentRoughness Material roughness (along the anisotropy bitangent)\n\
 * @param {float} tangentialRoughness Anisotropic roughness (along the anisotropy tangent)\n\
 * @param {vec3} lightDirection The direction from the fragment to the light source, transformed to tangent-bitangent-normal coordinates\n\
 * @param {vec3} viewDirection The direction from the fragment to the camera, transformed to tangent-bitangent-normal coordinates\n\
 */\n\
float smithVisibilityGGX_anisotropic(float bitangentRoughness, float tangentialRoughness, vec3 lightDirection, vec3 viewDirection)\n\
{\n\
    vec3 roughnessScale = vec3(tangentialRoughness, bitangentRoughness, 1.0);\n\
    float GGXV = lightDirection.z * length(roughnessScale * viewDirection);\n\
    float GGXL = viewDirection.z * length(roughnessScale * lightDirection);\n\
    float v = 0.5 / (GGXV + GGXL);\n\
    return clamp(v, 0.0, 1.0);\n\
}\n\
\n\
/**\n\
 * @param {float} bitangentRoughness Material roughness (along the anisotropy bitangent)\n\
 * @param {float} tangentialRoughness Anisotropic roughness (along the anisotropy tangent)\n\
 * @param {vec3} halfwayDirection The unit vector halfway between light and view directions, transformed to tangent-bitangent-normal coordinates\n\
 */\n\
float GGX_anisotropic(float bitangentRoughness, float tangentialRoughness, vec3 halfwayDirection)\n\
{\n\
    float roughnessSquared = bitangentRoughness * tangentialRoughness;\n\
    vec3 f = halfwayDirection * vec3(bitangentRoughness, tangentialRoughness, roughnessSquared);\n\
    float w2 = roughnessSquared / dot(f, f);\n\
    return roughnessSquared * w2 * w2 / czm_pi;\n\
}\n\
#endif\n\
\n\
/**\n\
 * Estimate the geometric self-shadowing of the microfacets in a surface,\n\
 * using the Smith Joint GGX visibility function.\n\
 * Note: Vis = G / (4 * NdotL * NdotV)\n\
 * see Eric Heitz. 2014. Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs. Journal of Computer Graphics Techniques, 3\n\
 * see Real-Time Rendering. Page 331 to 336.\n\
 * see https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf/geometricshadowing(specularg)\n\
 *\n\
 * @param {float} alphaRoughness The roughness of the material, expressed as the square of perceptual roughness.\n\
 * @param {float} NdotL The cosine of the angle between the surface normal and the direction to the light source.\n\
 * @param {float} NdotV The cosine of the angle between the surface normal and the direction to the camera.\n\
 */\n\
float smithVisibilityGGX(float alphaRoughness, float NdotL, float NdotV)\n\
{\n\
    float alphaRoughnessSq = alphaRoughness * alphaRoughness;\n\
\n\
    float GGXV = NdotL * sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);\n\
    float GGXL = NdotV * sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);\n\
\n\
    float GGX = GGXV + GGXL;\n\
    if (GGX > 0.0)\n\
    {\n\
        return 0.5 / GGX;\n\
    }\n\
    return 0.0;\n\
}\n\
\n\
/**\n\
 * Estimate the fraction of the microfacets in a surface that are aligned with\n\
 * the halfway vector, which is aligned halfway between the directions from\n\
 * the fragment to the camera and from the fragment to the light source.\n\
 *\n\
 * @param {float} alphaRoughness The roughness of the material, expressed as the square of perceptual roughness.\n\
 * @param {float} NdotH The cosine of the angle between the surface normal and the halfway vector.\n\
 * @return {float} The fraction of microfacets aligned to the halfway vector.\n\
 */\n\
float GGX(float alphaRoughness, float NdotH)\n\
{\n\
    float alphaRoughnessSquared = alphaRoughness * alphaRoughness;\n\
    float f = (NdotH * alphaRoughnessSquared - NdotH) * NdotH + 1.0;\n\
    return alphaRoughnessSquared / (czm_pi * f * f);\n\
}\n\
\n\
/**\n\
 * Compute the strength of the specular reflection due to direct lighting.\n\
 *\n\
 * @param {vec3} normal The surface normal.\n\
 * @param {vec3} lightDirection The unit vector pointing from the fragment to the light source.\n\
 * @param {vec3} viewDirection The unit vector pointing from the fragment to the camera.\n\
 * @param {vec3} halfwayDirection The unit vector pointing from the fragment to halfway between the light source and the camera.\n\
 * @param {float} alphaRoughness The roughness of the material, expressed as the square of perceptual roughness.\n\
 * @return {float} The strength of the specular reflection.\n\
 */\n\
float computeDirectSpecularStrength(vec3 normal, vec3 lightDirection, vec3 viewDirection, vec3 halfwayDirection, float alphaRoughness)\n\
{\n\
    float NdotL = clamp(dot(normal, lightDirection), 0.0, 1.0);\n\
    float NdotV = clamp(dot(normal, viewDirection), 0.0, 1.0);\n\
    float G = smithVisibilityGGX(alphaRoughness, NdotL, NdotV);\n\
    float NdotH = clamp(dot(normal, halfwayDirection), 0.0, 1.0);\n\
    float D = GGX(alphaRoughness, NdotH);\n\
    return G * D;\n\
}\n\
\n\
/**\n\
 * Compute the diffuse and specular contributions using physically based\n\
 * rendering. This function only handles direct lighting.\n\
 * <p>\n\
 * This function only handles the lighting calculations. Metallic/roughness\n\
 * and specular/glossy must be handled separately. See {@MaterialStageFS}\n\
 * </p>\n\
 *\n\
 * @name czm_pbrLighting\n\
 * @glslFunction\n\
 *\n\
 * @param {vec3} viewDirectionEC Unit vector pointing from the fragment to the eye position\n\
 * @param {vec3} normalEC The surface normal in eye coordinates\n\
 * @param {vec3} lightDirectionEC Unit vector pointing to the light source in eye coordinates.\n\
 * @param {czm_modelMaterial} The material properties.\n\
 * @return {vec3} The computed HDR color\n\
 */\n\
vec3 czm_pbrLighting(vec3 positionEC, vec3 viewDirectionEC, vec3 normalEC, vec3 lightDirectionEC, czm_modelMaterial material)\n\
{\n\
    #ifdef USE_CUSTOM_LIGHT_COLOR\n\
        vec3 lightColorHdr = model_lightColorHdr;\n\
    #else\n\
        vec3 lightColorHdr = czm_lightColorHdr;\n\
    #endif\n\
   #ifdef USE_VCS_CUSTOM_SHADING\n\
	    lightColorHdr *= 0.35;\n\
\n\
	    vec3 diffuseColor = material.diffuse;\n\
	    float u_lambertDiffuseMultiplier = 0.9;\n\
		float u_vertexShadowDarkness = 0.3;\n\
\n\
		float ambientLuminanceNight = 0.05;\n\
		float ambientLuminanceDay = (1.0 - ambientLuminanceNight) * u_vertexShadowDarkness + ambientLuminanceNight;\n\
\n\
	 	float distance = length(positionEC);\n\
	    vec3 v = -normalize(positionEC);\n\
	    vec3 l = lightDirectionEC;\n\
	    vec3 h = normalize(v + l);\n\
	    vec3 n = normalEC;\n\
	    float NdotL = dot(n, l);\n\
	    float NdotLclamped = clamp(NdotL, 0.0001, 1.0);\n\
	    float NdotV = abs(dot(n, v)) + 0.001;\n\
	    float NdotH = clamp(dot(n, h), 0.0, 1.0);\n\
	    float VdotH = clamp(dot(v, h), 0.0, 1.0);\n\
\n\
	    float directLight = clamp(NdotL*50.0, 0.0, 1.0);\n\
\n\
	    vec3 positionWC = vec3(czm_inverseView * vec4(positionEC, 1.0));\n\
	    vec3 upWC = normalize(positionWC);\n\
	    vec3 lWC = normalize(czm_inverseViewRotation * l);\n\
	    vec3 nWC = normalize(czm_inverseViewRotation * n);\n\
	    float LdotZ = dot(lWC, -upWC);\n\
	    float NdotZ = dot(nWC, upWC);\n\
	    float sunAboveHorizon = clamp(-200.0 * LdotZ, 0.0, 1.0);\n\
\n\
	    // beginning of nautical twilight at 12 degrees below horizon (in radiens)\n\
	    float LdotZclamped = clamp(LdotZ, 0.0, 1.0);\n\
	    float m = 0.209439510239;\n\
	    float nn = (-LdotZclamped + m) / m;\n\
	    float beta = smoothstep(0.0, 1.0, nn);\n\
	    float ambientLightLuminance = mix(ambientLuminanceNight, ambientLuminanceDay, beta);\n\
\n\
		//modify hue of sunlight\n\
		vec3 directLightColorHdr = lightColorHdr;\n\
	    float gamma = clamp(-20.0 * LdotZ, 0.0, 1.0);\n\
\n\
	    float sun_minB =  0.5; //0.7;\n\
	    float sun_minG = sun_minB * 0.5 + 0.5;\n\
	    float sun_G = gamma*(1.0 - sun_minG) + sun_minG;\n\
	    float sun_B = gamma*(1.0 - sun_minB) + sun_minB;\n\
	    directLightColorHdr.g *= sun_G;\n\
	    directLightColorHdr.b *= sun_B;\n\
\n\
	    //ambient diffuse light\n\
	    float ambientModulationMinimum = 0.2;\n\
	    float ambientModulation = ambientModulationMinimum + (NdotZ*0.5 + 0.5)*(NdotL*0.2 + 0.8)*(1.0 - ambientModulationMinimum);\n\
	    vec3 ambientLightContribution = diffuseColor * lightColorHdr * ambientLightLuminance * ambientModulation;\n\
\n\
		// direct light\n\
	    vec3 directLightContribution = diffuseColor * directLightColorHdr * NdotLclamped * u_lambertDiffuseMultiplier * sunAboveHorizon;\n\
\n\
	    //direct specular light\n\
	    vec3 f0 = material.specular;\n\
        float reflectance = czm_maximumComponent(f0);\n\
	    vec3 f90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0));\n\
	    vec3 F = fresnelSchlick2(f0, f90, VdotH);\n\
        float alphaRoughness = material.roughness * material.roughness;\n\
	    float G = smithVisibilityGGX(alphaRoughness, NdotLclamped, NdotV);\n\
	    float D = GGX(alphaRoughness, NdotH);\n\
	    vec3 directSpecularContribution = directLight * clamp(F * G * D / (4.0 * NdotLclamped * NdotV) * sunAboveHorizon * directLightColorHdr, 0.0, 1.0);\n\
\n\
		//ambient specular light\n\
		const vec3 blueSkyDiffuseColor = vec3(0.7, 0.85, 0.9);\n\
		const vec3 REFLECTANCE_DIELECTRIC = vec3(0.04);\n\
		vec3 g0 = (f0 - REFLECTANCE_DIELECTRIC) / (1.0 - REFLECTANCE_DIELECTRIC) ;\n\
	    vec3 ambientSpecularContribution = g0 * blueSkyDiffuseColor * ambientLightLuminance * ambientModulation;\n\
\n\
	    vec3 finalColorRGB = ambientLightContribution + directLightContribution + directSpecularContribution + ambientSpecularContribution;\n\
        return finalColorRGB;\n\
	#else\n\
\n\
    vec3 halfwayDirectionEC = normalize(viewDirectionEC + lightDirectionEC);\n\
    float VdotH = clamp(dot(viewDirectionEC, halfwayDirectionEC), 0.0, 1.0);\n\
    float NdotL = clamp(dot(normalEC, lightDirectionEC), 0.001, 1.0);\n\
\n\
    vec3 f0 = material.specular;\n\
    float reflectance = czm_maximumComponent(f0);\n\
    // Typical dielectrics will have reflectance 0.04, so f90 will be 1.0.\n\
    // In this case, at grazing angle, all incident energy is reflected.\n\
    vec3 f90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0));\n\
    vec3 F = fresnelSchlick2(f0, f90, VdotH);\n\
\n\
    #if defined(USE_SPECULAR)\n\
        F *= material.specularWeight;\n\
    #endif\n\
\n\
    float alphaRoughness = material.roughness * material.roughness;\n\
    #ifdef USE_ANISOTROPY\n\
        mat3 tbn = mat3(material.anisotropicT, material.anisotropicB, normalEC);\n\
        vec3 lightDirection = lightDirectionEC * tbn;\n\
        vec3 viewDirection = viewDirectionEC * tbn;\n\
        vec3 halfwayDirection = halfwayDirectionEC * tbn;\n\
        float anisotropyStrength = material.anisotropyStrength;\n\
        float tangentialRoughness = mix(alphaRoughness, 1.0, anisotropyStrength * anisotropyStrength);\n\
        float bitangentRoughness = clamp(alphaRoughness, 0.001, 1.0);\n\
        float G = smithVisibilityGGX_anisotropic(bitangentRoughness, tangentialRoughness, lightDirection, viewDirection);\n\
        float D = GGX_anisotropic(bitangentRoughness, tangentialRoughness, halfwayDirection);\n\
        vec3 specularContribution = F * G * D;\n\
    #else\n\
        float specularStrength = computeDirectSpecularStrength(normalEC, lightDirectionEC, viewDirectionEC, halfwayDirectionEC, alphaRoughness);\n\
        vec3 specularContribution = F * specularStrength;\n\
    #endif\n\
\n\
    vec3 diffuseColor = material.diffuse;\n\
    // F here represents the specular contribution\n\
    vec3 diffuseContribution = (1.0 - F) * lambertianDiffuse(diffuseColor);\n\
\n\
    // Lo = (diffuse + specular) * Li * NdotL\n\
    return (diffuseContribution + specularContribution) * NdotL * lightColorHdr;\n\
	#endif\n\
}\n\
";
