@luma.gl/shaders 10.0.0-alpha.10 → 10.0.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/dist.dev.js +1776 -58
  2. package/dist/dist.min.js +1394 -147
  3. package/dist/index.cjs +35 -0
  4. package/dist/index.cjs.map +3 -3
  5. package/dist/index.d.ts +17 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +9 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/modules/lighting/clustered-light-grid/clustered-light-grid.cjs +40 -0
  10. package/dist/modules/lighting/clustered-light-grid/clustered-light-grid.d.ts +6 -0
  11. package/dist/modules/lighting/clustered-light-grid/clustered-light-grid.d.ts.map +1 -0
  12. package/dist/modules/lighting/clustered-light-grid/clustered-light-grid.js +15 -0
  13. package/dist/modules/lighting/clustered-light-grid/clustered-light-grid.js.map +1 -0
  14. package/dist/modules/lighting/contact-shadow/contact-shadow.cjs +348 -0
  15. package/dist/modules/lighting/contact-shadow/contact-shadow.d.ts +188 -0
  16. package/dist/modules/lighting/contact-shadow/contact-shadow.d.ts.map +1 -0
  17. package/dist/modules/lighting/contact-shadow/contact-shadow.js +307 -0
  18. package/dist/modules/lighting/contact-shadow/contact-shadow.js.map +1 -0
  19. package/dist/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.cjs +87 -0
  20. package/dist/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.d.ts +21 -0
  21. package/dist/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.d.ts.map +1 -0
  22. package/dist/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.js +61 -0
  23. package/dist/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.js.map +1 -0
  24. package/dist/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.cjs +87 -0
  25. package/dist/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.d.ts +21 -0
  26. package/dist/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.d.ts.map +1 -0
  27. package/dist/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.js +61 -0
  28. package/dist/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.js.map +1 -0
  29. package/dist/modules/lighting/pbr-material/pbr-material-glsl.cjs +33 -11
  30. package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts +2 -2
  31. package/dist/modules/lighting/pbr-material/pbr-material-glsl.d.ts.map +1 -1
  32. package/dist/modules/lighting/pbr-material/pbr-material-glsl.js +33 -11
  33. package/dist/modules/lighting/pbr-material/pbr-material-glsl.js.map +1 -1
  34. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.cjs +33 -11
  35. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts +1 -1
  36. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.d.ts.map +1 -1
  37. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js +33 -11
  38. package/dist/modules/lighting/pbr-material/pbr-material-wgsl.js.map +1 -1
  39. package/dist/modules/lighting/pbr-material/pbr-material.d.ts +3 -3
  40. package/dist/modules/lighting/pbr-shadow/pbr-shadow.cjs +97 -0
  41. package/dist/modules/lighting/pbr-shadow/pbr-shadow.d.ts +15 -0
  42. package/dist/modules/lighting/pbr-shadow/pbr-shadow.d.ts.map +1 -0
  43. package/dist/modules/lighting/pbr-shadow/pbr-shadow.js +69 -0
  44. package/dist/modules/lighting/pbr-shadow/pbr-shadow.js.map +1 -0
  45. package/dist/modules/lighting/pbr-surface/pbr-surface.cjs +114 -0
  46. package/dist/modules/lighting/pbr-surface/pbr-surface.d.ts +15 -0
  47. package/dist/modules/lighting/pbr-surface/pbr-surface.d.ts.map +1 -0
  48. package/dist/modules/lighting/pbr-surface/pbr-surface.js +88 -0
  49. package/dist/modules/lighting/pbr-surface/pbr-surface.js.map +1 -0
  50. package/dist/modules/lighting/prefiltered-environment/prefiltered-environment.cjs +379 -0
  51. package/dist/modules/lighting/prefiltered-environment/prefiltered-environment.d.ts +41 -0
  52. package/dist/modules/lighting/prefiltered-environment/prefiltered-environment.d.ts.map +1 -0
  53. package/dist/modules/lighting/prefiltered-environment/prefiltered-environment.js +345 -0
  54. package/dist/modules/lighting/prefiltered-environment/prefiltered-environment.js.map +1 -0
  55. package/dist/modules/lighting/shadow/shadow-glsl.cjs +228 -0
  56. package/dist/modules/lighting/shadow/shadow-glsl.d.ts +3 -0
  57. package/dist/modules/lighting/shadow/shadow-glsl.d.ts.map +1 -0
  58. package/dist/modules/lighting/shadow/shadow-glsl.js +204 -0
  59. package/dist/modules/lighting/shadow/shadow-glsl.js.map +1 -0
  60. package/dist/modules/lighting/shadow/shadow-types.cjs +15 -0
  61. package/dist/modules/lighting/shadow/shadow-types.d.ts +63 -0
  62. package/dist/modules/lighting/shadow/shadow-types.d.ts.map +1 -0
  63. package/dist/modules/lighting/shadow/shadow-types.js +5 -0
  64. package/dist/modules/lighting/shadow/shadow-types.js.map +1 -0
  65. package/dist/modules/lighting/shadow/shadow.cjs +458 -0
  66. package/dist/modules/lighting/shadow/shadow.d.ts +117 -0
  67. package/dist/modules/lighting/shadow/shadow.d.ts.map +1 -0
  68. package/dist/modules/lighting/shadow/shadow.js +450 -0
  69. package/dist/modules/lighting/shadow/shadow.js.map +1 -0
  70. package/dist/modules/lighting/unlit-material/unlit-material.cjs +60 -0
  71. package/dist/modules/lighting/unlit-material/unlit-material.d.ts +9 -0
  72. package/dist/modules/lighting/unlit-material/unlit-material.d.ts.map +1 -0
  73. package/dist/modules/lighting/unlit-material/unlit-material.js +40 -0
  74. package/dist/modules/lighting/unlit-material/unlit-material.js.map +1 -0
  75. package/package.json +3 -3
  76. package/src/index.ts +48 -0
  77. package/src/modules/lighting/clustered-light-grid/clustered-light-grid.ts +17 -0
  78. package/src/modules/lighting/contact-shadow/contact-shadow.ts +365 -0
  79. package/src/modules/lighting/pbr-ambient-occlusion/pbr-ambient-occlusion.ts +78 -0
  80. package/src/modules/lighting/pbr-contact-shadow/pbr-contact-shadow.ts +78 -0
  81. package/src/modules/lighting/pbr-material/pbr-material-glsl.ts +33 -11
  82. package/src/modules/lighting/pbr-material/pbr-material-wgsl.ts +33 -11
  83. package/src/modules/lighting/pbr-shadow/pbr-shadow.ts +85 -0
  84. package/src/modules/lighting/pbr-surface/pbr-surface.ts +103 -0
  85. package/src/modules/lighting/prefiltered-environment/prefiltered-environment.ts +370 -0
  86. package/src/modules/lighting/shadow/shadow-glsl.ts +204 -0
  87. package/src/modules/lighting/shadow/shadow-types.ts +68 -0
  88. package/src/modules/lighting/shadow/shadow.ts +536 -0
  89. package/src/modules/lighting/unlit-material/unlit-material.ts +44 -0
