• Viewer address

Initial color vs. texture color vs. vertex color

  • Multiple colors (default color, map color, vertex color)
  • Default color x Map color x vertex color
vec4 baseColor = getBaseColor();

vec4 getBaseColor() {
    // Default eyes
    vec4 baseColor = vec4(1);
    #if defined(MATERIAL_SPECULARGLOSSINESS) // High optical flow
        baseColor = u_DiffuseFactor;  //diffuse
    #elif defined(MATERIAL_METALLICROUGHNESS) // Metal flow
        baseColor = u_BaseColorFactor; // Metal 1, 1, 1, 1
    #endif
    
    // Color map
    #if defined(MATERIAL_SPECULARGLOSSINESS) && defined(HAS_DIFFUSE_MAP)
        baseColor *= texture(u_DiffuseSampler, getDiffuseUV());
    #elif defined(MATERIAL_METALLICROUGHNESS) && defined(HAS_BASE_COLOR_MAP)
        baseColor *= texture(u_BaseColorSampler, getBaseColorUV());
    #endif
    
    // Vertex color
    return baseColor * getVertexColor(); // Just multiply
}
Copy the code

Here you can set the opacity to 1.0

#if ALPHAMODE == ALPHAMODE_OPAQUE
    baseColor.a = 1.0;
#endif
Copy the code

This is linear SRGB special case

#ifdef MATERIAL_UNLIT
    g_finalColor = (vec4(linearTosRGB(baseColor.rgb), baseColor.a));
    return;
#endif
const float GAMMA = 2.2;
const float INV_GAMMA = 1.0 / GAMMA;
// see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
vec3 linearTosRGB(vec3 color) {
    return pow(color, vec3(INV_GAMMA));
}
Copy the code

The normal information

vec3 v = normalize(u_Camera - v_Position); //view
NormalInfo normalInfo = getNormalInfo(v); // Tangent space
vec3 n = normalInfo.n;    / / normal
vec3 t = normalInfo.t;    / / are tangent
vec3 b = normalInfo.b;    / / deputy tangent
float NdotV = clampedDot(n, v); // Normals and angles
float TdotV = clampedDot(t, v); It's no use / /
float BdotV = clampedDot(b, v); It's no use / /

// Get normal, tangent and bitangent vectors.
NormalInfo getNormalInfo(vec3 v)
{
    vec2 UV = getNormalUV();
    vec3 uv_dx = dFdx(vec3(UV, 0.0));
    vec3 uv_dy = dFdy(vec3(UV, 0.0));
    vec3 t_ = (uv_dy.t * dFdx(v_Position) - uv_dx.t * dFdy(v_Position)) /
        (uv_dx.s * uv_dy.t - uv_dy.s * uv_dx.t); //how to do it 
    vec3 n, t, b, ng;
    // Compute geometrical TBN: if exists TBN
    #ifdef HAS_TANGENT_VEC4
        // Trivial TBN computation, present as vertex attribute.
        // Normalize eigenvectors as matrix is linearly interpolated.
        t = normalize(v_TBN[0]);
        b = normalize(v_TBN[1]);
        ng = normalize(v_TBN[2]);
    #else
        // Normals are either present as vertex attributes or approximated.
        #ifdef HAS_NORMAL_VEC3 // 
            ng = normalize(v_Normal);
        #else  
            ng = normalize(cross(dFdx(v_Position), dFdy(v_Position)));//cross ng
        #endif
        t = normalize(t_ - ng * dot(ng, t_)); / /??
        b = cross(ng, t);  //cross
    #endif 
    
    // For a back-facing surface, the tangential basis vectors are negated.
    if (gl_FrontFacing= =false) //false
    {
        t *= 1.0;
        b *= 1.0;
        ng *= 1.0;
    }
    
    // Compute pertubed normals:
    #ifdef HAS_NORMAL_MAP //
        n = texture(u_NormalSampler, UV).rgb * 2.0 - vec3(1.0); // From 0 to -1 to -1
        n *= vec3(u_NormalScale, u_NormalScale, 1.0); // NormalScale is multiplied only by the first two
        n = mat3(t, b, ng) * normalize(n); // Unit vector * tangent space time space normal line
    #else
        n = ng; / / normal
    #endif
    NormalInfo info;
    info.ng = ng; // The normal line perpendicular to the surface
    info.t = t;
    info.b = b;
    info.n = n;
    return info;
}
// Get the normal uv
vec2 getNormalUV()
{
    vec3 uv = vec3(u_NormalUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0); // There are two sets of UVs, so treat them differently
    #ifdef HAS_NORMAL_UV_TRANSFORM // Shift rotation scale
        uv = u_NormalUVTransform * uv;
    #endif
    return uv.xy;
}
Copy the code

Ior baseColor F0 specularWeight Basic computation

  • Associated with the Transmission
MaterialInfo materialInfo;
materialInfo.baseColor = baseColor.rgb; // Put RGB first
materialInfo.ior = 1.5;  / / the default
materialInfo.f0 = vec3(0.04); / / the default
materialInfo.specularWeight = 1.0;
#ifdef MATERIAL_IOR // If there is ior, calculate F0 if there is no IOR, 0.04 by default this is a metal flow
    materialInfo = getIorInfo(materialInfo);
#endif
#ifdef MATERIAL_IOR
    MaterialInfo getIorInfo(MaterialInfo info) {
        info.f0 = vec3(pow(( u_Ior - 1.0) /  (u_Ior + 1.0), 2.0)); //f0 is calculated by ior
        info.ior = u_Ior;
        return info;
    }
#endif
Copy the code

Roughness evaluation (RGB Roughness Evaluation A)

  • The roughness is in a
  • F0 is in RGB
  • * basecolor c_diff is (1 – FO)
#ifdef MATERIAL_SPECULARGLOSSINESS
    materialInfo = getSpecularGlossinessInfo(materialInfo);
#endif

#ifdef MATERIAL_SPECULARGLOSSINESS
    MaterialInfo getSpecularGlossinessInfo(MaterialInfo info) {
        info.f0 = u_SpecularFactor; //Factor
        info.perceptualRoughness = u_GlossinessFactor; //Factor
        #ifdef HAS_SPECULAR_GLOSSINESS_MAP
            vec4 sgSample = texture(u_SpecularGlossinessSampler, getSpecularGlossinessUV());  //UV offset, etc
            info.perceptualRoughness *= sgSample.a ; // Glossiness to roughness multiplication
            info.f0 *= sgSample.rgb; / / RGB is f0
        #endif 
        
        info.perceptualRoughness = 1.0 - info.perceptualRoughness; // 1 - glossiness
        info.c_diff = info.baseColor.rgb * (1.0 - max(max(info.f0.r, info.f0.g), info.f0.b));
        return info;
    }
