From aacdaef48a831620aaa3340fa8c22624db593924 Mon Sep 17 00:00:00 2001 From: Yuki Shimada Date: Sat, 2 Sep 2023 05:15:43 +0900 Subject: [PATCH 1/3] refactor: glTF PBR shader code --- .../PbrSingleShader/PbrSingleShader.frag | 91 +---- .../common/pbrDefinition.glsl | 332 +++++++++++++++++- .../common/pbrIridescence.glsl | 124 ------- .../shaderity_shaders/common/pbrSheen.glsl | 41 --- 4 files changed, 332 insertions(+), 256 deletions(-) delete mode 100644 src/webgl/shaderity_shaders/common/pbrIridescence.glsl delete mode 100644 src/webgl/shaderity_shaders/common/pbrSheen.glsl diff --git a/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag b/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag index c87bc0266..72198202a 100644 --- a/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag +++ b/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag @@ -112,21 +112,15 @@ uniform float u_alphaCutoff; // initialValue=(0.01) #pragma shaderity: require(../common/rt0.glsl) -#pragma shaderity: require(../common/pbrDefinition.glsl) -#ifdef RN_USE_SHEEN - #pragma shaderity: require(../common/pbrSheen.glsl) -#endif -#ifdef RN_USE_IRIDESCENCE - #pragma shaderity: require(../common/pbrIridescence.glsl) -#endif - /* shaderity: @{getters} */ +#pragma shaderity: require(../common/opticalDefinition.glsl) +#pragma shaderity: require(../common/pbrDefinition.glsl) + /* shaderity: @{matricesGetters} */ #pragma shaderity: require(../common/shadow.glsl) -#pragma shaderity: require(../common/opticalDefinition.glsl) vec3 get_irradiance(vec3 normal_forEnv, float materialSID, ivec2 hdriFormat) { vec4 diffuseTexel = texture(u_diffuseEnvTexture, normal_forEnv); @@ -573,6 +567,7 @@ void main () float TdotV = dot(anisotropicT, viewDirection); #else float anisotropy = 0.0; + vec3 anisotropicT = vec3(0.0, 0.0, 0.0); vec3 anisotropicB = vec3(0.0, 0.0, 0.0); #endif @@ -734,78 +729,12 @@ void main () // Light Light light = getLight(i, v_position_inWorld.xyz); - - // Fresnel - vec3 halfVector = normalize(light.direction + viewDirection); - float VdotH = dot(viewDirection, halfVector); - vec3 F = fresnel(F0, F90, VdotH); - - float NdotL = saturateEpsilonToOne(dot(normal_inWorld, light.direction)); - - // Diffuse - vec3 diffuseBrdf = diffuse_brdf(albedo); - vec3 pureDiffuse = (vec3(1.0) - F) * diffuseBrdf * vec3(NdotL) * light.attenuatedIntensity; - -#ifdef RN_USE_TRANSMISSION - vec3 refractionVector = refract(-viewDirection, normal_inWorld, 1.0 / ior); - Light transmittedLightFromUnderSurface = light; - transmittedLightFromUnderSurface.pointToLight -= refractionVector; - vec3 transmittedLightDirectionFromUnderSurface = normalize(transmittedLightFromUnderSurface.pointToLight); - transmittedLightFromUnderSurface.direction = transmittedLightDirectionFromUnderSurface; - - vec3 Ht = normalize(viewDirection + transmittedLightFromUnderSurface.direction); - float NdotHt = saturateEpsilonToOne(dot(normal_inWorld, Ht)); - float NdotLt = saturateEpsilonToOne(dot(normal_inWorld, transmittedLightFromUnderSurface.direction)); - - vec3 transmittedContrib = (vec3(1.0) - F) * specular_btdf(alphaRoughness, NdotLt, NdotV, NdotHt) * albedo * transmittedLightFromUnderSurface.attenuatedIntensity; - -#ifdef RN_USE_VOLUME - vec3 attenuationColor = get_attenuationColor(materialSID, 0); - float attenuationDistance = get_attenuationDistance(materialSID, 0); - transmittedContrib = volumeAttenuation(attenuationColor, attenuationDistance, transmittedContrib, length(transmittedLightFromUnderSurface.pointToLight)); -#endif // RN_USE_VOLUME - - vec3 diffuseContrib = mix(pureDiffuse, vec3(transmittedContrib), transmission); -#else - vec3 diffuseContrib = pureDiffuse; -#endif // RN_USE_TRANSMISSION - - // Specular - float NdotH = saturateEpsilonToOne(dot(normal_inWorld, halfVector)); -#ifdef RN_USE_ANISOTROPY - float TdotL = dot(anisotropicT, light.direction); - float BdotL = dot(anisotropicB, light.direction); - float TdotH = dot(anisotropicT, halfVector); - float BdotH = dot(anisotropicB, halfVector); - vec3 specularContrib = BRDF_specularAnisotropicGGX(F, alphaRoughness, VdotH, NdotL, NdotV, NdotH, BdotV, TdotV, TdotL, BdotL, TdotH, BdotH, anisotropy) * vec3(NdotL) * light.attenuatedIntensity; -#else - vec3 specularContrib = cook_torrance_specular_brdf(NdotH, NdotL, NdotV, F, alphaRoughness) * vec3(NdotL) * light.attenuatedIntensity; -#endif // RN_USE_ANISOTROPY - // Base Layer - vec3 baseLayer = diffuseContrib + specularContrib; - -#ifdef RN_USE_SHEEN - // Sheen - vec3 sheenContrib = sheen_brdf(sheenColor, sheenRoughness, NdotL, NdotV, NdotH) * NdotL * light.attenuatedIntensity; - float albedoSheenScaling = min( - albedoSheenScalingNdotV, - 1.0 - max3(sheenColor) * texture(u_sheenLutTexture, vec2(NdotL, sheenRoughness)).r); - vec3 color = sheenContrib + baseLayer * albedoSheenScaling; -#else - vec3 color = baseLayer; - float albedoSheenScaling = 1.0; -#endif // RN_USE_SHEEN - -#ifdef RN_USE_CLEARCOAT - // Clear Coat Layer - float NdotHc = saturateEpsilonToOne(dot(clearcoatNormal_inWorld, halfVector)); - float LdotNc = saturateEpsilonToOne(dot(light.direction, clearcoatNormal_inWorld)); - vec3 coated = coated_material_s(color, perceptualRoughness, - clearcoatRoughness, clearcoat, VdotNc, LdotNc, NdotHc); - rt0.xyz += coated; -#else - rt0.xyz += color; -#endif // RN_USE_CLEARCOAT + rt0.xyz += gltfBRDF(light, normal_inWorld, viewDirection, NdotV, albedo, + perceptualRoughness, metallic, F0, F90, ior, transmission, + clearcoat, clearcoatRoughness, clearcoatNormal_inWorld, VdotNc, + attenuationColor, attenuationDistance, + anisotropy, anisotropicT, anisotropicB, + sheenColor, sheenRoughness, albedoSheenScalingNdotV); } #ifdef RN_USE_SHADOW_MAPPING diff --git a/src/webgl/shaderity_shaders/common/pbrDefinition.glsl b/src/webgl/shaderity_shaders/common/pbrDefinition.glsl index 26a4522d4..649e855bb 100644 --- a/src/webgl/shaderity_shaders/common/pbrDefinition.glsl +++ b/src/webgl/shaderity_shaders/common/pbrDefinition.glsl @@ -266,6 +266,23 @@ vec2 uvTransform(vec2 scale, vec2 offset, float rotation, vec2 uv) { return uvTransformed; } +float IsotropicNDFFiltering(vec3 normal, float roughness2) { + float SIGMA2 = 0.15915494; + float KAPPA = 0.18; + vec3 dndu = dFdx(normal); + vec3 dndv = dFdy(normal); + float kernelRoughness2 = SIGMA2 * (dot(dndu, dndu) + dot(dndv, dndv)); + float clampedKernelRoughness2 = min(kernelRoughness2, KAPPA); + float filteredRoughness2 = saturate(roughness2 + clampedKernelRoughness2); + return filteredRoughness2; +} + + +//////////////////////////////////////// +// glTF KHR_materials_volume +//////////////////////////////////////// + +#ifdef RN_USE_VOLUME // https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md#attenuation vec3 volumeAttenuation(vec3 attenuationColor, float attenuationDistance, vec3 intensity, float transmissionDistance) { @@ -277,18 +294,17 @@ vec3 volumeAttenuation(vec3 attenuationColor, float attenuationDistance, vec3 in return intensity * attenuatedTransmittance; } } +#endif + -float IsotropicNDFFiltering(vec3 normal, float roughness2) { - float SIGMA2 = 0.15915494; - float KAPPA = 0.18; - vec3 dndu = dFdx(normal); - vec3 dndv = dFdy(normal); - float kernelRoughness2 = SIGMA2 * (dot(dndu, dndu) + dot(dndv, dndv)); - float clampedKernelRoughness2 = min(kernelRoughness2, KAPPA); - float filteredRoughness2 = saturate(roughness2 + clampedKernelRoughness2); - return filteredRoughness2; -} + + + +//////////////////////////////////////// +// glTF KHR_materials_anisotropy +//////////////////////////////////////// +#ifdef RN_USE_ANISOTROPY // https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_anisotropy float D_GGX_anisotropic(float NdotH, float TdotH, float BdotH, float at, float ab) { @@ -319,3 +335,299 @@ vec3 BRDF_specularAnisotropicGGX(vec3 F, float alphaRoughness, return F * V * D; } +#endif + + + +//////////////////////////////////////// +// glTF KHR_materials_sheen +//////////////////////////////////////// + +#ifdef RN_USE_SHEEN +float d_Charlie(float sheenPerceptualRoughness, float NoH) { + // Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF" + float alphaG = sheenPerceptualRoughness * sheenPerceptualRoughness; + float invAlpha = 1.0 / alphaG; + float cos2h = NoH * NoH; + float sin2h = 1.0 - cos2h; + return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI); +} + +// https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_sheen#sheen-visibility +float sheenSimpleVisibility(float NdotL, float NdotV) { + return 1.0 / (4.0 * (NdotL + NdotV - NdotL * NdotV)); +} + +// https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_sheen#sheen-visibility +float charlieL(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) +{ + return abs(cosTheta) < 0.5 ? exp(charlieL(cosTheta, alphaG)) : exp(2.0 * charlieL(0.5, alphaG) - charlieL(1.0 - cosTheta, alphaG)); +} + +float sheenCharlieVisibility(float NdotL, float NdotV, float sheenPerceptualRoughness) { + float alphaG = sheenPerceptualRoughness * sheenPerceptualRoughness; + float sheenVisibility = 1.0 / ((1.0 + lambdaSheen(NdotV, alphaG) + lambdaSheen(NdotL, alphaG)) * (4.0 * NdotV * NdotL)); + return sheenVisibility; +} + +vec3 sheen_brdf(vec3 sheenColor, float sheenPerceptualRoughness, float NdotL, float NdotV, float NdotH) { + float sheenDistribution = d_Charlie(sheenPerceptualRoughness, NdotH); + float sheenVisibility = sheenCharlieVisibility(NdotL, NdotV, sheenPerceptualRoughness); + return sheenColor * sheenDistribution * sheenVisibility; +} +#endif + + + + + + + + + +//////////////////////////////////////// +// glTF KHR_materials_irirdescence +//////////////////////////////////////// + +#ifdef RN_USE_IRIDESCENCE +// XYZ to REC709(sRGB) conversion matrix +const mat3 XYZ_TO_REC709 = mat3( + 3.2404542, -0.9692660, 0.0556434, + -1.5371385, 1.8760108, -0.2040259, + -0.4985314, 0.0415560, 1.0572252 +); + +// Assume air interface for top +vec3 Fresnel0ToIor(vec3 F0) { + vec3 sqrtF0 = sqrt(F0); + return (vec3(1.0) + sqrtF0) / (vec3(1.0) - sqrtF0); +} + +// Conversion from IOR to F0 +// ior is a value between 1.0 and 3.0. 1.0 is air interface +vec3 IorToFresnel0(vec3 transmittedIor, float incidentIor) { + return sq((transmittedIor - vec3(incidentIor)) / (transmittedIor + vec3(incidentIor))); +} +float IorToFresnel0(float transmittedIor, float incidentIor) { + return sq((transmittedIor - incidentIor) / (transmittedIor + incidentIor)); +} + +/** + * From: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_iridescence#analytic-spectral-integration + */ +vec3 evalSensitivity(float OPD, vec3 shift) { + float phase = 2.0 * M_PI * OPD * 1.0e-9; + vec3 val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13); + vec3 pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06); + vec3 var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09); + + vec3 xyz = val * sqrt(2.0 * M_PI * var) * cos(pos * phase + shift) * exp(-(phase * phase) * var); + xyz.x += 9.7470e-14 * sqrt(2.0 * M_PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift[0]) * exp(-4.5282e+09 * (phase * phase)); + xyz /= 1.0685e-7; + + vec3 rgb = XYZ_TO_REC709 * xyz; + return rgb; +} + +/** + * From: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_iridescence#iridescence-fresnel + */ +vec3 calcIridescence(float outsideIor, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0) { + + + // iridescenceIor is the index of refraction of the thin-film layer + // Force iridescenceIor -> outsideIOR when thinFilmThickness -> 0.0 + float iridescenceIor = mix(outsideIor, eta2, smoothstep(0.0, 0.03, thinFilmThickness)); + + // To calculate the reflectances R12 and R23 at the viewing angles (angle hitting the thin-film layer) + // and (angle after refraction in the thin-film) Schlick Fresnel is again used. + // This approximation allows to eliminate the split into S and P polarization for the exact Fresnel equations. + // can be calculated using Snell's law (with being outsideIor and being iridescenceIor): + float sinTheta2Sq = sq(outsideIor / iridescenceIor) * (1.0 - sq(cosTheta1)); + float cosTheta2Sq = 1.0 - sinTheta2Sq; + + // Handle total internal reflection + if (cosTheta2Sq < 0.0) { + return vec3(1.0); + } + + float cosTheta2 = sqrt(cosTheta2Sq); + + /// Material Interfaces + // The iridescence model defined by Belcour/Barla models two material interfaces + // - one from the outside to the thin-film layer + // and another one from the thin-film to the base material. These two interfaces are defined as follows: + + // First interface (from the outside to the thin-film layer) + float R0 = IorToFresnel0(iridescenceIor, outsideIor); + float R12 = fresnel(R0, cosTheta1); + float R21 = R12; + float T121 = 1.0 - R12; + + // Second interface (from the thin-film to the base material) + vec3 baseIor = Fresnel0ToIor(baseF0 + 0.0001); // guard against 1.0 + vec3 R1 = IorToFresnel0(baseIor, iridescenceIor); + vec3 R23 = fresnel(R1, cosTheta2); + + // phi12 and phi23 define the base phases per interface and are approximated with 0.0 + // if the IOR of the hit material (iridescenceIor or baseIor) is higher + // than the IOR of the previous material (outsideIor or iridescenceIor) and π otherwise. + // Also here, polarization is ignored. float phi12 = 0.0; + + // First interface (from the outside to the thin-film layer) + float phi12 = 0.0; + if (iridescenceIor < outsideIor) phi12 = M_PI; + float phi21 = M_PI - phi12; + + // Second interface (from the thin-film to the base material) + vec3 phi23 = vec3(0.0); + if (baseIor[0] < iridescenceIor) phi23[0] = M_PI; + if (baseIor[1] < iridescenceIor) phi23[1] = M_PI; + if (baseIor[2] < iridescenceIor) phi23[2] = M_PI; + + // OPD (optical path difference) + float OPD = 2.0 * iridescenceIor * thinFilmThickness * cosTheta2; + // Phase shift + vec3 phi = vec3(phi21) + phi23; + + // Compound terms + vec3 R123 = clamp(R12 * R23, 1e-5, 0.9999); + vec3 r123 = sqrt(R123); + vec3 Rs = (T121 * T121) * R23 / (vec3(1.0) - R123); + + // Reflectance term for m = 0 (DC term amplitude) + vec3 C0 = R12 + Rs; + vec3 I = C0; + + // Reflectance term for m > 0 (pairs of diracs) + vec3 Cm = Rs - T121; + for (int m = 1; m <= 2; ++m) + { + Cm *= r123; + vec3 Sm = 2.0 * evalSensitivity(float(m) * OPD, float(m) * phi); + I += Cm * Sm; + } + + vec3 F_iridescence = max(I, vec3(0.0)); + + return F_iridescence; +} +#endif + + + + + +//////////////////////////////////////// +// glTF BRDF for punctual lights +//////////////////////////////////////// +vec3 gltfBRDF( + Light light, + vec3 normal_inWorld, + vec3 viewDirection, + float NdotV, + vec3 albedo, + float perceptualRoughness, + float metallic, + vec3 F0, + vec3 F90, + float ior, + float transmission, + float clearcoat, + float clearcoatRoughness, + vec3 clearcoatNormal_inWorld, + float VdotNc, + vec3 attenuationColor, + float attenuationDistance, + float anisotropy, + vec3 anisotropicT, + vec3 anisotropicB, + vec3 sheenColor, + float sheenRoughness, + float albedoSheenScalingNdotV + ) +{ + float alphaRoughness = perceptualRoughness * perceptualRoughness; + + // Fresnel + vec3 halfVector = normalize(light.direction + viewDirection); + float VdotH = dot(viewDirection, halfVector); + vec3 F = fresnel(F0, F90, VdotH); + + float NdotL = saturateEpsilonToOne(dot(normal_inWorld, light.direction)); + + // Diffuse + vec3 diffuseBrdf = diffuse_brdf(albedo); + vec3 pureDiffuse = (vec3(1.0) - F) * diffuseBrdf * vec3(NdotL) * light.attenuatedIntensity; + +#ifdef RN_USE_TRANSMISSION + vec3 refractionVector = refract(-viewDirection, normal_inWorld, 1.0 / ior); + Light transmittedLightFromUnderSurface = light; + transmittedLightFromUnderSurface.pointToLight -= refractionVector; + vec3 transmittedLightDirectionFromUnderSurface = normalize(transmittedLightFromUnderSurface.pointToLight); + transmittedLightFromUnderSurface.direction = transmittedLightDirectionFromUnderSurface; + + vec3 Ht = normalize(viewDirection + transmittedLightFromUnderSurface.direction); + float NdotHt = saturateEpsilonToOne(dot(normal_inWorld, Ht)); + float NdotLt = saturateEpsilonToOne(dot(normal_inWorld, transmittedLightFromUnderSurface.direction)); + + vec3 transmittedContrib = (vec3(1.0) - F) * specular_btdf(alphaRoughness, NdotLt, NdotV, NdotHt) * albedo * transmittedLightFromUnderSurface.attenuatedIntensity; + +#ifdef RN_USE_VOLUME + transmittedContrib = volumeAttenuation(attenuationColor, attenuationDistance, transmittedContrib, length(transmittedLightFromUnderSurface.pointToLight)); +#endif // RN_USE_VOLUME + + vec3 diffuseContrib = mix(pureDiffuse, vec3(transmittedContrib), transmission); +#else + vec3 diffuseContrib = pureDiffuse; +#endif // RN_USE_TRANSMISSION + + // Specular + float NdotH = saturateEpsilonToOne(dot(normal_inWorld, halfVector)); +#ifdef RN_USE_ANISOTROPY + float TdotL = dot(anisotropicT, light.direction); + float BdotL = dot(anisotropicB, light.direction); + float TdotH = dot(anisotropicT, halfVector); + float BdotH = dot(anisotropicB, halfVector); + vec3 specularContrib = BRDF_specularAnisotropicGGX(F, alphaRoughness, VdotH, NdotL, NdotV, NdotH, BdotV, TdotV, TdotL, BdotL, TdotH, BdotH, anisotropy) * vec3(NdotL) * light.attenuatedIntensity; +#else + vec3 specularContrib = cook_torrance_specular_brdf(NdotH, NdotL, NdotV, F, alphaRoughness) * vec3(NdotL) * light.attenuatedIntensity; +#endif // RN_USE_ANISOTROPY + // Base Layer + vec3 baseLayer = diffuseContrib + specularContrib; + +#ifdef RN_USE_SHEEN + // Sheen + vec3 sheenContrib = sheen_brdf(sheenColor, sheenRoughness, NdotL, NdotV, NdotH) * NdotL * light.attenuatedIntensity; + float albedoSheenScaling = min( + albedoSheenScalingNdotV, + 1.0 - max3(sheenColor) * texture(u_sheenLutTexture, vec2(NdotL, sheenRoughness)).r); + vec3 color = sheenContrib + baseLayer * albedoSheenScaling; +#else + vec3 color = baseLayer; + float albedoSheenScaling = 1.0; +#endif // RN_USE_SHEEN + +#ifdef RN_USE_CLEARCOAT + // Clear Coat Layer + float NdotHc = saturateEpsilonToOne(dot(clearcoatNormal_inWorld, halfVector)); + float LdotNc = saturateEpsilonToOne(dot(light.direction, clearcoatNormal_inWorld)); + vec3 coated = coated_material_s(color, perceptualRoughness, + clearcoatRoughness, clearcoat, VdotNc, LdotNc, NdotHc); + vec3 finalColor = coated; +#else + vec3 finalColor = color; +#endif // RN_USE_CLEARCOAT + + return finalColor; +} diff --git a/src/webgl/shaderity_shaders/common/pbrIridescence.glsl b/src/webgl/shaderity_shaders/common/pbrIridescence.glsl deleted file mode 100644 index eebe2cdbc..000000000 --- a/src/webgl/shaderity_shaders/common/pbrIridescence.glsl +++ /dev/null @@ -1,124 +0,0 @@ - -// XYZ to REC709(sRGB) conversion matrix -const mat3 XYZ_TO_REC709 = mat3( - 3.2404542, -0.9692660, 0.0556434, - -1.5371385, 1.8760108, -0.2040259, - -0.4985314, 0.0415560, 1.0572252 -); - -// Assume air interface for top -vec3 Fresnel0ToIor(vec3 F0) { - vec3 sqrtF0 = sqrt(F0); - return (vec3(1.0) + sqrtF0) / (vec3(1.0) - sqrtF0); -} - -// Conversion from IOR to F0 -// ior is a value between 1.0 and 3.0. 1.0 is air interface -vec3 IorToFresnel0(vec3 transmittedIor, float incidentIor) { - return sq((transmittedIor - vec3(incidentIor)) / (transmittedIor + vec3(incidentIor))); -} -float IorToFresnel0(float transmittedIor, float incidentIor) { - return sq((transmittedIor - incidentIor) / (transmittedIor + incidentIor)); -} - -/** - * From: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_iridescence#analytic-spectral-integration - */ -vec3 evalSensitivity(float OPD, vec3 shift) { - float phase = 2.0 * M_PI * OPD * 1.0e-9; - vec3 val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13); - vec3 pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06); - vec3 var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09); - - vec3 xyz = val * sqrt(2.0 * M_PI * var) * cos(pos * phase + shift) * exp(-(phase * phase) * var); - xyz.x += 9.7470e-14 * sqrt(2.0 * M_PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift[0]) * exp(-4.5282e+09 * (phase * phase)); - xyz /= 1.0685e-7; - - vec3 rgb = XYZ_TO_REC709 * xyz; - return rgb; -} - - -/** - * From: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_iridescence#iridescence-fresnel - */ -vec3 calcIridescence(float outsideIor, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0) { - - - // iridescenceIor is the index of refraction of the thin-film layer - // Force iridescenceIor -> outsideIOR when thinFilmThickness -> 0.0 - float iridescenceIor = mix(outsideIor, eta2, smoothstep(0.0, 0.03, thinFilmThickness)); - - // To calculate the reflectances R12 and R23 at the viewing angles (angle hitting the thin-film layer) - // and (angle after refraction in the thin-film) Schlick Fresnel is again used. - // This approximation allows to eliminate the split into S and P polarization for the exact Fresnel equations. - // can be calculated using Snell's law (with being outsideIor and being iridescenceIor): - float sinTheta2Sq = sq(outsideIor / iridescenceIor) * (1.0 - sq(cosTheta1)); - float cosTheta2Sq = 1.0 - sinTheta2Sq; - - // Handle total internal reflection - if (cosTheta2Sq < 0.0) { - return vec3(1.0); - } - - float cosTheta2 = sqrt(cosTheta2Sq); - - /// Material Interfaces - // The iridescence model defined by Belcour/Barla models two material interfaces - // - one from the outside to the thin-film layer - // and another one from the thin-film to the base material. These two interfaces are defined as follows: - - // First interface (from the outside to the thin-film layer) - float R0 = IorToFresnel0(iridescenceIor, outsideIor); - float R12 = fresnel(R0, cosTheta1); - float R21 = R12; - float T121 = 1.0 - R12; - - // Second interface (from the thin-film to the base material) - vec3 baseIor = Fresnel0ToIor(baseF0 + 0.0001); // guard against 1.0 - vec3 R1 = IorToFresnel0(baseIor, iridescenceIor); - vec3 R23 = fresnel(R1, cosTheta2); - - // phi12 and phi23 define the base phases per interface and are approximated with 0.0 - // if the IOR of the hit material (iridescenceIor or baseIor) is higher - // than the IOR of the previous material (outsideIor or iridescenceIor) and π otherwise. - // Also here, polarization is ignored. float phi12 = 0.0; - - // First interface (from the outside to the thin-film layer) - float phi12 = 0.0; - if (iridescenceIor < outsideIor) phi12 = M_PI; - float phi21 = M_PI - phi12; - - // Second interface (from the thin-film to the base material) - vec3 phi23 = vec3(0.0); - if (baseIor[0] < iridescenceIor) phi23[0] = M_PI; - if (baseIor[1] < iridescenceIor) phi23[1] = M_PI; - if (baseIor[2] < iridescenceIor) phi23[2] = M_PI; - - // OPD (optical path difference) - float OPD = 2.0 * iridescenceIor * thinFilmThickness * cosTheta2; - // Phase shift - vec3 phi = vec3(phi21) + phi23; - - // Compound terms - vec3 R123 = clamp(R12 * R23, 1e-5, 0.9999); - vec3 r123 = sqrt(R123); - vec3 Rs = (T121 * T121) * R23 / (vec3(1.0) - R123); - - // Reflectance term for m = 0 (DC term amplitude) - vec3 C0 = R12 + Rs; - vec3 I = C0; - - // Reflectance term for m > 0 (pairs of diracs) - vec3 Cm = Rs - T121; - for (int m = 1; m <= 2; ++m) - { - Cm *= r123; - vec3 Sm = 2.0 * evalSensitivity(float(m) * OPD, float(m) * phi); - I += Cm * Sm; - } - - vec3 F_iridescence = max(I, vec3(0.0)); - - return F_iridescence; -} diff --git a/src/webgl/shaderity_shaders/common/pbrSheen.glsl b/src/webgl/shaderity_shaders/common/pbrSheen.glsl deleted file mode 100644 index c9f6fafa7..000000000 --- a/src/webgl/shaderity_shaders/common/pbrSheen.glsl +++ /dev/null @@ -1,41 +0,0 @@ -float d_Charlie(float sheenPerceptualRoughness, float NoH) { - // Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF" - float alphaG = sheenPerceptualRoughness * sheenPerceptualRoughness; - float invAlpha = 1.0 / alphaG; - float cos2h = NoH * NoH; - float sin2h = 1.0 - cos2h; - return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI); -} - -// https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_sheen#sheen-visibility -float sheenSimpleVisibility(float NdotL, float NdotV) { - return 1.0 / (4.0 * (NdotL + NdotV - NdotL * NdotV)); -} - -// https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_sheen#sheen-visibility -float charlieL(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) -{ - return abs(cosTheta) < 0.5 ? exp(charlieL(cosTheta, alphaG)) : exp(2.0 * charlieL(0.5, alphaG) - charlieL(1.0 - cosTheta, alphaG)); -} - -float sheenCharlieVisibility(float NdotL, float NdotV, float sheenPerceptualRoughness) { - float alphaG = sheenPerceptualRoughness * sheenPerceptualRoughness; - float sheenVisibility = 1.0 / ((1.0 + lambdaSheen(NdotV, alphaG) + lambdaSheen(NdotL, alphaG)) * (4.0 * NdotV * NdotL)); - return sheenVisibility; -} - -vec3 sheen_brdf(vec3 sheenColor, float sheenPerceptualRoughness, float NdotL, float NdotV, float NdotH) { - float sheenDistribution = d_Charlie(sheenPerceptualRoughness, NdotH); - float sheenVisibility = sheenCharlieVisibility(NdotL, NdotV, sheenPerceptualRoughness); - return sheenColor * sheenDistribution * sheenVisibility; -} From f2e04e0c7b07fe61a28ee322c842b7cd38696357 Mon Sep 17 00:00:00 2001 From: Yuki Shimada Date: Sat, 2 Sep 2023 05:58:11 +0900 Subject: [PATCH 2/3] refactor: IBL shader code --- .../PbrSingleShader/PbrSingleShader.frag | 348 +----------------- .../common/iblDefinition.glsl | 346 +++++++++++++++++ 2 files changed, 347 insertions(+), 347 deletions(-) create mode 100644 src/webgl/shaderity_shaders/common/iblDefinition.glsl diff --git a/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag b/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag index 72198202a..6c864019e 100644 --- a/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag +++ b/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag @@ -121,353 +121,7 @@ uniform float u_alphaCutoff; // initialValue=(0.01) #pragma shaderity: require(../common/shadow.glsl) - -vec3 get_irradiance(vec3 normal_forEnv, float materialSID, ivec2 hdriFormat) { - vec4 diffuseTexel = texture(u_diffuseEnvTexture, normal_forEnv); - - vec3 irradiance; - if (hdriFormat.x == 0) { - // LDR_SRGB - irradiance = srgbToLinear(diffuseTexel.rgb); - } - else if (hdriFormat.x == 3) { - // RGBE - irradiance = diffuseTexel.rgb * pow(2.0, diffuseTexel.a*255.0-128.0); - } - else { - irradiance = diffuseTexel.rgb; - } - - return irradiance; -} - -float scaleForLod(float perceptualRoughness, float ior) -{ - // Scale roughness to the range [0, 1], - // ior=1.0 will be scale 0, - // ior=1.5 will be scale 1.0, - // ior=2 will be scale 1.0 (clamped) - // - - float scale = clamp(ior * 2.0 - 2.0, 0.0, 1.0); - return perceptualRoughness * scale; -} - -#ifdef RN_USE_TRANSMISSION -vec3 get_sample_from_backbuffer(float materialSID, vec2 sampleCoord, float perceptualRoughness, float ior) { - ivec2 vrState = get_vrState(0.0, 0); - vec2 backBufferTextureSize = get_backBufferTextureSize(materialSID, 0); - float backBufferTextureLength = max(backBufferTextureSize.x, backBufferTextureSize.y); - if (vrState.x == 1) { // For VR - backBufferTextureLength = max(backBufferTextureSize.x / 2.0, backBufferTextureSize.y); - sampleCoord.x = sampleCoord.x * 0.5; - if (vrState.y == 1) { // For right eye - sampleCoord.x += 0.5; - } - } - float framebufferLod = log2(backBufferTextureLength) * scaleForLod(perceptualRoughness, ior); - - #ifdef WEBGL1_EXT_SHADER_TEXTURE_LOD - vec3 transmittedLight = texture2DLodEXT(u_backBufferTexture, sampleCoord, framebufferLod).rgb; - #elif defined(GLSL_ES3) - vec3 transmittedLight = textureLod(u_backBufferTexture, sampleCoord, framebufferLod).rgb; - #else - vec3 transmittedLight = texture(u_backBufferTexture, sampleCoord).rgb; - #endif - - return transmittedLight; -} -#endif - -vec3 get_radiance(vec3 reflection, float lod, ivec2 hdriFormat) { - #ifdef WEBGL1_EXT_SHADER_TEXTURE_LOD - vec4 specularTexel = textureCubeLodEXT(u_specularEnvTexture, reflection, lod); - #elif defined(GLSL_ES3) - vec4 specularTexel = textureLod(u_specularEnvTexture, reflection, lod); - #else - vec4 specularTexel = texture(u_specularEnvTexture, reflection); - #endif - -// #pragma shaderity: require(./../common/fetchCubeTexture.glsl) - - vec3 radiance; - if (hdriFormat.y == 0) { - // LDR_SRGB - radiance = srgbToLinear(specularTexel.rgb); - } - else if (hdriFormat.y == 3) { - // RGBE - radiance = specularTexel.rgb * pow(2.0, specularTexel.a*255.0-128.0); - } - else { - radiance = specularTexel.rgb; - } - - return radiance; -} - -// from glTF Sample Viewer: https://github.com/KhronosGroup/glTF-Sample-Viewer -vec3 getVolumeTransmissionRay(vec3 n, vec3 v, float thickness, float ior) -{ - vec3 refractionVector = refract(-v, normalize(n), 1.0 / ior); - mat4 worldMatrix = get_worldMatrix(v_instanceInfo); - - vec3 modelScale; - modelScale.x = length(vec3(worldMatrix[0].xyz)); - modelScale.y = length(vec3(worldMatrix[1].xyz)); - modelScale.z = length(vec3(worldMatrix[2].xyz)); - - return normalize(refractionVector) * thickness * modelScale; -} - -struct IblResult -{ - vec3 specular; - vec3 diffuse; - vec3 FssEss; -}; - -IblResult getIBLRadianceGGX(float materialSID, float NdotV, vec3 viewDirection, vec3 albedo, vec3 F0, - float perceptualRoughness, vec4 iblParameter, ivec2 hdriFormat, mat3 rotEnvMatrix, - vec3 normal_forEnv, vec3 reflection) -{ - // get radiance - float mipCount = iblParameter.x; - float lod = (perceptualRoughness * (mipCount - 1.0)); - vec3 radiance = get_radiance(reflection, lod, hdriFormat); - - // Roughness dependent fresnel - vec3 kS = fresnelSchlickRoughness(F0, NdotV, perceptualRoughness); - vec2 f_ab = envBRDFApprox(perceptualRoughness, NdotV); - vec3 FssEss = kS * f_ab.x + f_ab.y; - IblResult result; - result.FssEss = FssEss; - - // Specular IBL - vec3 specular = FssEss * radiance; - - // scale with user parameters - float IBLSpecularContribution = iblParameter.z; - specular *= IBLSpecularContribution; - - result.specular = specular; - - return result; -} - -IblResult getIBLRadianceGGXWithIridescence(float materialSID, float NdotV, vec3 viewDirection, vec3 albedo, vec3 F0, - float perceptualRoughness, vec4 iblParameter, ivec2 hdriFormat, mat3 rotEnvMatrix, - vec3 normal_forEnv, vec3 reflection, vec3 iridescenceFresnel, float iridescence) -{ - // get radiance - float mipCount = iblParameter.x; - float lod = (perceptualRoughness * (mipCount - 1.0)); - vec3 radiance = get_radiance(reflection, lod, hdriFormat); - - // Roughness dependent fresnel - vec3 kS = fresnelSchlickRoughnessWithIridescence(F0, NdotV, perceptualRoughness, iridescenceFresnel, iridescence); - vec2 f_ab = envBRDFApprox(perceptualRoughness, NdotV); - vec3 FssEss = kS * f_ab.x + f_ab.y; - IblResult result; - result.FssEss = FssEss; - - // Specular IBL - vec3 specular = FssEss * radiance; - - // scale with user parameters - float IBLSpecularContribution = iblParameter.z; - specular *= IBLSpecularContribution; - - result.specular = specular; - - return result; -} - -IblResult getIBLRadianceLambertian(float materialSID, float NdotV, vec3 viewDirection, vec3 albedo, vec3 F0, - float perceptualRoughness, vec4 iblParameter, ivec2 hdriFormat, mat3 rotEnvMatrix, - vec3 normal_forEnv, vec3 reflection) -{ - // get irradiance - vec3 irradiance = get_irradiance(normal_forEnv, materialSID, hdriFormat); - - // Roughness dependent fresnel - vec3 kS = fresnelSchlickRoughness(F0, NdotV, perceptualRoughness); - vec2 f_ab = envBRDFApprox(perceptualRoughness, NdotV); - vec3 FssEss = kS * f_ab.x + f_ab.y; - IblResult result; - result.FssEss = FssEss; - - // Multiple scattering, Fdez-Aguera's approach - float Ems = (1.0 - (f_ab.x + f_ab.y)); - vec3 F_avg = F0 + (1.0 - F0) / 21.0; - vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems); - vec3 k_D = albedo * (1.0 - FssEss - FmsEms); - - // Diffuse IBL - vec3 diffuse = (FmsEms + k_D) * irradiance; - - // scale with user parameters - float IBLDiffuseContribution = iblParameter.y; - diffuse *= IBLDiffuseContribution; - - result.diffuse = diffuse; - - return result; -} - -IblResult getIBLRadianceLambertianWithIridescence(float materialSID, float NdotV, vec3 viewDirection, vec3 albedo, vec3 F0, - float perceptualRoughness, vec4 iblParameter, ivec2 hdriFormat, mat3 rotEnvMatrix, - vec3 normal_forEnv, vec3 reflection, vec3 iridescenceF0, float iridescence) -{ - // get irradiance - vec3 irradiance = get_irradiance(normal_forEnv, materialSID, hdriFormat); - - // Use the maximum component of the iridescence Fresnel color - // Maximum is used instead of the RGB value to not get inverse colors for the diffuse BRDF - vec3 iridescenceF0Max = vec3(max(max(iridescenceF0.r, iridescenceF0.g), iridescenceF0.b)); - - // Blend between base F0 and iridescence F0 - vec3 mixedF0 = mix(F0, iridescenceF0Max, iridescence); - - // Roughness dependent fresnel - vec3 kS = fresnelSchlickRoughness(mixedF0, NdotV, perceptualRoughness); - vec2 f_ab = envBRDFApprox(perceptualRoughness, NdotV); - vec3 FssEss = kS * f_ab.x + f_ab.y; - IblResult result; - result.FssEss = FssEss; - - // Multiple scattering, Fdez-Aguera's approach - float Ems = (1.0 - (f_ab.x + f_ab.y)); - vec3 F_avg = mixedF0 + (1.0 - mixedF0) / 21.0; - vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems); - vec3 k_D = albedo * (1.0 - FssEss - FmsEms); - - // Diffuse IBL - vec3 diffuse = (FmsEms + k_D) * irradiance; - - // scale with user parameters - float IBLDiffuseContribution = iblParameter.y; - diffuse *= IBLDiffuseContribution; - - result.diffuse = diffuse; - - return result; -} - -#ifdef RN_USE_SHEEN -vec3 sheenIBL(float NdotV, float sheenPerceptualRoughness, vec3 sheenColor, vec4 iblParameter, vec3 reflection, ivec2 hdriFormat) -{ - float mipCount = iblParameter.x; - float lod = (sheenPerceptualRoughness * (mipCount - 1.0)); - - vec2 sheenLutUV = vec2(NdotV, sheenPerceptualRoughness); - float brdf = texture(u_sheenLutTexture, sheenLutUV).b; - vec3 sheenLight = get_radiance(reflection, lod, hdriFormat); - float IBLSpecularContribution = iblParameter.z; - sheenLight *= IBLSpecularContribution; - - return sheenLight * sheenColor * brdf; -} -#endif - -vec3 getNormalForEnv(mat3 rotEnvMatrix, vec3 normal_inWorld, float materialSID) { - vec3 normal_forEnv = rotEnvMatrix * normal_inWorld; - if (get_inverseEnvironment(materialSID, 0)) { - normal_forEnv.x *= -1.0; - } - return normal_forEnv; -} - -vec3 getReflection(mat3 rotEnvMatrix, vec3 viewDirection, vec3 normal_inWorld, float materialSID, float perceptualRoughness, float anisotropy, vec3 anisotropyDirection) { -#ifdef RN_USE_ANISOTROPY - - float tangentRoughness = mix(perceptualRoughness, 1.0, anisotropy * anisotropy); - vec3 anisotropicTangent = cross(anisotropyDirection, viewDirection); - vec3 anisotropicNormal = cross(anisotropicTangent, anisotropyDirection); - float bendFactor = 1.0 - anisotropy * (1.0 - perceptualRoughness); - float bendFactorPow4 = bendFactor * bendFactor * bendFactor * bendFactor; - vec3 bentNormal = normalize(mix(anisotropicNormal, normal_inWorld, bendFactorPow4)); - vec3 reflection = rotEnvMatrix * reflect(-viewDirection, bentNormal); -#else - vec3 reflection = rotEnvMatrix * reflect(-viewDirection, normal_inWorld); -#endif - if (get_inverseEnvironment(materialSID, 0)) { - reflection.x *= -1.0; - } - return reflection; -} - -vec3 IBLContribution(float materialSID, vec3 normal_inWorld, float NdotV, vec3 viewDirection, - vec3 albedo, vec3 F0, float perceptualRoughness, float clearcoatRoughness, vec3 clearcoatNormal_inWorld, - float clearcoat, float VdotNc, vec3 geomNormal_inWorld, float cameraSID, float transmission, vec3 v_position_inWorld, - float thickness, vec3 sheenColor, float sheenRoughness, float albedoSheenScalingNdotV, float ior, - vec3 iridescenceFresnel, vec3 iridescenceF0, float iridescence, float anisotropy, vec3 anisotropyDirection) -{ - vec4 iblParameter = get_iblParameter(materialSID, 0); - float rot = iblParameter.w + 3.1415; - mat3 rotEnvMatrix = mat3(cos(rot), 0.0, -sin(rot), 0.0, 1.0, 0.0, sin(rot), 0.0, cos(rot)); - ivec2 hdriFormat = get_hdriFormat(materialSID, 0); - - vec3 normal_forEnv = getNormalForEnv(rotEnvMatrix, normal_inWorld, materialSID); - vec3 reflection = getReflection(rotEnvMatrix, viewDirection, normal_inWorld, materialSID, perceptualRoughness, anisotropy, anisotropyDirection); - - // IBL - #ifdef RN_USE_IRIDESCENCE - IblResult baseRadianceResult = getIBLRadianceGGXWithIridescence(materialSID, NdotV, viewDirection, albedo, F0, - perceptualRoughness, iblParameter, hdriFormat, rotEnvMatrix, normal_forEnv, reflection, iridescenceFresnel, iridescence); - IblResult baseLambertianResult = getIBLRadianceLambertianWithIridescence(materialSID, NdotV, viewDirection, albedo, F0, - perceptualRoughness, iblParameter, hdriFormat, rotEnvMatrix, normal_forEnv, reflection, iridescenceF0, iridescence); - #else - IblResult baseRadianceResult = getIBLRadianceGGX(materialSID, NdotV, viewDirection, albedo, F0, - perceptualRoughness, iblParameter, hdriFormat, rotEnvMatrix, normal_forEnv, reflection); - IblResult baseLambertianResult = getIBLRadianceLambertian(materialSID, NdotV, viewDirection, albedo, F0, - perceptualRoughness, iblParameter, hdriFormat, rotEnvMatrix, normal_forEnv, reflection); - #endif - -#ifdef RN_USE_TRANSMISSION - vec3 refractedRay = getVolumeTransmissionRay(geomNormal_inWorld, viewDirection, thickness, ior); - vec3 refractedRayFromVPosition = v_position_inWorld + refractedRay; - vec4 ndcPoint = get_projectionMatrix(cameraSID, 0) * get_viewMatrix(cameraSID, 0) * vec4(refractedRayFromVPosition, 1.0); - vec2 refractionCoords = ndcPoint.xy / ndcPoint.w; - refractionCoords += 1.0; - refractionCoords /= 2.0; - vec3 transmittedLight = get_sample_from_backbuffer(materialSID, refractionCoords, perceptualRoughness, ior); - -#ifdef RN_USE_VOLUME - vec3 attenuationColor = get_attenuationColor(materialSID, 0); - float attenuationDistance = get_attenuationDistance(materialSID, 0); - transmittedLight = volumeAttenuation(attenuationColor, attenuationDistance, transmittedLight, length(refractedRay)); -#endif - - vec3 transmissionComp = (vec3(1.0) - baseRadianceResult.FssEss) * transmittedLight * albedo; - vec3 diffuse = mix(baseLambertianResult.diffuse, transmissionComp, transmission); - vec3 base = diffuse + baseRadianceResult.specular; -#else - vec3 base = baseLambertianResult.diffuse + baseRadianceResult.specular; -#endif - -#ifdef RN_USE_SHEEN - vec3 sheen = sheenIBL(NdotV, sheenRoughness, sheenColor, iblParameter, reflection, hdriFormat); - vec3 color = sheen + base * albedoSheenScalingNdotV; -#else - vec3 color = base; -#endif - -#ifdef RN_USE_CLEARCOAT - float VdotNg = dot(geomNormal_inWorld, viewDirection); - vec3 clearcoatNormal_forEnv = getNormalForEnv(rotEnvMatrix, normal_inWorld, materialSID); - IblResult coatResult = getIBLRadianceGGX(materialSID, VdotNc, viewDirection, vec3(0.0), F0, - clearcoatRoughness, iblParameter, hdriFormat, rotEnvMatrix, clearcoatNormal_forEnv, reflection); - vec3 coatLayer = coatResult.specular; - - float clearcoatFresnel = 0.04 + (1.0 - 0.04) * pow(1.0 - abs(VdotNc), 5.0); - vec3 coated = color * vec3(1.0 - clearcoat * clearcoatFresnel) + vec3(coatLayer * clearcoat); - return coated; -#else - return color; -#endif - -} +#pragma shaderity: require(../common/iblDefinition.glsl) float edge_ratio(vec3 bary3, float wireframeWidthInner, float wireframeWidthRelativeScale) { vec3 d = fwidth(bary3); diff --git a/src/webgl/shaderity_shaders/common/iblDefinition.glsl b/src/webgl/shaderity_shaders/common/iblDefinition.glsl new file mode 100644 index 000000000..aa575642c --- /dev/null +++ b/src/webgl/shaderity_shaders/common/iblDefinition.glsl @@ -0,0 +1,346 @@ +vec3 get_irradiance(vec3 normal_forEnv, float materialSID, ivec2 hdriFormat) { + vec4 diffuseTexel = texture(u_diffuseEnvTexture, normal_forEnv); + + vec3 irradiance; + if (hdriFormat.x == 0) { + // LDR_SRGB + irradiance = srgbToLinear(diffuseTexel.rgb); + } + else if (hdriFormat.x == 3) { + // RGBE + irradiance = diffuseTexel.rgb * pow(2.0, diffuseTexel.a*255.0-128.0); + } + else { + irradiance = diffuseTexel.rgb; + } + + return irradiance; +} + +float scaleForLod(float perceptualRoughness, float ior) +{ + // Scale roughness to the range [0, 1], + // ior=1.0 will be scale 0, + // ior=1.5 will be scale 1.0, + // ior=2 will be scale 1.0 (clamped) + // + + float scale = clamp(ior * 2.0 - 2.0, 0.0, 1.0); + return perceptualRoughness * scale; +} + +#ifdef RN_USE_TRANSMISSION +vec3 get_sample_from_backbuffer(float materialSID, vec2 sampleCoord, float perceptualRoughness, float ior) { + ivec2 vrState = get_vrState(0.0, 0); + vec2 backBufferTextureSize = get_backBufferTextureSize(materialSID, 0); + float backBufferTextureLength = max(backBufferTextureSize.x, backBufferTextureSize.y); + if (vrState.x == 1) { // For VR + backBufferTextureLength = max(backBufferTextureSize.x / 2.0, backBufferTextureSize.y); + sampleCoord.x = sampleCoord.x * 0.5; + if (vrState.y == 1) { // For right eye + sampleCoord.x += 0.5; + } + } + float framebufferLod = log2(backBufferTextureLength) * scaleForLod(perceptualRoughness, ior); + + #ifdef WEBGL1_EXT_SHADER_TEXTURE_LOD + vec3 transmittedLight = texture2DLodEXT(u_backBufferTexture, sampleCoord, framebufferLod).rgb; + #elif defined(GLSL_ES3) + vec3 transmittedLight = textureLod(u_backBufferTexture, sampleCoord, framebufferLod).rgb; + #else + vec3 transmittedLight = texture(u_backBufferTexture, sampleCoord).rgb; + #endif + + return transmittedLight; +} +#endif + +vec3 get_radiance(vec3 reflection, float lod, ivec2 hdriFormat) { + #ifdef WEBGL1_EXT_SHADER_TEXTURE_LOD + vec4 specularTexel = textureCubeLodEXT(u_specularEnvTexture, reflection, lod); + #elif defined(GLSL_ES3) + vec4 specularTexel = textureLod(u_specularEnvTexture, reflection, lod); + #else + vec4 specularTexel = texture(u_specularEnvTexture, reflection); + #endif + +// #pragma shaderity: require(./../common/fetchCubeTexture.glsl) + + vec3 radiance; + if (hdriFormat.y == 0) { + // LDR_SRGB + radiance = srgbToLinear(specularTexel.rgb); + } + else if (hdriFormat.y == 3) { + // RGBE + radiance = specularTexel.rgb * pow(2.0, specularTexel.a*255.0-128.0); + } + else { + radiance = specularTexel.rgb; + } + + return radiance; +} + +// from glTF Sample Viewer: https://github.com/KhronosGroup/glTF-Sample-Viewer +vec3 getVolumeTransmissionRay(vec3 n, vec3 v, float thickness, float ior) +{ + vec3 refractionVector = refract(-v, normalize(n), 1.0 / ior); + mat4 worldMatrix = get_worldMatrix(v_instanceInfo); + + vec3 modelScale; + modelScale.x = length(vec3(worldMatrix[0].xyz)); + modelScale.y = length(vec3(worldMatrix[1].xyz)); + modelScale.z = length(vec3(worldMatrix[2].xyz)); + + return normalize(refractionVector) * thickness * modelScale; +} + +struct IblResult +{ + vec3 specular; + vec3 diffuse; + vec3 FssEss; +}; + +IblResult getIBLRadianceGGX(float materialSID, float NdotV, vec3 viewDirection, vec3 albedo, vec3 F0, + float perceptualRoughness, vec4 iblParameter, ivec2 hdriFormat, mat3 rotEnvMatrix, + vec3 normal_forEnv, vec3 reflection) +{ + // get radiance + float mipCount = iblParameter.x; + float lod = (perceptualRoughness * (mipCount - 1.0)); + vec3 radiance = get_radiance(reflection, lod, hdriFormat); + + // Roughness dependent fresnel + vec3 kS = fresnelSchlickRoughness(F0, NdotV, perceptualRoughness); + vec2 f_ab = envBRDFApprox(perceptualRoughness, NdotV); + vec3 FssEss = kS * f_ab.x + f_ab.y; + IblResult result; + result.FssEss = FssEss; + + // Specular IBL + vec3 specular = FssEss * radiance; + + // scale with user parameters + float IBLSpecularContribution = iblParameter.z; + specular *= IBLSpecularContribution; + + result.specular = specular; + + return result; +} + +IblResult getIBLRadianceGGXWithIridescence(float materialSID, float NdotV, vec3 viewDirection, vec3 albedo, vec3 F0, + float perceptualRoughness, vec4 iblParameter, ivec2 hdriFormat, mat3 rotEnvMatrix, + vec3 normal_forEnv, vec3 reflection, vec3 iridescenceFresnel, float iridescence) +{ + // get radiance + float mipCount = iblParameter.x; + float lod = (perceptualRoughness * (mipCount - 1.0)); + vec3 radiance = get_radiance(reflection, lod, hdriFormat); + + // Roughness dependent fresnel + vec3 kS = fresnelSchlickRoughnessWithIridescence(F0, NdotV, perceptualRoughness, iridescenceFresnel, iridescence); + vec2 f_ab = envBRDFApprox(perceptualRoughness, NdotV); + vec3 FssEss = kS * f_ab.x + f_ab.y; + IblResult result; + result.FssEss = FssEss; + + // Specular IBL + vec3 specular = FssEss * radiance; + + // scale with user parameters + float IBLSpecularContribution = iblParameter.z; + specular *= IBLSpecularContribution; + + result.specular = specular; + + return result; +} + +IblResult getIBLRadianceLambertian(float materialSID, float NdotV, vec3 viewDirection, vec3 albedo, vec3 F0, + float perceptualRoughness, vec4 iblParameter, ivec2 hdriFormat, mat3 rotEnvMatrix, + vec3 normal_forEnv, vec3 reflection) +{ + // get irradiance + vec3 irradiance = get_irradiance(normal_forEnv, materialSID, hdriFormat); + + // Roughness dependent fresnel + vec3 kS = fresnelSchlickRoughness(F0, NdotV, perceptualRoughness); + vec2 f_ab = envBRDFApprox(perceptualRoughness, NdotV); + vec3 FssEss = kS * f_ab.x + f_ab.y; + IblResult result; + result.FssEss = FssEss; + + // Multiple scattering, Fdez-Aguera's approach + float Ems = (1.0 - (f_ab.x + f_ab.y)); + vec3 F_avg = F0 + (1.0 - F0) / 21.0; + vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems); + vec3 k_D = albedo * (1.0 - FssEss - FmsEms); + + // Diffuse IBL + vec3 diffuse = (FmsEms + k_D) * irradiance; + + // scale with user parameters + float IBLDiffuseContribution = iblParameter.y; + diffuse *= IBLDiffuseContribution; + + result.diffuse = diffuse; + + return result; +} + +IblResult getIBLRadianceLambertianWithIridescence(float materialSID, float NdotV, vec3 viewDirection, vec3 albedo, vec3 F0, + float perceptualRoughness, vec4 iblParameter, ivec2 hdriFormat, mat3 rotEnvMatrix, + vec3 normal_forEnv, vec3 reflection, vec3 iridescenceF0, float iridescence) +{ + // get irradiance + vec3 irradiance = get_irradiance(normal_forEnv, materialSID, hdriFormat); + + // Use the maximum component of the iridescence Fresnel color + // Maximum is used instead of the RGB value to not get inverse colors for the diffuse BRDF + vec3 iridescenceF0Max = vec3(max(max(iridescenceF0.r, iridescenceF0.g), iridescenceF0.b)); + + // Blend between base F0 and iridescence F0 + vec3 mixedF0 = mix(F0, iridescenceF0Max, iridescence); + + // Roughness dependent fresnel + vec3 kS = fresnelSchlickRoughness(mixedF0, NdotV, perceptualRoughness); + vec2 f_ab = envBRDFApprox(perceptualRoughness, NdotV); + vec3 FssEss = kS * f_ab.x + f_ab.y; + IblResult result; + result.FssEss = FssEss; + + // Multiple scattering, Fdez-Aguera's approach + float Ems = (1.0 - (f_ab.x + f_ab.y)); + vec3 F_avg = mixedF0 + (1.0 - mixedF0) / 21.0; + vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems); + vec3 k_D = albedo * (1.0 - FssEss - FmsEms); + + // Diffuse IBL + vec3 diffuse = (FmsEms + k_D) * irradiance; + + // scale with user parameters + float IBLDiffuseContribution = iblParameter.y; + diffuse *= IBLDiffuseContribution; + + result.diffuse = diffuse; + + return result; +} + +#ifdef RN_USE_SHEEN +vec3 sheenIBL(float NdotV, float sheenPerceptualRoughness, vec3 sheenColor, vec4 iblParameter, vec3 reflection, ivec2 hdriFormat) +{ + float mipCount = iblParameter.x; + float lod = (sheenPerceptualRoughness * (mipCount - 1.0)); + + vec2 sheenLutUV = vec2(NdotV, sheenPerceptualRoughness); + float brdf = texture(u_sheenLutTexture, sheenLutUV).b; + vec3 sheenLight = get_radiance(reflection, lod, hdriFormat); + float IBLSpecularContribution = iblParameter.z; + sheenLight *= IBLSpecularContribution; + + return sheenLight * sheenColor * brdf; +} +#endif + +vec3 getNormalForEnv(mat3 rotEnvMatrix, vec3 normal_inWorld, float materialSID) { + vec3 normal_forEnv = rotEnvMatrix * normal_inWorld; + if (get_inverseEnvironment(materialSID, 0)) { + normal_forEnv.x *= -1.0; + } + return normal_forEnv; +} + +vec3 getReflection(mat3 rotEnvMatrix, vec3 viewDirection, vec3 normal_inWorld, float materialSID, float perceptualRoughness, float anisotropy, vec3 anisotropyDirection) { +#ifdef RN_USE_ANISOTROPY + + float tangentRoughness = mix(perceptualRoughness, 1.0, anisotropy * anisotropy); + vec3 anisotropicTangent = cross(anisotropyDirection, viewDirection); + vec3 anisotropicNormal = cross(anisotropicTangent, anisotropyDirection); + float bendFactor = 1.0 - anisotropy * (1.0 - perceptualRoughness); + float bendFactorPow4 = bendFactor * bendFactor * bendFactor * bendFactor; + vec3 bentNormal = normalize(mix(anisotropicNormal, normal_inWorld, bendFactorPow4)); + vec3 reflection = rotEnvMatrix * reflect(-viewDirection, bentNormal); +#else + vec3 reflection = rotEnvMatrix * reflect(-viewDirection, normal_inWorld); +#endif + if (get_inverseEnvironment(materialSID, 0)) { + reflection.x *= -1.0; + } + return reflection; +} + +vec3 IBLContribution(float materialSID, vec3 normal_inWorld, float NdotV, vec3 viewDirection, + vec3 albedo, vec3 F0, float perceptualRoughness, float clearcoatRoughness, vec3 clearcoatNormal_inWorld, + float clearcoat, float VdotNc, vec3 geomNormal_inWorld, float cameraSID, float transmission, vec3 v_position_inWorld, + float thickness, vec3 sheenColor, float sheenRoughness, float albedoSheenScalingNdotV, float ior, + vec3 iridescenceFresnel, vec3 iridescenceF0, float iridescence, float anisotropy, vec3 anisotropyDirection) +{ + vec4 iblParameter = get_iblParameter(materialSID, 0); + float rot = iblParameter.w + 3.1415; + mat3 rotEnvMatrix = mat3(cos(rot), 0.0, -sin(rot), 0.0, 1.0, 0.0, sin(rot), 0.0, cos(rot)); + ivec2 hdriFormat = get_hdriFormat(materialSID, 0); + + vec3 normal_forEnv = getNormalForEnv(rotEnvMatrix, normal_inWorld, materialSID); + vec3 reflection = getReflection(rotEnvMatrix, viewDirection, normal_inWorld, materialSID, perceptualRoughness, anisotropy, anisotropyDirection); + + // IBL + #ifdef RN_USE_IRIDESCENCE + IblResult baseRadianceResult = getIBLRadianceGGXWithIridescence(materialSID, NdotV, viewDirection, albedo, F0, + perceptualRoughness, iblParameter, hdriFormat, rotEnvMatrix, normal_forEnv, reflection, iridescenceFresnel, iridescence); + IblResult baseLambertianResult = getIBLRadianceLambertianWithIridescence(materialSID, NdotV, viewDirection, albedo, F0, + perceptualRoughness, iblParameter, hdriFormat, rotEnvMatrix, normal_forEnv, reflection, iridescenceF0, iridescence); + #else + IblResult baseRadianceResult = getIBLRadianceGGX(materialSID, NdotV, viewDirection, albedo, F0, + perceptualRoughness, iblParameter, hdriFormat, rotEnvMatrix, normal_forEnv, reflection); + IblResult baseLambertianResult = getIBLRadianceLambertian(materialSID, NdotV, viewDirection, albedo, F0, + perceptualRoughness, iblParameter, hdriFormat, rotEnvMatrix, normal_forEnv, reflection); + #endif + +#ifdef RN_USE_TRANSMISSION + vec3 refractedRay = getVolumeTransmissionRay(geomNormal_inWorld, viewDirection, thickness, ior); + vec3 refractedRayFromVPosition = v_position_inWorld + refractedRay; + vec4 ndcPoint = get_projectionMatrix(cameraSID, 0) * get_viewMatrix(cameraSID, 0) * vec4(refractedRayFromVPosition, 1.0); + vec2 refractionCoords = ndcPoint.xy / ndcPoint.w; + refractionCoords += 1.0; + refractionCoords /= 2.0; + vec3 transmittedLight = get_sample_from_backbuffer(materialSID, refractionCoords, perceptualRoughness, ior); + +#ifdef RN_USE_VOLUME + vec3 attenuationColor = get_attenuationColor(materialSID, 0); + float attenuationDistance = get_attenuationDistance(materialSID, 0); + transmittedLight = volumeAttenuation(attenuationColor, attenuationDistance, transmittedLight, length(refractedRay)); +#endif + + vec3 transmissionComp = (vec3(1.0) - baseRadianceResult.FssEss) * transmittedLight * albedo; + vec3 diffuse = mix(baseLambertianResult.diffuse, transmissionComp, transmission); + vec3 base = diffuse + baseRadianceResult.specular; +#else + vec3 base = baseLambertianResult.diffuse + baseRadianceResult.specular; +#endif + +#ifdef RN_USE_SHEEN + vec3 sheen = sheenIBL(NdotV, sheenRoughness, sheenColor, iblParameter, reflection, hdriFormat); + vec3 color = sheen + base * albedoSheenScalingNdotV; +#else + vec3 color = base; +#endif + +#ifdef RN_USE_CLEARCOAT + float VdotNg = dot(geomNormal_inWorld, viewDirection); + vec3 clearcoatNormal_forEnv = getNormalForEnv(rotEnvMatrix, normal_inWorld, materialSID); + IblResult coatResult = getIBLRadianceGGX(materialSID, VdotNc, viewDirection, vec3(0.0), F0, + clearcoatRoughness, iblParameter, hdriFormat, rotEnvMatrix, clearcoatNormal_forEnv, reflection); + vec3 coatLayer = coatResult.specular; + + float clearcoatFresnel = 0.04 + (1.0 - 0.04) * pow(1.0 - abs(VdotNc), 5.0); + vec3 coated = color * vec3(1.0 - clearcoat * clearcoatFresnel) + vec3(coatLayer * clearcoat); + return coated; +#else + return color; +#endif + +} From 0100fdbc1b2a3d180d02afc87ad45a2d9b122e42 Mon Sep 17 00:00:00 2001 From: Yuki Shimada Date: Sat, 2 Sep 2023 06:15:17 +0900 Subject: [PATCH 3/3] refactor: PbrSingleShader.frag --- .../PbrSingleShader/PbrSingleShader.frag | 299 +++++++++--------- .../common/pbrDefinition.glsl | 2 + 2 files changed, 150 insertions(+), 151 deletions(-) diff --git a/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag b/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag index 6c864019e..f7713d145 100644 --- a/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag +++ b/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag @@ -151,9 +151,10 @@ void main () #pragma shaderity: require(../common/mainPrerequisites.glsl) - // View vector + // View direction vec3 viewPosition = get_viewPosition(cameraSID, 0); vec3 viewVector = viewPosition - v_position_inWorld.xyz; + vec3 viewDirection = normalize(viewVector); // Normal vec3 normal_inWorld = normalize(v_normal_inWorld); @@ -203,86 +204,87 @@ void main () #pragma shaderity: require(../common/alphaMask.glsl) - // NdotV - vec3 viewDirection = normalize(viewVector); - float NdotV = saturateEpsilonToOne(dot(normal_inWorld, viewDirection)); - -#ifdef RN_USE_ANISOTROPY - float anisotropy = get_anisotropyStrength(materialSID, 0); - vec2 anisotropyRotation = get_anisotropyRotation(materialSID, 0); - vec2 direction = anisotropyRotation; - vec3 anisotropyTex = texture(u_anisotropyTexture, baseColorTexUv).rgb; - direction = anisotropyTex.rg * 2.0 - vec2(1.0); - direction = mat2(anisotropyRotation.x, anisotropyRotation.y, -anisotropyRotation.y, anisotropyRotation.x) * normalize(direction); - anisotropy *= anisotropyTex.b; - vec3 anisotropicT = normalize(TBN * vec3(direction, 0.0)); - vec3 anisotropicB = normalize(cross(geomNormal_inWorld, anisotropicT)); - float BdotV = dot(anisotropicB, viewDirection); - float TdotV = dot(anisotropicT, viewDirection); -#else - float anisotropy = 0.0; - vec3 anisotropicT = vec3(0.0, 0.0, 0.0); - vec3 anisotropicB = vec3(0.0, 0.0, 0.0); -#endif - - // Clearcoat -#ifdef RN_USE_CLEARCOAT - float clearcoatFactor = get_clearCoatFactor(materialSID, 0); - vec4 clearcoatTextureTransform = get_clearCoatTextureTransform(materialSID, 0); - float clearcoatTextureRotation = get_clearCoatTextureRotation(materialSID, 0); - int clearCoatTexcoordIndex = get_clearCoatTexcoordIndex(materialSID, 0); - vec2 clearCoatTexcoord = getTexcoord(clearCoatTexcoordIndex); - vec2 clearcoatTexUv = uvTransform(clearcoatTextureTransform.xy, clearcoatTextureTransform.zw, clearcoatTextureRotation, clearCoatTexcoord); - float clearcoatTexture = texture(u_clearCoatTexture, clearcoatTexUv).r; - float clearcoat = clearcoatFactor * clearcoatTexture; -#else - float clearcoat = 0.0; -#endif // RN_USE_CLEARCOAT - - // Transmission -#ifdef RN_USE_TRANSMISSION - float transmissionFactor = get_transmissionFactor(materialSID, 0); - float transmissionTexture = texture(u_transmissionTexture, baseColorTexUv).r; - float transmission = transmissionFactor * transmissionTexture; - // alpha *= transmission; -#else - float transmission = 0.0; -#endif // RN_USE_TRANSMISSION #ifdef RN_IS_LIGHTING // Metallic & Roughness vec2 metallicRoughnessFactor = get_metallicRoughnessFactor(materialSID, 0); - float perceptualRoughness = metallicRoughnessFactor.y; float metallic = metallicRoughnessFactor.x; - vec4 metallicRoughnessTextureTransform = get_metallicRoughnessTextureTransform(materialSID, 0); float metallicRoughnessTextureRotation = get_metallicRoughnessTextureRotation(materialSID, 0); int metallicRoughnessTexcoordIndex = get_metallicRoughnessTexcoordIndex(materialSID, 0); vec2 metallicRoughnessTexcoord = getTexcoord(metallicRoughnessTexcoordIndex); vec2 metallicRoughnessTexUv = uvTransform(metallicRoughnessTextureTransform.xy, metallicRoughnessTextureTransform.zw, metallicRoughnessTextureRotation, metallicRoughnessTexcoord); vec4 ormTexel = texture(u_metallicRoughnessTexture, metallicRoughnessTexUv); - perceptualRoughness = ormTexel.g * perceptualRoughness; + float perceptualRoughness = ormTexel.g * metallicRoughnessFactor.y; metallic = ormTexel.b * metallic; - - perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0); metallic = clamp(metallic, 0.0, 1.0); + perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0); float alphaRoughness = perceptualRoughness * perceptualRoughness; - - // filter NDF for specular AA - // https://jcgt.org/published/0010/02/02/ + // filter NDF for specular AA --- https://jcgt.org/published/0010/02/02/ float alphaRoughness2 = alphaRoughness * alphaRoughness; float filteredRoughness2 = IsotropicNDFFiltering(normal_inWorld, alphaRoughness2); perceptualRoughness = sqrt(sqrt(filteredRoughness2)); -#ifdef RN_USE_SPECULAR - float specularTexture = texture(u_specularTexture, baseColorTexUv).a; - float specular = get_specularFactor(materialSID, 0) * specularTexture; - vec3 specularColorTexture = srgbToLinear(texture(u_specularTexture, baseColorTexUv).rgb); - vec3 specularColor = get_specularColorFactor(materialSID, 0) * specularColorTexture; -#else - float specular = 1.0; - vec3 specularColor = vec3(1.0, 1.0, 1.0); -#endif // RN_USE_SPECULAR + // Albedo + vec3 black = vec3(0.0); + vec3 albedo = mix(baseColor.rgb, black, metallic); + + // NdotV + float NdotV = saturateEpsilonToOne(dot(normal_inWorld, viewDirection)); + + #ifdef RN_USE_ANISOTROPY + float anisotropy = get_anisotropyStrength(materialSID, 0); + vec2 anisotropyRotation = get_anisotropyRotation(materialSID, 0); + vec2 direction = anisotropyRotation; + vec3 anisotropyTex = texture(u_anisotropyTexture, baseColorTexUv).rgb; + direction = anisotropyTex.rg * 2.0 - vec2(1.0); + direction = mat2(anisotropyRotation.x, anisotropyRotation.y, -anisotropyRotation.y, anisotropyRotation.x) * normalize(direction); + anisotropy *= anisotropyTex.b; + vec3 anisotropicT = normalize(TBN * vec3(direction, 0.0)); + vec3 anisotropicB = normalize(cross(geomNormal_inWorld, anisotropicT)); + float BdotV = dot(anisotropicB, viewDirection); + float TdotV = dot(anisotropicT, viewDirection); + #else + float anisotropy = 0.0; + vec3 anisotropicT = vec3(0.0, 0.0, 0.0); + vec3 anisotropicB = vec3(0.0, 0.0, 0.0); + float BdotV = 0.0; + float TdotV = 0.0; + #endif + + // Clearcoat + #ifdef RN_USE_CLEARCOAT + float clearcoatFactor = get_clearCoatFactor(materialSID, 0); + vec4 clearcoatTextureTransform = get_clearCoatTextureTransform(materialSID, 0); + float clearcoatTextureRotation = get_clearCoatTextureRotation(materialSID, 0); + int clearCoatTexcoordIndex = get_clearCoatTexcoordIndex(materialSID, 0); + vec2 clearCoatTexcoord = getTexcoord(clearCoatTexcoordIndex); + vec2 clearcoatTexUv = uvTransform(clearcoatTextureTransform.xy, clearcoatTextureTransform.zw, clearcoatTextureRotation, clearCoatTexcoord); + float clearcoatTexture = texture(u_clearCoatTexture, clearcoatTexUv).r; + float clearcoat = clearcoatFactor * clearcoatTexture; + #else + float clearcoat = 0.0; + #endif // RN_USE_CLEARCOAT + + // Transmission + #ifdef RN_USE_TRANSMISSION + float transmissionFactor = get_transmissionFactor(materialSID, 0); + float transmissionTexture = texture(u_transmissionTexture, baseColorTexUv).r; + float transmission = transmissionFactor * transmissionTexture; + // alpha *= transmission; + #else + float transmission = 0.0; + #endif // RN_USE_TRANSMISSION + + #ifdef RN_USE_SPECULAR + float specularTexture = texture(u_specularTexture, baseColorTexUv).a; + float specular = get_specularFactor(materialSID, 0) * specularTexture; + vec3 specularColorTexture = srgbToLinear(texture(u_specularTexture, baseColorTexUv).rgb); + vec3 specularColor = get_specularColorFactor(materialSID, 0) * specularColorTexture; + #else + float specular = 1.0; + vec3 specularColor = vec3(1.0, 1.0, 1.0); + #endif // RN_USE_SPECULAR // F0, F90 float ior = get_ior(materialSID, 0); @@ -295,87 +297,82 @@ void main () vec3 F0 = mix(dielectricSpecularF0, baseColor.rgb, metallic); vec3 F90 = mix(dielectricSpecularF90, vec3(1.0), metallic); - // Albedo - vec3 black = vec3(0.0); - vec3 albedo = mix(baseColor.rgb, black, metallic); + // Iridescence + #ifdef RN_USE_IRIDESCENCE + float iridescenceFactor = get_iridescenceFactor(materialSID, 0); + float iridescenceTexture = texture(u_iridescenceTexture, baseColorTexUv).r; + float iridescence = iridescenceFactor * iridescenceTexture; + float iridescenceIor = get_iridescenceIor(materialSID, 0); + float thicknessRatio = texture(u_iridescenceThicknessTexture, baseColorTexUv).r; + float iridescenceThicknessMinimum = get_iridescenceThicknessMinimum(materialSID, 0); + float iridescenceThicknessMaximum = get_iridescenceThicknessMaximum(materialSID, 0); + float iridescenceThickness = mix(iridescenceThicknessMinimum, iridescenceThicknessMaximum, thicknessRatio); + + vec3 iridescenceFresnel = calcIridescence(1.0, iridescenceIor, NdotV, iridescenceThickness, F0); + vec3 iridescenceF0 = Schlick_to_F0(iridescenceFresnel, NdotV); + + #else + float iridescence = 0.0; + vec3 iridescenceFresnel = vec3(0.0); + vec3 iridescenceF0 = F0; + #endif // RN_USE_IRIDESCENCE + + #ifdef RN_USE_CLEARCOAT + // Clearcoat + float clearcoatRoughnessFactor = get_clearCoatRoughnessFactor(materialSID, 0); + int clearCoatRoughnessTexcoordIndex = get_clearCoatRoughnessTexcoordIndex(materialSID, 0); + vec2 clearCoatRoughnessTexcoord = getTexcoord(clearCoatRoughnessTexcoordIndex); + vec4 clearcoatRoughnessTextureTransform = get_clearCoatRoughnessTextureTransform(materialSID, 0); + float clearcoatRoughnessTextureRotation = get_clearCoatRoughnessTextureRotation(materialSID, 0); + vec2 clearcoatRoughnessTexUv = uvTransform(clearcoatRoughnessTextureTransform.xy, clearcoatRoughnessTextureTransform.zw, clearcoatRoughnessTextureRotation, clearCoatRoughnessTexcoord); + float textureRoughnessTexture = texture(u_clearCoatRoughnessTexture, clearcoatRoughnessTexUv).g; + float clearcoatRoughness = clearcoatRoughnessFactor * textureRoughnessTexture; + + int clearCoatNormalTexcoordIndex = get_clearCoatNormalTexcoordIndex(materialSID, 0); + vec2 clearCoatNormalTexcoord = getTexcoord(clearCoatNormalTexcoordIndex); + vec4 clearcoatNormalTextureTransform = get_clearCoatNormalTextureTransform(materialSID, 0); + float clearcoatNormalTextureRotation = get_clearCoatNormalTextureRotation(materialSID, 0); + vec2 clearcoatNormalTexUv = uvTransform(clearcoatNormalTextureTransform.xy, clearcoatNormalTextureTransform.zw, clearcoatNormalTextureRotation, clearCoatNormalTexcoord); + vec3 textureNormal_tangent = texture(u_clearCoatNormalTexture, clearcoatNormalTexUv).xyz * vec3(2.0) - vec3(1.0); + vec3 clearcoatNormal_inWorld = normalize(TBN * textureNormal_tangent); + float VdotNc = saturateEpsilonToOne(dot(viewDirection, clearcoatNormal_inWorld)); + #else + float clearcoatRoughness = 0.0; + vec3 clearcoatNormal_inWorld = vec3(0.0); + float VdotNc = 0.0; + #endif // RN_USE_CLEARCOAT + + #ifdef RN_USE_VOLUME + // Volume + float thicknessFactor = get_thicknessFactor(materialSID, 0); + float thicknessTexture = texture(u_thicknessTexture, baseColorTexUv).g; + float attenuationDistance = get_attenuationDistance(materialSID, 0); + vec3 attenuationColor = get_attenuationColor(materialSID, 0); + float thickness = thicknessFactor * thicknessTexture; + #else + float thickness = 0.0; + vec3 attenuationColor = vec3(0.0); + float attenuationDistance = 0.000001; + #endif // RN_USE_VOLUME + + #ifdef RN_USE_SHEEN + // Sheen + vec3 sheenColorFactor = get_sheenColorFactor(materialSID, 0); + vec3 sheenColorTexture = texture(u_sheenColorTexture, baseColorTexUv).rgb; + float sheenRoughnessFactor = get_sheenRoughnessFactor(materialSID, 0); + float sheenRoughnessTexture = texture(u_sheenRoughnessTexture, baseColorTexUv).a; + vec3 sheenColor = sheenColorFactor * sheenColorTexture; + float sheenRoughness = clamp(sheenRoughnessFactor * sheenRoughnessTexture, 0.000001, 1.0); + float albedoSheenScalingNdotV = 1.0 - max3(sheenColor) * texture(u_sheenLutTexture, vec2(NdotV, sheenRoughness)).r; + #else + vec3 sheenColor = vec3(0.0); + float sheenRoughness = 0.000001; + float albedoSheenScalingNdotV = 1.0; + #endif // RN_USE_SHEEN rt0 = vec4(0.0, 0.0, 0.0, alpha); -// Iridescence -#ifdef RN_USE_IRIDESCENCE - float iridescenceFactor = get_iridescenceFactor(materialSID, 0); - float iridescenceTexture = texture(u_iridescenceTexture, baseColorTexUv).r; - float iridescence = iridescenceFactor * iridescenceTexture; - float iridescenceIor = get_iridescenceIor(materialSID, 0); - float thicknessRatio = texture(u_iridescenceThicknessTexture, baseColorTexUv).r; - float iridescenceThicknessMinimum = get_iridescenceThicknessMinimum(materialSID, 0); - float iridescenceThicknessMaximum = get_iridescenceThicknessMaximum(materialSID, 0); - float iridescenceThickness = mix(iridescenceThicknessMinimum, iridescenceThicknessMaximum, thicknessRatio); - - vec3 iridescenceFresnel = calcIridescence(1.0, iridescenceIor, NdotV, iridescenceThickness, F0); - vec3 iridescenceF0 = Schlick_to_F0(iridescenceFresnel, NdotV); - -#else - float iridescence = 0.0; - vec3 iridescenceFresnel = vec3(0.0); - vec3 iridescenceF0 = F0; -#endif // RN_USE_IRIDESCENCE - -#ifdef RN_USE_CLEARCOAT - // Clearcoat - float clearcoatRoughnessFactor = get_clearCoatRoughnessFactor(materialSID, 0); - int clearCoatRoughnessTexcoordIndex = get_clearCoatRoughnessTexcoordIndex(materialSID, 0); - vec2 clearCoatRoughnessTexcoord = getTexcoord(clearCoatRoughnessTexcoordIndex); - vec4 clearcoatRoughnessTextureTransform = get_clearCoatRoughnessTextureTransform(materialSID, 0); - float clearcoatRoughnessTextureRotation = get_clearCoatRoughnessTextureRotation(materialSID, 0); - vec2 clearcoatRoughnessTexUv = uvTransform(clearcoatRoughnessTextureTransform.xy, clearcoatRoughnessTextureTransform.zw, clearcoatRoughnessTextureRotation, clearCoatRoughnessTexcoord); - float textureRoughnessTexture = texture(u_clearCoatRoughnessTexture, clearcoatRoughnessTexUv).g; - float clearcoatRoughness = clearcoatRoughnessFactor * textureRoughnessTexture; - - int clearCoatNormalTexcoordIndex = get_clearCoatNormalTexcoordIndex(materialSID, 0); - vec2 clearCoatNormalTexcoord = getTexcoord(clearCoatNormalTexcoordIndex); - vec4 clearcoatNormalTextureTransform = get_clearCoatNormalTextureTransform(materialSID, 0); - float clearcoatNormalTextureRotation = get_clearCoatNormalTextureRotation(materialSID, 0); - vec2 clearcoatNormalTexUv = uvTransform(clearcoatNormalTextureTransform.xy, clearcoatNormalTextureTransform.zw, clearcoatNormalTextureRotation, clearCoatNormalTexcoord); - vec3 textureNormal_tangent = texture(u_clearCoatNormalTexture, clearcoatNormalTexUv).xyz * vec3(2.0) - vec3(1.0); - vec3 clearcoatNormal_inWorld = normalize(TBN * textureNormal_tangent); - float VdotNc = saturateEpsilonToOne(dot(viewDirection, clearcoatNormal_inWorld)); -#else - float clearcoatRoughness = 0.0; - vec3 clearcoatNormal_inWorld = vec3(0.0); - float VdotNc = 0.0; -#endif // RN_USE_CLEARCOAT - -#ifdef RN_USE_VOLUME - // Volume - float thicknessFactor = get_thicknessFactor(materialSID, 0); - float thicknessTexture = texture(u_thicknessTexture, baseColorTexUv).g; - float attenuationDistance = get_attenuationDistance(materialSID, 0); - vec3 attenuationColor = get_attenuationColor(materialSID, 0); - float thickness = thicknessFactor * thicknessTexture; -#else - float thickness = 0.0; - vec3 attenuationColor = vec3(0.0); - float attenuationDistance = 0.000001; -#endif // RN_USE_VOLUME - -#ifdef RN_USE_SHEEN - // Sheen - vec3 sheenColorFactor = get_sheenColorFactor(materialSID, 0); - vec3 sheenColorTexture = texture(u_sheenColorTexture, baseColorTexUv).rgb; - float sheenRoughnessFactor = get_sheenRoughnessFactor(materialSID, 0); - float sheenRoughnessTexture = texture(u_sheenRoughnessTexture, baseColorTexUv).a; - vec3 sheenColor = sheenColorFactor * sheenColorTexture; - float sheenRoughness = clamp(sheenRoughnessFactor * sheenRoughnessTexture, 0.000001, 1.0); - float albedoSheenScalingNdotV = 1.0 - max3(sheenColor) * texture(u_sheenLutTexture, vec2(NdotV, sheenRoughness)).r; -#else - vec3 sheenColor = vec3(0.0); - float sheenRoughness = 0.000001; - float albedoSheenScalingNdotV = 1.0; -#endif // RN_USE_SHEEN - // Lighting - vec3 diffuse = vec3(0.0, 0.0, 0.0); for (int i = 0; i < /* shaderity: @{Config.maxLightNumberInShader} */; i++) { if (i >= lightNumber) { break; @@ -387,20 +384,20 @@ void main () perceptualRoughness, metallic, F0, F90, ior, transmission, clearcoat, clearcoatRoughness, clearcoatNormal_inWorld, VdotNc, attenuationColor, attenuationDistance, - anisotropy, anisotropicT, anisotropicB, + anisotropy, anisotropicT, anisotropicB, BdotV, TdotV, sheenColor, sheenRoughness, albedoSheenScalingNdotV); } -#ifdef RN_USE_SHADOW_MAPPING - float bias = 0.001; - vec2 shadowCoord = v_shadowCoord.xy / v_shadowCoord.w; - float shadowContribusion = 1.0; - if (shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0) { - shadowContribusion = varianceShadowContribution(shadowCoord, (v_shadowCoord.z - bias)/v_shadowCoord.w); - } - // rt0.rgb = rt0.rgb * (0.5 + shadowContribusion * 0.5); - rt0.rgb = rt0.rgb * shadowContribusion; -#endif + #ifdef RN_USE_SHADOW_MAPPING + float bias = 0.001; + vec2 shadowCoord = v_shadowCoord.xy / v_shadowCoord.w; + float shadowContribusion = 1.0; + if (shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0) { + shadowContribusion = varianceShadowContribution(shadowCoord, (v_shadowCoord.z - bias)/v_shadowCoord.w); + } + // rt0.rgb = rt0.rgb * (0.5 + shadowContribusion * 0.5); + rt0.rgb = rt0.rgb * shadowContribusion; + #endif vec3 ibl = IBLContribution(materialSID, normal_inWorld, NdotV, viewDirection, albedo, F0, perceptualRoughness, clearcoatRoughness, clearcoatNormal_inWorld, diff --git a/src/webgl/shaderity_shaders/common/pbrDefinition.glsl b/src/webgl/shaderity_shaders/common/pbrDefinition.glsl index 649e855bb..8789de2c7 100644 --- a/src/webgl/shaderity_shaders/common/pbrDefinition.glsl +++ b/src/webgl/shaderity_shaders/common/pbrDefinition.glsl @@ -552,6 +552,8 @@ vec3 gltfBRDF( float anisotropy, vec3 anisotropicT, vec3 anisotropicB, + float BdotV, + float TdotV, vec3 sheenColor, float sheenRoughness, float albedoSheenScalingNdotV