@@ -1,3 +1,3 @@
1
- export declare const vs = "out vec3 pbr_vPosition;\nout vec2 pbr_vUV0;\nout vec2 pbr_vUV1;\n\n#ifdef HAS_NORMALS\n# ifdef HAS_TANGENTS\nout mat3 pbr_vTBN;\n# else\nout vec3 pbr_vNormal;\n# endif\n#endif\n\nvoid pbr_setPositionNormalTangentUV(\n vec4 position,\n vec4 normal,\n vec4 tangent,\n vec2 uv0,\n vec2 uv1\n)\n{\n vec4 pos = pbrProjection.modelMatrix * position;\n pbr_vPosition = vec3(pos.xyz) / pos.w;\n\n#ifdef HAS_NORMALS\n#ifdef HAS_TANGENTS\n vec3 normalW = normalize(vec3(pbrProjection.normalMatrix * vec4(normal.xyz, 0.0)));\n vec3 tangentW = normalize(vec3(pbrProjection.modelMatrix * vec4(tangent.xyz, 0.0)));\n vec3 bitangentW = cross(normalW, tangentW) * tangent.w;\n pbr_vTBN = mat3(tangentW, bitangentW, normalW);\n#else // HAS_TANGENTS != 1\n pbr_vNormal = normalize(vec3(pbrProjection.modelMatrix * vec4(normal.xyz, 0.0)));\n#endif\n#endif\n\n#ifdef HAS_UV\n pbr_vUV0 = uv0;\n#else\n pbr_vUV0 = vec2(0.,0.);\n#endif\n\n pbr_vUV1 = uv1;\n}\n";
2
- export declare const fs = "precision highp float;\n\nlayout(std140) uniform pbrMaterialUniforms {\n // Material is unlit\n bool unlit;\n\n // Base color map\n bool baseColorMapEnabled;\n vec4 baseColorFactor;\n\n bool normalMapEnabled; \n float normalScale; // #ifdef HAS_NORMALMAP\n\n bool emissiveMapEnabled;\n vec3 emissiveFactor; // #ifdef HAS_EMISSIVEMAP\n\n vec2 metallicRoughnessValues;\n bool metallicRoughnessMapEnabled;\n\n bool occlusionMapEnabled;\n float occlusionStrength; // #ifdef HAS_OCCLUSIONMAP\n \n bool alphaCutoffEnabled;\n float alphaCutoff; // #ifdef ALPHA_CUTOFF\n\n vec3 specularColorFactor;\n float specularIntensityFactor;\n bool specularColorMapEnabled;\n bool specularIntensityMapEnabled;\n\n float ior;\n\n float transmissionFactor;\n bool transmissionMapEnabled;\n\n float thicknessFactor;\n float attenuationDistance;\n vec3 attenuationColor;\n\n float clearcoatFactor;\n float clearcoatRoughnessFactor;\n bool clearcoatMapEnabled;\n bool clearcoatRoughnessMapEnabled;\n\n vec3 sheenColorFactor;\n float sheenRoughnessFactor;\n bool sheenColorMapEnabled;\n bool sheenRoughnessMapEnabled;\n\n float iridescenceFactor;\n float iridescenceIor;\n vec2 iridescenceThicknessRange;\n bool iridescenceMapEnabled;\n\n float anisotropyStrength;\n float anisotropyRotation;\n vec2 anisotropyDirection;\n bool anisotropyMapEnabled;\n\n float emissiveStrength;\n float dispersion;\n \n // IBL\n bool IBLenabled;\n vec2 scaleIBLAmbient; // #ifdef USE_IBL\n \n // debugging flags used for shader output of intermediate PBR variables\n // #ifdef PBR_DEBUG\n vec4 scaleDiffBaseMR;\n vec4 scaleFGDSpec;\n // #endif\n\n int baseColorUVSet;\n mat3 baseColorUVTransform;\n int metallicRoughnessUVSet;\n mat3 metallicRoughnessUVTransform;\n int normalUVSet;\n mat3 normalUVTransform;\n int occlusionUVSet;\n mat3 occlusionUVTransform;\n int emissiveUVSet;\n mat3 emissiveUVTransform;\n int specularColorUVSet;\n mat3 specularColorUVTransform;\n int specularIntensityUVSet;\n mat3 specularIntensityUVTransform;\n int transmissionUVSet;\n mat3 transmissionUVTransform;\n int thicknessUVSet;\n mat3 thicknessUVTransform;\n int clearcoatUVSet;\n mat3 clearcoatUVTransform;\n int clearcoatRoughnessUVSet;\n mat3 clearcoatRoughnessUVTransform;\n int clearcoatNormalUVSet;\n mat3 clearcoatNormalUVTransform;\n int sheenColorUVSet;\n mat3 sheenColorUVTransform;\n int sheenRoughnessUVSet;\n mat3 sheenRoughnessUVTransform;\n int iridescenceUVSet;\n mat3 iridescenceUVTransform;\n int iridescenceThicknessUVSet;\n mat3 iridescenceThicknessUVTransform;\n int anisotropyUVSet;\n mat3 anisotropyUVTransform;\n\n float bumpFactor;\n bool bumpMapEnabled;\n float diffuseTransmissionFactor;\n bool diffuseTransmissionMapEnabled;\n vec3 diffuseTransmissionColorFactor;\n bool diffuseTransmissionColorMapEnabled;\n vec3 multiscatterColorFactor;\n bool multiscatterColorMapEnabled;\n float scatterAnisotropy;\n\n int bumpUVSet;\n mat3 bumpUVTransform;\n int diffuseTransmissionUVSet;\n mat3 diffuseTransmissionUVTransform;\n int diffuseTransmissionColorUVSet;\n mat3 diffuseTransmissionColorUVTransform;\n int multiscatterColorUVSet;\n mat3 multiscatterColorUVTransform;\n bool lightmapMapEnabled;\n float lightmapIntensity;\n int lightmapUVSet;\n mat3 lightmapUVTransform;\n float scatterStrengthFactor;\n} pbrMaterial;\n\n// Samplers\n#ifdef HAS_BASECOLORMAP\nuniform sampler2D pbr_baseColorSampler;\n#endif\n#ifdef HAS_NORMALMAP\nuniform sampler2D pbr_normalSampler;\n#endif\n#ifdef HAS_EMISSIVEMAP\nuniform sampler2D pbr_emissiveSampler;\n#endif\n#ifdef HAS_LIGHTMAP\nuniform sampler2D pbr_lightmapSampler;\n#endif\n#ifdef HAS_METALROUGHNESSMAP\nuniform sampler2D pbr_metallicRoughnessSampler;\n#endif\n#ifdef HAS_OCCLUSIONMAP\nuniform sampler2D pbr_occlusionSampler;\n#endif\n#ifdef HAS_SPECULARCOLORMAP\nuniform sampler2D pbr_specularColorSampler;\n#endif\n#ifdef HAS_SPECULARINTENSITYMAP\nuniform sampler2D pbr_specularIntensitySampler;\n#endif\n#ifdef HAS_TRANSMISSIONMAP\nuniform sampler2D pbr_transmissionSampler;\n#endif\n#ifdef HAS_THICKNESSMAP\nuniform sampler2D pbr_thicknessSampler;\n#endif\n#ifdef HAS_CLEARCOATMAP\nuniform sampler2D pbr_clearcoatSampler;\n#endif\n#ifdef HAS_CLEARCOATROUGHNESSMAP\nuniform sampler2D pbr_clearcoatRoughnessSampler;\n#endif\n#ifdef HAS_CLEARCOATNORMALMAP\nuniform sampler2D pbr_clearcoatNormalSampler;\n#endif\n#ifdef HAS_SHEENCOLORMAP\nuniform sampler2D pbr_sheenColorSampler;\n#endif\n#ifdef HAS_SHEENROUGHNESSMAP\nuniform sampler2D pbr_sheenRoughnessSampler;\n#endif\n#ifdef HAS_IRIDESCENCEMAP\nuniform sampler2D pbr_iridescenceSampler;\n#endif\n#ifdef HAS_IRIDESCENCETHICKNESSMAP\nuniform sampler2D pbr_iridescenceThicknessSampler;\n#endif\n#ifdef HAS_ANISOTROPYMAP\nuniform sampler2D pbr_anisotropySampler;\n#endif\n#ifdef HAS_BUMPMAP\nuniform sampler2D pbr_bumpSampler;\n#endif\n#ifdef HAS_DIFFUSETRANSMISSIONMAP\nuniform sampler2D pbr_diffuseTransmissionSampler;\n#endif\n#ifdef HAS_DIFFUSETRANSMISSIONCOLORMAP\nuniform sampler2D pbr_diffuseTransmissionColorSampler;\n#endif\n#ifdef HAS_MULTISCATTERCOLORMAP\nuniform sampler2D pbr_multiscatterColorSampler;\n#endif\n// Inputs from vertex shader\n\nin vec3 pbr_vPosition;\nin vec2 pbr_vUV0;\nin vec2 pbr_vUV1;\n\n#ifdef HAS_NORMALS\n#ifdef HAS_TANGENTS\nin mat3 pbr_vTBN;\n#else\nin vec3 pbr_vNormal;\n#endif\n#endif\n\n// Encapsulate the various inputs used by the various functions in the shading equation\n// We store values in this struct to simplify the integration of alternative implementations\n// of the shading terms, outlined in the Readme.MD Appendix.\nstruct PBRInfo {\n float NdotL; // cos angle between normal and light direction\n float NdotV; // cos angle between normal and view direction\n float NdotH; // cos angle between normal and half vector\n float LdotH; // cos angle between light direction and half vector\n float VdotH; // cos angle between view direction and half vector\n float perceptualRoughness; // roughness value, as authored by the model creator (input to shader)\n float metalness; // metallic value at the surface\n vec3 reflectance0; // full reflectance color (normal incidence angle)\n vec3 reflectance90; // reflectance color at grazing angle\n float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2])\n vec3 diffuseColor; // color contribution from diffuse lighting\n vec3 specularColor; // color contribution from specular lighting\n vec3 n; // normal at surface point\n vec3 v; // vector from surface point to camera\n vec3 l; // direction from the surface toward the current light\n vec3 h; // half vector between the current light and camera\n};\n\nconst float M_PI = 3.141592653589793;\nconst float c_MinRoughness = 0.04;\n\n// Widen sub-pixel specular lobes using the screen-space normal footprint.\n// This is geometric specular antialiasing: the normal variance is converted\n// into an additional squared perceptual roughness before evaluating BRDFs.\nfloat widenSpecularRoughness(float perceptualRoughness, vec3 normal)\n{\n vec3 normalDerivativeX = dFdx(normal);\n vec3 normalDerivativeY = dFdy(normal);\n float normalVariance =\n dot(normalDerivativeX, normalDerivativeX) +\n dot(normalDerivativeY, normalDerivativeY);\n float kernelRoughnessSquared = min(2.0 * normalVariance, 1.0);\n return clamp(\n sqrt(perceptualRoughness * perceptualRoughness + kernelRoughnessSquared),\n c_MinRoughness,\n 1.0\n );\n}\n\nvec3 calculateFinalColor(PBRInfo pbrInfo, vec3 lightColor);\n\nvec4 SRGBtoLINEAR(vec4 srgbIn)\n{\n#ifdef MANUAL_SRGB\n#ifdef SRGB_FAST_APPROXIMATION\n vec3 linOut = pow(srgbIn.xyz,vec3(2.2));\n#else // SRGB_FAST_APPROXIMATION\n vec3 bLess = step(vec3(0.04045),srgbIn.xyz);\n vec3 linOut = mix( srgbIn.xyz/vec3(12.92), pow((srgbIn.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), bLess );\n#endif //SRGB_FAST_APPROXIMATION\n return vec4(linOut,srgbIn.w);;\n#else //MANUAL_SRGB\n return srgbIn;\n#endif //MANUAL_SRGB\n}\n\nvec2 getMaterialUV(int uvSet, mat3 uvTransform)\n{\n vec2 baseUV = uvSet == 1 ? pbr_vUV1 : pbr_vUV0;\n return (uvTransform * vec3(baseUV, 1.0)).xy;\n}\n\n// Build the tangent basis from interpolated attributes or screen-space derivatives.\nmat3 getTBN(vec2 uv)\n{\n#ifndef HAS_TANGENTS\n vec3 pos_dx = dFdx(pbr_vPosition);\n vec3 pos_dy = dFdy(pbr_vPosition);\n vec3 tex_dx = dFdx(vec3(uv, 0.0));\n vec3 tex_dy = dFdy(vec3(uv, 0.0));\n vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);\n\n#ifdef HAS_NORMALS\n vec3 ng = normalize(pbr_vNormal);\n#else\n vec3 ng = cross(pos_dx, pos_dy);\n#endif\n\n t = normalize(t - ng * dot(ng, t));\n vec3 b = normalize(cross(ng, t));\n mat3 tbn = mat3(t, b, ng);\n#else // HAS_TANGENTS\n mat3 tbn = pbr_vTBN;\n#endif\n\n#ifdef DOUBLE_SIDED\n#ifdef HAS_NORMALS\n // Derivative normals already face the viewer; only flip an authored basis.\n if (!gl_FrontFacing) tbn = mat3(-tbn[0], -tbn[1], -tbn[2]);\n#endif\n#endif\n return tbn;\n}\n\n// Find the normal for this fragment, pulling either from a predefined normal map\n// or from the interpolated mesh normal and tangent attributes.\nvec3 getMappedNormal(sampler2D normalSampler, mat3 tbn, float normalScale, vec2 uv)\n{\n vec3 n = texture(normalSampler, uv).rgb;\n return normalize(tbn * ((2.0 * n - 1.0) * vec3(normalScale, normalScale, 1.0)));\n}\n\nvec3 getNormal(mat3 tbn, vec2 uv)\n{\n#ifdef HAS_NORMALMAP\n vec3 n = getMappedNormal(pbr_normalSampler, tbn, pbrMaterial.normalScale, uv);\n#else\n // The tbn matrix is linearly interpolated, so we need to re-normalize\n vec3 n = normalize(tbn[2].xyz);\n#endif\n\n#ifdef HAS_BUMPMAP\n vec2 bumpUV = getMaterialUV(pbrMaterial.bumpUVSet, pbrMaterial.bumpUVTransform);\n vec2 bumpTexelSize = 1.0 / vec2(textureSize(pbr_bumpSampler, 0));\n float bumpHeight = texture(pbr_bumpSampler, bumpUV).r;\n vec2 bumpGradient = vec2(\n texture(pbr_bumpSampler, bumpUV + vec2(bumpTexelSize.x, 0.0)).r - bumpHeight,\n texture(pbr_bumpSampler, bumpUV + vec2(0.0, bumpTexelSize.y)).r - bumpHeight\n );\n n = normalize(n - pbrMaterial.bumpFactor *\n (tbn[0] * bumpGradient.x + tbn[1] * bumpGradient.y));\n#endif\n\n return n;\n}\n\nvec3 getClearcoatNormal(mat3 tbn, vec3 baseNormal, vec2 uv)\n{\n#ifdef HAS_CLEARCOATNORMALMAP\n return getMappedNormal(pbr_clearcoatNormalSampler, tbn, 1.0, uv);\n#else\n return baseNormal;\n#endif\n}\n\n// Calculation of the lighting contribution from an optional Image Based Light source.\n// Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1].\n// See our README.md on Environment Maps [3] for additional discussion.\n#ifdef USE_IBL\nvec3 getIBLContribution(PBRInfo pbrInfo, vec3 n, vec3 reflection)\n{\n#ifdef USE_SCENE_ENVIRONMENT\n float maximumMipLevel = max(pbrScene.environmentMipCount - 1.0, 0.0);\n float rotationSine = sin(pbrScene.environmentRotation);\n float rotationCosine = cos(pbrScene.environmentRotation);\n mat2 environmentRotation = mat2(rotationCosine, rotationSine, -rotationSine, rotationCosine);\n vec3 environmentNormal = vec3(environmentRotation * n.xz, n.y).xzy;\n vec3 environmentReflection = vec3(environmentRotation * reflection.xz, reflection.y).xzy;\n#else\n float maximumMipLevel = 9.0;\n vec3 environmentNormal = n;\n vec3 environmentReflection = reflection;\n#endif\n float lod = pbrInfo.perceptualRoughness * maximumMipLevel;\n // retrieve a scale and bias to F0. See [1], Figure 3\n vec4 brdfSample = texture(pbr_brdfLUT,\n vec2(pbrInfo.NdotV, 1.0 - pbrInfo.perceptualRoughness));\n vec4 diffuseSample = texture(pbr_diffuseEnvSampler, environmentNormal);\n\n#ifdef USE_TEX_LOD\n vec4 specularSample = textureLod(pbr_specularEnvSampler, environmentReflection, lod);\n#else\n vec4 specularSample = texture(pbr_specularEnvSampler, environmentReflection);\n#endif\n\n#ifdef USE_SCENE_ENVIRONMENT\n vec3 brdf = brdfSample.rgb;\n vec3 diffuseLight = diffuseSample.rgb;\n vec3 specularLight = specularSample.rgb;\n#else\n vec3 brdf = SRGBtoLINEAR(brdfSample).rgb;\n vec3 diffuseLight = SRGBtoLINEAR(diffuseSample).rgb;\n vec3 specularLight = SRGBtoLINEAR(specularSample).rgb;\n#endif\n\n vec3 diffuse = diffuseLight * pbrInfo.diffuseColor;\n vec3 specular = specularLight * (pbrInfo.specularColor * brdf.x + brdf.y);\n\n // For presentation, this allows us to disable IBL terms\n diffuse *= pbrMaterial.scaleIBLAmbient.x;\n specular *= pbrMaterial.scaleIBLAmbient.y;\n\n#ifdef USE_SCENE_ENVIRONMENT\n return (diffuse + specular) * max(pbrScene.environmentIntensity, 0.0);\n#else\n return diffuse + specular;\n#endif\n}\n#endif\n\n// Basic Lambertian diffuse\n// Implementation from Lambert's Photometria https://archive.org/details/lambertsphotome00lambgoog\n// See also [1], Equation 1\nvec3 diffuse(PBRInfo pbrInfo)\n{\n return pbrInfo.diffuseColor / M_PI;\n}\n\n// The following equation models the Fresnel reflectance term of the spec equation (aka F())\n// Implementation of fresnel from [4], Equation 15\nvec3 specularReflection(PBRInfo pbrInfo)\n{\n return pbrInfo.reflectance0 +\n (pbrInfo.reflectance90 - pbrInfo.reflectance0) *\n pow(clamp(1.0 - pbrInfo.VdotH, 0.0, 1.0), 5.0);\n}\n\n// This calculates the specular geometric attenuation (aka G()),\n// where rougher material will reflect less light back to the viewer.\n// This implementation is based on [1] Equation 4, and we adopt their modifications to\n// alphaRoughness as input as originally proposed in [2].\nfloat geometricOcclusion(PBRInfo pbrInfo)\n{\n float NdotL = pbrInfo.NdotL;\n float NdotV = pbrInfo.NdotV;\n float r = pbrInfo.alphaRoughness;\n\n float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));\n float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV)));\n return attenuationL * attenuationV;\n}\n\n// The following equation(s) model the distribution of microfacet normals across\n// the area being drawn (aka D())\n// Implementation from \"Average Irregularity Representation of a Roughened Surface\n// for Ray Reflection\" by T. S. Trowbridge, and K. P. Reitz\n// Follows the distribution function recommended in the SIGGRAPH 2013 course notes\n// from EPIC Games [1], Equation 3.\nfloat microfacetDistribution(PBRInfo pbrInfo)\n{\n float roughnessSq = pbrInfo.alphaRoughness * pbrInfo.alphaRoughness;\n float f = (pbrInfo.NdotH * roughnessSq - pbrInfo.NdotH) * pbrInfo.NdotH + 1.0;\n return roughnessSq / (M_PI * f * f);\n}\n\nfloat maxComponent(vec3 value)\n{\n return max(max(value.r, value.g), value.b);\n}\n\nfloat getDielectricF0(float ior)\n{\n float clampedIor = max(ior, 1.0);\n float ratio = (clampedIor - 1.0) / (clampedIor + 1.0);\n return ratio * ratio;\n}\n\nvec2 normalizeDirection(vec2 direction)\n{\n float directionLength = length(direction);\n return directionLength > 0.0001 ? direction / directionLength : vec2(1.0, 0.0);\n}\n\nvec2 rotateDirection(vec2 direction, float rotation)\n{\n float s = sin(rotation);\n float c = cos(rotation);\n return vec2(direction.x * c - direction.y * s, direction.x * s + direction.y * c);\n}\n\nvec3 encodeLinearSRGB(vec3 linearColor)\n{\n vec3 positiveColor = max(linearColor, vec3(0.0));\n return mix(\n positiveColor * 12.92,\n 1.055 * pow(positiveColor, vec3(1.0 / 2.4)) - 0.055,\n greaterThan(positiveColor, vec3(0.0031308))\n );\n}\n\nvec3 toneMapKhronosPBRNeutral(vec3 color)\n{\n const float startCompression = 0.76;\n float darkestChannel = min(color.r, min(color.g, color.b));\n float offset = darkestChannel < 0.08\n ? darkestChannel - 6.25 * darkestChannel * darkestChannel\n : 0.04;\n color -= vec3(offset);\n\n float peak = maxComponent(color);\n if (peak < startCompression) {\n return color;\n }\n\n float compressionRange = 1.0 - startCompression;\n float compressedPeak = 1.0 - compressionRange * compressionRange /\n (peak + compressionRange - startCompression);\n color *= compressedPeak / max(peak, 0.0001);\n float desaturation = 1.0 - 1.0 / (0.15 * (peak - compressedPeak) + 1.0);\n return mix(color, vec3(compressedPeak), desaturation);\n}\n\nvec3 applySceneColorManagement(vec3 sceneColor)\n{\n#ifdef USE_SCENE_COLOR_MANAGEMENT\n vec3 color = max(sceneColor, vec3(0.0)) * max(pbrScene.exposure, 0.0);\n if (pbrScene.toneMapMode == 1) {\n color /= vec3(1.0) + color;\n } else if (pbrScene.toneMapMode == 2) {\n color = toneMapKhronosPBRNeutral(color);\n } else if (pbrScene.toneMapMode == 3) {\n color = clamp(\n (color * (2.51 * color + 0.03)) / (color * (2.43 * color + 0.59) + 0.14),\n vec3(0.0),\n vec3(1.0)\n );\n }\n return pbrScene.outputEncoding == 0 ? color : encodeLinearSRGB(color);\n#else\n return pow(max(sceneColor, vec3(0.0)), vec3(1.0 / 2.2));\n#endif\n}\n\nfloat dielectricSchlick(float reflectance, float cosine)\n{\n return reflectance + (1.0 - reflectance) * pow(clamp(1.0 - cosine, 0.0, 1.0), 5.0);\n}\n\nvec3 evaluateIridescenceSensitivity(float opticalPathDifference, vec3 phaseShift)\n{\n float phase = 2.0 * M_PI * opticalPathDifference * 1.0e-9;\n vec3 sensitivity = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13);\n vec3 position = vec3(1.6810e6, 1.7953e6, 2.2084e6);\n vec3 variance = vec3(4.3278e9, 9.3046e9, 6.6121e9);\n vec3 xyz = sensitivity * sqrt(2.0 * M_PI * variance) *\n cos(position * phase + phaseShift) * exp(-phase * phase * variance);\n xyz.x += 9.7470e-14 * sqrt(2.0 * M_PI * 4.5282e9) *\n cos(2.2399e6 * phase + phaseShift.x) * exp(-4.5282e9 * phase * phase);\n xyz /= 1.0685e-7;\n return mat3(\n 3.2404542, -0.9692660, 0.0556434,\n -1.5371385, 1.8760108, -0.2040259,\n -0.4985314, 0.0415560, 1.0572252\n ) * xyz;\n}\n\nvec3 getIridescenceTint(float iridescence, float thickness, float NdotV, vec3 baseReflectance)\n{\n if (iridescence <= 0.0 || thickness <= 0.0) {\n return baseReflectance;\n }\n\n float filmIor = max(pbrMaterial.iridescenceIor, 1.0);\n float sineSquared = (1.0 - NdotV * NdotV) / (filmIor * filmIor);\n float cosineSquared = 1.0 - sineSquared;\n if (cosineSquared <= 0.0) {\n return mix(baseReflectance, vec3(1.0), iridescence);\n }\n float filmCosine = sqrt(cosineSquared);\n float firstInterfaceReflectance = dielectricSchlick(getDielectricF0(filmIor), NdotV);\n float transmittedEnergy = 1.0 - firstInterfaceReflectance;\n\n vec3 baseIor = (vec3(1.0) + sqrt(clamp(baseReflectance, vec3(0.0), vec3(0.9999)))) /\n (vec3(1.0) - sqrt(clamp(baseReflectance, vec3(0.0), vec3(0.9999))));\n vec3 secondInterfaceF0 = (baseIor - vec3(filmIor)) / (baseIor + vec3(filmIor));\n secondInterfaceF0 *= secondInterfaceF0;\n vec3 secondInterfaceReflectance = secondInterfaceF0 +\n (vec3(1.0) - secondInterfaceF0) * pow(1.0 - filmCosine, 5.0);\n vec3 phaseShift = vec3(M_PI);\n phaseShift += mix(vec3(0.0), vec3(M_PI), lessThan(baseIor, vec3(filmIor)));\n float opticalPathDifference = 2.0 * filmIor * thickness * filmCosine;\n vec3 combinedReflectance = clamp(\n firstInterfaceReflectance * secondInterfaceReflectance,\n vec3(0.00001),\n vec3(0.9999)\n );\n vec3 recurringAmplitude = sqrt(combinedReflectance);\n vec3 interfaceResponse = transmittedEnergy * transmittedEnergy * secondInterfaceReflectance /\n (vec3(1.0) - combinedReflectance);\n vec3 reflectedSpectrum = vec3(firstInterfaceReflectance) + interfaceResponse;\n vec3 harmonicAmplitude = interfaceResponse - vec3(transmittedEnergy);\n for (int harmonic = 1; harmonic <= 2; harmonic++) {\n harmonicAmplitude *= recurringAmplitude;\n reflectedSpectrum += harmonicAmplitude * 2.0 * evaluateIridescenceSensitivity(\n float(harmonic) * opticalPathDifference,\n float(harmonic) * phaseShift\n );\n }\n return mix(baseReflectance, clamp(reflectedSpectrum, vec3(0.0), vec3(1.0)), iridescence);\n}\n\nvec3 getVolumeAttenuation(float thickness)\n{\n if (thickness <= 0.0) {\n return vec3(1.0);\n }\n\n vec3 attenuationCoefficient =\n -log(max(pbrMaterial.attenuationColor, vec3(0.0001))) /\n max(pbrMaterial.attenuationDistance, 0.0001);\n return exp(-attenuationCoefficient * thickness);\n}\n\n// KHR_materials_volume_scatter is an active draft. This evaluates a local,\n// thickness-aware single-scattering approximation rather than random walk.\nvec3 getDiffuseTransmissionAttenuation(\n PBRInfo pbrInfo,\n vec3 multiscatterColor,\n float thickness\n)\n{\n vec3 volumeAttenuation = getVolumeAttenuation(thickness);\n float scatteringStrength = maxComponent(multiscatterColor);\n if (thickness <= 0.0 || scatteringStrength <= 0.0001) {\n return volumeAttenuation;\n }\n\n float anisotropy = clamp(pbrMaterial.scatterAnisotropy, -0.95, 0.95);\n float scatteringCosine = clamp(dot(-pbrInfo.v, pbrInfo.l), -1.0, 1.0);\n float phaseDenominator = max(\n 1.0 + anisotropy * anisotropy - 2.0 * anisotropy * scatteringCosine,\n 0.0001\n );\n float phaseWeight = clamp(\n (1.0 - anisotropy * anisotropy) / pow(phaseDenominator, 1.5),\n 0.0,\n 4.0\n );\n float scatteringDepth = thickness / max(pbrMaterial.attenuationDistance, 0.0001);\n float scatteringProbability = 1.0 - exp(-scatteringDepth);\n vec3 scatteringColor = clamp(multiscatterColor, vec3(0.0), vec3(1.0));\n return mix(\n volumeAttenuation,\n volumeAttenuation * mix(vec3(1.0), scatteringColor * phaseWeight, scatteringColor),\n scatteringProbability\n );\n}\n\nvec3 calculateDiffuseTransmissionLight(\n PBRInfo pbrInfo,\n vec3 lightColor,\n vec3 diffuseTransmissionColor,\n float diffuseTransmission,\n vec3 multiscatterColor,\n float thickness\n)\n{\n float oppositeHemisphere = max(dot(-pbrInfo.n, pbrInfo.l), 0.0);\n if (oppositeHemisphere <= 0.0 || diffuseTransmission <= 0.0) {\n return vec3(0.0);\n }\n\n vec3 nonReflectedEnergy = vec3(1.0) - clamp(pbrInfo.reflectance0, vec3(0.0), vec3(1.0));\n vec3 attenuatedColor = getDiffuseTransmissionAttenuation(\n pbrInfo,\n multiscatterColor,\n thickness\n );\n return lightColor * diffuseTransmissionColor * nonReflectedEnergy *\n attenuatedColor * (diffuseTransmission * oppositeHemisphere / M_PI);\n}\n\n#ifdef USE_IBL\nvec3 calculateDiffuseTransmissionIBL(\n PBRInfo pbrInfo,\n vec3 diffuseTransmissionColor,\n float diffuseTransmission,\n vec3 multiscatterColor,\n float thickness\n)\n{\n if (diffuseTransmission <= 0.0) {\n return vec3(0.0);\n }\n\n#ifdef USE_SCENE_ENVIRONMENT\n float rotationSine = sin(pbrScene.environmentRotation);\n float rotationCosine = cos(pbrScene.environmentRotation);\n mat2 environmentRotation = mat2(rotationCosine, rotationSine, -rotationSine, rotationCosine);\n vec3 oppositeNormal = vec3(environmentRotation * -pbrInfo.n.xz, -pbrInfo.n.y).xzy;\n vec3 environmentColor = texture(pbr_diffuseEnvSampler, oppositeNormal).rgb *\n max(pbrScene.environmentIntensity, 0.0);\n#else\n vec3 environmentColor = SRGBtoLINEAR(texture(pbr_diffuseEnvSampler, -pbrInfo.n)).rgb;\n#endif\n vec3 nonReflectedEnergy = vec3(1.0) - clamp(pbrInfo.reflectance0, vec3(0.0), vec3(1.0));\n return environmentColor * diffuseTransmissionColor * nonReflectedEnergy *\n getDiffuseTransmissionAttenuation(pbrInfo, multiscatterColor, thickness) *\n diffuseTransmission * pbrMaterial.scaleIBLAmbient.x;\n}\n#endif\n\n#ifdef USE_TRANSMISSION_FRAMEBUFFER\nvec3 sampleTransmittedSceneColor(\n vec3 position,\n vec3 normal,\n vec3 viewDirection,\n float thickness,\n float perceptualRoughness,\n float indexOfRefraction\n)\n{\n vec3 refractionDirection = refract(\n -viewDirection,\n normal,\n 1.0 / max(indexOfRefraction, 1.0)\n );\n vec3 refractedPosition = position + refractionDirection * thickness;\n vec4 clipPosition = pbrScene.projectionMatrix *\n pbrScene.viewMatrix * vec4(refractedPosition, 1.0);\n vec2 textureCoordinate = clipPosition.xy / max(clipPosition.w, 0.0001) * 0.5 + 0.5;\n textureCoordinate = clamp(textureCoordinate, vec2(0.001), vec2(0.999));\n\n vec2 blurRadius = perceptualRoughness * perceptualRoughness * 8.0 /\n max(pbrScene.framebufferSize, vec2(1.0));\n vec3 sceneColor = texture(pbr_transmissionFramebufferSampler, textureCoordinate).rgb * 0.4;\n sceneColor += texture(\n pbr_transmissionFramebufferSampler,\n textureCoordinate + vec2(blurRadius.x, 0.0)\n ).rgb * 0.15;\n sceneColor += texture(\n pbr_transmissionFramebufferSampler,\n textureCoordinate - vec2(blurRadius.x, 0.0)\n ).rgb * 0.15;\n sceneColor += texture(\n pbr_transmissionFramebufferSampler,\n textureCoordinate + vec2(0.0, blurRadius.y)\n ).rgb * 0.15;\n sceneColor += texture(\n pbr_transmissionFramebufferSampler,\n textureCoordinate - vec2(0.0, blurRadius.y)\n ).rgb * 0.15;\n return max(sceneColor, vec3(0.0));\n}\n\nvec3 getTransmittedSceneColor(\n vec3 position,\n vec3 normal,\n vec3 viewDirection,\n float thickness,\n float perceptualRoughness\n)\n{\n if (pbrMaterial.dispersion <= 0.0) {\n return sampleTransmittedSceneColor(\n position,\n normal,\n viewDirection,\n thickness,\n perceptualRoughness,\n pbrMaterial.ior\n );\n }\n\n float halfSpread = (max(pbrMaterial.ior, 1.0) - 1.0) * 0.025 * pbrMaterial.dispersion;\n vec3 indicesOfRefraction = max(\n vec3(pbrMaterial.ior - halfSpread, pbrMaterial.ior, pbrMaterial.ior + halfSpread),\n vec3(1.0)\n );\n return vec3(\n sampleTransmittedSceneColor(\n position, normal, viewDirection, thickness, perceptualRoughness, indicesOfRefraction.r\n ).r,\n sampleTransmittedSceneColor(\n position, normal, viewDirection, thickness, perceptualRoughness, indicesOfRefraction.g\n ).g,\n sampleTransmittedSceneColor(\n position, normal, viewDirection, thickness, perceptualRoughness, indicesOfRefraction.b\n ).b\n );\n}\n#endif\n\nPBRInfo createClearcoatPBRInfo(PBRInfo basePBRInfo, vec3 clearcoatNormal, float clearcoatRoughness)\n{\n float perceptualRoughness = clamp(clearcoatRoughness, c_MinRoughness, 1.0);\n float alphaRoughness = perceptualRoughness * perceptualRoughness;\n float NdotV = clamp(abs(dot(clearcoatNormal, basePBRInfo.v)), 0.001, 1.0);\n\n return PBRInfo(\n basePBRInfo.NdotL,\n NdotV,\n basePBRInfo.NdotH,\n basePBRInfo.LdotH,\n basePBRInfo.VdotH,\n perceptualRoughness,\n 0.0,\n vec3(0.04),\n vec3(1.0),\n alphaRoughness,\n vec3(0.0),\n vec3(0.04),\n clearcoatNormal,\n basePBRInfo.v,\n basePBRInfo.l,\n basePBRInfo.h\n );\n}\n\nvec3 calculateClearcoatContribution(\n PBRInfo pbrInfo,\n vec3 lightColor,\n vec3 clearcoatNormal,\n float clearcoatFactor,\n float clearcoatRoughness\n) {\n if (clearcoatFactor <= 0.0) {\n return vec3(0.0);\n }\n\n PBRInfo clearcoatPBRInfo = createClearcoatPBRInfo(pbrInfo, clearcoatNormal, clearcoatRoughness);\n return calculateFinalColor(clearcoatPBRInfo, lightColor) * clearcoatFactor;\n}\n\n#ifdef USE_IBL\nvec3 calculateClearcoatIBLContribution(\n PBRInfo pbrInfo,\n vec3 clearcoatNormal,\n vec3 reflection,\n float clearcoatFactor,\n float clearcoatRoughness\n) {\n if (clearcoatFactor <= 0.0) {\n return vec3(0.0);\n }\n\n PBRInfo clearcoatPBRInfo = createClearcoatPBRInfo(pbrInfo, clearcoatNormal, clearcoatRoughness);\n return getIBLContribution(clearcoatPBRInfo, clearcoatNormal, reflection) * clearcoatFactor;\n}\n#endif\n\nvec3 calculateSheenContribution(\n PBRInfo pbrInfo,\n vec3 lightColor,\n vec3 sheenColor,\n float sheenRoughness\n) {\n if (maxComponent(sheenColor) <= 0.0) {\n return vec3(0.0);\n }\n\n float alpha = max(sheenRoughness * sheenRoughness, 0.0001);\n float inverseAlpha = 1.0 / alpha;\n float sineSquared = max(1.0 - pbrInfo.NdotH * pbrInfo.NdotH, 0.0);\n float distribution = (2.0 + inverseAlpha) * pow(sineSquared, inverseAlpha * 0.5) /\n (2.0 * M_PI);\n float visibility = 1.0 / max(\n 4.0 * (pbrInfo.NdotL + pbrInfo.NdotV - pbrInfo.NdotL * pbrInfo.NdotV),\n 0.0001\n );\n return pbrInfo.NdotL * lightColor * sheenColor * distribution * visibility *\n (1.0 - pbrInfo.metalness);\n}\n\nvec3 calculateAnisotropicLightColor(\n PBRInfo pbrInfo,\n vec3 lightColor,\n vec3 anisotropyTangent,\n float anisotropyStrength\n) {\n if (anisotropyStrength <= 0.0) {\n return calculateFinalColor(pbrInfo, lightColor);\n }\n\n vec3 anisotropyBitangent = normalize(cross(pbrInfo.n, anisotropyTangent));\n float tangentRoughness = mix(\n pbrInfo.alphaRoughness,\n 1.0,\n anisotropyStrength * anisotropyStrength\n );\n float bitangentRoughness = clamp(pbrInfo.alphaRoughness, 0.001, 1.0);\n float roughnessProduct = tangentRoughness * bitangentRoughness;\n vec3 distributionVector = vec3(\n bitangentRoughness * dot(anisotropyTangent, pbrInfo.h),\n tangentRoughness * dot(anisotropyBitangent, pbrInfo.h),\n roughnessProduct * pbrInfo.NdotH\n );\n float distributionFactor = roughnessProduct /\n max(dot(distributionVector, distributionVector), 0.000001);\n float distribution = roughnessProduct * distributionFactor * distributionFactor / M_PI;\n float viewMask = pbrInfo.NdotL * length(vec3(\n tangentRoughness * dot(anisotropyTangent, pbrInfo.v),\n bitangentRoughness * dot(anisotropyBitangent, pbrInfo.v),\n pbrInfo.NdotV\n ));\n float lightMask = pbrInfo.NdotV * length(vec3(\n tangentRoughness * dot(anisotropyTangent, pbrInfo.l),\n bitangentRoughness * dot(anisotropyBitangent, pbrInfo.l),\n pbrInfo.NdotL\n ));\n float visibility = clamp(0.5 / max(viewMask + lightMask, 0.000001), 0.0, 1.0);\n vec3 fresnel = specularReflection(pbrInfo);\n vec3 diffuseContribution = (vec3(1.0) - fresnel) * diffuse(pbrInfo);\n return pbrInfo.NdotL * lightColor *\n (diffuseContribution + fresnel * distribution * visibility);\n}\n\nvec3 getAnisotropicReflection(PBRInfo pbrInfo, vec3 anisotropyTangent, float anisotropyStrength)\n{\n if (anisotropyStrength <= 0.0) {\n return -normalize(reflect(pbrInfo.v, pbrInfo.n));\n }\n vec3 anisotropyBitangent = normalize(cross(pbrInfo.n, anisotropyTangent));\n vec3 anisotropicNormal = normalize(cross(anisotropyBitangent, pbrInfo.v));\n anisotropicNormal = normalize(cross(anisotropicNormal, anisotropyBitangent));\n float bend = anisotropyStrength * (1.0 - pbrInfo.perceptualRoughness);\n return -normalize(reflect(pbrInfo.v, normalize(mix(pbrInfo.n, anisotropicNormal, bend))));\n}\n\nvec3 calculateMaterialLightColor(\n PBRInfo pbrInfo,\n vec3 lightColor,\n vec3 clearcoatNormal,\n float clearcoatFactor,\n float clearcoatRoughness,\n vec3 sheenColor,\n float sheenRoughness,\n vec3 anisotropyTangent,\n float anisotropyStrength\n) {\n vec3 color = calculateAnisotropicLightColor(\n pbrInfo,\n lightColor,\n anisotropyTangent,\n anisotropyStrength\n );\n color += calculateClearcoatContribution(\n pbrInfo,\n lightColor,\n clearcoatNormal,\n clearcoatFactor,\n clearcoatRoughness\n );\n color += calculateSheenContribution(pbrInfo, lightColor, sheenColor, sheenRoughness);\n return color;\n}\n\nvoid PBRInfo_setAmbientLight(inout PBRInfo pbrInfo) {\n pbrInfo.NdotL = 1.0;\n pbrInfo.NdotH = 0.0;\n pbrInfo.LdotH = 0.0;\n pbrInfo.VdotH = 1.0;\n pbrInfo.l = pbrInfo.n;\n pbrInfo.h = pbrInfo.n;\n}\n\nvoid PBRInfo_setDirectionalLight(inout PBRInfo pbrInfo, vec3 lightDirection) {\n vec3 n = pbrInfo.n;\n vec3 v = pbrInfo.v;\n vec3 l = normalize(lightDirection); // Vector from surface point to light\n vec3 h = normalize(l+v); // Half vector between both l and v\n\n pbrInfo.NdotL = clamp(dot(n, l), 0.001, 1.0);\n pbrInfo.NdotH = clamp(dot(n, h), 0.0, 1.0);\n pbrInfo.LdotH = clamp(dot(l, h), 0.0, 1.0);\n pbrInfo.VdotH = clamp(dot(v, h), 0.0, 1.0);\n pbrInfo.l = l;\n pbrInfo.h = h;\n}\n\nvoid PBRInfo_setPointLight(inout PBRInfo pbrInfo, PointLight pointLight) {\n vec3 light_direction = normalize(pointLight.position - pbr_vPosition);\n PBRInfo_setDirectionalLight(pbrInfo, light_direction);\n}\n\nvoid PBRInfo_setSpotLight(inout PBRInfo pbrInfo, SpotLight spotLight) {\n vec3 light_direction = normalize(spotLight.position - pbr_vPosition);\n PBRInfo_setDirectionalLight(pbrInfo, light_direction);\n}\n\nvec3 calculateFinalColor(PBRInfo pbrInfo, vec3 lightColor) {\n // Calculate the shading terms for the microfacet specular shading model\n vec3 F = specularReflection(pbrInfo);\n float G = geometricOcclusion(pbrInfo);\n float D = microfacetDistribution(pbrInfo);\n\n // Calculation of analytical lighting contribution\n vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInfo);\n vec3 specContrib = F * G * D / (4.0 * pbrInfo.NdotL * pbrInfo.NdotV);\n // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)\n return pbrInfo.NdotL * lightColor * (diffuseContrib + specContrib);\n}\n\n// Visibility for the first four spotlights; environment and other lights are unaffected.\nvec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)\n{\n vec2 baseColorUV = getMaterialUV(pbrMaterial.baseColorUVSet, pbrMaterial.baseColorUVTransform);\n vec2 metallicRoughnessUV = getMaterialUV(\n pbrMaterial.metallicRoughnessUVSet,\n pbrMaterial.metallicRoughnessUVTransform\n );\n vec2 normalUV = getMaterialUV(pbrMaterial.normalUVSet, pbrMaterial.normalUVTransform);\n vec2 occlusionUV = getMaterialUV(pbrMaterial.occlusionUVSet, pbrMaterial.occlusionUVTransform);\n vec2 emissiveUV = getMaterialUV(pbrMaterial.emissiveUVSet, pbrMaterial.emissiveUVTransform);\n vec2 lightmapUV = getMaterialUV(pbrMaterial.lightmapUVSet, pbrMaterial.lightmapUVTransform);\n vec2 specularColorUV = getMaterialUV(\n pbrMaterial.specularColorUVSet,\n pbrMaterial.specularColorUVTransform\n );\n vec2 specularIntensityUV = getMaterialUV(\n pbrMaterial.specularIntensityUVSet,\n pbrMaterial.specularIntensityUVTransform\n );\n vec2 transmissionUV = getMaterialUV(\n pbrMaterial.transmissionUVSet,\n pbrMaterial.transmissionUVTransform\n );\n vec2 thicknessUV = getMaterialUV(pbrMaterial.thicknessUVSet, pbrMaterial.thicknessUVTransform);\n vec2 clearcoatUV = getMaterialUV(pbrMaterial.clearcoatUVSet, pbrMaterial.clearcoatUVTransform);\n vec2 clearcoatRoughnessUV = getMaterialUV(\n pbrMaterial.clearcoatRoughnessUVSet,\n pbrMaterial.clearcoatRoughnessUVTransform\n );\n vec2 clearcoatNormalUV = getMaterialUV(\n pbrMaterial.clearcoatNormalUVSet,\n pbrMaterial.clearcoatNormalUVTransform\n );\n vec2 sheenColorUV = getMaterialUV(\n pbrMaterial.sheenColorUVSet,\n pbrMaterial.sheenColorUVTransform\n );\n vec2 sheenRoughnessUV = getMaterialUV(\n pbrMaterial.sheenRoughnessUVSet,\n pbrMaterial.sheenRoughnessUVTransform\n );\n vec2 iridescenceUV = getMaterialUV(\n pbrMaterial.iridescenceUVSet,\n pbrMaterial.iridescenceUVTransform\n );\n vec2 iridescenceThicknessUV = getMaterialUV(\n pbrMaterial.iridescenceThicknessUVSet,\n pbrMaterial.iridescenceThicknessUVTransform\n );\n vec2 anisotropyUV = getMaterialUV(\n pbrMaterial.anisotropyUVSet,\n pbrMaterial.anisotropyUVTransform\n );\n vec2 diffuseTransmissionUV = getMaterialUV(\n pbrMaterial.diffuseTransmissionUVSet,\n pbrMaterial.diffuseTransmissionUVTransform\n );\n vec2 diffuseTransmissionColorUV = getMaterialUV(\n pbrMaterial.diffuseTransmissionColorUVSet,\n pbrMaterial.diffuseTransmissionColorUVTransform\n );\n vec2 multiscatterColorUV = getMaterialUV(\n pbrMaterial.multiscatterColorUVSet,\n pbrMaterial.multiscatterColorUVTransform\n );\n\n // The albedo may be defined from a base texture or a flat color\n#ifdef HAS_BASECOLORMAP\n vec4 baseColor =\n SRGBtoLINEAR(texture(pbr_baseColorSampler, baseColorUV)) *\n pbrMaterial.baseColorFactor * vertexColor;\n#else\n vec4 baseColor = pbrMaterial.baseColorFactor * vertexColor;\n#endif\n\n#ifdef ALPHA_CUTOFF\n if (baseColor.a < pbrMaterial.alphaCutoff) {\n discard;\n }\n#endif\n\n vec3 color = vec3(0, 0, 0);\n\n float transmission = 0.0;\n\n vec3 lightmapIrradiance = vec3(0.0);\n#ifdef HAS_LIGHTMAP\n if (pbrMaterial.lightmapMapEnabled) {\n lightmapIrradiance = texture(pbr_lightmapSampler, lightmapUV).rgb * pbrMaterial.lightmapIntensity;\n }\n#endif\n\n if(pbrMaterial.unlit){\n color.rgb = baseColor.rgb;\n#ifdef HAS_LIGHTMAP\n if (pbrMaterial.lightmapMapEnabled) {\n color *= lightmapIrradiance / M_PI;\n#ifdef HAS_OCCLUSIONMAP\n if (pbrMaterial.occlusionMapEnabled) {\n float ao = texture(pbr_occlusionSampler, occlusionUV).r;\n color = mix(color, color * ao, pbrMaterial.occlusionStrength);\n }\n#endif\n }\n#endif\n }\n else{\n // Metallic and Roughness material properties are packed together\n // In glTF, these factors can be specified by fixed scalar values\n // or from a metallic-roughness map\n float perceptualRoughness = pbrMaterial.metallicRoughnessValues.y;\n float metallic = pbrMaterial.metallicRoughnessValues.x;\n#ifdef HAS_METALROUGHNESSMAP\n // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.\n // This layout intentionally reserves the 'r' channel for (optional) occlusion map data\n vec4 mrSample = texture(pbr_metallicRoughnessSampler, metallicRoughnessUV);\n perceptualRoughness = mrSample.g * perceptualRoughness;\n metallic = mrSample.b * metallic;\n#endif\n perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);\n metallic = clamp(metallic, 0.0, 1.0);\n mat3 tbn = getTBN(normalUV);\n vec3 n = getNormal(tbn, normalUV); // normal at surface point\n perceptualRoughness = widenSpecularRoughness(perceptualRoughness, n);\n vec3 v = normalize(pbrProjection.camera - pbr_vPosition); // Vector from surface point to camera\n float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);\n#ifdef USE_MATERIAL_EXTENSIONS\n bool useExtendedPBR =\n pbrMaterial.specularColorMapEnabled ||\n pbrMaterial.specularIntensityMapEnabled ||\n abs(pbrMaterial.specularIntensityFactor - 1.0) > 0.0001 ||\n maxComponent(abs(pbrMaterial.specularColorFactor - vec3(1.0))) > 0.0001 ||\n abs(pbrMaterial.ior - 1.5) > 0.0001 ||\n pbrMaterial.dispersion > 0.0001 ||\n pbrMaterial.transmissionMapEnabled ||\n pbrMaterial.transmissionFactor > 0.0001 ||\n pbrMaterial.diffuseTransmissionMapEnabled ||\n pbrMaterial.diffuseTransmissionColorMapEnabled ||\n pbrMaterial.diffuseTransmissionFactor > 0.0001 ||\n pbrMaterial.multiscatterColorMapEnabled ||\n maxComponent(pbrMaterial.multiscatterColorFactor) > 0.0001 ||\n pbrMaterial.clearcoatMapEnabled ||\n pbrMaterial.clearcoatRoughnessMapEnabled ||\n pbrMaterial.clearcoatFactor > 0.0001 ||\n pbrMaterial.clearcoatRoughnessFactor > 0.0001 ||\n pbrMaterial.sheenColorMapEnabled ||\n pbrMaterial.sheenRoughnessMapEnabled ||\n maxComponent(pbrMaterial.sheenColorFactor) > 0.0001 ||\n pbrMaterial.sheenRoughnessFactor > 0.0001 ||\n pbrMaterial.iridescenceMapEnabled ||\n pbrMaterial.iridescenceFactor > 0.0001 ||\n abs(pbrMaterial.iridescenceIor - 1.3) > 0.0001 ||\n abs(pbrMaterial.iridescenceThicknessRange.x - 100.0) > 0.0001 ||\n abs(pbrMaterial.iridescenceThicknessRange.y - 400.0) > 0.0001 ||\n pbrMaterial.anisotropyMapEnabled ||\n pbrMaterial.anisotropyStrength > 0.0001 ||\n abs(pbrMaterial.anisotropyRotation) > 0.0001 ||\n length(pbrMaterial.anisotropyDirection - vec2(1.0, 0.0)) > 0.0001;\n#else\n bool useExtendedPBR = false;\n#endif\n\n if (!useExtendedPBR) {\n // Keep the baseline metallic-roughness implementation byte-for-byte equivalent in behavior.\n float alphaRoughness = perceptualRoughness * perceptualRoughness;\n\n vec3 f0 = vec3(0.04);\n vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0);\n diffuseColor *= 1.0 - metallic;\n vec3 specularColor = mix(f0, baseColor.rgb, metallic);\n\n float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);\n vec3 specularEnvironmentR0 = specularColor.rgb;\n vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;\n vec3 reflection = -normalize(reflect(v, n));\n\n PBRInfo pbrInfo = PBRInfo(\n 0.0, // NdotL\n NdotV,\n 0.0, // NdotH\n 0.0, // LdotH\n 0.0, // VdotH\n perceptualRoughness,\n metallic,\n specularEnvironmentR0,\n specularEnvironmentR90,\n alphaRoughness,\n diffuseColor,\n specularColor,\n n,\n v,\n n,\n n\n );\n\n#ifdef USE_LIGHTS\n PBRInfo_setAmbientLight(pbrInfo);\n color += calculateFinalColor(pbrInfo, lighting.ambientColor);\n\n for(int i = 0; i < lighting.directionalLightCount; i++) {\n if (i < lighting.directionalLightCount) {\n PBRInfo_setDirectionalLight(pbrInfo, -lighting_getDirectionalLight(i).direction);\n color += calculateFinalColor(pbrInfo, lighting_getDirectionalLight(i).color);\n }\n }\n\n for(int i = 0; i < lighting.pointLightCount; i++) {\n if (i < lighting.pointLightCount) {\n PBRInfo_setPointLight(pbrInfo, lighting_getPointLight(i));\n float attenuation = getPointLightAttenuation(lighting_getPointLight(i), distance(lighting_getPointLight(i).position, pbr_vPosition));\n color += calculateFinalColor(pbrInfo, lighting_getPointLight(i).color / attenuation);\n }\n }\n\n for(int i = 0; i < lighting.spotLightCount; i++) {\n if (i < lighting.spotLightCount) {\n PBRInfo_setSpotLight(pbrInfo, lighting_getSpotLight(i));\n float attenuation = getSpotLightAttenuation(lighting_getSpotLight(i), pbr_vPosition);\n color += calculateFinalColor(pbrInfo, lighting_getSpotLight(i).color * (i < 4 ? clamp(spotVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation);\n }\n }\n for (int areaIndex = 0; areaIndex < areaLighting_getLightCount(); areaIndex++) {\n#ifdef USE_AREA_LIGHT_LTC\n color += areaLTC_evaluate(areaIndex, pbr_vPosition, pbrInfo.n, pbrInfo.v, pbrInfo.perceptualRoughness, pbrInfo.diffuseColor, pbrInfo.reflectance0, pbrInfo.reflectance90);\n#else\n for (int sampleIndex = 0; sampleIndex < areaLighting.sampleCount; sampleIndex++) {\n PointLight sampleLight = areaLighting_getSample(areaIndex, sampleIndex, pbr_vPosition);\n if (dot(sampleLight.color, sampleLight.color) > 0.0) {\n PBRInfo_setPointLight(pbrInfo, sampleLight);\n color += calculateFinalColor(pbrInfo, sampleLight.color);\n }\n }\n#endif\n }\n#endif\n\n#ifdef USE_IBL\n if (pbrMaterial.IBLenabled) {\n color += getIBLContribution(pbrInfo, n, reflection);\n }\n#endif\n\n // The pinned KHR_lightmap draft explicitly defines c_diff = (1 - metallic) * baseColor.\n color += baseColor.rgb * (1.0 - metallic) * lightmapIrradiance / M_PI;\n\n#ifdef HAS_OCCLUSIONMAP\n if (pbrMaterial.occlusionMapEnabled) {\n float ao = texture(pbr_occlusionSampler, occlusionUV).r;\n color = mix(color, color * ao, pbrMaterial.occlusionStrength);\n }\n#endif\n\n vec3 emissive = pbrMaterial.emissiveFactor;\n#ifdef HAS_EMISSIVEMAP\n if (pbrMaterial.emissiveMapEnabled) {\n emissive *= SRGBtoLINEAR(texture(pbr_emissiveSampler, emissiveUV)).rgb;\n }\n#endif\n color += emissive * pbrMaterial.emissiveStrength;\n\n#ifdef PBR_DEBUG\n color = mix(color, baseColor.rgb, pbrMaterial.scaleDiffBaseMR.y);\n color = mix(color, vec3(metallic), pbrMaterial.scaleDiffBaseMR.z);\n color = mix(color, vec3(perceptualRoughness), pbrMaterial.scaleDiffBaseMR.w);\n#endif\n\n return vec4(applySceneColorManagement(color), baseColor.a);\n }\n\n float specularIntensity = pbrMaterial.specularIntensityFactor;\n#ifdef HAS_SPECULARINTENSITYMAP\n if (pbrMaterial.specularIntensityMapEnabled) {\n specularIntensity *= texture(pbr_specularIntensitySampler, specularIntensityUV).a;\n }\n#endif\n\n vec3 specularFactor = pbrMaterial.specularColorFactor;\n#ifdef HAS_SPECULARCOLORMAP\n if (pbrMaterial.specularColorMapEnabled) {\n specularFactor *= SRGBtoLINEAR(texture(pbr_specularColorSampler, specularColorUV)).rgb;\n }\n#endif\n\n transmission = pbrMaterial.transmissionFactor;\n#ifdef HAS_TRANSMISSIONMAP\n if (pbrMaterial.transmissionMapEnabled) {\n transmission *= texture(pbr_transmissionSampler, transmissionUV).r;\n }\n#endif\n transmission = clamp(transmission * (1.0 - metallic), 0.0, 1.0);\n float thickness = max(pbrMaterial.thicknessFactor, 0.0);\n#ifdef HAS_THICKNESSMAP\n thickness *= texture(pbr_thicknessSampler, thicknessUV).g;\n#endif\n\n float diffuseTransmission = clamp(pbrMaterial.diffuseTransmissionFactor, 0.0, 1.0);\n#ifdef HAS_DIFFUSETRANSMISSIONMAP\n if (pbrMaterial.diffuseTransmissionMapEnabled) {\n diffuseTransmission *= texture(pbr_diffuseTransmissionSampler, diffuseTransmissionUV).a;\n }\n#endif\n diffuseTransmission *= (1.0 - metallic) * (1.0 - transmission);\n vec3 diffuseTransmissionColor = pbrMaterial.diffuseTransmissionColorFactor;\n#ifdef HAS_DIFFUSETRANSMISSIONCOLORMAP\n if (pbrMaterial.diffuseTransmissionColorMapEnabled) {\n diffuseTransmissionColor *= SRGBtoLINEAR(\n texture(pbr_diffuseTransmissionColorSampler, diffuseTransmissionColorUV)\n ).rgb;\n }\n#endif\n vec3 multiscatterColor = pbrMaterial.multiscatterColorFactor;\n#ifdef HAS_MULTISCATTERCOLORMAP\n if (pbrMaterial.multiscatterColorMapEnabled) {\n multiscatterColor *= SRGBtoLINEAR(\n texture(pbr_multiscatterColorSampler, multiscatterColorUV)\n ).rgb;\n }\n#endif\n\n float originalTransmission = transmission;\n float scatterReflection = 0.0;\n#ifdef HAS_MATERIAL_SCATTER\n if (thickness <= 0.0) {\n float strength = clamp(pbrMaterial.scatterStrengthFactor, 0.0, 1.0);\n#ifdef HAS_DIFFUSETRANSMISSIONMAP\n if (pbrMaterial.diffuseTransmissionMapEnabled) {\n strength *= texture(pbr_diffuseTransmissionSampler, diffuseTransmissionUV).a;\n }\n#endif\n float anisotropy = pbrMaterial.scatterAnisotropy;\n scatterReflection = originalTransmission * strength * (1.0 - anisotropy) * 0.5;\n diffuseTransmission = originalTransmission * strength * (1.0 + anisotropy) * 0.5;\n diffuseTransmissionColor = multiscatterColor;\n transmission *= 1.0 - strength;\n }\n#endif\n\n float clearcoatFactor = pbrMaterial.clearcoatFactor;\n float clearcoatRoughness = pbrMaterial.clearcoatRoughnessFactor;\n#ifdef HAS_CLEARCOATMAP\n if (pbrMaterial.clearcoatMapEnabled) {\n clearcoatFactor *= texture(pbr_clearcoatSampler, clearcoatUV).r;\n }\n#endif\n#ifdef HAS_CLEARCOATROUGHNESSMAP\n if (pbrMaterial.clearcoatRoughnessMapEnabled) {\n clearcoatRoughness *= texture(pbr_clearcoatRoughnessSampler, clearcoatRoughnessUV).g;\n }\n#endif\n clearcoatFactor = clamp(clearcoatFactor, 0.0, 1.0);\n clearcoatRoughness = clamp(clearcoatRoughness, c_MinRoughness, 1.0);\n vec3 clearcoatNormal = getClearcoatNormal(getTBN(clearcoatNormalUV), n, clearcoatNormalUV);\n clearcoatRoughness = widenSpecularRoughness(clearcoatRoughness, clearcoatNormal);\n\n vec3 sheenColor = pbrMaterial.sheenColorFactor;\n float sheenRoughness = pbrMaterial.sheenRoughnessFactor;\n#ifdef HAS_SHEENCOLORMAP\n if (pbrMaterial.sheenColorMapEnabled) {\n sheenColor *= SRGBtoLINEAR(texture(pbr_sheenColorSampler, sheenColorUV)).rgb;\n }\n#endif\n#ifdef HAS_SHEENROUGHNESSMAP\n if (pbrMaterial.sheenRoughnessMapEnabled) {\n sheenRoughness *= texture(pbr_sheenRoughnessSampler, sheenRoughnessUV).a;\n }\n#endif\n sheenRoughness = clamp(sheenRoughness, c_MinRoughness, 1.0);\n\n float iridescence = pbrMaterial.iridescenceFactor;\n#ifdef HAS_IRIDESCENCEMAP\n if (pbrMaterial.iridescenceMapEnabled) {\n iridescence *= texture(pbr_iridescenceSampler, iridescenceUV).r;\n }\n#endif\n iridescence = clamp(iridescence, 0.0, 1.0);\n float iridescenceThickness = mix(\n pbrMaterial.iridescenceThicknessRange.x,\n pbrMaterial.iridescenceThicknessRange.y,\n 0.5\n );\n#ifdef HAS_IRIDESCENCETHICKNESSMAP\n iridescenceThickness = mix(\n pbrMaterial.iridescenceThicknessRange.x,\n pbrMaterial.iridescenceThicknessRange.y,\n texture(pbr_iridescenceThicknessSampler, iridescenceThicknessUV).g\n );\n#endif\n\n float anisotropyStrength = clamp(pbrMaterial.anisotropyStrength, 0.0, 1.0);\n vec2 anisotropyDirection = normalizeDirection(pbrMaterial.anisotropyDirection);\n#ifdef HAS_ANISOTROPYMAP\n if (pbrMaterial.anisotropyMapEnabled) {\n vec3 anisotropySample = texture(pbr_anisotropySampler, anisotropyUV).rgb;\n anisotropyStrength *= anisotropySample.b;\n vec2 mappedDirection = anisotropySample.rg * 2.0 - 1.0;\n if (length(mappedDirection) > 0.0001) {\n anisotropyDirection = normalize(mappedDirection);\n }\n }\n#endif\n anisotropyDirection = rotateDirection(anisotropyDirection, pbrMaterial.anisotropyRotation);\n vec3 anisotropyTangent = normalize(tbn[0] * anisotropyDirection.x + tbn[1] * anisotropyDirection.y);\n if (length(anisotropyTangent) < 0.0001) {\n anisotropyTangent = normalize(tbn[0]);\n }\n // Roughness is authored as perceptual roughness; as is convention,\n // convert to material roughness by squaring the perceptual roughness [2].\n float alphaRoughness = perceptualRoughness * perceptualRoughness;\n\n float dielectricF0 = getDielectricF0(pbrMaterial.ior);\n vec3 dielectricSpecularF0 = min(\n vec3(dielectricF0) * specularFactor * specularIntensity,\n vec3(1.0)\n );\n dielectricSpecularF0 = getIridescenceTint(\n iridescence,\n iridescenceThickness,\n NdotV,\n dielectricSpecularF0\n );\n vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - dielectricSpecularF0);\n diffuseColor *= (1.0 - metallic) * (1.0 - transmission) * (1.0 - diffuseTransmission);\n#ifdef HAS_MATERIAL_SCATTER\n diffuseColor = (baseColor.rgb * (1.0 - metallic) * (1.0 - originalTransmission) +\n multiscatterColor * scatterReflection) * (vec3(1.0) - dielectricSpecularF0);\n#endif\n vec3 specularColor = mix(dielectricSpecularF0, baseColor.rgb, metallic);\n\n float clearcoatViewFresnel = dielectricSchlick(\n 0.04,\n clamp(abs(dot(clearcoatNormal, v)), 0.0, 1.0)\n );\n float sheenDirectionalAlbedo = maxComponent(sheenColor) *\n (0.157 + 0.343 * (1.0 - NdotV)) * (1.0 - sheenRoughness * 0.5);\n float baseLayerEnergy = (1.0 - clearcoatFactor * clearcoatViewFresnel) *\n (1.0 - clamp(sheenDirectionalAlbedo, 0.0, 1.0));\n diffuseColor *= baseLayerEnergy;\n specularColor *= baseLayerEnergy;\n\n // Compute reflectance.\n float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n\n // For typical incident reflectance range (between 4% to 100%) set the grazing\n // reflectance to 100% for typical fresnel effect.\n // For very low reflectance range on highly diffuse objects (below 4%),\n // incrementally reduce grazing reflecance to 0%.\n float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);\n vec3 specularEnvironmentR0 = specularColor.rgb;\n vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;\n vec3 reflection = -normalize(reflect(v, n));\n\n PBRInfo pbrInfo = PBRInfo(\n 0.0, // NdotL\n NdotV,\n 0.0, // NdotH\n 0.0, // LdotH\n 0.0, // VdotH\n perceptualRoughness,\n metallic,\n specularEnvironmentR0,\n specularEnvironmentR90,\n alphaRoughness,\n diffuseColor,\n specularColor,\n n,\n v,\n n,\n n\n );\n\n\n#ifdef USE_LIGHTS\n // Apply ambient light\n PBRInfo_setAmbientLight(pbrInfo);\n color += calculateMaterialLightColor(\n pbrInfo,\n lighting.ambientColor,\n clearcoatNormal,\n clearcoatFactor,\n clearcoatRoughness,\n sheenColor,\n sheenRoughness,\n anisotropyTangent,\n anisotropyStrength\n );\n\n // Apply directional light\n for(int i = 0; i < lighting.directionalLightCount; i++) {\n if (i < lighting.directionalLightCount) {\n PBRInfo_setDirectionalLight(pbrInfo, -lighting_getDirectionalLight(i).direction);\n color += calculateMaterialLightColor(\n pbrInfo,\n lighting_getDirectionalLight(i).color,\n clearcoatNormal,\n clearcoatFactor,\n clearcoatRoughness,\n sheenColor,\n sheenRoughness,\n anisotropyTangent,\n anisotropyStrength\n );\n color += calculateDiffuseTransmissionLight(\n pbrInfo,\n lighting_getDirectionalLight(i).color,\n diffuseTransmissionColor,\n diffuseTransmission,\n multiscatterColor,\n thickness\n );\n }\n }\n\n // Apply point light\n for(int i = 0; i < lighting.pointLightCount; i++) {\n if (i < lighting.pointLightCount) {\n PBRInfo_setPointLight(pbrInfo, lighting_getPointLight(i));\n float attenuation = getPointLightAttenuation(lighting_getPointLight(i), distance(lighting_getPointLight(i).position, pbr_vPosition));\n color += calculateMaterialLightColor(\n pbrInfo,\n lighting_getPointLight(i).color / attenuation,\n clearcoatNormal,\n clearcoatFactor,\n clearcoatRoughness,\n sheenColor,\n sheenRoughness,\n anisotropyTangent,\n anisotropyStrength\n );\n color += calculateDiffuseTransmissionLight(\n pbrInfo,\n lighting_getPointLight(i).color / attenuation,\n diffuseTransmissionColor,\n diffuseTransmission,\n multiscatterColor,\n thickness\n );\n }\n }\n\n for(int i = 0; i < lighting.spotLightCount; i++) {\n if (i < lighting.spotLightCount) {\n PBRInfo_setSpotLight(pbrInfo, lighting_getSpotLight(i));\n float attenuation = getSpotLightAttenuation(lighting_getSpotLight(i), pbr_vPosition);\n color += calculateMaterialLightColor(\n pbrInfo,\n lighting_getSpotLight(i).color * (i < 4 ? clamp(spotVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation,\n clearcoatNormal,\n clearcoatFactor,\n clearcoatRoughness,\n sheenColor,\n sheenRoughness,\n anisotropyTangent,\n anisotropyStrength\n );\n color += calculateDiffuseTransmissionLight(\n pbrInfo,\n lighting_getSpotLight(i).color * (i < 4 ? clamp(spotVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation,\n diffuseTransmissionColor,\n diffuseTransmission,\n multiscatterColor,\n thickness\n );\n }\n }\n for (int areaIndex = 0; areaIndex < areaLighting_getLightCount(); areaIndex++) {\n#ifdef USE_AREA_LIGHT_LTC\n // Unsupported fits retain numerical integration rather than silently dropping material lobes.\n if (anisotropyStrength <= 0.0001 && dot(sheenColor, sheenColor) <= 0.000001 && diffuseTransmission <= 0.0001) {\n color += areaLTC_evaluate(areaIndex, pbr_vPosition, pbrInfo.n, pbrInfo.v, pbrInfo.perceptualRoughness, pbrInfo.diffuseColor, pbrInfo.reflectance0, pbrInfo.reflectance90);\n color += clearcoatFactor * areaLTC_specular(areaLighting_getLight(areaIndex), pbr_vPosition, clearcoatNormal, pbrInfo.v, clearcoatRoughness, vec3(0.04), vec3(1.0));\n } else {\n for (int sampleIndex = 0; sampleIndex < areaLighting.sampleCount; sampleIndex++) {\n PointLight sampleLight = areaLighting_getSample(areaIndex, sampleIndex, pbr_vPosition);\n if (dot(sampleLight.color, sampleLight.color) > 0.0) {\n PBRInfo_setPointLight(pbrInfo, sampleLight);\n color += calculateMaterialLightColor(pbrInfo, sampleLight.color, clearcoatNormal,\n clearcoatFactor, clearcoatRoughness, sheenColor, sheenRoughness, anisotropyTangent, anisotropyStrength);\n color += calculateDiffuseTransmissionLight(pbrInfo, sampleLight.color,\n diffuseTransmissionColor, diffuseTransmission, multiscatterColor, thickness);\n }\n }\n\n }\n#else\n for (int sampleIndex = 0; sampleIndex < areaLighting.sampleCount; sampleIndex++) {\n PointLight sampleLight = areaLighting_getSample(areaIndex, sampleIndex, pbr_vPosition);\n if (dot(sampleLight.color, sampleLight.color) > 0.0) {\n PBRInfo_setPointLight(pbrInfo, sampleLight);\n color += calculateMaterialLightColor(pbrInfo, sampleLight.color, clearcoatNormal,\n clearcoatFactor, clearcoatRoughness, sheenColor, sheenRoughness, anisotropyTangent, anisotropyStrength);\n color += calculateDiffuseTransmissionLight(pbrInfo, sampleLight.color,\n diffuseTransmissionColor, diffuseTransmission, multiscatterColor, thickness);\n }\n }\n\n#endif\n }\n#endif\n\n // Calculate lighting contribution from image based lighting source (IBL)\n#ifdef USE_IBL\n if (pbrMaterial.IBLenabled) {\n color += getIBLContribution(\n pbrInfo,\n n,\n getAnisotropicReflection(pbrInfo, anisotropyTangent, anisotropyStrength)\n );\n color += calculateClearcoatIBLContribution(\n pbrInfo,\n clearcoatNormal,\n -normalize(reflect(v, clearcoatNormal)),\n clearcoatFactor,\n clearcoatRoughness\n );\n color += calculateDiffuseTransmissionIBL(\n pbrInfo,\n diffuseTransmissionColor,\n diffuseTransmission,\n multiscatterColor,\n thickness\n );\n color += sheenColor * pbrMaterial.scaleIBLAmbient.x * (1.0 - sheenRoughness) * 0.25;\n }\n#endif\n\n#ifdef HAS_MATERIAL_SCATTER\n color += (baseColor.rgb * (1.0 - metallic) * (1.0 - originalTransmission) +\n multiscatterColor * scatterReflection) * baseLayerEnergy * lightmapIrradiance / M_PI;\n#else\n color += baseColor.rgb * (1.0 - metallic) * (1.0 - transmission) *\n (1.0 - diffuseTransmission) * baseLayerEnergy * lightmapIrradiance / M_PI;\n#endif\n\n // Apply optional PBR terms for additional (optional) shading\n#ifdef HAS_OCCLUSIONMAP\n if (pbrMaterial.occlusionMapEnabled) {\n float ao = texture(pbr_occlusionSampler, occlusionUV).r;\n color = mix(color, color * ao, pbrMaterial.occlusionStrength);\n }\n#endif\n\n vec3 emissive = pbrMaterial.emissiveFactor;\n#ifdef HAS_EMISSIVEMAP\n if (pbrMaterial.emissiveMapEnabled) {\n emissive *= SRGBtoLINEAR(texture(pbr_emissiveSampler, emissiveUV)).rgb;\n }\n#endif\n color += emissive * pbrMaterial.emissiveStrength;\n\n if (transmission > 0.0) {\n#ifdef USE_TRANSMISSION_FRAMEBUFFER\n float dielectricFresnel = getDielectricF0(pbrMaterial.ior);\n float transmissionFresnel = dielectricFresnel +\n (1.0 - dielectricFresnel) * pow(1.0 - NdotV, 5.0);\n vec3 transmittedColor = getTransmittedSceneColor(\n pbr_vPosition,\n n,\n v,\n thickness,\n perceptualRoughness\n );\n color += transmittedColor * getVolumeAttenuation(thickness) *\n transmission * (1.0 - transmissionFresnel);\n#else\n color = mix(color, color * getVolumeAttenuation(thickness), transmission);\n#endif\n }\n\n // This section uses mix to override final color for reference app visualization\n // of various parameters in the lighting equation.\n#ifdef PBR_DEBUG\n // TODO: Figure out how to debug multiple lights\n\n // color = mix(color, F, pbr_scaleFGDSpec.x);\n // color = mix(color, vec3(G), pbr_scaleFGDSpec.y);\n // color = mix(color, vec3(D), pbr_scaleFGDSpec.z);\n // color = mix(color, specContrib, pbr_scaleFGDSpec.w);\n\n // color = mix(color, diffuseContrib, pbr_scaleDiffBaseMR.x);\n color = mix(color, baseColor.rgb, pbrMaterial.scaleDiffBaseMR.y);\n color = mix(color, vec3(metallic), pbrMaterial.scaleDiffBaseMR.z);\n color = mix(color, vec3(perceptualRoughness), pbrMaterial.scaleDiffBaseMR.w);\n#endif\n\n }\n\n#ifdef USE_TRANSMISSION_FRAMEBUFFER\n float alpha = clamp(baseColor.a, 0.0, 1.0);\n#else\n float alpha = clamp(baseColor.a * (1.0 - transmission), 0.0, 1.0);\n#endif\n return vec4(applySceneColorManagement(color), alpha);\n}\n\nvec4 pbr_filterColor(vec4 vertexColor) {\n return pbr_filterColorWithSpotShadows(vertexColor, vec4(1.0));\n}\n";
1
+ export declare const vs = "out vec3 pbr_vPosition;\nout vec2 pbr_vUV0;\nout vec2 pbr_vUV1;\n\n#ifdef HAS_NORMALS\n# ifdef HAS_TANGENTS\nout mat3 pbr_vTBN;\n# else\nout vec3 pbr_vNormal;\n# endif\n#endif\n\nvoid pbr_setPositionNormalTangentUV(\n vec4 position,\n vec4 normal,\n vec4 tangent,\n vec2 uv0,\n vec2 uv1\n)\n{\n vec4 pos = pbrProjection.modelMatrix * position;\n pbr_vPosition = vec3(pos.xyz) / pos.w;\n\n#ifdef HAS_NORMALS\n#ifdef HAS_TANGENTS\n vec3 normalW = normalize(vec3(pbrProjection.normalMatrix * vec4(normal.xyz, 0.0)));\n vec3 tangentW = normalize(vec3(pbrProjection.modelMatrix * vec4(tangent.xyz, 0.0)));\n vec3 bitangentW = cross(normalW, tangentW) * tangent.w;\n pbr_vTBN = mat3(tangentW, bitangentW, normalW);\n#else // HAS_TANGENTS != 1\n pbr_vNormal = normalize(vec3(pbrProjection.normalMatrix * vec4(normal.xyz, 0.0)));\n#endif\n#endif\n\n#ifdef HAS_UV\n pbr_vUV0 = uv0;\n#else\n pbr_vUV0 = vec2(0.,0.);\n#endif\n\n pbr_vUV1 = uv1;\n}\n";
2
+ export declare const fs = "precision highp float;\n\nlayout(std140) uniform pbrMaterialUniforms {\n // Material is unlit\n bool unlit;\n\n // Base color map\n bool baseColorMapEnabled;\n vec4 baseColorFactor;\n\n bool normalMapEnabled; \n float normalScale; // #ifdef HAS_NORMALMAP\n\n bool emissiveMapEnabled;\n vec3 emissiveFactor; // #ifdef HAS_EMISSIVEMAP\n\n vec2 metallicRoughnessValues;\n bool metallicRoughnessMapEnabled;\n\n bool occlusionMapEnabled;\n float occlusionStrength; // #ifdef HAS_OCCLUSIONMAP\n \n bool alphaCutoffEnabled;\n float alphaCutoff; // #ifdef ALPHA_CUTOFF\n\n vec3 specularColorFactor;\n float specularIntensityFactor;\n bool specularColorMapEnabled;\n bool specularIntensityMapEnabled;\n\n float ior;\n\n float transmissionFactor;\n bool transmissionMapEnabled;\n\n float thicknessFactor;\n float attenuationDistance;\n vec3 attenuationColor;\n\n float clearcoatFactor;\n float clearcoatRoughnessFactor;\n bool clearcoatMapEnabled;\n bool clearcoatRoughnessMapEnabled;\n\n vec3 sheenColorFactor;\n float sheenRoughnessFactor;\n bool sheenColorMapEnabled;\n bool sheenRoughnessMapEnabled;\n\n float iridescenceFactor;\n float iridescenceIor;\n vec2 iridescenceThicknessRange;\n bool iridescenceMapEnabled;\n\n float anisotropyStrength;\n float anisotropyRotation;\n vec2 anisotropyDirection;\n bool anisotropyMapEnabled;\n\n float emissiveStrength;\n float dispersion;\n \n // IBL\n bool IBLenabled;\n vec2 scaleIBLAmbient; // #ifdef USE_IBL\n \n // debugging flags used for shader output of intermediate PBR variables\n // #ifdef PBR_DEBUG\n vec4 scaleDiffBaseMR;\n vec4 scaleFGDSpec;\n // #endif\n\n int baseColorUVSet;\n mat3 baseColorUVTransform;\n int metallicRoughnessUVSet;\n mat3 metallicRoughnessUVTransform;\n int normalUVSet;\n mat3 normalUVTransform;\n int occlusionUVSet;\n mat3 occlusionUVTransform;\n int emissiveUVSet;\n mat3 emissiveUVTransform;\n int specularColorUVSet;\n mat3 specularColorUVTransform;\n int specularIntensityUVSet;\n mat3 specularIntensityUVTransform;\n int transmissionUVSet;\n mat3 transmissionUVTransform;\n int thicknessUVSet;\n mat3 thicknessUVTransform;\n int clearcoatUVSet;\n mat3 clearcoatUVTransform;\n int clearcoatRoughnessUVSet;\n mat3 clearcoatRoughnessUVTransform;\n int clearcoatNormalUVSet;\n mat3 clearcoatNormalUVTransform;\n int sheenColorUVSet;\n mat3 sheenColorUVTransform;\n int sheenRoughnessUVSet;\n mat3 sheenRoughnessUVTransform;\n int iridescenceUVSet;\n mat3 iridescenceUVTransform;\n int iridescenceThicknessUVSet;\n mat3 iridescenceThicknessUVTransform;\n int anisotropyUVSet;\n mat3 anisotropyUVTransform;\n\n float bumpFactor;\n bool bumpMapEnabled;\n float diffuseTransmissionFactor;\n bool diffuseTransmissionMapEnabled;\n vec3 diffuseTransmissionColorFactor;\n bool diffuseTransmissionColorMapEnabled;\n vec3 multiscatterColorFactor;\n bool multiscatterColorMapEnabled;\n float scatterAnisotropy;\n\n int bumpUVSet;\n mat3 bumpUVTransform;\n int diffuseTransmissionUVSet;\n mat3 diffuseTransmissionUVTransform;\n int diffuseTransmissionColorUVSet;\n mat3 diffuseTransmissionColorUVTransform;\n int multiscatterColorUVSet;\n mat3 multiscatterColorUVTransform;\n bool lightmapMapEnabled;\n float lightmapIntensity;\n int lightmapUVSet;\n mat3 lightmapUVTransform;\n float scatterStrengthFactor;\n} pbrMaterial;\n\n// Samplers\n#ifdef HAS_BASECOLORMAP\nuniform sampler2D pbr_baseColorSampler;\n#endif\n#ifdef HAS_NORMALMAP\nuniform sampler2D pbr_normalSampler;\n#endif\n#ifdef HAS_EMISSIVEMAP\nuniform sampler2D pbr_emissiveSampler;\n#endif\n#ifdef HAS_LIGHTMAP\nuniform sampler2D pbr_lightmapSampler;\n#endif\n#ifdef HAS_METALROUGHNESSMAP\nuniform sampler2D pbr_metallicRoughnessSampler;\n#endif\n#ifdef HAS_OCCLUSIONMAP\nuniform sampler2D pbr_occlusionSampler;\n#endif\n#ifdef HAS_SPECULARCOLORMAP\nuniform sampler2D pbr_specularColorSampler;\n#endif\n#ifdef HAS_SPECULARINTENSITYMAP\nuniform sampler2D pbr_specularIntensitySampler;\n#endif\n#ifdef HAS_TRANSMISSIONMAP\nuniform sampler2D pbr_transmissionSampler;\n#endif\n#ifdef HAS_THICKNESSMAP\nuniform sampler2D pbr_thicknessSampler;\n#endif\n#ifdef HAS_CLEARCOATMAP\nuniform sampler2D pbr_clearcoatSampler;\n#endif\n#ifdef HAS_CLEARCOATROUGHNESSMAP\nuniform sampler2D pbr_clearcoatRoughnessSampler;\n#endif\n#ifdef HAS_CLEARCOATNORMALMAP\nuniform sampler2D pbr_clearcoatNormalSampler;\n#endif\n#ifdef HAS_SHEENCOLORMAP\nuniform sampler2D pbr_sheenColorSampler;\n#endif\n#ifdef HAS_SHEENROUGHNESSMAP\nuniform sampler2D pbr_sheenRoughnessSampler;\n#endif\n#ifdef HAS_IRIDESCENCEMAP\nuniform sampler2D pbr_iridescenceSampler;\n#endif\n#ifdef HAS_IRIDESCENCETHICKNESSMAP\nuniform sampler2D pbr_iridescenceThicknessSampler;\n#endif\n#ifdef HAS_ANISOTROPYMAP\nuniform sampler2D pbr_anisotropySampler;\n#endif\n#ifdef HAS_BUMPMAP\nuniform sampler2D pbr_bumpSampler;\n#endif\n#ifdef HAS_DIFFUSETRANSMISSIONMAP\nuniform sampler2D pbr_diffuseTransmissionSampler;\n#endif\n#ifdef HAS_DIFFUSETRANSMISSIONCOLORMAP\nuniform sampler2D pbr_diffuseTransmissionColorSampler;\n#endif\n#ifdef HAS_MULTISCATTERCOLORMAP\nuniform sampler2D pbr_multiscatterColorSampler;\n#endif\n// Inputs from vertex shader\n\nin vec3 pbr_vPosition;\nin vec2 pbr_vUV0;\nin vec2 pbr_vUV1;\n\n#ifdef HAS_NORMALS\n#ifdef HAS_TANGENTS\nin mat3 pbr_vTBN;\n#else\nin vec3 pbr_vNormal;\n#endif\n#endif\n\n// Encapsulate the various inputs used by the various functions in the shading equation\n// We store values in this struct to simplify the integration of alternative implementations\n// of the shading terms, outlined in the Readme.MD Appendix.\nstruct PBRInfo {\n float NdotL; // cos angle between normal and light direction\n float NdotV; // cos angle between normal and view direction\n float NdotH; // cos angle between normal and half vector\n float LdotH; // cos angle between light direction and half vector\n float VdotH; // cos angle between view direction and half vector\n float perceptualRoughness; // roughness value, as authored by the model creator (input to shader)\n float metalness; // metallic value at the surface\n vec3 reflectance0; // full reflectance color (normal incidence angle)\n vec3 reflectance90; // reflectance color at grazing angle\n float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2])\n vec3 diffuseColor; // color contribution from diffuse lighting\n vec3 specularColor; // color contribution from specular lighting\n vec3 n; // normal at surface point\n vec3 v; // vector from surface point to camera\n vec3 l; // direction from the surface toward the current light\n vec3 h; // half vector between the current light and camera\n};\n\nconst float M_PI = 3.141592653589793;\nconst float c_MinRoughness = 0.04;\n\n// Widen sub-pixel specular lobes using the screen-space normal footprint.\n// This is geometric specular antialiasing: the normal variance is converted\n// into an additional squared perceptual roughness before evaluating BRDFs.\nfloat widenSpecularRoughness(float perceptualRoughness, vec3 normal)\n{\n vec3 normalDerivativeX = dFdx(normal);\n vec3 normalDerivativeY = dFdy(normal);\n float normalVariance =\n dot(normalDerivativeX, normalDerivativeX) +\n dot(normalDerivativeY, normalDerivativeY);\n float kernelRoughnessSquared = min(2.0 * normalVariance, 1.0);\n return clamp(\n sqrt(perceptualRoughness * perceptualRoughness + kernelRoughnessSquared),\n c_MinRoughness,\n 1.0\n );\n}\n\nvec3 calculateFinalColor(PBRInfo pbrInfo, vec3 lightColor);\n\nvec4 SRGBtoLINEAR(vec4 srgbIn)\n{\n#ifdef MANUAL_SRGB\n#ifdef SRGB_FAST_APPROXIMATION\n vec3 linOut = pow(srgbIn.xyz,vec3(2.2));\n#else // SRGB_FAST_APPROXIMATION\n vec3 bLess = step(vec3(0.04045),srgbIn.xyz);\n vec3 linOut = mix( srgbIn.xyz/vec3(12.92), pow((srgbIn.xyz+vec3(0.055))/vec3(1.055),vec3(2.4)), bLess );\n#endif //SRGB_FAST_APPROXIMATION\n return vec4(linOut,srgbIn.w);;\n#else //MANUAL_SRGB\n return srgbIn;\n#endif //MANUAL_SRGB\n}\n\nvec2 getMaterialUV(int uvSet, mat3 uvTransform)\n{\n vec2 baseUV = uvSet == 1 ? pbr_vUV1 : pbr_vUV0;\n return (uvTransform * vec3(baseUV, 1.0)).xy;\n}\n\n// Build the tangent basis from interpolated attributes or screen-space derivatives.\nmat3 getTBN(vec2 uv)\n{\n#ifndef HAS_TANGENTS\n vec3 pos_dx = dFdx(pbr_vPosition);\n vec3 pos_dy = dFdy(pbr_vPosition);\n vec3 tex_dx = dFdx(vec3(uv, 0.0));\n vec3 tex_dy = dFdy(vec3(uv, 0.0));\n vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);\n\n#ifdef HAS_NORMALS\n vec3 ng = normalize(pbr_vNormal);\n#else\n vec3 ng = cross(pos_dx, pos_dy);\n#endif\n\n t = normalize(t - ng * dot(ng, t));\n vec3 b = normalize(cross(ng, t));\n mat3 tbn = mat3(t, b, ng);\n#else // HAS_TANGENTS\n mat3 tbn = pbr_vTBN;\n#endif\n\n#ifdef DOUBLE_SIDED\n#ifdef HAS_NORMALS\n // Derivative normals already face the viewer; only flip an authored basis.\n if (!gl_FrontFacing) tbn = mat3(-tbn[0], -tbn[1], -tbn[2]);\n#endif\n#endif\n return tbn;\n}\n\n// Find the normal for this fragment, pulling either from a predefined normal map\n// or from the interpolated mesh normal and tangent attributes.\nvec3 getMappedNormal(sampler2D normalSampler, mat3 tbn, float normalScale, vec2 uv)\n{\n vec3 n = texture(normalSampler, uv).rgb;\n return normalize(tbn * ((2.0 * n - 1.0) * vec3(normalScale, normalScale, 1.0)));\n}\n\nvec3 getNormal(mat3 tbn, vec2 uv)\n{\n#ifdef HAS_NORMALMAP\n vec3 n = getMappedNormal(pbr_normalSampler, tbn, pbrMaterial.normalScale, uv);\n#else\n // The tbn matrix is linearly interpolated, so we need to re-normalize\n vec3 n = normalize(tbn[2].xyz);\n#endif\n\n#ifdef HAS_BUMPMAP\n vec2 bumpUV = getMaterialUV(pbrMaterial.bumpUVSet, pbrMaterial.bumpUVTransform);\n vec2 bumpTexelSize = 1.0 / vec2(textureSize(pbr_bumpSampler, 0));\n float bumpHeight = texture(pbr_bumpSampler, bumpUV).r;\n vec2 bumpGradient = vec2(\n texture(pbr_bumpSampler, bumpUV + vec2(bumpTexelSize.x, 0.0)).r - bumpHeight,\n texture(pbr_bumpSampler, bumpUV + vec2(0.0, bumpTexelSize.y)).r - bumpHeight\n );\n n = normalize(n - pbrMaterial.bumpFactor *\n (tbn[0] * bumpGradient.x + tbn[1] * bumpGradient.y));\n#endif\n\n return n;\n}\n\nvec3 getClearcoatNormal(mat3 tbn, vec3 baseNormal, vec2 uv)\n{\n#ifdef HAS_CLEARCOATNORMALMAP\n return getMappedNormal(pbr_clearcoatNormalSampler, tbn, 1.0, uv);\n#else\n return baseNormal;\n#endif\n}\n\n// Calculation of the lighting contribution from an optional Image Based Light source.\n// Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1].\n// See our README.md on Environment Maps [3] for additional discussion.\n#ifdef USE_IBL\nvec3 getIBLContribution(PBRInfo pbrInfo, vec3 n, vec3 reflection)\n{\n#ifdef USE_SCENE_ENVIRONMENT\n float maximumMipLevel = max(pbrScene.environmentMipCount - 1.0, 0.0);\n float rotationSine = sin(pbrScene.environmentRotation);\n float rotationCosine = cos(pbrScene.environmentRotation);\n mat2 environmentRotation = mat2(rotationCosine, rotationSine, -rotationSine, rotationCosine);\n vec3 environmentNormal = vec3(environmentRotation * n.xz, n.y).xzy;\n vec3 environmentReflection = vec3(environmentRotation * reflection.xz, reflection.y).xzy;\n#else\n float maximumMipLevel = 9.0;\n vec3 environmentNormal = n;\n vec3 environmentReflection = reflection;\n#endif\n float lod = pbrInfo.perceptualRoughness * maximumMipLevel;\n // retrieve a scale and bias to F0. See [1], Figure 3\n vec4 brdfSample = texture(pbr_brdfLUT,\n vec2(pbrInfo.NdotV, 1.0 - pbrInfo.perceptualRoughness));\n vec4 diffuseSample = texture(pbr_diffuseEnvSampler, environmentNormal);\n\n#ifdef USE_TEX_LOD\n vec4 specularSample = textureLod(pbr_specularEnvSampler, environmentReflection, lod);\n#else\n vec4 specularSample = texture(pbr_specularEnvSampler, environmentReflection);\n#endif\n\n#ifdef USE_SCENE_ENVIRONMENT\n vec3 brdf = brdfSample.rgb;\n vec3 diffuseLight = diffuseSample.rgb;\n vec3 specularLight = specularSample.rgb;\n#else\n vec3 brdf = SRGBtoLINEAR(brdfSample).rgb;\n vec3 diffuseLight = SRGBtoLINEAR(diffuseSample).rgb;\n vec3 specularLight = SRGBtoLINEAR(specularSample).rgb;\n#endif\n\n vec3 diffuse = diffuseLight * pbrInfo.diffuseColor;\n vec3 specular = specularLight * (pbrInfo.specularColor * brdf.x + brdf.y);\n\n // For presentation, this allows us to disable IBL terms\n diffuse *= pbrMaterial.scaleIBLAmbient.x;\n specular *= pbrMaterial.scaleIBLAmbient.y;\n\n#ifdef USE_SCENE_ENVIRONMENT\n return (diffuse + specular) * max(pbrScene.environmentIntensity, 0.0);\n#else\n return diffuse + specular;\n#endif\n}\n#endif\n\n// Basic Lambertian diffuse\n// Implementation from Lambert's Photometria https://archive.org/details/lambertsphotome00lambgoog\n// See also [1], Equation 1\nvec3 diffuse(PBRInfo pbrInfo)\n{\n return pbrInfo.diffuseColor / M_PI;\n}\n\n// The following equation models the Fresnel reflectance term of the spec equation (aka F())\n// Implementation of fresnel from [4], Equation 15\nvec3 specularReflection(PBRInfo pbrInfo)\n{\n return pbrInfo.reflectance0 +\n (pbrInfo.reflectance90 - pbrInfo.reflectance0) *\n pow(clamp(1.0 - pbrInfo.VdotH, 0.0, 1.0), 5.0);\n}\n\n// This calculates the specular geometric attenuation (aka G()),\n// where rougher material will reflect less light back to the viewer.\n// This implementation is based on [1] Equation 4, and we adopt their modifications to\n// alphaRoughness as input as originally proposed in [2].\nfloat geometricOcclusion(PBRInfo pbrInfo)\n{\n float NdotL = pbrInfo.NdotL;\n float NdotV = pbrInfo.NdotV;\n float r = pbrInfo.alphaRoughness;\n\n float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));\n float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV)));\n return attenuationL * attenuationV;\n}\n\n// The following equation(s) model the distribution of microfacet normals across\n// the area being drawn (aka D())\n// Implementation from \"Average Irregularity Representation of a Roughened Surface\n// for Ray Reflection\" by T. S. Trowbridge, and K. P. Reitz\n// Follows the distribution function recommended in the SIGGRAPH 2013 course notes\n// from EPIC Games [1], Equation 3.\nfloat microfacetDistribution(PBRInfo pbrInfo)\n{\n float roughnessSq = pbrInfo.alphaRoughness * pbrInfo.alphaRoughness;\n float f = (pbrInfo.NdotH * roughnessSq - pbrInfo.NdotH) * pbrInfo.NdotH + 1.0;\n return roughnessSq / (M_PI * f * f);\n}\n\nfloat maxComponent(vec3 value)\n{\n return max(max(value.r, value.g), value.b);\n}\n\nfloat getDielectricF0(float ior)\n{\n float clampedIor = max(ior, 1.0);\n float ratio = (clampedIor - 1.0) / (clampedIor + 1.0);\n return ratio * ratio;\n}\n\nvec2 normalizeDirection(vec2 direction)\n{\n float directionLength = length(direction);\n return directionLength > 0.0001 ? direction / directionLength : vec2(1.0, 0.0);\n}\n\nvec2 rotateDirection(vec2 direction, float rotation)\n{\n float s = sin(rotation);\n float c = cos(rotation);\n return vec2(direction.x * c - direction.y * s, direction.x * s + direction.y * c);\n}\n\nvec3 encodeLinearSRGB(vec3 linearColor)\n{\n vec3 positiveColor = max(linearColor, vec3(0.0));\n return mix(\n positiveColor * 12.92,\n 1.055 * pow(positiveColor, vec3(1.0 / 2.4)) - 0.055,\n greaterThan(positiveColor, vec3(0.0031308))\n );\n}\n\nvec3 toneMapKhronosPBRNeutral(vec3 color)\n{\n const float startCompression = 0.76;\n float darkestChannel = min(color.r, min(color.g, color.b));\n float offset = darkestChannel < 0.08\n ? darkestChannel - 6.25 * darkestChannel * darkestChannel\n : 0.04;\n color -= vec3(offset);\n\n float peak = maxComponent(color);\n if (peak < startCompression) {\n return color;\n }\n\n float compressionRange = 1.0 - startCompression;\n float compressedPeak = 1.0 - compressionRange * compressionRange /\n (peak + compressionRange - startCompression);\n color *= compressedPeak / max(peak, 0.0001);\n float desaturation = 1.0 - 1.0 / (0.15 * (peak - compressedPeak) + 1.0);\n return mix(color, vec3(compressedPeak), desaturation);\n}\n\nvec3 applySceneColorManagement(vec3 sceneColor)\n{\n#ifdef USE_SCENE_COLOR_MANAGEMENT\n vec3 color = max(sceneColor, vec3(0.0)) * max(pbrScene.exposure, 0.0);\n if (pbrScene.toneMapMode == 1) {\n color /= vec3(1.0) + color;\n } else if (pbrScene.toneMapMode == 2) {\n color = toneMapKhronosPBRNeutral(color);\n } else if (pbrScene.toneMapMode == 3) {\n color = clamp(\n (color * (2.51 * color + 0.03)) / (color * (2.43 * color + 0.59) + 0.14),\n vec3(0.0),\n vec3(1.0)\n );\n }\n return pbrScene.outputEncoding == 0 ? color : encodeLinearSRGB(color);\n#else\n return pow(max(sceneColor, vec3(0.0)), vec3(1.0 / 2.2));\n#endif\n}\n\nfloat dielectricSchlick(float reflectance, float cosine)\n{\n return reflectance + (1.0 - reflectance) * pow(clamp(1.0 - cosine, 0.0, 1.0), 5.0);\n}\n\nvec3 evaluateIridescenceSensitivity(float opticalPathDifference, vec3 phaseShift)\n{\n float phase = 2.0 * M_PI * opticalPathDifference * 1.0e-9;\n vec3 sensitivity = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13);\n vec3 position = vec3(1.6810e6, 1.7953e6, 2.2084e6);\n vec3 variance = vec3(4.3278e9, 9.3046e9, 6.6121e9);\n vec3 xyz = sensitivity * sqrt(2.0 * M_PI * variance) *\n cos(position * phase + phaseShift) * exp(-phase * phase * variance);\n xyz.x += 9.7470e-14 * sqrt(2.0 * M_PI * 4.5282e9) *\n cos(2.2399e6 * phase + phaseShift.x) * exp(-4.5282e9 * phase * phase);\n xyz /= 1.0685e-7;\n return mat3(\n 3.2404542, -0.9692660, 0.0556434,\n -1.5371385, 1.8760108, -0.2040259,\n -0.4985314, 0.0415560, 1.0572252\n ) * xyz;\n}\n\nvec3 getIridescenceTint(float iridescence, float thickness, float NdotV, vec3 baseReflectance)\n{\n if (iridescence <= 0.0 || thickness <= 0.0) {\n return baseReflectance;\n }\n\n float filmIor = max(pbrMaterial.iridescenceIor, 1.0);\n float sineSquared = (1.0 - NdotV * NdotV) / (filmIor * filmIor);\n float cosineSquared = 1.0 - sineSquared;\n if (cosineSquared <= 0.0) {\n return mix(baseReflectance, vec3(1.0), iridescence);\n }\n float filmCosine = sqrt(cosineSquared);\n float firstInterfaceReflectance = dielectricSchlick(getDielectricF0(filmIor), NdotV);\n float transmittedEnergy = 1.0 - firstInterfaceReflectance;\n\n vec3 baseIor = (vec3(1.0) + sqrt(clamp(baseReflectance, vec3(0.0), vec3(0.9999)))) /\n (vec3(1.0) - sqrt(clamp(baseReflectance, vec3(0.0), vec3(0.9999))));\n vec3 secondInterfaceF0 = (baseIor - vec3(filmIor)) / (baseIor + vec3(filmIor));\n secondInterfaceF0 *= secondInterfaceF0;\n vec3 secondInterfaceReflectance = secondInterfaceF0 +\n (vec3(1.0) - secondInterfaceF0) * pow(1.0 - filmCosine, 5.0);\n vec3 phaseShift = vec3(M_PI);\n phaseShift += mix(vec3(0.0), vec3(M_PI), lessThan(baseIor, vec3(filmIor)));\n float opticalPathDifference = 2.0 * filmIor * thickness * filmCosine;\n vec3 combinedReflectance = clamp(\n firstInterfaceReflectance * secondInterfaceReflectance,\n vec3(0.00001),\n vec3(0.9999)\n );\n vec3 recurringAmplitude = sqrt(combinedReflectance);\n vec3 interfaceResponse = transmittedEnergy * transmittedEnergy * secondInterfaceReflectance /\n (vec3(1.0) - combinedReflectance);\n vec3 reflectedSpectrum = vec3(firstInterfaceReflectance) + interfaceResponse;\n vec3 harmonicAmplitude = interfaceResponse - vec3(transmittedEnergy);\n for (int harmonic = 1; harmonic <= 2; harmonic++) {\n harmonicAmplitude *= recurringAmplitude;\n reflectedSpectrum += harmonicAmplitude * 2.0 * evaluateIridescenceSensitivity(\n float(harmonic) * opticalPathDifference,\n float(harmonic) * phaseShift\n );\n }\n return mix(baseReflectance, clamp(reflectedSpectrum, vec3(0.0), vec3(1.0)), iridescence);\n}\n\nvec3 getVolumeAttenuation(float thickness)\n{\n if (thickness <= 0.0) {\n return vec3(1.0);\n }\n\n vec3 attenuationCoefficient =\n -log(max(pbrMaterial.attenuationColor, vec3(0.0001))) /\n max(pbrMaterial.attenuationDistance, 0.0001);\n return exp(-attenuationCoefficient * thickness);\n}\n\n// KHR_materials_volume_scatter is an active draft. This evaluates a local,\n// thickness-aware single-scattering approximation rather than random walk.\nvec3 getDiffuseTransmissionAttenuation(\n PBRInfo pbrInfo,\n vec3 multiscatterColor,\n float thickness\n)\n{\n vec3 volumeAttenuation = getVolumeAttenuation(thickness);\n float scatteringStrength = maxComponent(multiscatterColor);\n if (thickness <= 0.0 || scatteringStrength <= 0.0001) {\n return volumeAttenuation;\n }\n\n float anisotropy = clamp(pbrMaterial.scatterAnisotropy, -0.95, 0.95);\n float scatteringCosine = clamp(dot(-pbrInfo.v, pbrInfo.l), -1.0, 1.0);\n float phaseDenominator = max(\n 1.0 + anisotropy * anisotropy - 2.0 * anisotropy * scatteringCosine,\n 0.0001\n );\n float phaseWeight = clamp(\n (1.0 - anisotropy * anisotropy) / pow(phaseDenominator, 1.5),\n 0.0,\n 4.0\n );\n float scatteringDepth = thickness / max(pbrMaterial.attenuationDistance, 0.0001);\n float scatteringProbability = 1.0 - exp(-scatteringDepth);\n vec3 scatteringColor = clamp(multiscatterColor, vec3(0.0), vec3(1.0));\n return mix(\n volumeAttenuation,\n volumeAttenuation * mix(vec3(1.0), scatteringColor * phaseWeight, scatteringColor),\n scatteringProbability\n );\n}\n\nvec3 calculateDiffuseTransmissionLight(\n PBRInfo pbrInfo,\n vec3 lightColor,\n vec3 diffuseTransmissionColor,\n float diffuseTransmission,\n vec3 multiscatterColor,\n float thickness\n)\n{\n float oppositeHemisphere = max(dot(-pbrInfo.n, pbrInfo.l), 0.0);\n if (oppositeHemisphere <= 0.0 || diffuseTransmission <= 0.0) {\n return vec3(0.0);\n }\n\n vec3 nonReflectedEnergy = vec3(1.0) - clamp(pbrInfo.reflectance0, vec3(0.0), vec3(1.0));\n vec3 attenuatedColor = getDiffuseTransmissionAttenuation(\n pbrInfo,\n multiscatterColor,\n thickness\n );\n return lightColor * diffuseTransmissionColor * nonReflectedEnergy *\n attenuatedColor * (diffuseTransmission * oppositeHemisphere / M_PI);\n}\n\n#ifdef USE_IBL\nvec3 calculateDiffuseTransmissionIBL(\n PBRInfo pbrInfo,\n vec3 diffuseTransmissionColor,\n float diffuseTransmission,\n vec3 multiscatterColor,\n float thickness\n)\n{\n if (diffuseTransmission <= 0.0) {\n return vec3(0.0);\n }\n\n#ifdef USE_SCENE_ENVIRONMENT\n float rotationSine = sin(pbrScene.environmentRotation);\n float rotationCosine = cos(pbrScene.environmentRotation);\n mat2 environmentRotation = mat2(rotationCosine, rotationSine, -rotationSine, rotationCosine);\n vec3 oppositeNormal = vec3(environmentRotation * -pbrInfo.n.xz, -pbrInfo.n.y).xzy;\n vec3 environmentColor = texture(pbr_diffuseEnvSampler, oppositeNormal).rgb *\n max(pbrScene.environmentIntensity, 0.0);\n#else\n vec3 environmentColor = SRGBtoLINEAR(texture(pbr_diffuseEnvSampler, -pbrInfo.n)).rgb;\n#endif\n vec3 nonReflectedEnergy = vec3(1.0) - clamp(pbrInfo.reflectance0, vec3(0.0), vec3(1.0));\n return environmentColor * diffuseTransmissionColor * nonReflectedEnergy *\n getDiffuseTransmissionAttenuation(pbrInfo, multiscatterColor, thickness) *\n diffuseTransmission * pbrMaterial.scaleIBLAmbient.x;\n}\n#endif\n\n#ifdef USE_TRANSMISSION_FRAMEBUFFER\nvec3 sampleTransmittedSceneColor(\n vec3 position,\n vec3 normal,\n vec3 viewDirection,\n float thickness,\n float perceptualRoughness,\n float indexOfRefraction\n)\n{\n vec3 refractionDirection = refract(\n -viewDirection,\n normal,\n 1.0 / max(indexOfRefraction, 1.0)\n );\n vec3 refractedPosition = position + refractionDirection * thickness;\n vec4 clipPosition = pbrScene.projectionMatrix *\n pbrScene.viewMatrix * vec4(refractedPosition, 1.0);\n vec2 textureCoordinate = clipPosition.xy / max(clipPosition.w, 0.0001) * 0.5 + 0.5;\n textureCoordinate = clamp(textureCoordinate, vec2(0.001), vec2(0.999));\n\n vec2 blurRadius = perceptualRoughness * perceptualRoughness * 8.0 /\n max(pbrScene.framebufferSize, vec2(1.0));\n vec3 sceneColor = texture(pbr_transmissionFramebufferSampler, textureCoordinate).rgb * 0.4;\n sceneColor += texture(\n pbr_transmissionFramebufferSampler,\n textureCoordinate + vec2(blurRadius.x, 0.0)\n ).rgb * 0.15;\n sceneColor += texture(\n pbr_transmissionFramebufferSampler,\n textureCoordinate - vec2(blurRadius.x, 0.0)\n ).rgb * 0.15;\n sceneColor += texture(\n pbr_transmissionFramebufferSampler,\n textureCoordinate + vec2(0.0, blurRadius.y)\n ).rgb * 0.15;\n sceneColor += texture(\n pbr_transmissionFramebufferSampler,\n textureCoordinate - vec2(0.0, blurRadius.y)\n ).rgb * 0.15;\n return max(sceneColor, vec3(0.0));\n}\n\nvec3 getTransmittedSceneColor(\n vec3 position,\n vec3 normal,\n vec3 viewDirection,\n float thickness,\n float perceptualRoughness\n)\n{\n if (pbrMaterial.dispersion <= 0.0) {\n return sampleTransmittedSceneColor(\n position,\n normal,\n viewDirection,\n thickness,\n perceptualRoughness,\n pbrMaterial.ior\n );\n }\n\n float halfSpread = (max(pbrMaterial.ior, 1.0) - 1.0) * 0.025 * pbrMaterial.dispersion;\n vec3 indicesOfRefraction = max(\n vec3(pbrMaterial.ior - halfSpread, pbrMaterial.ior, pbrMaterial.ior + halfSpread),\n vec3(1.0)\n );\n return vec3(\n sampleTransmittedSceneColor(\n position, normal, viewDirection, thickness, perceptualRoughness, indicesOfRefraction.r\n ).r,\n sampleTransmittedSceneColor(\n position, normal, viewDirection, thickness, perceptualRoughness, indicesOfRefraction.g\n ).g,\n sampleTransmittedSceneColor(\n position, normal, viewDirection, thickness, perceptualRoughness, indicesOfRefraction.b\n ).b\n );\n}\n#endif\n\nPBRInfo createClearcoatPBRInfo(PBRInfo basePBRInfo, vec3 clearcoatNormal, float clearcoatRoughness)\n{\n float perceptualRoughness = clamp(clearcoatRoughness, c_MinRoughness, 1.0);\n float alphaRoughness = perceptualRoughness * perceptualRoughness;\n float NdotV = clamp(abs(dot(clearcoatNormal, basePBRInfo.v)), 0.001, 1.0);\n\n return PBRInfo(\n basePBRInfo.NdotL,\n NdotV,\n basePBRInfo.NdotH,\n basePBRInfo.LdotH,\n basePBRInfo.VdotH,\n perceptualRoughness,\n 0.0,\n vec3(0.04),\n vec3(1.0),\n alphaRoughness,\n vec3(0.0),\n vec3(0.04),\n clearcoatNormal,\n basePBRInfo.v,\n basePBRInfo.l,\n basePBRInfo.h\n );\n}\n\nvec3 calculateClearcoatContribution(\n PBRInfo pbrInfo,\n vec3 lightColor,\n vec3 clearcoatNormal,\n float clearcoatFactor,\n float clearcoatRoughness\n) {\n if (clearcoatFactor <= 0.0) {\n return vec3(0.0);\n }\n\n PBRInfo clearcoatPBRInfo = createClearcoatPBRInfo(pbrInfo, clearcoatNormal, clearcoatRoughness);\n return calculateFinalColor(clearcoatPBRInfo, lightColor) * clearcoatFactor;\n}\n\n#ifdef USE_IBL\nvec3 calculateClearcoatIBLContribution(\n PBRInfo pbrInfo,\n vec3 clearcoatNormal,\n vec3 reflection,\n float clearcoatFactor,\n float clearcoatRoughness\n) {\n if (clearcoatFactor <= 0.0) {\n return vec3(0.0);\n }\n\n PBRInfo clearcoatPBRInfo = createClearcoatPBRInfo(pbrInfo, clearcoatNormal, clearcoatRoughness);\n return getIBLContribution(clearcoatPBRInfo, clearcoatNormal, reflection) * clearcoatFactor;\n}\n#endif\n\nvec3 calculateSheenContribution(\n PBRInfo pbrInfo,\n vec3 lightColor,\n vec3 sheenColor,\n float sheenRoughness\n) {\n if (maxComponent(sheenColor) <= 0.0) {\n return vec3(0.0);\n }\n\n float alpha = max(sheenRoughness * sheenRoughness, 0.0001);\n float inverseAlpha = 1.0 / alpha;\n float sineSquared = max(1.0 - pbrInfo.NdotH * pbrInfo.NdotH, 0.0);\n float distribution = (2.0 + inverseAlpha) * pow(sineSquared, inverseAlpha * 0.5) /\n (2.0 * M_PI);\n float visibility = 1.0 / max(\n 4.0 * (pbrInfo.NdotL + pbrInfo.NdotV - pbrInfo.NdotL * pbrInfo.NdotV),\n 0.0001\n );\n return pbrInfo.NdotL * lightColor * sheenColor * distribution * visibility *\n (1.0 - pbrInfo.metalness);\n}\n\nvec3 calculateAnisotropicLightColor(\n PBRInfo pbrInfo,\n vec3 lightColor,\n vec3 anisotropyTangent,\n float anisotropyStrength\n) {\n if (anisotropyStrength <= 0.0) {\n return calculateFinalColor(pbrInfo, lightColor);\n }\n\n vec3 anisotropyBitangent = normalize(cross(pbrInfo.n, anisotropyTangent));\n float tangentRoughness = mix(\n pbrInfo.alphaRoughness,\n 1.0,\n anisotropyStrength * anisotropyStrength\n );\n float bitangentRoughness = clamp(pbrInfo.alphaRoughness, 0.001, 1.0);\n float roughnessProduct = tangentRoughness * bitangentRoughness;\n vec3 distributionVector = vec3(\n bitangentRoughness * dot(anisotropyTangent, pbrInfo.h),\n tangentRoughness * dot(anisotropyBitangent, pbrInfo.h),\n roughnessProduct * pbrInfo.NdotH\n );\n float distributionFactor = roughnessProduct /\n max(dot(distributionVector, distributionVector), 0.000001);\n float distribution = roughnessProduct * distributionFactor * distributionFactor / M_PI;\n float viewMask = pbrInfo.NdotL * length(vec3(\n tangentRoughness * dot(anisotropyTangent, pbrInfo.v),\n bitangentRoughness * dot(anisotropyBitangent, pbrInfo.v),\n pbrInfo.NdotV\n ));\n float lightMask = pbrInfo.NdotV * length(vec3(\n tangentRoughness * dot(anisotropyTangent, pbrInfo.l),\n bitangentRoughness * dot(anisotropyBitangent, pbrInfo.l),\n pbrInfo.NdotL\n ));\n float visibility = clamp(0.5 / max(viewMask + lightMask, 0.000001), 0.0, 1.0);\n vec3 fresnel = specularReflection(pbrInfo);\n vec3 diffuseContribution = (vec3(1.0) - fresnel) * diffuse(pbrInfo);\n return pbrInfo.NdotL * lightColor *\n (diffuseContribution + fresnel * distribution * visibility);\n}\n\nvec3 getAnisotropicReflection(PBRInfo pbrInfo, vec3 anisotropyTangent, float anisotropyStrength)\n{\n if (anisotropyStrength <= 0.0) {\n return -normalize(reflect(pbrInfo.v, pbrInfo.n));\n }\n vec3 anisotropyBitangent = normalize(cross(pbrInfo.n, anisotropyTangent));\n vec3 anisotropicNormal = normalize(cross(anisotropyBitangent, pbrInfo.v));\n anisotropicNormal = normalize(cross(anisotropicNormal, anisotropyBitangent));\n float bend = anisotropyStrength * (1.0 - pbrInfo.perceptualRoughness);\n return -normalize(reflect(pbrInfo.v, normalize(mix(pbrInfo.n, anisotropicNormal, bend))));\n}\n\nvec3 calculateMaterialLightColor(\n PBRInfo pbrInfo,\n vec3 lightColor,\n vec3 clearcoatNormal,\n float clearcoatFactor,\n float clearcoatRoughness,\n vec3 sheenColor,\n float sheenRoughness,\n vec3 anisotropyTangent,\n float anisotropyStrength\n) {\n vec3 color = calculateAnisotropicLightColor(\n pbrInfo,\n lightColor,\n anisotropyTangent,\n anisotropyStrength\n );\n color += calculateClearcoatContribution(\n pbrInfo,\n lightColor,\n clearcoatNormal,\n clearcoatFactor,\n clearcoatRoughness\n );\n color += calculateSheenContribution(pbrInfo, lightColor, sheenColor, sheenRoughness);\n return color;\n}\n\nvoid PBRInfo_setAmbientLight(inout PBRInfo pbrInfo) {\n pbrInfo.NdotL = 1.0;\n pbrInfo.NdotH = 0.0;\n pbrInfo.LdotH = 0.0;\n pbrInfo.VdotH = 1.0;\n pbrInfo.l = pbrInfo.n;\n pbrInfo.h = pbrInfo.n;\n}\n\nvoid PBRInfo_setDirectionalLight(inout PBRInfo pbrInfo, vec3 lightDirection) {\n vec3 n = pbrInfo.n;\n vec3 v = pbrInfo.v;\n vec3 l = normalize(lightDirection); // Vector from surface point to light\n vec3 h = normalize(l+v); // Half vector between both l and v\n\n pbrInfo.NdotL = clamp(dot(n, l), 0.001, 1.0);\n pbrInfo.NdotH = clamp(dot(n, h), 0.0, 1.0);\n pbrInfo.LdotH = clamp(dot(l, h), 0.0, 1.0);\n pbrInfo.VdotH = clamp(dot(v, h), 0.0, 1.0);\n pbrInfo.l = l;\n pbrInfo.h = h;\n}\n\nvoid PBRInfo_setPointLight(inout PBRInfo pbrInfo, PointLight pointLight) {\n vec3 light_direction = normalize(pointLight.position - pbr_vPosition);\n PBRInfo_setDirectionalLight(pbrInfo, light_direction);\n}\n\nvoid PBRInfo_setSpotLight(inout PBRInfo pbrInfo, SpotLight spotLight) {\n vec3 light_direction = normalize(spotLight.position - pbr_vPosition);\n PBRInfo_setDirectionalLight(pbrInfo, light_direction);\n}\n\nvec3 calculateFinalColor(PBRInfo pbrInfo, vec3 lightColor) {\n // Calculate the shading terms for the microfacet specular shading model\n vec3 F = specularReflection(pbrInfo);\n float G = geometricOcclusion(pbrInfo);\n float D = microfacetDistribution(pbrInfo);\n\n // Calculation of analytical lighting contribution\n vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInfo);\n vec3 specContrib = F * G * D / (4.0 * pbrInfo.NdotL * pbrInfo.NdotV);\n // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)\n return pbrInfo.NdotL * lightColor * (diffuseContrib + specContrib);\n}\n\n// Visibility for the first four spotlights; environment and other lights are unaffected.\nfloat pbr_ambientVisibility = 1.0;\n\nvec4 pbr_filterColorWithShadows(vec4 vertexColor, float directionalVisibility, vec4 pointVisibility, vec4 spotVisibility)\n{\n vec2 baseColorUV = getMaterialUV(pbrMaterial.baseColorUVSet, pbrMaterial.baseColorUVTransform);\n vec2 metallicRoughnessUV = getMaterialUV(\n pbrMaterial.metallicRoughnessUVSet,\n pbrMaterial.metallicRoughnessUVTransform\n );\n vec2 normalUV = getMaterialUV(pbrMaterial.normalUVSet, pbrMaterial.normalUVTransform);\n vec2 occlusionUV = getMaterialUV(pbrMaterial.occlusionUVSet, pbrMaterial.occlusionUVTransform);\n vec2 emissiveUV = getMaterialUV(pbrMaterial.emissiveUVSet, pbrMaterial.emissiveUVTransform);\n vec2 lightmapUV = getMaterialUV(pbrMaterial.lightmapUVSet, pbrMaterial.lightmapUVTransform);\n vec2 specularColorUV = getMaterialUV(\n pbrMaterial.specularColorUVSet,\n pbrMaterial.specularColorUVTransform\n );\n vec2 specularIntensityUV = getMaterialUV(\n pbrMaterial.specularIntensityUVSet,\n pbrMaterial.specularIntensityUVTransform\n );\n vec2 transmissionUV = getMaterialUV(\n pbrMaterial.transmissionUVSet,\n pbrMaterial.transmissionUVTransform\n );\n vec2 thicknessUV = getMaterialUV(pbrMaterial.thicknessUVSet, pbrMaterial.thicknessUVTransform);\n vec2 clearcoatUV = getMaterialUV(pbrMaterial.clearcoatUVSet, pbrMaterial.clearcoatUVTransform);\n vec2 clearcoatRoughnessUV = getMaterialUV(\n pbrMaterial.clearcoatRoughnessUVSet,\n pbrMaterial.clearcoatRoughnessUVTransform\n );\n vec2 clearcoatNormalUV = getMaterialUV(\n pbrMaterial.clearcoatNormalUVSet,\n pbrMaterial.clearcoatNormalUVTransform\n );\n vec2 sheenColorUV = getMaterialUV(\n pbrMaterial.sheenColorUVSet,\n pbrMaterial.sheenColorUVTransform\n );\n vec2 sheenRoughnessUV = getMaterialUV(\n pbrMaterial.sheenRoughnessUVSet,\n pbrMaterial.sheenRoughnessUVTransform\n );\n vec2 iridescenceUV = getMaterialUV(\n pbrMaterial.iridescenceUVSet,\n pbrMaterial.iridescenceUVTransform\n );\n vec2 iridescenceThicknessUV = getMaterialUV(\n pbrMaterial.iridescenceThicknessUVSet,\n pbrMaterial.iridescenceThicknessUVTransform\n );\n vec2 anisotropyUV = getMaterialUV(\n pbrMaterial.anisotropyUVSet,\n pbrMaterial.anisotropyUVTransform\n );\n vec2 diffuseTransmissionUV = getMaterialUV(\n pbrMaterial.diffuseTransmissionUVSet,\n pbrMaterial.diffuseTransmissionUVTransform\n );\n vec2 diffuseTransmissionColorUV = getMaterialUV(\n pbrMaterial.diffuseTransmissionColorUVSet,\n pbrMaterial.diffuseTransmissionColorUVTransform\n );\n vec2 multiscatterColorUV = getMaterialUV(\n pbrMaterial.multiscatterColorUVSet,\n pbrMaterial.multiscatterColorUVTransform\n );\n\n // The albedo may be defined from a base texture or a flat color\n#ifdef HAS_BASECOLORMAP\n vec4 baseColor =\n SRGBtoLINEAR(texture(pbr_baseColorSampler, baseColorUV)) *\n pbrMaterial.baseColorFactor * vertexColor;\n#else\n vec4 baseColor = pbrMaterial.baseColorFactor * vertexColor;\n#endif\n\n#ifdef ALPHA_CUTOFF\n if (baseColor.a < pbrMaterial.alphaCutoff) {\n discard;\n }\n#endif\n\n vec3 color = vec3(0, 0, 0);\n\n float transmission = 0.0;\n\n vec3 lightmapIrradiance = vec3(0.0);\n#ifdef HAS_LIGHTMAP\n if (pbrMaterial.lightmapMapEnabled) {\n lightmapIrradiance = texture(pbr_lightmapSampler, lightmapUV).rgb * pbrMaterial.lightmapIntensity;\n }\n#endif\n\n if(pbrMaterial.unlit){\n color.rgb = baseColor.rgb;\n#ifdef HAS_LIGHTMAP\n if (pbrMaterial.lightmapMapEnabled) {\n color *= lightmapIrradiance / M_PI * pbr_ambientVisibility;\n#ifdef HAS_OCCLUSIONMAP\n if (pbrMaterial.occlusionMapEnabled) {\n float ao = texture(pbr_occlusionSampler, occlusionUV).r;\n color = mix(color, color * ao, pbrMaterial.occlusionStrength);\n }\n#endif\n }\n#endif\n }\n else{\n // Metallic and Roughness material properties are packed together\n // In glTF, these factors can be specified by fixed scalar values\n // or from a metallic-roughness map\n float perceptualRoughness = pbrMaterial.metallicRoughnessValues.y;\n float metallic = pbrMaterial.metallicRoughnessValues.x;\n#ifdef HAS_METALROUGHNESSMAP\n // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.\n // This layout intentionally reserves the 'r' channel for (optional) occlusion map data\n vec4 mrSample = texture(pbr_metallicRoughnessSampler, metallicRoughnessUV);\n perceptualRoughness = mrSample.g * perceptualRoughness;\n metallic = mrSample.b * metallic;\n#endif\n perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);\n metallic = clamp(metallic, 0.0, 1.0);\n mat3 tbn = getTBN(normalUV);\n vec3 n = getNormal(tbn, normalUV); // normal at surface point\n perceptualRoughness = widenSpecularRoughness(perceptualRoughness, n);\n vec3 v = normalize(pbrProjection.camera - pbr_vPosition); // Vector from surface point to camera\n float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);\n#ifdef USE_MATERIAL_EXTENSIONS\n bool useExtendedPBR =\n pbrMaterial.specularColorMapEnabled ||\n pbrMaterial.specularIntensityMapEnabled ||\n abs(pbrMaterial.specularIntensityFactor - 1.0) > 0.0001 ||\n maxComponent(abs(pbrMaterial.specularColorFactor - vec3(1.0))) > 0.0001 ||\n abs(pbrMaterial.ior - 1.5) > 0.0001 ||\n pbrMaterial.dispersion > 0.0001 ||\n pbrMaterial.transmissionMapEnabled ||\n pbrMaterial.transmissionFactor > 0.0001 ||\n pbrMaterial.diffuseTransmissionMapEnabled ||\n pbrMaterial.diffuseTransmissionColorMapEnabled ||\n pbrMaterial.diffuseTransmissionFactor > 0.0001 ||\n pbrMaterial.multiscatterColorMapEnabled ||\n maxComponent(pbrMaterial.multiscatterColorFactor) > 0.0001 ||\n pbrMaterial.clearcoatMapEnabled ||\n pbrMaterial.clearcoatRoughnessMapEnabled ||\n pbrMaterial.clearcoatFactor > 0.0001 ||\n pbrMaterial.clearcoatRoughnessFactor > 0.0001 ||\n pbrMaterial.sheenColorMapEnabled ||\n pbrMaterial.sheenRoughnessMapEnabled ||\n maxComponent(pbrMaterial.sheenColorFactor) > 0.0001 ||\n pbrMaterial.sheenRoughnessFactor > 0.0001 ||\n pbrMaterial.iridescenceMapEnabled ||\n pbrMaterial.iridescenceFactor > 0.0001 ||\n abs(pbrMaterial.iridescenceIor - 1.3) > 0.0001 ||\n abs(pbrMaterial.iridescenceThicknessRange.x - 100.0) > 0.0001 ||\n abs(pbrMaterial.iridescenceThicknessRange.y - 400.0) > 0.0001 ||\n pbrMaterial.anisotropyMapEnabled ||\n pbrMaterial.anisotropyStrength > 0.0001 ||\n abs(pbrMaterial.anisotropyRotation) > 0.0001 ||\n length(pbrMaterial.anisotropyDirection - vec2(1.0, 0.0)) > 0.0001;\n#else\n bool useExtendedPBR = false;\n#endif\n\n if (!useExtendedPBR) {\n // Keep the baseline metallic-roughness implementation byte-for-byte equivalent in behavior.\n float alphaRoughness = perceptualRoughness * perceptualRoughness;\n\n vec3 f0 = vec3(0.04);\n vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0);\n diffuseColor *= 1.0 - metallic;\n vec3 specularColor = mix(f0, baseColor.rgb, metallic);\n\n float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);\n vec3 specularEnvironmentR0 = specularColor.rgb;\n vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;\n vec3 reflection = -normalize(reflect(v, n));\n\n PBRInfo pbrInfo = PBRInfo(\n 0.0, // NdotL\n NdotV,\n 0.0, // NdotH\n 0.0, // LdotH\n 0.0, // VdotH\n perceptualRoughness,\n metallic,\n specularEnvironmentR0,\n specularEnvironmentR90,\n alphaRoughness,\n diffuseColor,\n specularColor,\n n,\n v,\n n,\n n\n );\n\n#ifdef USE_LIGHTS\n PBRInfo_setAmbientLight(pbrInfo);\n color += calculateFinalColor(pbrInfo, lighting.ambientColor * pbr_ambientVisibility);\n\n for(int i = 0; i < lighting.directionalLightCount; i++) {\n if (i < lighting.directionalLightCount) {\n PBRInfo_setDirectionalLight(pbrInfo, -lighting_getDirectionalLight(i).direction);\n color += calculateFinalColor(pbrInfo, lighting_getDirectionalLight(i).color * (i == 0 ? clamp(directionalVisibility, 0.0, 1.0) : 1.0));\n }\n }\n\n for(int i = 0; i < lighting.pointLightCount; i++) {\n if (i < lighting.pointLightCount) {\n PBRInfo_setPointLight(pbrInfo, lighting_getPointLight(i));\n float attenuation = getPointLightAttenuation(lighting_getPointLight(i), distance(lighting_getPointLight(i).position, pbr_vPosition));\n color += calculateFinalColor(pbrInfo, lighting_getPointLight(i).color * (i < 4 ? clamp(pointVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation);\n }\n }\n\n for(int i = 0; i < lighting.spotLightCount; i++) {\n if (i < lighting.spotLightCount) {\n PBRInfo_setSpotLight(pbrInfo, lighting_getSpotLight(i));\n float attenuation = getSpotLightAttenuation(lighting_getSpotLight(i), pbr_vPosition);\n color += calculateFinalColor(pbrInfo, lighting_getSpotLight(i).color * (i < 4 ? clamp(spotVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation);\n }\n }\n for (int areaIndex = 0; areaIndex < areaLighting_getLightCount(); areaIndex++) {\n#ifdef USE_AREA_LIGHT_LTC\n color += areaLTC_evaluate(areaIndex, pbr_vPosition, pbrInfo.n, pbrInfo.v, pbrInfo.perceptualRoughness, pbrInfo.diffuseColor, pbrInfo.reflectance0, pbrInfo.reflectance90);\n#else\n for (int sampleIndex = 0; sampleIndex < areaLighting.sampleCount; sampleIndex++) {\n PointLight sampleLight = areaLighting_getSample(areaIndex, sampleIndex, pbr_vPosition);\n if (dot(sampleLight.color, sampleLight.color) > 0.0) {\n PBRInfo_setPointLight(pbrInfo, sampleLight);\n color += calculateFinalColor(pbrInfo, sampleLight.color);\n }\n }\n#endif\n }\n#endif\n\nvec3 indirectBaseColor = color;\n#ifdef USE_IBL\n if (pbrMaterial.IBLenabled) {\n color += getIBLContribution(pbrInfo, n, reflection);\n }\n#endif\n\n // The pinned KHR_lightmap draft explicitly defines c_diff = (1 - metallic) * baseColor.\n color += baseColor.rgb * (1.0 - metallic) * lightmapIrradiance / M_PI;\n color = indirectBaseColor + (color - indirectBaseColor) * pbr_ambientVisibility;\n\n#ifdef HAS_OCCLUSIONMAP\n if (pbrMaterial.occlusionMapEnabled) {\n float ao = texture(pbr_occlusionSampler, occlusionUV).r;\n color = mix(color, color * ao, pbrMaterial.occlusionStrength);\n }\n#endif\n\n vec3 emissive = pbrMaterial.emissiveFactor;\n#ifdef HAS_EMISSIVEMAP\n if (pbrMaterial.emissiveMapEnabled) {\n emissive *= SRGBtoLINEAR(texture(pbr_emissiveSampler, emissiveUV)).rgb;\n }\n#endif\n color += emissive * pbrMaterial.emissiveStrength;\n\n#ifdef PBR_DEBUG\n color = mix(color, baseColor.rgb, pbrMaterial.scaleDiffBaseMR.y);\n color = mix(color, vec3(metallic), pbrMaterial.scaleDiffBaseMR.z);\n color = mix(color, vec3(perceptualRoughness), pbrMaterial.scaleDiffBaseMR.w);\n#endif\n\n return vec4(applySceneColorManagement(color), baseColor.a);\n }\n\n float specularIntensity = pbrMaterial.specularIntensityFactor;\n#ifdef HAS_SPECULARINTENSITYMAP\n if (pbrMaterial.specularIntensityMapEnabled) {\n specularIntensity *= texture(pbr_specularIntensitySampler, specularIntensityUV).a;\n }\n#endif\n\n vec3 specularFactor = pbrMaterial.specularColorFactor;\n#ifdef HAS_SPECULARCOLORMAP\n if (pbrMaterial.specularColorMapEnabled) {\n specularFactor *= SRGBtoLINEAR(texture(pbr_specularColorSampler, specularColorUV)).rgb;\n }\n#endif\n\n transmission = pbrMaterial.transmissionFactor;\n#ifdef HAS_TRANSMISSIONMAP\n if (pbrMaterial.transmissionMapEnabled) {\n transmission *= texture(pbr_transmissionSampler, transmissionUV).r;\n }\n#endif\n transmission = clamp(transmission * (1.0 - metallic), 0.0, 1.0);\n float thickness = max(pbrMaterial.thicknessFactor, 0.0);\n#ifdef HAS_THICKNESSMAP\n thickness *= texture(pbr_thicknessSampler, thicknessUV).g;\n#endif\n\n float diffuseTransmission = clamp(pbrMaterial.diffuseTransmissionFactor, 0.0, 1.0);\n#ifdef HAS_DIFFUSETRANSMISSIONMAP\n if (pbrMaterial.diffuseTransmissionMapEnabled) {\n diffuseTransmission *= texture(pbr_diffuseTransmissionSampler, diffuseTransmissionUV).a;\n }\n#endif\n diffuseTransmission *= (1.0 - metallic) * (1.0 - transmission);\n vec3 diffuseTransmissionColor = pbrMaterial.diffuseTransmissionColorFactor;\n#ifdef HAS_DIFFUSETRANSMISSIONCOLORMAP\n if (pbrMaterial.diffuseTransmissionColorMapEnabled) {\n diffuseTransmissionColor *= SRGBtoLINEAR(\n texture(pbr_diffuseTransmissionColorSampler, diffuseTransmissionColorUV)\n ).rgb;\n }\n#endif\n vec3 multiscatterColor = pbrMaterial.multiscatterColorFactor;\n#ifdef HAS_MULTISCATTERCOLORMAP\n if (pbrMaterial.multiscatterColorMapEnabled) {\n multiscatterColor *= SRGBtoLINEAR(\n texture(pbr_multiscatterColorSampler, multiscatterColorUV)\n ).rgb;\n }\n#endif\n\n float originalTransmission = transmission;\n float scatterReflection = 0.0;\n#ifdef HAS_MATERIAL_SCATTER\n if (thickness <= 0.0) {\n float strength = clamp(pbrMaterial.scatterStrengthFactor, 0.0, 1.0);\n#ifdef HAS_DIFFUSETRANSMISSIONMAP\n if (pbrMaterial.diffuseTransmissionMapEnabled) {\n strength *= texture(pbr_diffuseTransmissionSampler, diffuseTransmissionUV).a;\n }\n#endif\n float anisotropy = pbrMaterial.scatterAnisotropy;\n scatterReflection = originalTransmission * strength * (1.0 - anisotropy) * 0.5;\n diffuseTransmission = originalTransmission * strength * (1.0 + anisotropy) * 0.5;\n diffuseTransmissionColor = multiscatterColor;\n transmission *= 1.0 - strength;\n }\n#endif\n\n float clearcoatFactor = pbrMaterial.clearcoatFactor;\n float clearcoatRoughness = pbrMaterial.clearcoatRoughnessFactor;\n#ifdef HAS_CLEARCOATMAP\n if (pbrMaterial.clearcoatMapEnabled) {\n clearcoatFactor *= texture(pbr_clearcoatSampler, clearcoatUV).r;\n }\n#endif\n#ifdef HAS_CLEARCOATROUGHNESSMAP\n if (pbrMaterial.clearcoatRoughnessMapEnabled) {\n clearcoatRoughness *= texture(pbr_clearcoatRoughnessSampler, clearcoatRoughnessUV).g;\n }\n#endif\n clearcoatFactor = clamp(clearcoatFactor, 0.0, 1.0);\n clearcoatRoughness = clamp(clearcoatRoughness, c_MinRoughness, 1.0);\n vec3 clearcoatNormal = getClearcoatNormal(getTBN(clearcoatNormalUV), n, clearcoatNormalUV);\n clearcoatRoughness = widenSpecularRoughness(clearcoatRoughness, clearcoatNormal);\n\n vec3 sheenColor = pbrMaterial.sheenColorFactor;\n float sheenRoughness = pbrMaterial.sheenRoughnessFactor;\n#ifdef HAS_SHEENCOLORMAP\n if (pbrMaterial.sheenColorMapEnabled) {\n sheenColor *= SRGBtoLINEAR(texture(pbr_sheenColorSampler, sheenColorUV)).rgb;\n }\n#endif\n#ifdef HAS_SHEENROUGHNESSMAP\n if (pbrMaterial.sheenRoughnessMapEnabled) {\n sheenRoughness *= texture(pbr_sheenRoughnessSampler, sheenRoughnessUV).a;\n }\n#endif\n sheenRoughness = clamp(sheenRoughness, c_MinRoughness, 1.0);\n\n float iridescence = pbrMaterial.iridescenceFactor;\n#ifdef HAS_IRIDESCENCEMAP\n if (pbrMaterial.iridescenceMapEnabled) {\n iridescence *= texture(pbr_iridescenceSampler, iridescenceUV).r;\n }\n#endif\n iridescence = clamp(iridescence, 0.0, 1.0);\n float iridescenceThickness = mix(\n pbrMaterial.iridescenceThicknessRange.x,\n pbrMaterial.iridescenceThicknessRange.y,\n 0.5\n );\n#ifdef HAS_IRIDESCENCETHICKNESSMAP\n iridescenceThickness = mix(\n pbrMaterial.iridescenceThicknessRange.x,\n pbrMaterial.iridescenceThicknessRange.y,\n texture(pbr_iridescenceThicknessSampler, iridescenceThicknessUV).g\n );\n#endif\n\n float anisotropyStrength = clamp(pbrMaterial.anisotropyStrength, 0.0, 1.0);\n vec2 anisotropyDirection = normalizeDirection(pbrMaterial.anisotropyDirection);\n#ifdef HAS_ANISOTROPYMAP\n if (pbrMaterial.anisotropyMapEnabled) {\n vec3 anisotropySample = texture(pbr_anisotropySampler, anisotropyUV).rgb;\n anisotropyStrength *= anisotropySample.b;\n vec2 mappedDirection = anisotropySample.rg * 2.0 - 1.0;\n if (length(mappedDirection) > 0.0001) {\n anisotropyDirection = normalize(mappedDirection);\n }\n }\n#endif\n anisotropyDirection = rotateDirection(anisotropyDirection, pbrMaterial.anisotropyRotation);\n vec3 anisotropyTangent = normalize(tbn[0] * anisotropyDirection.x + tbn[1] * anisotropyDirection.y);\n if (length(anisotropyTangent) < 0.0001) {\n anisotropyTangent = normalize(tbn[0]);\n }\n // Roughness is authored as perceptual roughness; as is convention,\n // convert to material roughness by squaring the perceptual roughness [2].\n float alphaRoughness = perceptualRoughness * perceptualRoughness;\n\n float dielectricF0 = getDielectricF0(pbrMaterial.ior);\n vec3 dielectricSpecularF0 = min(\n vec3(dielectricF0) * specularFactor * specularIntensity,\n vec3(1.0)\n );\n dielectricSpecularF0 = getIridescenceTint(\n iridescence,\n iridescenceThickness,\n NdotV,\n dielectricSpecularF0\n );\n vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - dielectricSpecularF0);\n diffuseColor *= (1.0 - metallic) * (1.0 - transmission) * (1.0 - diffuseTransmission);\n#ifdef HAS_MATERIAL_SCATTER\n diffuseColor = (baseColor.rgb * (1.0 - metallic) * (1.0 - originalTransmission) +\n multiscatterColor * scatterReflection) * (vec3(1.0) - dielectricSpecularF0);\n#endif\n vec3 specularColor = mix(dielectricSpecularF0, baseColor.rgb, metallic);\n\n float clearcoatViewFresnel = dielectricSchlick(\n 0.04,\n clamp(abs(dot(clearcoatNormal, v)), 0.0, 1.0)\n );\n float sheenDirectionalAlbedo = maxComponent(sheenColor) *\n (0.157 + 0.343 * (1.0 - NdotV)) * (1.0 - sheenRoughness * 0.5);\n float baseLayerEnergy = (1.0 - clearcoatFactor * clearcoatViewFresnel) *\n (1.0 - clamp(sheenDirectionalAlbedo, 0.0, 1.0));\n diffuseColor *= baseLayerEnergy;\n specularColor *= baseLayerEnergy;\n\n // Compute reflectance.\n float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n\n // For typical incident reflectance range (between 4% to 100%) set the grazing\n // reflectance to 100% for typical fresnel effect.\n // For very low reflectance range on highly diffuse objects (below 4%),\n // incrementally reduce grazing reflecance to 0%.\n float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);\n vec3 specularEnvironmentR0 = specularColor.rgb;\n vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;\n vec3 reflection = -normalize(reflect(v, n));\n\n PBRInfo pbrInfo = PBRInfo(\n 0.0, // NdotL\n NdotV,\n 0.0, // NdotH\n 0.0, // LdotH\n 0.0, // VdotH\n perceptualRoughness,\n metallic,\n specularEnvironmentR0,\n specularEnvironmentR90,\n alphaRoughness,\n diffuseColor,\n specularColor,\n n,\n v,\n n,\n n\n );\n\n\n#ifdef USE_LIGHTS\n // Apply ambient light\n PBRInfo_setAmbientLight(pbrInfo);\n color += calculateMaterialLightColor(\n pbrInfo,\n lighting.ambientColor * pbr_ambientVisibility,\n clearcoatNormal,\n clearcoatFactor,\n clearcoatRoughness,\n sheenColor,\n sheenRoughness,\n anisotropyTangent,\n anisotropyStrength\n );\n\n // Apply directional light\n for(int i = 0; i < lighting.directionalLightCount; i++) {\n if (i < lighting.directionalLightCount) {\n PBRInfo_setDirectionalLight(pbrInfo, -lighting_getDirectionalLight(i).direction);\n color += calculateMaterialLightColor(\n pbrInfo,\n lighting_getDirectionalLight(i).color * (i == 0 ? clamp(directionalVisibility, 0.0, 1.0) : 1.0),\n clearcoatNormal,\n clearcoatFactor,\n clearcoatRoughness,\n sheenColor,\n sheenRoughness,\n anisotropyTangent,\n anisotropyStrength\n );\n color += calculateDiffuseTransmissionLight(\n pbrInfo,\n lighting_getDirectionalLight(i).color * (i == 0 ? clamp(directionalVisibility, 0.0, 1.0) : 1.0),\n diffuseTransmissionColor,\n diffuseTransmission,\n multiscatterColor,\n thickness\n );\n }\n }\n\n // Apply point light\n for(int i = 0; i < lighting.pointLightCount; i++) {\n if (i < lighting.pointLightCount) {\n PBRInfo_setPointLight(pbrInfo, lighting_getPointLight(i));\n float attenuation = getPointLightAttenuation(lighting_getPointLight(i), distance(lighting_getPointLight(i).position, pbr_vPosition));\n color += calculateMaterialLightColor(\n pbrInfo,\n lighting_getPointLight(i).color * (i < 4 ? clamp(pointVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation,\n clearcoatNormal,\n clearcoatFactor,\n clearcoatRoughness,\n sheenColor,\n sheenRoughness,\n anisotropyTangent,\n anisotropyStrength\n );\n color += calculateDiffuseTransmissionLight(\n pbrInfo,\n lighting_getPointLight(i).color * (i < 4 ? clamp(pointVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation,\n diffuseTransmissionColor,\n diffuseTransmission,\n multiscatterColor,\n thickness\n );\n }\n }\n\n for(int i = 0; i < lighting.spotLightCount; i++) {\n if (i < lighting.spotLightCount) {\n PBRInfo_setSpotLight(pbrInfo, lighting_getSpotLight(i));\n float attenuation = getSpotLightAttenuation(lighting_getSpotLight(i), pbr_vPosition);\n color += calculateMaterialLightColor(\n pbrInfo,\n lighting_getSpotLight(i).color * (i < 4 ? clamp(spotVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation,\n clearcoatNormal,\n clearcoatFactor,\n clearcoatRoughness,\n sheenColor,\n sheenRoughness,\n anisotropyTangent,\n anisotropyStrength\n );\n color += calculateDiffuseTransmissionLight(\n pbrInfo,\n lighting_getSpotLight(i).color * (i < 4 ? clamp(spotVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation,\n diffuseTransmissionColor,\n diffuseTransmission,\n multiscatterColor,\n thickness\n );\n }\n }\n for (int areaIndex = 0; areaIndex < areaLighting_getLightCount(); areaIndex++) {\n#ifdef USE_AREA_LIGHT_LTC\n // Unsupported fits retain numerical integration rather than silently dropping material lobes.\n if (anisotropyStrength <= 0.0001 && dot(sheenColor, sheenColor) <= 0.000001 && diffuseTransmission <= 0.0001) {\n color += areaLTC_evaluate(areaIndex, pbr_vPosition, pbrInfo.n, pbrInfo.v, pbrInfo.perceptualRoughness, pbrInfo.diffuseColor, pbrInfo.reflectance0, pbrInfo.reflectance90);\n color += clearcoatFactor * areaLTC_specular(areaLighting_getLight(areaIndex), pbr_vPosition, clearcoatNormal, pbrInfo.v, clearcoatRoughness, vec3(0.04), vec3(1.0));\n } else {\n for (int sampleIndex = 0; sampleIndex < areaLighting.sampleCount; sampleIndex++) {\n PointLight sampleLight = areaLighting_getSample(areaIndex, sampleIndex, pbr_vPosition);\n if (dot(sampleLight.color, sampleLight.color) > 0.0) {\n PBRInfo_setPointLight(pbrInfo, sampleLight);\n color += calculateMaterialLightColor(pbrInfo, sampleLight.color, clearcoatNormal,\n clearcoatFactor, clearcoatRoughness, sheenColor, sheenRoughness, anisotropyTangent, anisotropyStrength);\n color += calculateDiffuseTransmissionLight(pbrInfo, sampleLight.color,\n diffuseTransmissionColor, diffuseTransmission, multiscatterColor, thickness);\n }\n }\n\n }\n#else\n for (int sampleIndex = 0; sampleIndex < areaLighting.sampleCount; sampleIndex++) {\n PointLight sampleLight = areaLighting_getSample(areaIndex, sampleIndex, pbr_vPosition);\n if (dot(sampleLight.color, sampleLight.color) > 0.0) {\n PBRInfo_setPointLight(pbrInfo, sampleLight);\n color += calculateMaterialLightColor(pbrInfo, sampleLight.color, clearcoatNormal,\n clearcoatFactor, clearcoatRoughness, sheenColor, sheenRoughness, anisotropyTangent, anisotropyStrength);\n color += calculateDiffuseTransmissionLight(pbrInfo, sampleLight.color,\n diffuseTransmissionColor, diffuseTransmission, multiscatterColor, thickness);\n }\n }\n\n#endif\n }\n#endif\n\n vec3 indirectBaseColor = color;\n // Calculate lighting contribution from image based lighting source (IBL)\n#ifdef USE_IBL\n if (pbrMaterial.IBLenabled) {\n color += getIBLContribution(\n pbrInfo,\n n,\n getAnisotropicReflection(pbrInfo, anisotropyTangent, anisotropyStrength)\n );\n color += calculateClearcoatIBLContribution(\n pbrInfo,\n clearcoatNormal,\n -normalize(reflect(v, clearcoatNormal)),\n clearcoatFactor,\n clearcoatRoughness\n );\n color += calculateDiffuseTransmissionIBL(\n pbrInfo,\n diffuseTransmissionColor,\n diffuseTransmission,\n multiscatterColor,\n thickness\n );\n color += sheenColor * pbrMaterial.scaleIBLAmbient.x * (1.0 - sheenRoughness) * 0.25;\n }\n#endif\n\n#ifdef HAS_MATERIAL_SCATTER\n color += (baseColor.rgb * (1.0 - metallic) * (1.0 - originalTransmission) +\n multiscatterColor * scatterReflection) * baseLayerEnergy * lightmapIrradiance / M_PI;\n#else\n color += baseColor.rgb * (1.0 - metallic) * (1.0 - transmission) *\n (1.0 - diffuseTransmission) * baseLayerEnergy * lightmapIrradiance / M_PI;\n#endif\n\n color = indirectBaseColor + (color - indirectBaseColor) * pbr_ambientVisibility;\n\n // Apply optional PBR terms for additional (optional) shading\n#ifdef HAS_OCCLUSIONMAP\n if (pbrMaterial.occlusionMapEnabled) {\n float ao = texture(pbr_occlusionSampler, occlusionUV).r;\n color = mix(color, color * ao, pbrMaterial.occlusionStrength);\n }\n#endif\n\n vec3 emissive = pbrMaterial.emissiveFactor;\n#ifdef HAS_EMISSIVEMAP\n if (pbrMaterial.emissiveMapEnabled) {\n emissive *= SRGBtoLINEAR(texture(pbr_emissiveSampler, emissiveUV)).rgb;\n }\n#endif\n color += emissive * pbrMaterial.emissiveStrength;\n\n if (transmission > 0.0) {\n#ifdef USE_TRANSMISSION_FRAMEBUFFER\n float dielectricFresnel = getDielectricF0(pbrMaterial.ior);\n float transmissionFresnel = dielectricFresnel +\n (1.0 - dielectricFresnel) * pow(1.0 - NdotV, 5.0);\n vec3 transmittedColor = getTransmittedSceneColor(\n pbr_vPosition,\n n,\n v,\n thickness,\n perceptualRoughness\n );\n color += transmittedColor * getVolumeAttenuation(thickness) *\n transmission * (1.0 - transmissionFresnel);\n#else\n color = mix(color, color * getVolumeAttenuation(thickness), transmission);\n#endif\n }\n\n // This section uses mix to override final color for reference app visualization\n // of various parameters in the lighting equation.\n#ifdef PBR_DEBUG\n // TODO: Figure out how to debug multiple lights\n\n // color = mix(color, F, pbr_scaleFGDSpec.x);\n // color = mix(color, vec3(G), pbr_scaleFGDSpec.y);\n // color = mix(color, vec3(D), pbr_scaleFGDSpec.z);\n // color = mix(color, specContrib, pbr_scaleFGDSpec.w);\n\n // color = mix(color, diffuseContrib, pbr_scaleDiffBaseMR.x);\n color = mix(color, baseColor.rgb, pbrMaterial.scaleDiffBaseMR.y);\n color = mix(color, vec3(metallic), pbrMaterial.scaleDiffBaseMR.z);\n color = mix(color, vec3(perceptualRoughness), pbrMaterial.scaleDiffBaseMR.w);\n#endif\n\n }\n\n#ifdef USE_TRANSMISSION_FRAMEBUFFER\n float alpha = clamp(baseColor.a, 0.0, 1.0);\n#else\n float alpha = clamp(baseColor.a * (1.0 - transmission), 0.0, 1.0);\n#endif\n return vec4(applySceneColorManagement(color), alpha);\n}\n\n// Depth-only passes use the same base-color alpha, vertex color and UV transform.\nvoid pbr_discardMaskedFragment(vec4 vertexColor) {\n#ifdef ALPHA_CUTOFF\n float alpha = pbrMaterial.baseColorFactor.a * vertexColor.a;\n#ifdef HAS_BASECOLORMAP\n alpha *= texture(pbr_baseColorSampler, getMaterialUV(pbrMaterial.baseColorUVSet, pbrMaterial.baseColorUVTransform)).a;\n#endif\n if (alpha < pbrMaterial.alphaCutoff) {discard;}\n#endif\n}\n\nvec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility) {\n return pbr_filterColorWithShadows(vertexColor, 1.0, vec4(1.0), spotVisibility);\n}\n\nvec4 pbr_filterColor(vec4 vertexColor) {\n return pbr_filterColorWithSpotShadows(vertexColor, vec4(1.0));\n}\n";
3
3
  //# sourceMappingURL=pbr-material-glsl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pbr-material-glsl.d.ts","sourceRoot":"","sources":["../../../../src/modules/lighting/pbr-material/pbr-material-glsl.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,EAAE,67BA2Cd,CAAC;AAEF,eAAO,MAAM,EAAE,on3DA0pDd,CAAC"}