#endif
#ifdef MATERIAL_SPECULARGLOSSINESS
    uniform sampler2D u_DiffuseSampler;
    uniform int u_DiffuseUVSet;
    uniform mat3 u_DiffuseUVTransform;
    uniform sampler2D u_SpecularGlossinessSampler;
    uniform int u_SpecularGlossinessUVSet;
    uniform mat3 u_SpecularGlossinessUVTransform;
    vec2 getSpecularGlossinessUV() { // Also two sets of UV
        vec3 uv = vec3(u_SpecularGlossinessUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_SPECULARGLOSSINESS_UV_TRANSFORM
            uv = u_SpecularGlossinessUVTransform * uv;
        #endif
        return uv.xy;
    }
    vec2 getDiffuseUV() {
        vec3 uv = vec3(u_DiffuseUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_DIFFUSE_UV_TRANSFORM
            uv = u_DiffuseUVTransform * uv;
        #endif
        return uv.xy;
    }
#endif
Copy the code

Metal flow gets F0 Diffusecolor

  • Roughness in g
  • B
  • diffuse basecolor * (1 – f0) * (1 – metallic)
  • F0 f0 * (1 – metallic) + basecolor * metallic
#ifdef MATERIAL_METALLICROUGHNESS
    materialInfo = getMetallicRoughnessInfo(materialInfo);
#endif
#ifdef MATERIAL_METALLICROUGHNESS
    MaterialInfo getMetallicRoughnessInfo(MaterialInfo info) {
        info.metallic = u_MetallicFactor;  //factor
        info.perceptualRoughness = u_RoughnessFactor; //factor
        #ifdef HAS_METALLIC_ROUGHNESS_MAP
            // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
            // This layout intentionally reserves the 'r' channel for (optional) occlusion map data
            vec4 mrSample = texture(u_MetallicRoughnessSampler, getMetallicRoughnessUV());
            info.perceptualRoughness *= mrSample.g; 
            info.metallic *= mrSample.b;
        #endif
        
        // Achromatic f0 based on IOR.
        info.c_diff = mix(info.baseColor.rgb * (vec3(1.0) - info.f0), vec3(0), info.metallic);
        info.f0 = mix(info.f0, info.baseColor.rgb, info.metallic);
        return info;
    }
#endif
Copy the code

Sheen Information Collection

  • Sheen Color texture RGB
  • Sheen Roughness Map A
#ifdef MATERIAL_SHEEN
    materialInfo = getSheenInfo(materialInfo);
#endif
#ifdef MATERIAL_SHEEN
    MaterialInfo getSheenInfo(MaterialInfo info) {
        info.sheenColorFactor = u_SheenColorFactor;
        info.sheenRoughnessFactor = u_SheenRoughnessFactor;
        #ifdef HAS_SHEEN_COLOR_MAP
            vec4 sheenColorSample = texture(u_SheenColorSampler, getSheenColorUV());
            info.sheenColorFactor *= sheenColorSample.rgb;
        #endif
        
        #ifdef HAS_SHEEN_ROUGHNESS_MAP
            vec4 sheenRoughnessSample = texture(u_SheenRoughnessSampler, getSheenRoughnessUV());
            info.sheenRoughnessFactor *= sheenRoughnessSample.a;
        #endif
        return info;
    }
#endif
Copy the code

Clearcoat collects information

  • ClearcoatF0 is f0
  • ClearcoatF90 1.0
  • Clearcoat takes the r of the map
  • Step 6. ClearcoatRoughness step 6
#ifdef MATERIAL_CLEARCOAT
    materialInfo = getClearCoatInfo(materialInfo, normalInfo);
#endif

#ifdef MATERIAL_CLEARCOAT
    MaterialInfo getClearCoatInfo(MaterialInfo info, NormalInfo normalInfo) {
        info.clearcoatFactor = u_ClearcoatFactor;
        info.clearcoatRoughness = u_ClearcoatRoughnessFactor;
        info.clearcoatF0 = vec3(info.f0); //f0
        info.clearcoatF90 = vec3(1.0);  //F90
        #ifdef HAS_CLEARCOAT_MAP
            vec4 clearcoatSample = texture(u_ClearcoatSampler, getClearcoatUV());
            info.clearcoatFactor *= clearcoatSample.r;
        #endif
        
        #ifdef HAS_CLEARCOAT_ROUGHNESS_MAP
            vec4 clearcoatSampleRoughness = texture(u_ClearcoatRoughnessSampler, getClearcoatRoughnessUV());
            info.clearcoatRoughness *= clearcoatSampleRoughness.g;
        #endif
        
        info.clearcoatNormal = getClearcoatNormal(normalInfo);
        info.clearcoatRoughness = clamp(info.clearcoatRoughness, 0.0.1.0);
        return info;
    }
#endif
Copy the code

Specular highlights flow

  • Specular a
  • SpecularColor Fetch map RGB
  • DielectricSpecularF0 f0 * specularColor
  • F0 dielectricSpecularF0 * (1-metallic) + basecolor.rgb * metallic
  • specularWeight
  • C_diff basecolor * (1.0-max3 (dielectricSpecularF0)) * (1-metallic) c_diff basecolor * (1.0-max3 (dielectricSpecularF0)) * (1-metallic)
#ifdef MATERIAL_SPECULAR
    materialInfo = getSpecularInfo(materialInfo);
#endif
#ifdef MATERIAL_SPECULAR
    MaterialInfo getSpecularInfo(MaterialInfo info) {
        vec4 specularTexture = vec4(1.0);
        #ifdef HAS_SPECULAR_MAP
            specularTexture.a = texture(u_SpecularSampler, getSpecularColorUV()).a;
        #endif
        #ifdef HAS_SPECULAR_COLOR_MAP
            specularTexture.rgb = texture(u_SpecularColorSampler, getSpecularUV()).rgb;
        #endif
        
        vec3 dielectricSpecularF0 = min(info.f0 * u_KHR_materials_specular_specularColorFactor * specularTexture.rgb, vec3(1.0));
        info.f0 = mix(dielectricSpecularF0, info.baseColor.rgb, info.metallic);
        info.specularWeight = u_KHR_materials_specular_specularFactor * specularTexture.a;
        info.c_diff = mix(info.baseColor.rgb * (1.0 - max3(dielectricSpecularF0)), vec3(0), info.metallic);
        return info;
    }
#endif
Copy the code

TRANSMISSION

  • The R in TRANSMISSION map
#ifdef MATERIAL_TRANSMISSION
    materialInfo = getTransmissionInfo(materialInfo);
#endif
#ifdef MATERIAL_TRANSMISSION
    MaterialInfo getTransmissionInfo(MaterialInfo info) {
        info.transmissionFactor = u_TransmissionFactor;
        #ifdef HAS_TRANSMISSION_MAP
            vec4 transmissionSample = texture(u_TransmissionSampler, getTransmissionUV());
            info.transmissionFactor *= transmissionSample.r;
        #endif
        return info;
    }
#endif
Copy the code

Volume

#ifdef MATERIAL_VOLUME
    materialInfo = getVolumeInfo(materialInfo);
#endif
#ifdef MATERIAL_VOLUME
    MaterialInfo getVolumeInfo(MaterialInfo info) {
        info.thickness = u_ThicknessFactor;
        info.attenuationColor = u_AttenuationColor;
        info.attenuationDistance = u_AttenuationDistance;
        #ifdef HAS_THICKNESS_MAP
            vec4 thicknessSample = texture(u_ThicknessSampler, getThicknessUV());
            info.thickness *= thicknessSample.g;
        #endif
        return info;
    }
#endif
Copy the code

PBR Basic information

  • AlphaRoughness roughness squared
  • Reflectance is set to the maximum value of F0
  • F90 is still going to be 1
materialInfo.perceptualRoughness = clamp(materialInfo.perceptualRoughness, 0.0.1.0);
materialInfo.metallic = clamp(materialInfo.metallic, 0.0.1.0);

// Roughness is authored as perceptual roughness; as is convention, // convert to material roughness by squaring the perceptual roughness.
materialInfo.alphaRoughness = materialInfo.perceptualRoughness * materialInfo.perceptualRoughness;

// Compute reflectance.
float reflectance = max(max(materialInfo.f0.r, materialInfo.f0.g), materialInfo.f0.b);

// Anything less than 2% is physically impossible and is instead considered to be shadowing. Compare to "Real-Time-Rendering" 4th editon on page 325.
materialInfo.f90 = vec3(1.0);
// LIGHTING

vec3 f_specular = vec3(0.0);
vec3 f_diffuse = vec3(0.0);
vec3 f_emissive = vec3(0.0);
vec3 f_clearcoat = vec3(0.0);
vec3 f_sheen = vec3(0.0);
vec3 f_transmission = vec3(0.0);
float albedoSheenScaling = 1.0;
Copy the code

IBL Sheen Clearcoat

  • IBL is a five-part Specular Diffuse Clearcoat Sheen
  • specularLight * (specularColor * brdf.x + brdf.y)
f_specular += getIBLRadianceGGX(n, v, materialInfo.perceptualRoughness, materialInfo.f0, materialInfo.specularWeight);
vec3 getIBLRadianceGGX(vec3 n, vec3 v, float roughness, vec3 F0, float specularWeight) {
    float NdotV = clampedDot(n, v);
    float lod = roughness * float(u_MipCount - 1);
    vec3 reflection = normalize(reflect(-v, n));
    vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0.0.0), vec2(1.0.1.0));
    vec2 f_ab = texture(u_GGXLUT, brdfSamplePoint).rg;
    vec4 specularLight = getSpecularSample(reflection, lod).rgb;
    
    // see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
    
    // Roughness dependent fresnel, from Fdez-Aguera
    vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
    vec3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
    vec3 FssEss = k_S * f_ab.x + f_ab.y;
    return specularWeight * specularLight * FssEss;
}
vec4 getSpecularSample(vec3 reflection, float lod) {
    return textureLod(u_GGXEnvSampler, u_EnvRotation * reflection, lod);
}
Copy the code
  • I don’t understand this calculation
