- 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