1
+ {"version":3,"file":"pbr-material-glsl.d.ts","sourceRoot":"","sources":["../../../../src/modules/lighting/pbr-material/pbr-material-glsl.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,EAAE,87BA2Cd,CAAC;AAEF,eAAO,MAAM,EAAE,685DAgrDd,CAAC"}
@@ -38,7 +38,7 @@ void pbr_setPositionNormalTangentUV(
38
38
  vec3 bitangentW = cross(normalW, tangentW) * tangent.w;
39
39
  pbr_vTBN = mat3(tangentW, bitangentW, normalW);
40
40
  #else // HAS_TANGENTS != 1
41
- pbr_vNormal = normalize(vec3(pbrProjection.modelMatrix * vec4(normal.xyz, 0.0)));
41
+ pbr_vNormal = normalize(vec3(pbrProjection.normalMatrix * vec4(normal.xyz, 0.0)));
42
42
  #endif
43
43
  #endif
44
44
 
@@ -1043,7 +1043,9 @@ vec3 calculateFinalColor(PBRInfo pbrInfo, vec3 lightColor) {
1043
1043
  }
1044
1044
 
1045
1045
  // Visibility for the first four spotlights; environment and other lights are unaffected.
1046
- vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1046
+ float pbr_ambientVisibility = 1.0;
1047
+
1048
+ vec4 pbr_filterColorWithShadows(vec4 vertexColor, float directionalVisibility, vec4 pointVisibility, vec4 spotVisibility)
1047
1049
  {
1048
1050
  vec2 baseColorUV = getMaterialUV(pbrMaterial.baseColorUVSet, pbrMaterial.baseColorUVTransform);
1049
1051
  vec2 metallicRoughnessUV = getMaterialUV(
@@ -1139,7 +1141,7 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1139
1141
  color.rgb = baseColor.rgb;
1140
1142
  #ifdef HAS_LIGHTMAP
1141
1143
  if (pbrMaterial.lightmapMapEnabled) {
1142
- color *= lightmapIrradiance / M_PI;
1144
+ color *= lightmapIrradiance / M_PI * pbr_ambientVisibility;
1143
1145
  #ifdef HAS_OCCLUSIONMAP
1144
1146
  if (pbrMaterial.occlusionMapEnabled) {
1145
1147
  float ao = texture(pbr_occlusionSampler, occlusionUV).r;
@@ -1241,12 +1243,12 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1241
1243
 
1242
1244
  #ifdef USE_LIGHTS
1243
1245
  PBRInfo_setAmbientLight(pbrInfo);
1244
- color += calculateFinalColor(pbrInfo, lighting.ambientColor);
1246
+ color += calculateFinalColor(pbrInfo, lighting.ambientColor * pbr_ambientVisibility);
1245
1247
 
1246
1248
  for(int i = 0; i < lighting.directionalLightCount; i++) {
1247
1249
  if (i < lighting.directionalLightCount) {
1248
1250
  PBRInfo_setDirectionalLight(pbrInfo, -lighting_getDirectionalLight(i).direction);
1249
- color += calculateFinalColor(pbrInfo, lighting_getDirectionalLight(i).color);
1251
+ color += calculateFinalColor(pbrInfo, lighting_getDirectionalLight(i).color * (i == 0 ? clamp(directionalVisibility, 0.0, 1.0) : 1.0));
1250
1252
  }
1251
1253
  }
1252
1254
 
@@ -1254,7 +1256,7 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1254
1256
  if (i < lighting.pointLightCount) {
1255
1257
  PBRInfo_setPointLight(pbrInfo, lighting_getPointLight(i));
1256
1258
  float attenuation = getPointLightAttenuation(lighting_getPointLight(i), distance(lighting_getPointLight(i).position, pbr_vPosition));
1257
- color += calculateFinalColor(pbrInfo, lighting_getPointLight(i).color / attenuation);
1259
+ color += calculateFinalColor(pbrInfo, lighting_getPointLight(i).color * (i < 4 ? clamp(pointVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation);
1258
1260
  }
1259
1261
  }
1260
1262
 
@@ -1280,6 +1282,7 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1280
1282
  }
1281
1283
  #endif
1282
1284
 
1285
+ vec3 indirectBaseColor = color;
1283
1286
  #ifdef USE_IBL
1284
1287
  if (pbrMaterial.IBLenabled) {
1285
1288
  color += getIBLContribution(pbrInfo, n, reflection);
@@ -1288,6 +1291,7 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1288
1291
 
1289
1292
  // The pinned KHR_lightmap draft explicitly defines c_diff = (1 - metallic) * baseColor.
1290
1293
  color += baseColor.rgb * (1.0 - metallic) * lightmapIrradiance / M_PI;
1294
+ color = indirectBaseColor + (color - indirectBaseColor) * pbr_ambientVisibility;
1291
1295
 
1292
1296
  #ifdef HAS_OCCLUSIONMAP
1293
1297
  if (pbrMaterial.occlusionMapEnabled) {
@@ -1520,7 +1524,7 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1520
1524
  PBRInfo_setAmbientLight(pbrInfo);
1521
1525
  color += calculateMaterialLightColor(
1522
1526
  pbrInfo,
1523
- lighting.ambientColor,
1527
+ lighting.ambientColor * pbr_ambientVisibility,
1524
1528
  clearcoatNormal,
1525
1529
  clearcoatFactor,
1526
1530
  clearcoatRoughness,
@@ -1536,7 +1540,7 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1536
1540
  PBRInfo_setDirectionalLight(pbrInfo, -lighting_getDirectionalLight(i).direction);
1537
1541
  color += calculateMaterialLightColor(
1538
1542
  pbrInfo,
1539
- lighting_getDirectionalLight(i).color,
1543
+ lighting_getDirectionalLight(i).color * (i == 0 ? clamp(directionalVisibility, 0.0, 1.0) : 1.0),
1540
1544
  clearcoatNormal,
1541
1545
  clearcoatFactor,
1542
1546
  clearcoatRoughness,
@@ -1547,7 +1551,7 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1547
1551
  );
1548
1552
  color += calculateDiffuseTransmissionLight(
1549
1553
  pbrInfo,
1550
- lighting_getDirectionalLight(i).color,
1554
+ lighting_getDirectionalLight(i).color * (i == 0 ? clamp(directionalVisibility, 0.0, 1.0) : 1.0),
1551
1555
  diffuseTransmissionColor,
1552
1556
  diffuseTransmission,
1553
1557
  multiscatterColor,
@@ -1563,7 +1567,7 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1563
1567
  float attenuation = getPointLightAttenuation(lighting_getPointLight(i), distance(lighting_getPointLight(i).position, pbr_vPosition));
1564
1568
  color += calculateMaterialLightColor(
1565
1569
  pbrInfo,
1566
- lighting_getPointLight(i).color / attenuation,
1570
+ lighting_getPointLight(i).color * (i < 4 ? clamp(pointVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation,
1567
1571
  clearcoatNormal,
1568
1572
  clearcoatFactor,
1569
1573
  clearcoatRoughness,
@@ -1574,7 +1578,7 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1574
1578
  );
1575
1579
  color += calculateDiffuseTransmissionLight(
1576
1580
  pbrInfo,
1577
- lighting_getPointLight(i).color / attenuation,
1581
+ lighting_getPointLight(i).color * (i < 4 ? clamp(pointVisibility[min(i, 3)], 0.0, 1.0) : 1.0) / attenuation,
1578
1582
  diffuseTransmissionColor,
1579
1583
  diffuseTransmission,
1580
1584
  multiscatterColor,
@@ -1643,6 +1647,7 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1643
1647
  }
1644
1648
  #endif
1645
1649
 
1650
+ vec3 indirectBaseColor = color;
1646
1651
  // Calculate lighting contribution from image based lighting source (IBL)
1647
1652
  #ifdef USE_IBL
1648
1653
  if (pbrMaterial.IBLenabled) {
@@ -1677,6 +1682,8 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1677
1682
  (1.0 - diffuseTransmission) * baseLayerEnergy * lightmapIrradiance / M_PI;
1678
1683
  #endif
1679
1684
 
1685
+ color = indirectBaseColor + (color - indirectBaseColor) * pbr_ambientVisibility;
1686
+
1680
1687
  // Apply optional PBR terms for additional (optional) shading
1681
1688
  #ifdef HAS_OCCLUSIONMAP
1682
1689
  if (pbrMaterial.occlusionMapEnabled) {
@@ -1738,6 +1745,21 @@ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility)
1738
1745
  return vec4(applySceneColorManagement(color), alpha);
1739
1746
  }
1740
1747
 
1748
+ // Depth-only passes use the same base-color alpha, vertex color and UV transform.
1749
+ void pbr_discardMaskedFragment(vec4 vertexColor) {
1750
+ #ifdef ALPHA_CUTOFF
1751
+ float alpha = pbrMaterial.baseColorFactor.a * vertexColor.a;
1752
+ #ifdef HAS_BASECOLORMAP
1753
+ alpha *= texture(pbr_baseColorSampler, getMaterialUV(pbrMaterial.baseColorUVSet, pbrMaterial.baseColorUVTransform)).a;
1754
+ #endif
1755
+ if (alpha < pbrMaterial.alphaCutoff) {discard;}
1756
+ #endif
1757
+ }
1758
+
1759
+ vec4 pbr_filterColorWithSpotShadows(vec4 vertexColor, vec4 spotVisibility) {
1760
+ return pbr_filterColorWithShadows(vertexColor, 1.0, vec4(1.0), spotVisibility);
1761
+ }
1762
+
1741
1763
  vec4 pbr_filterColor(vec4 vertexColor) {
1742
1764
  return pbr_filterColorWithSpotShadows(vertexColor, vec4(1.0));
1743
1765
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pbr-material-glsl.js","sourceRoot":"","sources":["../../../../src/modules/lighting/pbr-material/pbr-material-glsl.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,+BAA+B;AAC/B,4DAA4D;AAC5D,oFAAoF;AAEpF,eAAe;AACf,yEAAyE;AACzE,0FAA0F;AAC1F,yDAAyD;AAEzD,gDAAgD;AAEhD,MAAM,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2C5B,CAAC;AAEF,MAAM,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0pD5B,CAAC"}
1
+ {"version":3,"file":"pbr-material-glsl.js","sourceRoot":"","sources":["../../../../src/modules/lighting/pbr-material/pbr-material-glsl.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,+BAA+B;AAC/B,4DAA4D;AAC5D,oFAAoF;AAEpF,eAAe;AACf,yEAAyE;AACzE,0FAA0F;AAC1F,yDAAyD;AAEzD,gDAAgD;AAEhD,MAAM,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2C5B,CAAC;AAEF,MAAM,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgrD5B,CAAC"}
@@ -1281,7 +1281,9 @@ fn calculateFinalColor(pbrInfo: PBRInfo, lightColor: vec3<f32>) -> vec3<f32> {
1281
1281
  }
1282
1282
 
1283
1283
  // Visibility for the first four spotlights; environment and other lights are unaffected.
1284
- fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f) -> vec4<f32> {
1284
+ var<private> pbr_ambientVisibility: f32 = 1.0;
1285
+
1286
+ fn pbr_filterColorWithShadows(vertexColor: vec4<f32>, directionalVisibility: f32, pointVisibility: vec4f, spotVisibility: vec4f) -> vec4<f32> {
1285
1287
  let baseColorUV = getMaterialUV(pbrMaterial.baseColorUVSet, pbrMaterial.baseColorUVTransform);
1286
1288
  let metallicRoughnessUV = getMaterialUV(
1287
1289
  pbrMaterial.metallicRoughnessUVSet,
@@ -1374,7 +1376,7 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1374
1376
  color = baseColor.rgb;
1375
1377
  #ifdef HAS_LIGHTMAP
1376
1378
  if (pbrMaterial.lightmapMapEnabled != 0u) {
1377
- color *= lightmapIrradiance / M_PI;
1379
+ color *= lightmapIrradiance / M_PI * pbr_ambientVisibility;
1378
1380
  #ifdef HAS_OCCLUSIONMAP
1379
1381
  if (pbrMaterial.occlusionMapEnabled != 0) {
1380
1382
  let ao = textureSample(pbr_occlusionSampler, pbr_occlusionSamplerSampler, occlusionUV).r;
@@ -1477,12 +1479,12 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1477
1479
 
1478
1480
  #ifdef USE_LIGHTS
1479
1481
  PBRInfo_setAmbientLight(&pbrInfo);
1480
- color += calculateFinalColor(pbrInfo, lighting.ambientColor);
1482
+ color += calculateFinalColor(pbrInfo, lighting.ambientColor * pbr_ambientVisibility);
1481
1483
 
1482
1484
  for (var i = 0; i < lighting.directionalLightCount; i++) {
1483
1485
  if (i < lighting.directionalLightCount) {
1484
1486
  PBRInfo_setDirectionalLight(&pbrInfo, -lighting_getDirectionalLight(i).direction);
1485
- color += calculateFinalColor(pbrInfo, lighting_getDirectionalLight(i).color);
1487
+ color += calculateFinalColor(pbrInfo, lighting_getDirectionalLight(i).color * select(1.0, clamp(directionalVisibility, 0.0, 1.0), i == 0));
1486
1488
  }
1487
1489
  }
1488
1490
 
@@ -1493,7 +1495,7 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1493
1495
  lighting_getPointLight(i),
1494
1496
  distance(lighting_getPointLight(i).position, fragmentInputs.pbr_vPosition)
1495
1497
  );
1496
- color += calculateFinalColor(pbrInfo, lighting_getPointLight(i).color / attenuation);
1498
+ color += calculateFinalColor(pbrInfo, lighting_getPointLight(i).color * select(1.0, clamp(pointVisibility[min(i, 3)], 0.0, 1.0), i < 4) / attenuation);
1497
1499
  }
1498
1500
  }
1499
1501
 
@@ -1522,7 +1524,8 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1522
1524
  }
1523
1525
  #endif
1524
1526
 
1525
- #ifdef USE_IBL
1527
+ let indirectBaseColor = color;
1528
+ #ifdef USE_IBL
1526
1529
  if (pbrMaterial.IBLenabled != 0) {
1527
1530
  color += getIBLContribution(pbrInfo, n, reflection);
1528
1531
  }
@@ -1530,6 +1533,7 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1530
1533
 
1531
1534
  // The pinned KHR_lightmap draft explicitly defines c_diff = (1 - metallic) * baseColor.
1532
1535
  color += baseColor.rgb * (1.0 - metallic) * lightmapIrradiance / M_PI;
1536
+ color = indirectBaseColor + (color - indirectBaseColor) * pbr_ambientVisibility;
1533
1537
 
1534
1538
  #ifdef HAS_OCCLUSIONMAP
1535
1539
  if (pbrMaterial.occlusionMapEnabled != 0) {
@@ -1828,7 +1832,7 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1828
1832
  PBRInfo_setAmbientLight(&pbrInfo);
1829
1833
  color += calculateMaterialLightColor(
1830
1834
  pbrInfo,
1831
- lighting.ambientColor,
1835
+ lighting.ambientColor * pbr_ambientVisibility,
1832
1836
  clearcoatNormal,
1833
1837
  clearcoatFactor,
1834
1838
  clearcoatRoughness,
@@ -1844,7 +1848,7 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1844
1848
  PBRInfo_setDirectionalLight(&pbrInfo, -lighting_getDirectionalLight(i).direction);
1845
1849
  color += calculateMaterialLightColor(
1846
1850
  pbrInfo,
1847
- lighting_getDirectionalLight(i).color,
1851
+ lighting_getDirectionalLight(i).color * select(1.0, clamp(directionalVisibility, 0.0, 1.0), i == 0),
1848
1852
  clearcoatNormal,
1849
1853
  clearcoatFactor,
1850
1854
  clearcoatRoughness,
@@ -1855,7 +1859,7 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1855
1859
  );
1856
1860
  color += calculateDiffuseTransmissionLight(
1857
1861
  pbrInfo,
1858
- lighting_getDirectionalLight(i).color,
1862
+ lighting_getDirectionalLight(i).color * select(1.0, clamp(directionalVisibility, 0.0, 1.0), i == 0),
1859
1863
  diffuseTransmissionColor,
1860
1864
  diffuseTransmission,
1861
1865
  multiscatterColor,
@@ -1874,7 +1878,7 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1874
1878
  );
1875
1879
  color += calculateMaterialLightColor(
1876
1880
  pbrInfo,
1877
- lighting_getPointLight(i).color / attenuation,
1881
+ lighting_getPointLight(i).color * select(1.0, clamp(pointVisibility[min(i, 3)], 0.0, 1.0), i < 4) / attenuation,
1878
1882
  clearcoatNormal,
1879
1883
  clearcoatFactor,
1880
1884
  clearcoatRoughness,
@@ -1885,7 +1889,7 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1885
1889
  );
1886
1890
  color += calculateDiffuseTransmissionLight(
1887
1891
  pbrInfo,
1888
- lighting_getPointLight(i).color / attenuation,
1892
+ lighting_getPointLight(i).color * select(1.0, clamp(pointVisibility[min(i, 3)], 0.0, 1.0), i < 4) / attenuation,
1889
1893
  diffuseTransmissionColor,
1890
1894
  diffuseTransmission,
1891
1895
  multiscatterColor,
@@ -1954,6 +1958,7 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1954
1958
  }
1955
1959
  #endif
1956
1960
 
1961
+ let indirectBaseColor = color;
1957
1962
  // Calculate lighting contribution from image based lighting source (IBL)
1958
1963
  #ifdef USE_IBL
1959
1964
  if (pbrMaterial.IBLenabled != 0) {
@@ -1988,6 +1993,8 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
1988
1993
  (1.0 - diffuseTransmission) * baseLayerEnergy * lightmapIrradiance / M_PI;
1989
1994
  #endif
1990
1995
 
1996
+ color = indirectBaseColor + (color - indirectBaseColor) * pbr_ambientVisibility;
1997
+
1991
1998
  // Apply optional PBR terms for additional (optional) shading
1992
1999
  #ifdef HAS_OCCLUSIONMAP
1993
2000
  if (pbrMaterial.occlusionMapEnabled != 0) {
@@ -2050,6 +2057,21 @@ fn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f)
2050
2057
  return vec4<f32>(applySceneColorManagement(color), alpha);
2051
2058
  }
2052
2059
 
2060
+ // Depth-only passes use the same base-color alpha, vertex color and UV transform.
2061
+ fn pbr_discardMaskedFragment(vertexColor: vec4f) {
2062
+ #ifdef ALPHA_CUTOFF
2063
+ var alpha = pbrMaterial.baseColorFactor.a * vertexColor.a;
2064
+ #ifdef HAS_BASECOLORMAP
2065
+ alpha *= textureSample(pbr_baseColorSampler, pbr_baseColorSamplerSampler, getMaterialUV(pbrMaterial.baseColorUVSet, pbrMaterial.baseColorUVTransform)).a;
2066
+ #endif
2067
+ if (alpha < pbrMaterial.alphaCutoff) {discard;}
2068
+ #endif
2069
+ }
2070
+
2071
+ fn pbr_filterColorWithSpotShadows(vertexColor: vec4f, spotVisibility: vec4f) -> vec4f {
2072
+ return pbr_filterColorWithShadows(vertexColor, 1.0, vec4f(1.0), spotVisibility);
2073
+ }
2074
+
2053
2075
  fn pbr_filterColor(vertexColor: vec4<f32>) -> vec4<f32> {
2054
2076
  return pbr_filterColorWithSpotShadows(vertexColor, vec4f(1.0));
2055
2077
  }