f_diffuse += getIBLRadianceLambertian(n, v, materialInfo.perceptualRoughness, materialInfo.c_diff, materialInfo.f0, materialInfo.specularWeight);
vec3 getIBLRadianceLambertian(vec3 n, vec3 v, float roughness, vec3 diffuseColor, vec3 F0, float specularWeight) {
    float NdotV = clampedDot(n, v);
    vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0.0.0), vec2(1.0.1.0));
    vec2 f_ab = texture(u_GGXLUT, brdfSamplePoint).rg;
    vec3 irradiance = getDiffuseLight(n);
    
    // see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
    
    // Roughness dependent fresnel, from Fdez-Aguera
    
    vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
    vec3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
    vec3 FssEss = specularWeight * k_S * f_ab.x + f_ab.y; // <--- GGX / specular light contribution (scale it down if the specularWeight is low)
    
    
    // Multiple scattering, from Fdez-Aguera
    float Ems = (1.0 - (f_ab.x + f_ab.y));
    vec3 F_avg = specularWeight * (F0 + (1.0 - F0) / 21.0);
    vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems);
    vec3 k_D = diffuseColor * (1.0 - FssEss + FmsEms); // we use +FmsEms as indicated by the formula in the blog post (might be a typo in the implementation)
    
    
    return (FmsEms + k_D) * irradiance;
}
vec3 getDiffuseLight(vec3 n) {
    return texture(u_LambertianEnvSampler, u_EnvRotation * n).rgb;
}
Copy the code
  • It’s highlighted in the same way
f_clearcoat += getIBLRadianceGGX(materialInfo.clearcoatNormal, v, materialInfo.clearcoatRoughness, materialInfo.clearcoatF0, 1.0);
Copy the code
  • sheenLight * sheenColor * brdf
f_sheen += getIBLRadianceCharlie(n, v, materialInfo.sheenRoughnessFactor, materialInfo.sheenColorFactor);
vec3 getIBLRadianceCharlie(vec3 n, vec3 v, float sheenRoughness, vec3 sheenColor) {
    float NdotV = clampedDot(n, v);
    float lod = sheenRoughness * float(u_MipCount - 1);
    vec3 reflection = normalize(reflect(-v, n));
    vec2 brdfSamplePoint = clamp(vec2(NdotV, sheenRoughness), vec2(0.0.0.0), vec2(1.0.1.0));
    float brdf = texture(u_CharlieLUT, brdfSamplePoint).b;
    vec4 sheenSample = getSheenSample(reflection, lod);
    vec3 sheenLight = sheenSample.rgb;
    return sheenLight * sheenColor * brdf;
}
Copy the code

transmission

  • Different from the PBR at the back see
#if (defined(MATERIAL_TRANSMISSION) || defined(MATERIAL_VOLUME)) && (defined(USE_PUNCTUAL) || defined(USE_IBL))
    f_transmission += materialInfo.transmissionFactor * getIBLVolumeRefraction(
    n, v, materialInfo.perceptualRoughness, materialInfo.baseColor, materialInfo.f0, materialInfo.f90, v_Position, u_ModelMatrix, u_ViewMatrix, u_ProjectionMatrix, materialInfo.ior, materialInfo.thickness, materialInfo.attenuationColor, materialInfo.attenuationDistance);
#endif
Copy the code

OA

float ao = 1.0;
// Apply optional PBR terms for additional (optional) shading

#ifdef HAS_OCCLUSION_MAP
    ao = texture(u_OcclusionSampler, getOcclusionUV()).r;
    f_diffuse = mix(f_diffuse, f_diffuse * ao, u_OcclusionStrength);
    // apply ambient occlusion to all lighting that is not punctual

    f_specular = mix(f_specular, f_specular * ao, u_OcclusionStrength);
    f_sheen = mix(f_sheen, f_sheen * ao, u_OcclusionStrength);
    f_clearcoat = mix(f_clearcoat, f_clearcoat * ao, u_OcclusionStrength);
#endif
Copy the code

Direct sunlight

#ifdef USE_PUNCTUAL
    for (int i = 0; i < LIGHT_COUNT; ++i) {
        Light light = u_Lights[i];
        vec3 pointToLight;
        if (light.type ! = LightType_Directional) {
            pointToLight = light.position - v_Position;
        }
        else {
            pointToLight = -light.direction;
        }
        // BSTF
        vec3 l = normalize(pointToLight);   // Direction from surface point to light

        vec3 h = normalize(l + v);          // Direction of the vector between l and v, called halfway vector

        float NdotL = clampedDot(n, l);
        float NdotV = clampedDot(n, v);
        float NdotH = clampedDot(n, h);
        float LdotH = clampedDot(l, h);
        float VdotH = clampedDot(v, h);
        if (NdotL > 0.0 || NdotV > 0.0) {
            // Calculation of analytical light
            / / https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
            vec3 intensity = getLighIntensity(light, pointToLight);
            f_diffuse += intensity * NdotL *  BRDF_lambertian(materialInfo.f0, materialInfo.f90, materialInfo.c_diff, materialInfo.specularWeight, VdotH);
            f_specular += intensity * NdotL * BRDF_specularGGX(materialInfo.f0, materialInfo.f90, materialInfo.alphaRoughness, materialInfo.specularWeight, VdotH, NdotL, NdotV, NdotH);
            #ifdef MATERIAL_SHEEN
                f_sheen += intensity * getPunctualRadianceSheen(materialInfo.sheenColorFactor, materialInfo.sheenRoughnessFactor, NdotL, NdotV, NdotH);
                albedoSheenScaling = min(1.0 - max3(materialInfo.sheenColorFactor) * albedoSheenScalingLUT(NdotV, materialInfo.sheenRoughnessFactor), 1.0 - max3(materialInfo.sheenColorFactor) * albedoSheenScalingLUT(NdotL, materialInfo.sheenRoughnessFactor));
            #endif

            #ifdef MATERIAL_CLEARCOAT
                f_clearcoat += intensity * getPunctualRadianceClearCoat(materialInfo.clearcoatNormal, v, l, h, VdotH, materialInfo.clearcoatF0, materialInfo.clearcoatF90, materialInfo.clearcoatRoughness);
            #endif
        }
        // BDTF
        #ifdef MATERIAL_TRANSMISSION
            // If the light ray travels through the geometry, use the point it exits the geometry again.
            // That will change the angle to the light source, if the material refracts the light ray.
            vec3 transmissionRay = getVolumeTransmissionRay(n, v, materialInfo.thickness, materialInfo.ior, u_ModelMatrix);
            pointToLight -= transmissionRay;
            l = normalize(pointToLight);
            vec3 intensity = getLighIntensity(light, pointToLight);
            vec3 transmittedLight = intensity * getPunctualRadianceTransmission(n, v, l, materialInfo.alphaRoughness, materialInfo.f0, materialInfo.f90, materialInfo.baseColor, materialInfo.ior);
            #ifdef MATERIAL_VOLUME
                transmittedLight = applyVolumeAttenuation(transmittedLight, length(transmissionRay), materialInfo.attenuationColor, materialInfo.attenuationDistance);
            #endif

            f_transmission += materialInfo.transmissionFactor * transmittedLight;
        #endif
    }
#endif
Copy the code

final

f_emissive = u_EmissiveFactor;
#ifdef HAS_EMISSIVE_MAP
    f_emissive *= texture(u_EmissiveSampler, getEmissiveUV()).rgb;
#endif

vec3 color = vec3(0);

// Layer blending


float clearcoatFactor = 0.0;
vec3 clearcoatFresnel = vec3(0);
#ifdef MATERIAL_CLEARCOAT
    clearcoatFactor = materialInfo.clearcoatFactor;
    clearcoatFresnel = F_Schlick(materialInfo.clearcoatF0, materialInfo.clearcoatF90, clampedDot(materialInfo.clearcoatNormal, v));
    f_clearcoat = f_clearcoat * clearcoatFactor;
#endif

#ifdef MATERIAL_TRANSMISSION
    vec3 diffuse = mix(f_diffuse, f_transmission, materialInfo.transmissionFactor);
#else
    vec3 diffuse = f_diffuse;
#endif

color = f_emissive + diffuse + f_specular;
color = f_sheen + color * albedoSheenScaling;
color = color * (1.0 - clearcoatFactor * clearcoatFresnel) + f_clearcoat;
Copy the code
#if DEBUG == DEBUG_NONE

    #if ALPHAMODE == ALPHAMODE_MASK
        // Late discard to avoid samplig artifacts. See https://github.com/KhronosGroup/glTF-Sample-Viewer/issues/267
        if (baseColor.a < u_AlphaCutoff) {
            discard;
        }
        baseColor.a = 1.0;
    #endif

    #ifdef LINEAR_OUTPUT
        g_finalColor = vec4(color.rgb, baseColor.a);
    #else
        g_finalColor = vec4(toneMap(color), baseColor.a);
    #endif

#else
    g_finalColor.a = 1.0;
#endif

#if DEBUG == DEBUG_METALLIC
    g_finalColor.rgb = vec3(materialInfo.metallic);
#endif

#if DEBUG == DEBUG_ROUGHNESS
    g_finalColor.rgb = vec3(materialInfo.perceptualRoughness);
#endif

#if DEBUG == DEBUG_NORMAL
    #ifdef HAS_NORMAL_MAP
        g_finalColor.rgb = texture(u_NormalSampler, getNormalUV()).rgb;
    #else
        g_finalColor.rgb = vec3(0.5.0.5.1.0);
    #endif
#endif

#if DEBUG == DEBUG_NORMAL_GEOMETRY
    g_finalColor.rgb = (normalInfo.ng + 1.0) / 2.0;
#endif

#if DEBUG == DEBUG_NORMAL_WORLD
    g_finalColor.rgb = (n + 1.0) / 2.0;
#endif

#if DEBUG == DEBUG_TANGENT
    g_finalColor.rgb = t * 0.5 + vec3(0.5);
#endif

#if DEBUG == DEBUG_BITANGENT
    g_finalColor.rgb = b * 0.5 + vec3(0.5);
#endif

#if DEBUG == DEBUG_BASE_COLOR_SRGB
    g_finalColor.rgb = linearTosRGB(materialInfo.baseColor);
#endif

#if DEBUG == DEBUG_BASE_COLOR_LINEAR
    g_finalColor.rgb = materialInfo.baseColor;
#endif

#if DEBUG == DEBUG_OCCLUSION
    g_finalColor.rgb = vec3(ao);
#endif

#if DEBUG == DEBUG_F0
    g_finalColor.rgb = materialInfo.f0;
#endif

#if DEBUG == DEBUG_EMISSIVE_SRGB
    g_finalColor.rgb = linearTosRGB(f_emissive);
#endif

#if DEBUG == DEBUG_EMISSIVE_LINEAR
    g_finalColor.rgb = f_emissive;
#endif

#if DEBUG == DEBUG_SPECULAR_SRGB
    g_finalColor.rgb = linearTosRGB(f_specular);
#endif

#if DEBUG == DEBUG_DIFFUSE_SRGB
    g_finalColor.rgb = linearTosRGB(f_diffuse);
#endif

#if DEBUG == DEBUG_CLEARCOAT_SRGB
    g_finalColor.rgb = linearTosRGB(f_clearcoat);
#endif

#if DEBUG == DEBUG_SHEEN_SRGB
    g_finalColor.rgb = linearTosRGB(f_sheen);
#endif

#if DEBUG == DEBUG_TRANSMISSION_SRGB
    g_finalColor.rgb = linearTosRGB(f_transmission);
#endif

#if DEBUG == DEBUG_ALPHA
    g_finalColor.rgb = vec3(baseColor.a);
#endif
Copy the code
#version 300 es
#define HAS_NORMAL_MAP 1
#define HAS_OCCLUSION_MAP 1
#define HAS_EMISSIVE_MAP 1
#define HAS_BASE_COLOR_MAP 1
#define HAS_METALLIC_ROUGHNESS_MAP 1
#define ALPHAMODE_OPAQUE 0
#define ALPHAMODE_MASK 1
#define ALPHAMODE_BLEND 2
#define ALPHAMODE ALPHAMODE_OPAQUE
#define MATERIAL_METALLICROUGHNESS 1
#define HAS_NORMAL_VEC3 1
#define HAS_POSITION_VEC3 1
#define HAS_TEXCOORD_0_VEC2 1
#define USE_PUNCTUAL 1
#define LIGHT_COUNT 0
#define USE_IBL 1
#define DEBUG_NONE 0
#define DEBUG_NORMAL 1
#define DEBUG_NORMAL_WORLD 2
#define DEBUG_NORMAL_GEOMETRY 3
#define DEBUG_TANGENT 4
#define DEBUG_BITANGENT 5
#define DEBUG_ROUGHNESS 6
#define DEBUG_METALLIC 7
#define DEBUG_BASE_COLOR_SRGB 8
#define DEBUG_BASE_COLOR_LINEAR 9
#define DEBUG_OCCLUSION 10
#define DEBUG_EMISSIVE_SRGB 11
#define DEBUG_EMISSIVE_LINEAR 12
#define DEBUG_F0 13
#define DEBUG_ALPHA 14
#define DEBUG_DIFFUSE_SRGB 15
#define DEBUG_SPECULAR_SRGB 16
#define DEBUG_CLEARCOAT_SRGB 17
#define DEBUG_SHEEN_SRGB 18
#define DEBUG_TRANSMISSION_SRGB 19
#define DEBUG DEBUG_NONE
//
// This fragment shader defines a reference implementation for Physically Based Shading of
// a microfacet surface material defined by a glTF model.
//
// References:
// [1] Real Shading in Unreal Engine 4
// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
// [2] Physically Based Shading at Disney
// http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf
// [3] README.md - Environment Maps
// https://github.com/KhronosGroup/glTF-WebGL-PBR/#environment-maps
// [4] "An Inexpensive BRDF Model for Physically based Rendering" by Christophe Schlick
// https://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf
// [5] "KHR_materials_clearcoat"
/ / https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_clearcoat

precision highp float;
#define GLSLIFY 1

#define GLSLIFY 1
uniform float u_Exposure;
const float GAMMA = 2.2;
const float INV_GAMMA = 1.0 / GAMMA;

// sRGB = > XYZ = > D65_2_D60 = > AP1 = > RRT_SAT

const mat3 ACESInputMat = mat3
(
0.59719.0.07600.0.02840.0.35458.0.90834.0.13383.0.04823.0.01566.0.83777
);

// ODT_SAT = > XYZ = > D60_2_D65 = > sRGB

const mat3 ACESOutputMat = mat3
(
1.60475.0.10208.0.00327.0.53108.1.10813.0.07276.0.07367.0.00605.1.07602
);

// linear to sRGB approximation

// see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
vec3 linearTosRGB(vec3 color) {
    return pow(color, vec3(INV_GAMMA));
}
// sRGB to linear approximation
// see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
vec3 sRGBToLinear(vec3 srgbIn) {
    return vec3(pow(srgbIn.xyz, vec3(GAMMA)));
}
vec4 sRGBToLinear(vec4 srgbIn) {
    return vec4(sRGBToLinear(srgbIn.xyz), srgbIn.w);
}
// ACES tone map (faster approximation)
// see: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
vec3 toneMapACES_Narkowicz(vec3 color) {
    const float A = 2.51;
    const float B = 0.03;
    const float C = 2.43;
    const float D = 0.59;
    const float E = 0.14;
    return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0.1.0);
}
// ACES filmic tone map approximation
// see https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
vec3 RRTAndODTFit(vec3 color) {
    vec3 a = color * (color + 0.0245786) - 0.000090537;
    vec3 b = color * (0.983729 * color + 0.4329510) + 0.238081;
    return a / b;
}
// tone mapping 
vec3 toneMapACES_Hill(vec3 color) {
    color = ACESInputMat * color;
    
    // Apply RRT and ODT
    
    color = RRTAndODTFit(color);
    color = ACESOutputMat * color;
    
    // Clamp to [0, 1]
    
    color = clamp(color, 0.0.1.0);
    return color;
}
vec3 toneMap(vec3 color) {
    color *= u_Exposure;
    #ifdef TONEMAP_ACES_NARKOWICZ
        color = toneMapACES_Narkowicz(color);
    #endif
    
    #ifdef TONEMAP_ACES_HILL
        color = toneMapACES_Hill(color);
    #endif
    
    #ifdef TONEMAP_ACES_HILL_EXPOSURE_BOOST
        // boost exposure as discussed in https://github.com/mrdoob/three.js/pull/19621
        // this factor is based on the exposure correction of Krzysztof Narkowicz in his
        // implemetation of ACES tone mapping
        color /= 0.6;
        color = toneMapACES_Hill(color);
    #endif
    
    return linearTosRGB(color);
}
#define GLSLIFY 1
// IBL

uniform int u_MipCount;
uniform samplerCube u_LambertianEnvSampler;
uniform samplerCube u_GGXEnvSampler;
uniform sampler2D u_GGXLUT;
uniform samplerCube u_CharlieEnvSampler;
uniform sampler2D u_CharlieLUT;
uniform sampler2D u_SheenELUT;
uniform mat3 u_EnvRotation;

// General Material


uniform sampler2D u_NormalSampler;
uniform float u_NormalScale;
uniform int u_NormalUVSet;
uniform mat3 u_NormalUVTransform;
uniform vec3 u_EmissiveFactor;
uniform sampler2D u_EmissiveSampler;
uniform int u_EmissiveUVSet;
uniform mat3 u_EmissiveUVTransform;
uniform sampler2D u_OcclusionSampler;
uniform int u_OcclusionUVSet;
uniform float u_OcclusionStrength;
uniform mat3 u_OcclusionUVTransform;
in vec2 v_texcoord_0;
in vec2 v_texcoord_1;
vec2 getNormalUV() {
    vec3 uv = vec3(u_NormalUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
    #ifdef HAS_NORMAL_UV_TRANSFORM
        uv = u_NormalUVTransform * uv;
    #endif
    
    return uv.xy;
}
vec2 getEmissiveUV() {
    vec3 uv = vec3(u_EmissiveUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
    #ifdef HAS_EMISSIVE_UV_TRANSFORM
        uv = u_EmissiveUVTransform * uv;
    #endif
    
    return uv.xy;
}
vec2 getOcclusionUV() {
    vec3 uv = vec3(u_OcclusionUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
    #ifdef HAS_OCCLUSION_UV_TRANSFORM
        uv = u_OcclusionUVTransform * uv;
    #endif
    
    return uv.xy;
}
// Metallic Roughness Material

#ifdef MATERIAL_METALLICROUGHNESS
    
    uniform sampler2D u_BaseColorSampler;
    uniform int u_BaseColorUVSet;
    uniform mat3 u_BaseColorUVTransform;
    uniform sampler2D u_MetallicRoughnessSampler;
    uniform int u_MetallicRoughnessUVSet;
    uniform mat3 u_MetallicRoughnessUVTransform;
    vec2 getBaseColorUV() {
        vec3 uv = vec3(u_BaseColorUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_BASECOLOR_UV_TRANSFORM
            uv = u_BaseColorUVTransform * uv;
        #endif
        
        return uv.xy;
    }
    vec2 getMetallicRoughnessUV() {
        vec3 uv = vec3(u_MetallicRoughnessUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_METALLICROUGHNESS_UV_TRANSFORM
            uv = u_MetallicRoughnessUVTransform * uv;
        #endif
        
        return uv.xy;
    }
#endif

// Specular Glossiness Material

#ifdef MATERIAL_SPECULARGLOSSINESS
    
    uniform sampler2D u_DiffuseSampler;
    uniform int u_DiffuseUVSet;
    uniform mat3 u_DiffuseUVTransform;
    uniform sampler2D u_SpecularGlossinessSampler;
    uniform int u_SpecularGlossinessUVSet;
    uniform mat3 u_SpecularGlossinessUVTransform;
    vec2 getSpecularGlossinessUV() {
        vec3 uv = vec3(u_SpecularGlossinessUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_SPECULARGLOSSINESS_UV_TRANSFORM
            uv = u_SpecularGlossinessUVTransform * uv;
        #endif
        
        return uv.xy;
    }
    vec2 getDiffuseUV() {
        vec3 uv = vec3(u_DiffuseUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_DIFFUSE_UV_TRANSFORM
            uv = u_DiffuseUVTransform * uv;
        #endif
        
        return uv.xy;
    }
#endif

// Clearcoat Material

#ifdef MATERIAL_CLEARCOAT
    
    uniform sampler2D u_ClearcoatSampler;
    uniform int u_ClearcoatUVSet;
    uniform mat3 u_ClearcoatUVTransform;
    uniform sampler2D u_ClearcoatRoughnessSampler;
    uniform int u_ClearcoatRoughnessUVSet;
    uniform mat3 u_ClearcoatRoughnessUVTransform;
    uniform sampler2D u_ClearcoatNormalSampler;
    uniform int u_ClearcoatNormalUVSet;
    uniform mat3 u_ClearcoatNormalUVTransform;
    uniform float u_ClearcoatNormalScale;
    vec2 getClearcoatUV() {
        vec3 uv = vec3(u_ClearcoatUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_CLEARCOAT_UV_TRANSFORM
            uv = u_ClearcoatUVTransform * uv;
        #endif
        return uv.xy;
    }
    vec2 getClearcoatRoughnessUV() {
        vec3 uv = vec3(u_ClearcoatRoughnessUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_CLEARCOATROUGHNESS_UV_TRANSFORM
            uv = u_ClearcoatRoughnessUVTransform * uv;
        #endif
        return uv.xy;
    }
    vec2 getClearcoatNormalUV() {
        vec3 uv = vec3(u_ClearcoatNormalUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_CLEARCOATNORMAL_UV_TRANSFORM
            uv = u_ClearcoatNormalUVTransform * uv;
        #endif
        return uv.xy;
    }
#endif

// Sheen Material

#ifdef MATERIAL_SHEEN
    
    uniform sampler2D u_SheenColorSampler;
    uniform int u_SheenColorUVSet;
    uniform mat3 u_SheenColorUVTransform;
    uniform sampler2D u_SheenRoughnessSampler;
    uniform int u_SheenRoughnessUVSet;
    uniform mat3 u_SheenRoughnessUVTransform;
    vec2 getSheenColorUV() {
        vec3 uv = vec3(u_SheenColorUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_SHEENCOLOR_UV_TRANSFORM
            uv = u_SheenColorUVTransform * uv;
        #endif
        return uv.xy;
    }
    vec2 getSheenRoughnessUV() {
        vec3 uv = vec3(u_SheenRoughnessUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_SHEENROUGHNESS_UV_TRANSFORM
            uv = u_SheenRoughnessUVTransform * uv;
        #endif
        return uv.xy;
    }
#endif

// Specular Material

#ifdef MATERIAL_SPECULAR
    
    uniform sampler2D u_SpecularSampler;
    uniform int u_SpecularUVSet;
    uniform mat3 u_SpecularUVTransform;
    uniform sampler2D u_SpecularColorSampler;
    uniform int u_SpecularColorUVSet;
    uniform mat3 u_SpecularColorUVTransform;
    vec2 getSpecularUV() {
        vec3 uv = vec3(u_SpecularUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_SPECULAR_UV_TRANSFORM
            uv = u_SpecularUVTransform * uv;
        #endif
        return uv.xy;
    }
    vec2 getSpecularColorUV() {
        vec3 uv = vec3(u_SpecularColorUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_SPECULARCOLOR_UV_TRANSFORM
            uv = u_SpecularColorUVTransform * uv;
        #endif
        return uv.xy;
    }
#endif

// Transmission Material

#ifdef MATERIAL_TRANSMISSION
    
    uniform sampler2D u_TransmissionSampler;
    uniform int u_TransmissionUVSet;
    uniform mat3 u_TransmissionUVTransform;
    uniform sampler2D u_TransmissionFramebufferSampler;
    uniform ivec2 u_TransmissionFramebufferSize;
    vec2 getTransmissionUV() {
        vec3 uv = vec3(u_TransmissionUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_TRANSMISSION_UV_TRANSFORM
            uv = u_TransmissionUVTransform * uv;
        #endif
        return uv.xy;
    }
#endif

// Volume Material

#ifdef MATERIAL_VOLUME
    
    uniform sampler2D u_ThicknessSampler;
    uniform int u_ThicknessUVSet;
    uniform mat3 u_ThicknessUVTransform;
    vec2 getThicknessUV() {
        vec3 uv = vec3(u_ThicknessUVSet < 1 ? v_texcoord_0 : v_texcoord_1, 1.0);
        #ifdef HAS_THICKNESS_UV_TRANSFORM
            uv = u_ThicknessUVTransform * uv;
        #endif
        return uv.xy;
    }
#endif

#define GLSLIFY 1
const float M_PI = 3.141592653589793;
in vec3 v_Position;
#ifdef HAS_NORMAL_VEC3
    #ifdef HAS_TANGENT_VEC4
        in mat3 v_TBN;
    #else
        in vec3 v_Normal;
    #endif
#endif

#ifdef HAS_COLOR_0_VEC3
    in vec3 v_Color;
#endif
#ifdef HAS_COLOR_0_VEC4
    in vec4 v_Color;
#endif

vec4 getVertexColor() {
    vec4 color = vec4(1.0);
    #ifdef HAS_COLOR_0_VEC3
        color.rgb = v_Color.rgb;
    #endif
    #ifdef HAS_COLOR_0_VEC4
        color = v_Color;
    #endif
    
    return color;
}
struct NormalInfo {
    vec3 ng;   // Geometric normal
    
    vec3 n;    // Pertubed normal
    
    vec3 t;    // Pertubed tangent
    
    vec3 b;    // Pertubed bitangent
};
float clampedDot(vec3 x, vec3 y) {
    return clamp(dot(x, y), 0.0.1.0);
}
float max3(vec3 v) {
    return max(max(v.x, v.y), v.z);
}
float applyIorToRoughness(float roughness, float ior) {
    // Scale Roughness evaluation with IOR so that an IOR of 1.0 results in no microfacet refraction and
    // an IOR of 1.5 results in the default amount of microfacet refraction.
    return roughness * clamp(ior * 2.0 - 2.0.0.0.1.0);
}
#define GLSLIFY 1
//
// Fresnel
//
// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
// https://github.com/wdas/brdf/tree/master/src/brdfs
// https://google.github.io/filament/Filament.md.html
//

// The following equation models the Fresnel reflectance term of the spec equation (aka F())
// Implementation of fresnel from [4], Equation 15
vec3 F_Schlick(vec3 f0, vec3 f90, float VdotH) {
    return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0.1.0), 5.0);
}
// Smith Joint GGX
// Note: Vis = G / (4 * NdotL * NdotV)
// see Eric Heitz. 2014. Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs. Journal of Computer Graphics Techniques, 3
// see Real-Time Rendering. Page 331 to 336.
// see https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf/geometricshadowing(specularg)
float V_GGX(float NdotL, float NdotV, float alphaRoughness) {
    float alphaRoughnessSq = alphaRoughness * alphaRoughness;
    float GGXV = NdotL * sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);
    float GGXL = NdotV * sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);
    float GGX = GGXV + GGXL;
    if (GGX > 0.0) {
        return 0.5 / GGX;
    }
    return 0.0;
}
// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D())
// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz
// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3.
float D_GGX(float NdotH, float alphaRoughness) {
    float alphaRoughnessSq = alphaRoughness * alphaRoughness;
    float f = (NdotH * NdotH) * (alphaRoughnessSq - 1.0) + 1.0;
    return alphaRoughnessSq / (M_PI * f * f);
}
float lambdaSheenNumericHelper(float x, float alphaG) {
    float oneMinusAlphaSq = (1.0 - alphaG) * (1.0 - alphaG);
    float a = mix(21.5473.25.3245, oneMinusAlphaSq);
    float b = mix(3.82987.3.32435, oneMinusAlphaSq);
    float c = mix(0.19823.0.16801, oneMinusAlphaSq);
    float d = mix(1.97760.1.27393, oneMinusAlphaSq);
    float e = mix(4.32054.4.85967, oneMinusAlphaSq);
    return a / (1.0 + b * pow(x, c)) + d * x + e;
}
float lambdaSheen(float cosTheta, float alphaG) {
    if (abs(cosTheta) < 0.5) {
        return exp(lambdaSheenNumericHelper(cosTheta, alphaG));
    }
    else {
        return exp(2.0 * lambdaSheenNumericHelper(0.5, alphaG) - lambdaSheenNumericHelper(1.0- cosTheta, alphaG)); }}float V_Sheen(float NdotL, float NdotV, float sheenRoughness) {
    sheenRoughness = max(sheenRoughness, 0.000001); //clamp (0, 1]
    
    float alphaG = sheenRoughness * sheenRoughness;
    return clamp(1.0 / ((1.0 + lambdaSheen(NdotV, alphaG) + lambdaSheen(NdotL, alphaG)) *
    (4.0 * NdotV * NdotL)), 0.0.1.0);
}
//Sheen implementation-------------------------------------------------------------------------------------
// See  https://github.com/sebavan/glTF/tree/KHR_materials_sheen/extensions/2.0/Khronos/KHR_materials_sheen

// Estevez and Kulla http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
float D_Charlie(float sheenRoughness, float NdotH) {
    sheenRoughness = max(sheenRoughness, 0.000001); //clamp (0, 1]
    
    float alphaG = sheenRoughness * sheenRoughness;
    float invR = 1.0 / alphaG;
    float cos2h = NdotH * NdotH;
    float sin2h = 1.0 - cos2h;
    return (2.0 + invR) * pow(sin2h, invR * 0.5)/(2.0 * M_PI);
}
/ / https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
vec3 BRDF_lambertian(vec3 f0, vec3 f90, vec3 diffuseColor, float specularWeight, float VdotH) {
    // see https://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
    return (1.0 - specularWeight * F_Schlick(f0, f90, VdotH)) * (diffuseColor / M_PI);
}
//  https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
vec3 BRDF_specularGGX(vec3 f0, vec3 f90, float alphaRoughness, float specularWeight, float VdotH, float NdotL, float NdotV, float NdotH) {
    vec3 F = F_Schlick(f0, f90, VdotH);
    float Vis = V_GGX(NdotL, NdotV, alphaRoughness);
    float D = D_GGX(NdotH, alphaRoughness);
    return specularWeight * F * Vis * D;
}
// f_sheen
vec3 BRDF_specularSheen(vec3 sheenColor, float sheenRoughness, float NdotL, float NdotV, float NdotH) {
    float sheenDistribution = D_Charlie(sheenRoughness, NdotH);
    float sheenVisibility = V_Sheen(NdotL, NdotV, sheenRoughness);
    return sheenColor * sheenDistribution * sheenVisibility;
}
#define GLSLIFY 1
// KHR_lights_punctual extension.
/ / see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
struct Light {
    vec3 direction;
    float range;
    vec3 color;
    float intensity;
    vec3 position;
    float innerConeCos;
    float outerConeCos;
    int type;
};
const int LightType_Directional = 0;
const int LightType_Point = 1;
const int LightType_Spot = 2;
#ifdef USE_PUNCTUAL
    uniform Light u_Lights[LIGHT_COUNT + 1]; //Array [0] is not allowed
    
#endif

/ / https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_lights_punctual/README.md#range-property
float getRangeAttenuation(float range, float distance) {
    if (range <= 0.0) {
        // negative range means unlimited
        return 1.0 / pow(distance.2.0);
    }
    return max(min(1.0 - pow(distance / range, 4.0), 1.0), 0.0) / pow(distance.2.0);
}
// https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_lights_punctual/README.md#inner-and-outer-co ne-angles
float getSpotAttenuation(vec3 pointToLight, vec3 spotDirection, float outerConeCos, float innerConeCos) {
    float actualCos = dot(normalize(spotDirection), normalize(-pointToLight));
    if (actualCos > outerConeCos) {
        if (actualCos < innerConeCos) {
            return smoothstep(outerConeCos, innerConeCos, actualCos);
        }
        return 1.0;
    }
    return 0.0;
}
vec3 getLighIntensity(Light light, vec3 pointToLight) {
    float rangeAttenuation = 1.0;
    float spotAttenuation = 1.0;
    if (light.type ! = LightType_Directional) {
        rangeAttenuation = getRangeAttenuation(light.range, length(pointToLight));
    }
    if (light.type == LightType_Spot) {
        spotAttenuation = getSpotAttenuation(pointToLight, light.direction, light.outerConeCos, light.innerConeCos);
    }
    return rangeAttenuation * spotAttenuation * light.intensity * light.color;
}
vec3 getPunctualRadianceTransmission(vec3 normal, vec3 view, vec3 pointToLight, float alphaRoughness, vec3 f0, vec3 f90, vec3 baseColor, float ior) {
    float transmissionRougness = applyIorToRoughness(alphaRoughness, ior);
    vec3 n = normalize(normal);           // Outward direction of surface point
    
    vec3 v = normalize(view);             // Direction from surface point to view
    
    vec3 l = normalize(pointToLight);
    vec3 l_mirror = normalize(l + 2.0*n*dot(-l, n));     // Mirror light reflection vector on surface
    
    vec3 h = normalize(l_mirror + v);            // Halfway vector between transmission light vector and v
    
    
    float D = D_GGX(clamp(dot(n, h), 0.0.1.0), transmissionRougness);
    vec3 F = F_Schlick(f0, f90, clamp(dot(v, h), 0.0.1.0));
    float Vis = V_GGX(clamp(dot(n, l_mirror), 0.0.1.0), clamp(dot(n, v), 0.0.1.0), transmissionRougness);
    
    // Transmission BTDF
    
    return (1.0 - F) * baseColor * D * Vis;
}
vec3 getPunctualRadianceClearCoat(vec3 clearcoatNormal, vec3 v, vec3 l, vec3 h, float VdotH, vec3 f0, vec3 f90, float clearcoatRoughness) {
    float NdotL = clampedDot(clearcoatNormal, l);
    float NdotV = clampedDot(clearcoatNormal, v);
    float NdotH = clampedDot(clearcoatNormal, h);
    return NdotL * BRDF_specularGGX(f0, f90, clearcoatRoughness * clearcoatRoughness, 1.0, VdotH, NdotL, NdotV, NdotH);
}
vec3 getPunctualRadianceSheen(vec3 sheenColor, float sheenRoughness, float NdotL, float NdotV, float NdotH) {
    return NdotL * BRDF_specularSheen(sheenColor, sheenRoughness, NdotL, NdotV, NdotH);
}
// Compute attenuated light as it travels through a volume.
vec3 applyVolumeAttenuation(vec3 radiance, float transmissionDistance, vec3 attenuationColor, float attenuationDistance) {
    if (attenuationDistance == 0.0) {
        // Anxious distance is +∞ (which we indicate by zero), i.e. the color is not attenuated at all.
        return radiance;
    }
    else {
        // Compute light attenuation using Beer's law.
        vec3 attenuationCoefficient = -log(attenuationColor) / attenuationDistance;
        vec3 transmittance = exp(-attenuationCoefficient * transmissionDistance); // Beer's law
        
        returntransmittance * radiance; }}vec3 getVolumeTransmissionRay(vec3 n, vec3 v, float thickness, float ior, mat4 modelMatrix) {
    // Direction of refracted light.
    vec3 refractionVector = refract(-v, normalize(n), 1.0 / ior);
    
    // Compute rotation-independant scaling of the model matrix.
    
    vec3 modelScale;
    modelScale.x = length(vec3(modelMatrix[0].xyz));
    modelScale.y = length(vec3(modelMatrix[1].xyz));
    modelScale.z = length(vec3(modelMatrix[2].xyz));
    
    // The thickness is specified in local space.
    
    return normalize(refractionVector) * thickness * modelScale;
}
#define GLSLIFY 1
vec3 getDiffuseLight(vec3 n) {
    return texture(u_LambertianEnvSampler, u_EnvRotation * n).rgb;
}
vec4 getSpecularSample(vec3 reflection, float lod) {
    return textureLod(u_GGXEnvSampler, u_EnvRotation * reflection, lod);
}
vec4 getSheenSample(vec3 reflection, float lod) {
    return textureLod(u_CharlieEnvSampler, u_EnvRotation * reflection, lod);
}
vec3 getIBLRadianceGGX(vec3 n, vec3 v, float roughness, vec3 F0, float specularWeight) {
    float NdotV = clampedDot(n, v);
    float lod = roughness * float(u_MipCount - 1);
    vec3 reflection = normalize(reflect(-v, n));
    vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0.0.0), vec2(1.0.1.0));
    vec2 f_ab = texture(u_GGXLUT, brdfSamplePoint).rg;
    vec4 specularSample = getSpecularSample(reflection, lod);
    vec3 specularLight = specularSample.rgb;
    
    // see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
    
    // Roughness dependent fresnel, from Fdez-Aguera
    vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
    vec3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
    vec3 FssEss = k_S * f_ab.x + f_ab.y;
    return specularWeight * specularLight * FssEss;
}
#ifdef MATERIAL_TRANSMISSION
    vec3 getTransmissionSample(vec2 fragCoord, float roughness, float ior) {
        float framebufferLod = log2(float(u_TransmissionFramebufferSize.x)) * applyIorToRoughness(roughness, ior);
        vec3 transmittedLight = textureLod(u_TransmissionFramebufferSampler, fragCoord.xy, framebufferLod).rgb;
        return transmittedLight;
    }
#endif

#ifdef MATERIAL_TRANSMISSION
    vec3 getIBLVolumeRefraction(vec3 n, vec3 v, float perceptualRoughness, vec3 baseColor, vec3 f0, vec3 f90, vec3 position, mat4 modelMatrix, mat4 viewMatrix, mat4 projMatrix, float ior, float thickness, vec3 attenuationColor, float attenuationDistance) {
        vec3 transmissionRay = getVolumeTransmissionRay(n, v, thickness, ior, modelMatrix);
        vec3 refractedRayExit = position + transmissionRay;
        
        // Project refracted vector on the framebuffer, while mapping to normalized device coordinates.
        
        vec4 ndcPos = projMatrix * viewMatrix * vec4(refractedRayExit, 1.0);
        vec2 refractionCoords = ndcPos.xy / ndcPos.w;
        refractionCoords += 1.0;
        refractionCoords /= 2.0;
        
        // Sample framebuffer to get pixel the refracted ray hits.
        
        vec3 transmittedLight = getTransmissionSample(refractionCoords, perceptualRoughness, ior);
        vec3 attenuatedColor = applyVolumeAttenuation(transmittedLight, length(transmissionRay), attenuationColor, attenuationDistance);
        
        // Sample GGX LUT to get the specular component.
        
        float NdotV = clampedDot(n, v);
        vec2 brdfSamplePoint = clamp(vec2(NdotV, perceptualRoughness), vec2(0.0.0.0), vec2(1.0.1.0));
        vec2 brdf = texture(u_GGXLUT, brdfSamplePoint).rg;
        vec3 specularColor = f0 * brdf.x + f90 * brdf.y;
        return (1.0 - specularColor) * attenuatedColor * baseColor;
    }
#endif

// specularWeight is introduced with KHR_materials_specular
vec3 getIBLRadianceLambertian(vec3 n, vec3 v, float roughness, vec3 diffuseColor, vec3 F0, float specularWeight) {
    float NdotV = clampedDot(n, v);
    vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0.0.0), vec2(1.0.1.0));
    vec2 f_ab = texture(u_GGXLUT, brdfSamplePoint).rg;
    vec3 irradiance = getDiffuseLight(n);
    
    // see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
    
    // Roughness dependent fresnel, from Fdez-Aguera
    
    vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
    vec3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
    vec3 FssEss = specularWeight * k_S * f_ab.x + f_ab.y; // <--- GGX / specular light contribution (scale it down if the specularWeight is low)
    
    
    // Multiple scattering, from Fdez-Aguera
    float Ems = (1.0 - (f_ab.x + f_ab.y));
    vec3 F_avg = specularWeight * (F0 + (1.0 - F0) / 21.0);
    vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems);
    vec3 k_D = diffuseColor * (1.0 - FssEss + FmsEms); // we use +FmsEms as indicated by the formula in the blog post (might be a typo in the implementation)
    
    
    return (FmsEms + k_D) * irradiance;
}
vec3 getIBLRadianceCharlie(vec3 n, vec3 v, float sheenRoughness, vec3 sheenColor) {
    float NdotV = clampedDot(n, v);
    float lod = sheenRoughness * float(u_MipCount - 1);
    vec3 reflection = normalize(reflect(-v, n));
    vec2 brdfSamplePoint = clamp(vec2(NdotV, sheenRoughness), vec2(0.0.0.0), vec2(1.0.1.0));
    float brdf = texture(u_CharlieLUT, brdfSamplePoint).b;
    vec4 sheenSample = getSheenSample(reflection, lod);
    vec3 sheenLight = sheenSample.rgb;
    return sheenLight * sheenColor * brdf;
}
#define GLSLIFY 1
// Metallic Roughness
uniform float u_MetallicFactor;
uniform float u_RoughnessFactor;
uniform vec4 u_BaseColorFactor;

// Specular Glossiness

uniform vec3 u_SpecularFactor;
uniform vec4 u_DiffuseFactor;
uniform float u_GlossinessFactor;

// Sheen

uniform float u_SheenRoughnessFactor;
uniform vec3 u_SheenColorFactor;

// Clearcoat

uniform float u_ClearcoatFactor;
uniform float u_ClearcoatRoughnessFactor;

// Specular

uniform vec3 u_KHR_materials_specular_specularColorFactor;
uniform float u_KHR_materials_specular_specularFactor;

// Transmission

uniform float u_TransmissionFactor;

// Volume

uniform float u_ThicknessFactor;
uniform vec3 u_AttenuationColor;
uniform float u_AttenuationDistance;

//PBR Next IOR

uniform float u_Ior;

// Alpha mode

uniform float u_AlphaCutoff;
uniform vec3 u_Camera;
#ifdef MATERIAL_TRANSMISSION
    uniform ivec2 u_ScreenSize;
#endif

uniform mat4 u_ModelMatrix;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjectionMatrix;
struct MaterialInfo {
    float ior;
    float perceptualRoughness;      // roughness value, as authored by the model creator (input to shader)
    
    vec3 f0;                        // full reflectance color (n incidence angle)
    
    
    float alphaRoughness;           // roughness mapped to a more linear change in the roughness (proposed by [2])
    
    vec3 c_diff;
    vec3 f90;                       // reflectance color at grazing angle
    
    float metallic;
    vec3 baseColor;
    float sheenRoughnessFactor;
    vec3 sheenColorFactor;
    vec3 clearcoatF0;
    vec3 clearcoatF90;
    float clearcoatFactor;
    vec3 clearcoatNormal;
    float clearcoatRoughness;
    
    // KHR_materials_specular
    
    float specularWeight; // product of specularFactor and specularTexture.a
    
    
    float transmissionFactor;
    float thickness;
    vec3 attenuationColor;
    float attenuationDistance;
};

// Get normal, tangent and bitangent vectors.

NormalInfo getNormalInfo(vec3 v) {
    vec2 UV = getNormalUV();
    vec3 uv_dx = dFdx(vec3(UV, 0.0));
    vec3 uv_dy = dFdy(vec3(UV, 0.0));
    vec3 t_ = (uv_dy.t * dFdx(v_Position) - uv_dx.t * dFdy(v_Position)) /
    (uv_dx.s * uv_dy.t - uv_dy.s * uv_dx.t);
    vec3 n, t, b, ng;
    
    // Compute geometrical TBN:
    
    #ifdef HAS_TANGENT_VEC4
        // Trivial TBN computation, present as vertex attribute.
        // Normalize eigenvectors as matrix is linearly interpolated.
        t = normalize(v_TBN[0]);
        b = normalize(v_TBN[1]);
        ng = normalize(v_TBN[2]);
    #else
        // Normals are either present as vertex attributes or approximated.
        #ifdef HAS_NORMAL_VEC3
            ng = normalize(v_Normal);
        #else
            ng = normalize(cross(dFdx(v_Position), dFdy(v_Position)));
        #endif
        t = normalize(t_ - ng * dot(ng, t_));
        b = cross(ng, t);
    #endif
    
    // For a back-facing surface, the tangential basis vectors are negated.
    if (gl_FrontFacing= =false) {
        t *= 1.0;
        b *= 1.0;
        ng *= 1.0;
    }
    // Compute pertubed normals:
    #ifdef HAS_NORMAL_MAP
        n = texture(u_NormalSampler, UV).rgb * 2.0 - vec3(1.0);
        n *= vec3(u_NormalScale, u_NormalScale, 1.0);
        n = mat3(t, b, ng) * normalize(n);
    #else
        n = ng;
    #endif
    
    NormalInfo info;
    info.ng = ng;
    info.t = t;
    info.b = b;
    info.n = n;
    return info;
}
vec3 getClearcoatNormal(NormalInfo normalInfo) {
    #ifdef HAS_CLEARCOAT_NORMAL_MAP
        vec3 n = texture(u_ClearcoatNormalSampler, getClearcoatNormalUV()).rgb * 2.0 - vec3(1.0);
        n *= vec3(u_ClearcoatNormalScale, u_ClearcoatNormalScale, 1.0);
        n = mat3(normalInfo.t, normalInfo.b, normalInfo.ng) * normalize(n);
        return n;
    #else
        return normalInfo.ng;
    #endif
}
vec4 getBaseColor() {
    vec4 baseColor = vec4(1);
    #if defined(MATERIAL_SPECULARGLOSSINESS)
        baseColor = u_DiffuseFactor;
        #elif defined(MATERIAL_METALLICROUGHNESS)
        baseColor = u_BaseColorFactor;
    #endif
    
    #if defined(MATERIAL_SPECULARGLOSSINESS) && defined(HAS_DIFFUSE_MAP)
        baseColor *= texture(u_DiffuseSampler, getDiffuseUV());
        #elif defined(MATERIAL_METALLICROUGHNESS) && defined(HAS_BASE_COLOR_MAP)
        baseColor *= texture(u_BaseColorSampler, getBaseColorUV());
    #endif
    
    return baseColor * getVertexColor();
}
#ifdef MATERIAL_SPECULARGLOSSINESS
    MaterialInfo getSpecularGlossinessInfo(MaterialInfo info) {
        info.f0 = u_SpecularFactor;
        info.perceptualRoughness = u_GlossinessFactor;
        #ifdef HAS_SPECULAR_GLOSSINESS_MAP
            vec4 sgSample = texture(u_SpecularGlossinessSampler, getSpecularGlossinessUV());
            info.perceptualRoughness *= sgSample.a ; // glossiness to roughness
            
            info.f0 *= sgSample.rgb; // specular
            
        #endif // ! HAS_SPECULAR_GLOSSINESS_MAP
        
        info.perceptualRoughness = 1.0 - info.perceptualRoughness; // 1 - glossiness
        
        info.c_diff = info.baseColor.rgb * (1.0 - max(max(info.f0.r, info.f0.g), info.f0.b));
        return info;
    }
#endif

#ifdef MATERIAL_METALLICROUGHNESS
    MaterialInfo getMetallicRoughnessInfo(MaterialInfo info) {
        info.metallic = u_MetallicFactor;
        info.perceptualRoughness = u_RoughnessFactor;
        #ifdef HAS_METALLIC_ROUGHNESS_MAP
            // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
            // This layout intentionally reserves the 'r' channel for (optional) occlusion map data
            vec4 mrSample = texture(u_MetallicRoughnessSampler, getMetallicRoughnessUV());
            info.perceptualRoughness *= mrSample.g;
            info.metallic *= mrSample.b;
        #endif
        
        // Achromatic f0 based on IOR.
        info.c_diff = mix(info.baseColor.rgb * (vec3(1.0) - info.f0), vec3(0), info.metallic);
        info.f0 = mix(info.f0, info.baseColor.rgb, info.metallic);
        return info;
    }
#endif

#ifdef MATERIAL_SHEEN
    MaterialInfo getSheenInfo(MaterialInfo info) {
        info.sheenColorFactor = u_SheenColorFactor;
        info.sheenRoughnessFactor = u_SheenRoughnessFactor;
        #ifdef HAS_SHEEN_COLOR_MAP
            vec4 sheenColorSample = texture(u_SheenColorSampler, getSheenColorUV());
            info.sheenColorFactor *= sheenColorSample.rgb;
        #endif
        
        #ifdef HAS_SHEEN_ROUGHNESS_MAP
            vec4 sheenRoughnessSample = texture(u_SheenRoughnessSampler, getSheenRoughnessUV());
            info.sheenRoughnessFactor *= sheenRoughnessSample.a;
        #endif
        return info;
    }
#endif

#ifdef MATERIAL_SPECULAR
    MaterialInfo getSpecularInfo(MaterialInfo info) {
        vec4 specularTexture = vec4(1.0);
        #ifdef HAS_SPECULAR_MAP
            specularTexture.a = texture(u_SpecularSampler, getSpecularColorUV()).a;
        #endif
        #ifdef HAS_SPECULAR_COLOR_MAP
            specularTexture.rgb = texture(u_SpecularColorSampler, getSpecularUV()).rgb;
        #endif
        
        vec3 dielectricSpecularF0 = min(info.f0 * u_KHR_materials_specular_specularColorFactor * specularTexture.rgb, vec3(1.0));
        info.f0 = mix(dielectricSpecularF0, info.baseColor.rgb, info.metallic);
        info.specularWeight = u_KHR_materials_specular_specularFactor * specularTexture.a;
        info.c_diff = mix(info.baseColor.rgb * (1.0 - max3(dielectricSpecularF0)), vec3(0), info.metallic);
        return info;
    }
#endif

#ifdef MATERIAL_TRANSMISSION
    MaterialInfo getTransmissionInfo(MaterialInfo info) {
        info.transmissionFactor = u_TransmissionFactor;
        #ifdef HAS_TRANSMISSION_MAP
            vec4 transmissionSample = texture(u_TransmissionSampler, getTransmissionUV());
            info.transmissionFactor *= transmissionSample.r;
        #endif
        return info;
    }
#endif

#ifdef MATERIAL_VOLUME
    MaterialInfo getVolumeInfo(MaterialInfo info) {
        info.thickness = u_ThicknessFactor;
        info.attenuationColor = u_AttenuationColor;
        info.attenuationDistance = u_AttenuationDistance;
        #ifdef HAS_THICKNESS_MAP
            vec4 thicknessSample = texture(u_ThicknessSampler, getThicknessUV());
            info.thickness *= thicknessSample.g;
        #endif
        return info;
    }
#endif

#ifdef MATERIAL_CLEARCOAT
    MaterialInfo getClearCoatInfo(MaterialInfo info, NormalInfo normalInfo) {
        info.clearcoatFactor = u_ClearcoatFactor;
        info.clearcoatRoughness = u_ClearcoatRoughnessFactor;
        info.clearcoatF0 = vec3(info.f0);
        info.clearcoatF90 = vec3(1.0);
        #ifdef HAS_CLEARCOAT_MAP
            vec4 clearcoatSample = texture(u_ClearcoatSampler, getClearcoatUV());
            info.clearcoatFactor *= clearcoatSample.r;
        #endif
        
        #ifdef HAS_CLEARCOAT_ROUGHNESS_MAP
            vec4 clearcoatSampleRoughness = texture(u_ClearcoatRoughnessSampler, getClearcoatRoughnessUV());
            info.clearcoatRoughness *= clearcoatSampleRoughness.g;
        #endif
        
        info.clearcoatNormal = getClearcoatNormal(normalInfo);
        info.clearcoatRoughness = clamp(info.clearcoatRoughness, 0.0.1.0);
        return info;
    }
#endif

#ifdef MATERIAL_IOR
    MaterialInfo getIorInfo(MaterialInfo info) {
        info.f0 = vec3(pow(( u_Ior - 1.0) /  (u_Ior + 1.0), 2.0));
        info.ior = u_Ior;
        return info;
    }
#endif

float albedoSheenScalingLUT(float NdotV, float sheenRoughnessFactor) {
    return texture(u_SheenELUT, vec2(NdotV, sheenRoughnessFactor)).r;
}
out vec4 g_finalColor;
Copy the code