Variable: pbrMaterial
constpbrMaterial:object
Defined in: modules/lighting/pbr-material/pbr-material.ts:199
An implementation of PBR (Physically-Based Rendering). Physically Based Shading of a microfacet surface defined by a glTF material.
Type Declaration
bindingLayout
readonlybindingLayout: readonly [{group:3;name:"pbrMaterial"; }, {group:3;name:"pbr_baseColorSampler"; }, {group:3;name:"pbr_normalSampler"; }, {group:3;name:"pbr_emissiveSampler"; }, {group:3;name:"pbr_lightmapSampler"; }, {group:3;name:"pbr_metallicRoughnessSampler"; }, {group:3;name:"pbr_occlusionSampler"; }, {group:3;name:"pbr_specularColorSampler"; }, {group:3;name:"pbr_specularIntensitySampler"; }, {group:3;name:"pbr_transmissionSampler"; }, {group:3;name:"pbr_thicknessSampler"; }, {group:3;name:"pbr_clearcoatSampler"; }, {group:3;name:"pbr_clearcoatRoughnessSampler"; }, {group:3;name:"pbr_clearcoatNormalSampler"; }, {group:3;name:"pbr_sheenColorSampler"; }, {group:3;name:"pbr_sheenRoughnessSampler"; }, {group:3;name:"pbr_iridescenceSampler"; }, {group:3;name:"pbr_iridescenceThicknessSampler"; }, {group:3;name:"pbr_anisotropySampler"; }, {group:3;name:"pbr_bumpSampler"; }, {group:3;name:"pbr_diffuseTransmissionSampler"; }, {group:3;name:"pbr_diffuseTransmissionColorSampler"; }, {group:3;name:"pbr_multiscatterColorSampler"; }]
defaultUniforms
readonlydefaultUniforms:Required<PBRMaterialUniforms>
defines
readonlydefines:object
defines.ALPHA_CUTOFF
readonlyALPHA_CUTOFF:false=false
defines.HAS_ANISOTROPYMAP
readonlyHAS_ANISOTROPYMAP:false=false
defines.HAS_BASECOLORMAP
readonlyHAS_BASECOLORMAP:false=false
defines.HAS_BUMPMAP
readonlyHAS_BUMPMAP:false=false
defines.HAS_CLEARCOATMAP
readonlyHAS_CLEARCOATMAP:false=false
defines.HAS_CLEARCOATNORMALMAP
readonlyHAS_CLEARCOATNORMALMAP:false=false
defines.HAS_CLEARCOATROUGHNESSMAP
readonlyHAS_CLEARCOATROUGHNESSMAP:false=false
defines.HAS_DIFFUSETRANSMISSIONCOLORMAP
readonlyHAS_DIFFUSETRANSMISSIONCOLORMAP:false=false
defines.HAS_DIFFUSETRANSMISSIONMAP
readonlyHAS_DIFFUSETRANSMISSIONMAP:false=false
defines.HAS_EMISSIVEMAP
readonlyHAS_EMISSIVEMAP:false=false
defines.HAS_IRIDESCENCEMAP
readonlyHAS_IRIDESCENCEMAP:false=false
defines.HAS_IRIDESCENCETHICKNESSMAP
readonlyHAS_IRIDESCENCETHICKNESSMAP:false=false
defines.HAS_LIGHTMAP
readonlyHAS_LIGHTMAP:false=false
defines.HAS_METALROUGHNESSMAP
readonlyHAS_METALROUGHNESSMAP:false=false
defines.HAS_MULTISCATTERCOLORMAP
readonlyHAS_MULTISCATTERCOLORMAP:false=false
defines.HAS_NORMALMAP
readonlyHAS_NORMALMAP:false=false
defines.HAS_OCCLUSIONMAP
readonlyHAS_OCCLUSIONMAP:false=false
defines.HAS_SHEENCOLORMAP
readonlyHAS_SHEENCOLORMAP:false=false
defines.HAS_SHEENROUGHNESSMAP
readonlyHAS_SHEENROUGHNESSMAP:false=false
defines.HAS_SPECULARCOLORMAP
readonlyHAS_SPECULARCOLORMAP:false=false
defines.HAS_SPECULARINTENSITYMAP
readonlyHAS_SPECULARINTENSITYMAP:false=false
defines.HAS_THICKNESSMAP
readonlyHAS_THICKNESSMAP:false=false
defines.HAS_TRANSMISSIONMAP
readonlyHAS_TRANSMISSIONMAP:false=false
defines.LIGHTING_FRAGMENT
readonlyLIGHTING_FRAGMENT:true=true
defines.PBR_DEBUG
readonlyPBR_DEBUG:false=false
defines.USE_IBL
readonlyUSE_IBL:false=false
defines.USE_MATERIAL_EXTENSIONS
readonlyUSE_MATERIAL_EXTENSIONS:false=false
dependencies
readonlydependencies: [{bindingLayout: readonly [{group:2;name:"lighting"; }];defaultUniforms:LightingUniforms;defines: { };firstBindingSlot:0;fs: "precision highp int;\n\n// #if (defined(SHADER_TYPE_FRAGMENT) && defined(LIGHTING_FRAGMENT)) || (defined(SHADER_TYPE_VERTEX) && defined(LIGHTING_VERTEX))\nstruct AmbientLight {\n vec3 color;\n};\n\nstruct PointLight {\n vec3 color;\n vec3 position;\n vec3 attenuation; // 2nd order x:Constant-y:Linear-z:Exponential\n};\n\nstruct SpotLight {\n vec3 color;\n vec3 position;\n vec3 direction;\n vec3 attenuation;\n vec2 coneCos;\n};\n\nstruct DirectionalLight {\n vec3 color;\n vec3 direction;\n};\n\nstruct UniformLight {\n vec3 color;\n vec3 position;\n vec3 direction;\n vec3 attenuation;\n vec2 coneCos;\n};\n\nstruct AreaLightUniform {\n vec3 color; vec3 position; vec3 halfAxisX; vec3 halfAxisY; vec3 normal; int disk;\n};\n\nlayout(std140) uniform lightingUniforms {\n int enabled;\n int directionalLightCount;\n int pointLightCount;\n int spotLightCount;\n vec3 ambientColor;\n UniformLight lights[5];\n int areaLightCount;\n AreaLightUniform areaLights[4];\n} lighting;\n\nPointLight lighting_getPointLight(int index) {\n UniformLight light = lighting.lights[index];\n return PointLight(light.color, light.position, light.attenuation);\n}\n\nSpotLight lighting_getSpotLight(int index) {\n UniformLight light = lighting.lights[lighting.pointLightCount + index];\n return SpotLight(light.color, light.position, light.direction, light.attenuation, light.coneCos);\n}\n\nDirectionalLight lighting_getDirectionalLight(int index) {\n UniformLight light =\n lighting.lights[lighting.pointLightCount + lighting.spotLightCount + index];\n return DirectionalLight(light.color, light.direction);\n}\n\nfloat getPointLightAttenuation(PointLight pointLight, float distance) {\n return pointLight.attenuation.x\n + pointLight.attenuation.y * distance\n + pointLight.attenuation.z * distance * distance;\n}\n\nfloat getSpotLightAttenuation(SpotLight spotLight, vec3 positionWorldspace) {\n vec3 light_direction = normalize(positionWorldspace - spotLight.position);\n float coneFactor = smoothstep(\n spotLight.coneCos.y,\n spotLight.coneCos.x,\n dot(normalize(spotLight.direction), light_direction)\n );\n float distanceAttenuation = getPointLightAttenuation(\n PointLight(spotLight.color, spotLight.position, spotLight.attenuation),\n distance(spotLight.position, positionWorldspace)\n );\n return distanceAttenuation / max(coneFactor, 0.0001);\n}\n\n// #endif\n";getUniforms: (props?,_prevUniforms) =>LightingUniforms;name:"lighting";props:LightingProps;source: "// #if (defined(SHADER_TYPE_FRAGMENT) && defined(LIGHTING_FRAGMENT)) || (defined(SHADER_TYPE_VERTEX) && defined(LIGHTING_VERTEX))\nconst MAX_LIGHTS: i32 = 5;\n\nstruct AmbientLight {\n color: vec3<f32>,\n};\n\nstruct PointLight {\n color: vec3<f32>,\n position: vec3<f32>,\n attenuation: vec3<f32>, // 2nd order x:Constant-y:Linear-z:Exponential\n};\n\nstruct SpotLight {\n color: vec3<f32>,\n position: vec3<f32>,\n direction: vec3<f32>,\n attenuation: vec3<f32>,\n coneCos: vec2<f32>,\n};\n\nstruct DirectionalLight {\n color: vec3<f32>,\n direction: vec3<f32>,\n};\n\nstruct UniformLight {\n color: vec3<f32>,\n position: vec3<f32>,\n direction: vec3<f32>,\n attenuation: vec3<f32>,\n coneCos: vec2<f32>,\n};\n\nstruct AreaLightUniform {\n color: vec3f, position: vec3f, halfAxisX: vec3f, halfAxisY: vec3f, normal: vec3f, disk: i32,\n};\n\nstruct lightingUniforms {\n enabled: i32,\n directionalLightCount: i32,\n pointLightCount: i32,\n spotLightCount: i32,\n ambientColor: vec3<f32>,\n lights: array<UniformLight, 5>,\n areaLightCount: i32,\n areaLights: array<AreaLightUniform, 4>,\n};\n\n@group(2) @binding(auto) var<uniform> lighting : lightingUniforms;\n\nfn lighting_getPointLight(index: i32) -> PointLight {\n let light = lighting.lights[index];\n return PointLight(light.color, light.position, light.attenuation);\n}\n\nfn lighting_getSpotLight(index: i32) -> SpotLight {\n let light = lighting.lights[lighting.pointLightCount + index];\n return SpotLight(light.color, light.position, light.direction, light.attenuation, light.coneCos);\n}\n\nfn lighting_getDirectionalLight(index: i32) -> DirectionalLight {\n let light = lighting.lights[lighting.pointLightCount + lighting.spotLightCount + index];\n return DirectionalLight(light.color, light.direction);\n}\n\nfn getPointLightAttenuation(pointLight: PointLight, distance: f32) -> f32 {\n return pointLight.attenuation.x\n + pointLight.attenuation.y * distance\n + pointLight.attenuation.z * distance * distance;\n}\n\nfn getSpotLightAttenuation(spotLight: SpotLight, positionWorldspace: vec3<f32>) -> f32 {\n let lightDirection = normalize(positionWorldspace - spotLight.position);\n let coneFactor = smoothstep(\n spotLight.coneCos.y,\n spotLight.coneCos.x,\n dot(normalize(spotLight.direction), lightDirection)\n );\n let distanceAttenuation = getPointLightAttenuation(\n PointLight(spotLight.color, spotLight.position, spotLight.attenuation),\n distance(spotLight.position, positionWorldspace)\n );\n return distanceAttenuation / max(coneFactor, 0.0001);\n}\n";uniforms:LightingUniforms;uniformTypes: {ambientColor:"vec3<f32>";areaLightCount:"i32";areaLights: readonly [{color:"vec3<f32>";disk:"i32";halfAxisX:"vec3<f32>";halfAxisY:"vec3<f32>";normal:"vec3<f32>";position:"vec3<f32>"; },4];directionalLightCount:"i32";enabled:"i32";lights: readonly [{attenuation:"vec3<f32>";color:"vec3<f32>";coneCos:"vec2<f32>";direction:"vec3<f32>";position:"vec3<f32>"; },5];pointLightCount:"i32";spotLightCount:"i32"; };vs: "precision highp int;\n\n// #if (defined(SHADER_TYPE_FRAGMENT) && defined(LIGHTING_FRAGMENT)) || (defined(SHADER_TYPE_VERTEX) && defined(LIGHTING_VERTEX))\nstruct AmbientLight {\n vec3 color;\n};\n\nstruct PointLight {\n vec3 color;\n vec3 position;\n vec3 attenuation; // 2nd order x:Constant-y:Linear-z:Exponential\n};\n\nstruct SpotLight {\n vec3 color;\n vec3 position;\n vec3 direction;\n vec3 attenuation;\n vec2 coneCos;\n};\n\nstruct DirectionalLight {\n vec3 color;\n vec3 direction;\n};\n\nstruct UniformLight {\n vec3 color;\n vec3 position;\n vec3 direction;\n vec3 attenuation;\n vec2 coneCos;\n};\n\nstruct AreaLightUniform {\n vec3 color; vec3 position; vec3 halfAxisX; vec3 halfAxisY; vec3 normal; int disk;\n};\n\nlayout(std140) uniform lightingUniforms {\n int enabled;\n int directionalLightCount;\n int pointLightCount;\n int spotLightCount;\n vec3 ambientColor;\n UniformLight lights[5];\n int areaLightCount;\n AreaLightUniform areaLights[4];\n} lighting;\n\nPointLight lighting_getPointLight(int index) {\n UniformLight light = lighting.lights[index];\n return PointLight(light.color, light.position, light.attenuation);\n}\n\nSpotLight lighting_getSpotLight(int index) {\n UniformLight light = lighting.lights[lighting.pointLightCount + index];\n return SpotLight(light.color, light.position, light.direction, light.attenuation, light.coneCos);\n}\n\nDirectionalLight lighting_getDirectionalLight(int index) {\n UniformLight light =\n lighting.lights[lighting.pointLightCount + lighting.spotLightCount + index];\n return DirectionalLight(light.color, light.direction);\n}\n\nfloat getPointLightAttenuation(PointLight pointLight, float distance) {\n return pointLight.attenuation.x\n + pointLight.attenuation.y * distance\n + pointLight.attenuation.z * distance * distance;\n}\n\nfloat getSpotLightAttenuation(SpotLight spotLight, vec3 positionWorldspace) {\n vec3 light_direction = normalize(positionWorldspace - spotLight.position);\n float coneFactor = smoothstep(\n spotLight.coneCos.y,\n spotLight.coneCos.x,\n dot(normalize(spotLight.direction), light_direction)\n );\n float distanceAttenuation = getPointLightAttenuation(\n PointLight(spotLight.color, spotLight.position, spotLight.attenuation),\n distance(spotLight.position, positionWorldspace)\n );\n return distanceAttenuation / max(coneFactor, 0.0001);\n}\n\n// #endif\n"; }, {bindingLayout: readonly [{group:2;name:"areaLighting"; }, {group:2;name:"areaLTCMatrix"; }, {group:2;name:"areaLTCAmplitude"; }];defaultUniforms: {lightCount:0;lights:AreaLightUniform[];sampleCount:64; };dependencies: [{bindingLayout: readonly [{group:2;name:"lighting"; }];defaultUniforms:LightingUniforms;defines: { };firstBindingSlot:0;fs: "precision highp int;\n\n// #if (defined(SHADER_TYPE_FRAGMENT) && defined(LIGHTING_FRAGMENT)) || (defined(SHADER_TYPE_VERTEX) && defined(LIGHTING_VERTEX))\nstruct AmbientLight {\n vec3 color;\n};\n\nstruct PointLight {\n vec3 color;\n vec3 position;\n vec3 attenuation; // 2nd order x:Constant-y:Linear-z:Exponential\n};\n\nstruct SpotLight {\n vec3 color;\n vec3 position;\n vec3 direction;\n vec3 attenuation;\n vec2 coneCos;\n};\n\nstruct DirectionalLight {\n vec3 color;\n vec3 direction;\n};\n\nstruct UniformLight {\n vec3 color;\n vec3 position;\n vec3 direction;\n vec3 attenuation;\n vec2 coneCos;\n};\n\nstruct AreaLightUniform {\n vec3 color; vec3 position; vec3 halfAxisX; vec3 halfAxisY; vec3 normal; int disk;\n};\n\nlayout(std140) uniform lightingUniforms {\n int enabled;\n int directionalLightCount;\n int pointLightCount;\n int spotLightCount;\n vec3 ambientColor;\n UniformLight lights[5];\n int areaLightCount;\n AreaLightUniform areaLights[4];\n} lighting;\n\nPointLight lighting_getPointLight(int index) {\n UniformLight light = lighting.lights[index];\n return PointLight(light.color, light.position, light.attenuation);\n}\n\nSpotLight lighting_getSpotLight(int index) {\n UniformLight light = lighting.lights[lighting.pointLightCount + index];\n return SpotLight(light.color, light.position, light.direction, light.attenuation, light.coneCos);\n}\n\nDirectionalLight lighting_getDirectionalLight(int index) {\n UniformLight light =\n lighting.lights[lighting.pointLightCount + lighting.spotLightCount + index];\n return DirectionalLight(light.color, light.direction);\n}\n\nfloat getPointLightAttenuation(PointLight pointLight, float distance) {\n return pointLight.attenuation.x\n + pointLight.attenuation.y * distance\n + pointLight.attenuation.z * distance * distance;\n}\n\nfloat getSpotLightAttenuation(SpotLight spotLight, vec3 positionWorldspace) {\n vec3 light_direction = normalize(positionWorldspace - spotLight.position);\n float coneFactor = smoothstep(\n spotLight.coneCos.y,\n spotLight.coneCos.x,\n dot(normalize(spotLight.direction), light_direction)\n );\n float distanceAttenuation = getPointLightAttenuation(\n PointLight(spotLight.color, spotLight.position, spotLight.attenuation),\n distance(spotLight.position, positionWorldspace)\n );\n return distanceAttenuation / max(coneFactor, 0.0001);\n}\n\n// #endif\n";getUniforms: (props?,_prevUniforms) =>LightingUniforms;name:"lighting";props:LightingProps;source: "// #if (defined(SHADER_TYPE_FRAGMENT) && defined(LIGHTING_FRAGMENT)) || (defined(SHADER_TYPE_VERTEX) && defined(LIGHTING_VERTEX))\nconst MAX_LIGHTS: i32 = 5;\n\nstruct AmbientLight {\n color: vec3<f32>,\n};\n\nstruct PointLight {\n color: vec3<f32>,\n position: vec3<f32>,\n attenuation: vec3<f32>, // 2nd order x:Constant-y:Linear-z:Exponential\n};\n\nstruct SpotLight {\n color: vec3<f32>,\n position: vec3<f32>,\n direction: vec3<f32>,\n attenuation: vec3<f32>,\n coneCos: vec2<f32>,\n};\n\nstruct DirectionalLight {\n color: vec3<f32>,\n direction: vec3<f32>,\n};\n\nstruct UniformLight {\n color: vec3<f32>,\n position: vec3<f32>,\n direction: vec3<f32>,\n attenuation: vec3<f32>,\n coneCos: vec2<f32>,\n};\n\nstruct AreaLightUniform {\n color: vec3f, position: vec3f, halfAxisX: vec3f, halfAxisY: vec3f, normal: vec3f, disk: i32,\n};\n\nstruct lightingUniforms {\n enabled: i32,\n directionalLightCount: i32,\n pointLightCount: i32,\n spotLightCount: i32,\n ambientColor: vec3<f32>,\n lights: array<UniformLight, 5>,\n areaLightCount: i32,\n areaLights: array<AreaLightUniform, 4>,\n};\n\n@group(2) @binding(auto) var<uniform> lighting : lightingUniforms;\n\nfn lighting_getPointLight(index: i32) -> PointLight {\n let light = lighting.lights[index];\n return PointLight(light.color, light.position, light.attenuation);\n}\n\nfn lighting_getSpotLight(index: i32) -> SpotLight {\n let light = lighting.lights[lighting.pointLightCount + index];\n return SpotLight(light.color, light.position, light.direction, light.attenuation, light.coneCos);\n}\n\nfn lighting_getDirectionalLight(index: i32) -> DirectionalLight {\n let light = lighting.lights[lighting.pointLightCount + lighting.spotLightCount + index];\n return DirectionalLight(light.color, light.direction);\n}\n\nfn getPointLightAttenuation(pointLight: PointLight, distance: f32) -> f32 {\n return pointLight.attenuation.x\n + pointLight.attenuation.y * distance\n + pointLight.attenuation.z * distance * distance;\n}\n\nfn getSpotLightAttenuation(spotLight: SpotLight, positionWorldspace: vec3<f32>) -> f32 {\n let lightDirection = normalize(positionWorldspace - spotLight.position);\n let coneFactor = smoothstep(\n spotLight.coneCos.y,\n spotLight.coneCos.x,\n dot(normalize(spotLight.direction), lightDirection)\n );\n let distanceAttenuation = getPointLightAttenuation(\n PointLight(spotLight.color, spotLight.position, spotLight.attenuation),\n distance(spotLight.position, positionWorldspace)\n );\n return distanceAttenuation / max(coneFactor, 0.0001);\n}\n";uniforms:LightingUniforms;uniformTypes: {ambientColor:"vec3<f32>";areaLightCount:"i32";areaLights: readonly [{color:"vec3<f32>";disk:"i32";halfAxisX:"vec3<f32>";halfAxisY:"vec3<f32>";normal:"vec3<f32>";position:"vec3<f32>"; },4];directionalLightCount:"i32";enabled:"i32";lights: readonly [{attenuation:"vec3<f32>";color:"vec3<f32>";coneCos:"vec2<f32>";direction:"vec3<f32>";position:"vec3<f32>"; },5];pointLightCount:"i32";spotLightCount:"i32"; };vs: "precision highp int;\n\n// #if (defined(SHADER_TYPE_FRAGMENT) && defined(LIGHTING_FRAGMENT)) || (defined(SHADER_TYPE_VERTEX) && defined(LIGHTING_VERTEX))\nstruct AmbientLight {\n vec3 color;\n};\n\nstruct PointLight {\n vec3 color;\n vec3 position;\n vec3 attenuation; // 2nd order x:Constant-y:Linear-z:Exponential\n};\n\nstruct SpotLight {\n vec3 color;\n vec3 position;\n vec3 direction;\n vec3 attenuation;\n vec2 coneCos;\n};\n\nstruct DirectionalLight {\n vec3 color;\n vec3 direction;\n};\n\nstruct UniformLight {\n vec3 color;\n vec3 position;\n vec3 direction;\n vec3 attenuation;\n vec2 coneCos;\n};\n\nstruct AreaLightUniform {\n vec3 color; vec3 position; vec3 halfAxisX; vec3 halfAxisY; vec3 normal; int disk;\n};\n\nlayout(std140) uniform lightingUniforms {\n int enabled;\n int directionalLightCount;\n int pointLightCount;\n int spotLightCount;\n vec3 ambientColor;\n UniformLight lights[5];\n int areaLightCount;\n AreaLightUniform areaLights[4];\n} lighting;\n\nPointLight lighting_getPointLight(int index) {\n UniformLight light = lighting.lights[index];\n return PointLight(light.color, light.position, light.attenuation);\n}\n\nSpotLight lighting_getSpotLight(int index) {\n UniformLight light = lighting.lights[lighting.pointLightCount + index];\n return SpotLight(light.color, light.position, light.direction, light.attenuation, light.coneCos);\n}\n\nDirectionalLight lighting_getDirectionalLight(int index) {\n UniformLight light =\n lighting.lights[lighting.pointLightCount + lighting.spotLightCount + index];\n return DirectionalLight(light.color, light.direction);\n}\n\nfloat getPointLightAttenuation(PointLight pointLight, float distance) {\n return pointLight.attenuation.x\n + pointLight.attenuation.y * distance\n + pointLight.attenuation.z * distance * distance;\n}\n\nfloat getSpotLightAttenuation(SpotLight spotLight, vec3 positionWorldspace) {\n vec3 light_direction = normalize(positionWorldspace - spotLight.position);\n float coneFactor = smoothstep(\n spotLight.coneCos.y,\n spotLight.coneCos.x,\n dot(normalize(spotLight.direction), light_direction)\n );\n float distanceAttenuation = getPointLightAttenuation(\n PointLight(spotLight.color, spotLight.position, spotLight.attenuation),\n distance(spotLight.position, positionWorldspace)\n );\n return distanceAttenuation / max(coneFactor, 0.0001);\n}\n\n// #endif\n"; }];fs:string;name:"areaLighting";props:AreaLightingProps;source:string;uniforms:AreaLightingUniforms;uniformTypes: {lightCount:"i32";lights: readonly [{color:"vec3<f32>";disk:"i32";halfAxisX:"vec3<f32>";halfAxisY:"vec3<f32>";normal:"vec3<f32>";position:"vec3<f32>"; },4];sampleCount:"i32"; };vs:string;getUniforms:AreaLightingUniforms; }, {bindingLayout: readonly [{group:2;name:"pbr_diffuseEnvSampler"; }, {group:2;name:"pbr_specularEnvSampler"; }, {group:2;name:"pbr_brdfLUT"; }];firstBindingSlot:32;fs: "#ifdef USE_IBL\nuniform samplerCube pbr_diffuseEnvSampler;\nuniform samplerCube pbr_specularEnvSampler;\nuniform sampler2D pbr_brdfLUT;\n#endif\n";name:"ibl";source: "#ifdef USE_IBL\n@group(2) @binding(auto) var pbr_diffuseEnvSampler: texture_cube<f32>;\n@group(2) @binding(auto) var pbr_diffuseEnvSamplerSampler: sampler;\n@group(2) @binding(auto) var pbr_specularEnvSampler: texture_cube<f32>;\n@group(2) @binding(auto) var pbr_specularEnvSamplerSampler: sampler;\n@group(2) @binding(auto) var pbr_brdfLUT: texture_2d<f32>;\n@group(2) @binding(auto) var pbr_brdfLUTSampler: sampler;\n#endif\n";vs: "#ifdef USE_IBL\nuniform samplerCube pbr_diffuseEnvSampler;\nuniform samplerCube pbr_specularEnvSampler;\nuniform sampler2D pbr_brdfLUT;\n#endif\n"; },ShaderModule<PBRProjectionProps>, {bindingLayout: readonly [{group:1;name:"pbrScene"; }, {group:1;name:"pbr_transmissionFramebufferSampler"; }];defaultUniforms:Required<PBRSceneUniforms>;fs: "layout(std140) uniform pbrSceneUniforms {\n float exposure;\n highp int toneMapMode;\n float environmentIntensity;\n float environmentRotation;\n float environmentMipCount;\n highp int outputEncoding;\n vec2 framebufferSize;\n mat4 viewMatrix;\n mat4 projectionMatrix;\n} pbrScene;\n\n#ifdef USE_TRANSMISSION_FRAMEBUFFER\nuniform sampler2D pbr_transmissionFramebufferSampler;\n#endif\n";getUniforms: (props) =>PBRSceneProps<unknown>;name:"pbrScene";source: "struct pbrSceneUniforms {\n exposure: f32,\n toneMapMode: i32,\n environmentIntensity: f32,\n environmentRotation: f32,\n environmentMipCount: f32,\n outputEncoding: i32,\n framebufferSize: vec2<f32>,\n viewMatrix: mat4x4<f32>,\n projectionMatrix: mat4x4<f32>\n};\n\n@group(1) @binding(auto) var<uniform> pbrScene: pbrSceneUniforms;\n\n#ifdef USE_TRANSMISSION_FRAMEBUFFER\n@group(1) @binding(auto) var pbr_transmissionFramebufferSampler: texture_2d<f32>;\n@group(1) @binding(auto) var pbr_transmissionFramebufferSamplerSampler: sampler;\n#endif\n";uniformTypes: {environmentIntensity:"f32";environmentMipCount:"f32";environmentRotation:"f32";exposure:"f32";framebufferSize:"vec2<f32>";outputEncoding:"i32";projectionMatrix:"mat4x4<f32>";toneMapMode:"i32";viewMatrix:"mat4x4<f32>"; };vs: "layout(std140) uniform pbrSceneUniforms {\n float exposure;\n highp int toneMapMode;\n float environmentIntensity;\n float environmentRotation;\n float environmentMipCount;\n highp int outputEncoding;\n vec2 framebufferSize;\n mat4 viewMatrix;\n mat4 projectionMatrix;\n} pbrScene;\n\n#ifdef USE_TRANSMISSION_FRAMEBUFFER\nuniform sampler2D pbr_transmissionFramebufferSampler;\n#endif\n"; }]
firstBindingSlot
readonlyfirstBindingSlot:0=0
fs
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"
getUniforms
readonlygetUniforms: (props) =>Partial<PBRMaterialProps<unknown>>
Parameters
props
Partial<PBRMaterialProps<unknown>>
Returns
Partial<PBRMaterialProps<unknown>>
name
readonlyname:"pbrMaterial"='pbrMaterial'
props
readonlyprops:PBRMaterialProps<unknown>
source
source: "#ifdef DOUBLE_SIDED\nvar<private> pbr_frontFacing: bool = true;\n#endif\nstruct PBRFragmentInputs {\n pbr_vPosition: vec3f,\n pbr_vUV0: vec2f,\n pbr_vUV1: vec2f,\n pbr_vTBN: mat3x3f,\n pbr_vNormal: vec3f\n};\n\nvar<private> fragmentInputs: PBRFragmentInputs;\n\nfn pbr_setPositionNormalTangentUV(\n position: vec4f,\n normal: vec4f,\n tangent: vec4f,\n uv0: vec2f,\n uv1: vec2f\n)\n{\n var pos: vec4f = pbrProjection.modelMatrix * position;\n fragmentInputs.pbr_vPosition = pos.xyz / pos.w;\n fragmentInputs.pbr_vNormal = vec3f(0.0, 0.0, 1.0);\n fragmentInputs.pbr_vTBN = mat3x3f(\n vec3f(1.0, 0.0, 0.0),\n vec3f(0.0, 1.0, 0.0),\n vec3f(0.0, 0.0, 1.0)\n );\n fragmentInputs.pbr_vUV0 = vec2f(0.0, 0.0);\n fragmentInputs.pbr_vUV1 = uv1;\n\n#ifdef HAS_NORMALS\n let normalW: vec3f = normalize((pbrProjection.normalMatrix * vec4f(normal.xyz, 0.0)).xyz);\n fragmentInputs.pbr_vNormal = normalW;\n#ifdef HAS_TANGENTS\n let tangentW: vec3f = normalize((pbrProjection.modelMatrix * vec4f(tangent.xyz, 0.0)).xyz);\n let bitangentW: vec3f = cross(normalW, tangentW) * tangent.w;\n fragmentInputs.pbr_vTBN = mat3x3f(tangentW, bitangentW, normalW);\n#endif\n#endif\n\n#ifdef HAS_UV\n fragmentInputs.pbr_vUV0 = uv0;\n#endif\n}\n\nstruct pbrMaterialUniforms {\n // Material is unlit\n unlit: u32,\n\n // Base color map\n baseColorMapEnabled: u32,\n baseColorFactor: vec4f,\n\n normalMapEnabled : u32,\n normalScale: f32, // #ifdef HAS_NORMALMAP\n\n emissiveMapEnabled: u32,\n emissiveFactor: vec3f, // #ifdef HAS_EMISSIVEMAP\n\n metallicRoughnessValues: vec2f,\n metallicRoughnessMapEnabled: u32,\n\n occlusionMapEnabled: i32,\n occlusionStrength: f32, // #ifdef HAS_OCCLUSIONMAP\n \n alphaCutoffEnabled: i32,\n alphaCutoff: f32, // #ifdef ALPHA_CUTOFF\n\n specularColorFactor: vec3f,\n specularIntensityFactor: f32,\n specularColorMapEnabled: i32,\n specularIntensityMapEnabled: i32,\n\n ior: f32,\n\n transmissionFactor: f32,\n transmissionMapEnabled: i32,\n\n thicknessFactor: f32,\n attenuationDistance: f32,\n attenuationColor: vec3f,\n\n clearcoatFactor: f32,\n clearcoatRoughnessFactor: f32,\n clearcoatMapEnabled: i32,\n clearcoatRoughnessMapEnabled: i32,\n\n sheenColorFactor: vec3f,\n sheenRoughnessFactor: f32,\n sheenColorMapEnabled: i32,\n sheenRoughnessMapEnabled: i32,\n\n iridescenceFactor: f32,\n iridescenceIor: f32,\n iridescenceThicknessRange: vec2f,\n iridescenceMapEnabled: i32,\n\n anisotropyStrength: f32,\n anisotropyRotation: f32,\n anisotropyDirection: vec2f,\n anisotropyMapEnabled: i32,\n\n emissiveStrength: f32,\n dispersion: f32,\n \n // IBL\n IBLenabled: i32,\n scaleIBLAmbient: vec2f, // #ifdef USE_IBL\n \n // debugging flags used for shader output of intermediate PBR variables\n // #ifdef PBR_DEBUG\n scaleDiffBaseMR: vec4f,\n scaleFGDSpec: vec4f,\n // #endif\n\n baseColorUVSet: i32,\n baseColorUVTransform: mat3x3f,\n metallicRoughnessUVSet: i32,\n metallicRoughnessUVTransform: mat3x3f,\n normalUVSet: i32,\n normalUVTransform: mat3x3f,\n occlusionUVSet: i32,\n occlusionUVTransform: mat3x3f,\n emissiveUVSet: i32,\n emissiveUVTransform: mat3x3f,\n specularColorUVSet: i32,\n specularColorUVTransform: mat3x3f,\n specularIntensityUVSet: i32,\n specularIntensityUVTransform: mat3x3f,\n transmissionUVSet: i32,\n transmissionUVTransform: mat3x3f,\n thicknessUVSet: i32,\n thicknessUVTransform: mat3x3f,\n clearcoatUVSet: i32,\n clearcoatUVTransform: mat3x3f,\n clearcoatRoughnessUVSet: i32,\n clearcoatRoughnessUVTransform: mat3x3f,\n clearcoatNormalUVSet: i32,\n clearcoatNormalUVTransform: mat3x3f,\n sheenColorUVSet: i32,\n sheenColorUVTransform: mat3x3f,\n sheenRoughnessUVSet: i32,\n sheenRoughnessUVTransform: mat3x3f,\n iridescenceUVSet: i32,\n iridescenceUVTransform: mat3x3f,\n iridescenceThicknessUVSet: i32,\n iridescenceThicknessUVTransform: mat3x3f,\n anisotropyUVSet: i32,\n anisotropyUVTransform: mat3x3f,\n\n bumpFactor: f32,\n bumpMapEnabled: i32,\n diffuseTransmissionFactor: f32,\n diffuseTransmissionMapEnabled: i32,\n diffuseTransmissionColorFactor: vec3f,\n diffuseTransmissionColorMapEnabled: i32,\n multiscatterColorFactor: vec3f,\n multiscatterColorMapEnabled: i32,\n scatterAnisotropy: f32,\n\n bumpUVSet: i32,\n bumpUVTransform: mat3x3f,\n diffuseTransmissionUVSet: i32,\n diffuseTransmissionUVTransform: mat3x3f,\n diffuseTransmissionColorUVSet: i32,\n diffuseTransmissionColorUVTransform: mat3x3f,\n multiscatterColorUVSet: i32,\n multiscatterColorUVTransform: mat3x3f,\n lightmapMapEnabled: u32,\n lightmapIntensity: f32,\n lightmapUVSet: i32,\n lightmapUVTransform: mat3x3f,\n scatterStrengthFactor: f32,\n}\n\n@group(3) @binding(auto) var<uniform> pbrMaterial : pbrMaterialUniforms;\n\n// Samplers\n#ifdef HAS_BASECOLORMAP\n@group(3) @binding(auto) var pbr_baseColorSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_baseColorSamplerSampler: sampler;\n#endif\n#ifdef HAS_NORMALMAP\n@group(3) @binding(auto) var pbr_normalSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_normalSamplerSampler: sampler;\n#endif\n#ifdef HAS_EMISSIVEMAP\n@group(3) @binding(auto) var pbr_emissiveSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_emissiveSamplerSampler: sampler;\n#endif\n#ifdef HAS_LIGHTMAP\n@group(3) @binding(auto) var pbr_lightmapSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_lightmapSamplerSampler: sampler;\n#endif\n#ifdef HAS_METALROUGHNESSMAP\n@group(3) @binding(auto) var pbr_metallicRoughnessSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_metallicRoughnessSamplerSampler: sampler;\n#endif\n#ifdef HAS_OCCLUSIONMAP\n@group(3) @binding(auto) var pbr_occlusionSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_occlusionSamplerSampler: sampler;\n#endif\n#ifdef HAS_SPECULARCOLORMAP\n@group(3) @binding(auto) var pbr_specularColorSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_specularColorSamplerSampler: sampler;\n#endif\n#ifdef HAS_SPECULARINTENSITYMAP\n@group(3) @binding(auto) var pbr_specularIntensitySampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_specularIntensitySamplerSampler: sampler;\n#endif\n#ifdef HAS_TRANSMISSIONMAP\n@group(3) @binding(auto) var pbr_transmissionSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_transmissionSamplerSampler: sampler;\n#endif\n#ifdef HAS_THICKNESSMAP\n@group(3) @binding(auto) var pbr_thicknessSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_thicknessSamplerSampler: sampler;\n#endif\n#ifdef HAS_CLEARCOATMAP\n@group(3) @binding(auto) var pbr_clearcoatSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_clearcoatSamplerSampler: sampler;\n#endif\n#ifdef HAS_CLEARCOATROUGHNESSMAP\n@group(3) @binding(auto) var pbr_clearcoatRoughnessSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_clearcoatRoughnessSamplerSampler: sampler;\n#endif\n#ifdef HAS_CLEARCOATNORMALMAP\n@group(3) @binding(auto) var pbr_clearcoatNormalSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_clearcoatNormalSamplerSampler: sampler;\n#endif\n#ifdef HAS_SHEENCOLORMAP\n@group(3) @binding(auto) var pbr_sheenColorSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_sheenColorSamplerSampler: sampler;\n#endif\n#ifdef HAS_SHEENROUGHNESSMAP\n@group(3) @binding(auto) var pbr_sheenRoughnessSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_sheenRoughnessSamplerSampler: sampler;\n#endif\n#ifdef HAS_IRIDESCENCEMAP\n@group(3) @binding(auto) var pbr_iridescenceSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_iridescenceSamplerSampler: sampler;\n#endif\n#ifdef HAS_IRIDESCENCETHICKNESSMAP\n@group(3) @binding(auto) var pbr_iridescenceThicknessSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_iridescenceThicknessSamplerSampler: sampler;\n#endif\n#ifdef HAS_ANISOTROPYMAP\n@group(3) @binding(auto) var pbr_anisotropySampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_anisotropySamplerSampler: sampler;\n#endif\n#ifdef HAS_BUMPMAP\n@group(3) @binding(auto) var pbr_bumpSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_bumpSamplerSampler: sampler;\n#endif\n#ifdef HAS_DIFFUSETRANSMISSIONMAP\n@group(3) @binding(auto) var pbr_diffuseTransmissionSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_diffuseTransmissionSamplerSampler: sampler;\n#endif\n#ifdef HAS_DIFFUSETRANSMISSIONCOLORMAP\n@group(3) @binding(auto) var pbr_diffuseTransmissionColorSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_diffuseTransmissionColorSamplerSampler: sampler;\n#endif\n#ifdef HAS_MULTISCATTERCOLORMAP\n@group(3) @binding(auto) var pbr_multiscatterColorSampler: texture_2d<f32>;\n@group(3) @binding(auto) var pbr_multiscatterColorSamplerSampler: sampler;\n#endif\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 NdotL: f32, // cos angle between normal and light direction\n NdotV: f32, // cos angle between normal and view direction\n NdotH: f32, // cos angle between normal and half vector\n LdotH: f32, // cos angle between light direction and half vector\n VdotH: f32, // cos angle between view direction and half vector\n perceptualRoughness: f32, // roughness value, as authored by the model creator (input to shader)\n metalness: f32, // metallic value at the surface\n reflectance0: vec3f, // full reflectance color (normal incidence angle)\n reflectance90: vec3f, // reflectance color at grazing angle\n alphaRoughness: f32, // roughness mapped to a more linear change in the roughness (proposed by [2])\n diffuseColor: vec3f, // color contribution from diffuse lighting\n specularColor: vec3f, // color contribution from specular lighting\n n: vec3f, // normal at surface point\n v: vec3f, // vector from surface point to camera\n l: vec3f, // direction from the surface toward the current light\n h: vec3f // half vector between the current light and camera\n};\n\nconst M_PI = 3.141592653589793;\nconst 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.\nfn widenSpecularRoughness(perceptualRoughness: f32, normal: vec3f) -> f32 {\n let normalDerivativeX = dpdx(normal);\n let normalDerivativeY = dpdy(normal);\n let normalVariance =\n dot(normalDerivativeX, normalDerivativeX) +\n dot(normalDerivativeY, normalDerivativeY);\n let kernelRoughnessSquared = min(2.0 * normalVariance, 1.0);\n return clamp(\n sqrt(perceptualRoughness * perceptualRoughness + kernelRoughnessSquared),\n c_MinRoughness,\n 1.0\n );\n}\n\nfn SRGBtoLINEAR(srgbIn: vec4f ) -> vec4f\n{\n var linOut: vec3f = srgbIn.xyz;\n#ifdef MANUAL_SRGB\n let bLess: vec3f = step(vec3f(0.04045), srgbIn.xyz);\n linOut = mix(\n srgbIn.xyz / vec3f(12.92),\n pow((srgbIn.xyz + vec3f(0.055)) / vec3f(1.055), vec3f(2.4)),\n bLess\n );\n#ifdef SRGB_FAST_APPROXIMATION\n linOut = pow(srgbIn.xyz, vec3f(2.2));\n#endif\n#endif\n return vec4f(linOut, srgbIn.w);\n}\n\nfn getMaterialUV(uvSet: i32, uvTransform: mat3x3f) -> vec2f\n{\n var baseUV = fragmentInputs.pbr_vUV0;\n if (uvSet == 1) {\n baseUV = fragmentInputs.pbr_vUV1;\n }\n return (uvTransform * vec3f(baseUV, 1.0)).xy;\n}\n\n// Build the tangent basis from interpolated attributes or screen-space derivatives.\nfn getTBN(uv: vec2f) -> mat3x3f\n{\n let pos_dx: vec3f = dpdx(fragmentInputs.pbr_vPosition);\n let pos_dy: vec3f = dpdy(fragmentInputs.pbr_vPosition);\n let tex_dx: vec3f = dpdx(vec3f(uv, 0.0));\n let tex_dy: vec3f = dpdy(vec3f(uv, 0.0));\n var t: vec3f = (tex_dy.y * pos_dx - tex_dx.y * pos_dy) / (tex_dx.x * tex_dy.y - tex_dy.x * tex_dx.y);\n\n var ng: vec3f = cross(pos_dy, pos_dx);\n#ifdef HAS_NORMALS\n ng = normalize(fragmentInputs.pbr_vNormal);\n#endif\n t = normalize(t - ng * dot(ng, t));\n var b: vec3f = normalize(cross(ng, t));\n var tbn: mat3x3f = mat3x3f(t, b, ng);\n#ifdef HAS_TANGENTS\n tbn = fragmentInputs.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 (!pbr_frontFacing) { tbn = mat3x3f(-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.\nfn getMappedNormal(\n normalSampler: texture_2d<f32>,\n normalSamplerBinding: sampler,\n tbn: mat3x3f,\n normalScale: f32,\n uv: vec2f\n) -> vec3f\n{\n let n = textureSample(normalSampler, normalSamplerBinding, uv).rgb;\n return normalize(tbn * ((2.0 * n - 1.0) * vec3f(normalScale, normalScale, 1.0)));\n}\n\nfn getNormal(tbn: mat3x3f, uv: vec2f) -> vec3f\n{\n // The tbn matrix is linearly interpolated, so we need to re-normalize\n var n: vec3f = normalize(tbn[2].xyz);\n#ifdef HAS_NORMALMAP\n n = getMappedNormal(\n pbr_normalSampler,\n pbr_normalSamplerSampler,\n tbn,\n pbrMaterial.normalScale,\n uv\n );\n#endif\n\n#ifdef HAS_BUMPMAP\n let bumpUV = getMaterialUV(pbrMaterial.bumpUVSet, pbrMaterial.bumpUVTransform);\n let bumpTexelSize = 1.0 / vec2f(textureDimensions(pbr_bumpSampler, 0));\n let bumpHeight = textureSample(pbr_bumpSampler, pbr_bumpSamplerSampler, bumpUV).r;\n let bumpGradient = vec2f(\n textureSample(\n pbr_bumpSampler,\n pbr_bumpSamplerSampler,\n bumpUV + vec2f(bumpTexelSize.x, 0.0)\n ).r - bumpHeight,\n textureSample(\n pbr_bumpSampler,\n pbr_bumpSamplerSampler,\n bumpUV + vec2f(0.0, bumpTexelSize.y)\n ).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\nfn getClearcoatNormal(tbn: mat3x3f, baseNormal: vec3f, uv: vec2f) -> vec3f\n{\n#ifdef HAS_CLEARCOATNORMALMAP\n return getMappedNormal(\n pbr_clearcoatNormalSampler,\n pbr_clearcoatNormalSamplerSampler,\n tbn,\n 1.0,\n uv\n );\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\nfn getIBLContribution(pbrInfo: PBRInfo, n: vec3f, reflection: vec3f) -> vec3f\n{\n#ifdef USE_SCENE_ENVIRONMENT\n let maximumMipLevel = max(pbrScene.environmentMipCount - 1.0, 0.0);\n let rotationSine = sin(pbrScene.environmentRotation);\n let rotationCosine = cos(pbrScene.environmentRotation);\n let environmentRotation = mat2x2f(\n vec2f(rotationCosine, rotationSine),\n vec2f(-rotationSine, rotationCosine)\n );\n let rotatedNormal = environmentRotation * n.xz;\n let rotatedReflection = environmentRotation * reflection.xz;\n let environmentNormal = vec3f(rotatedNormal.x, n.y, rotatedNormal.y);\n let environmentReflection = vec3f(rotatedReflection.x, reflection.y, rotatedReflection.y);\n#else\n let maximumMipLevel = 9.0;\n let environmentNormal = n;\n let environmentReflection = reflection;\n#endif\n let lod = pbrInfo.perceptualRoughness * maximumMipLevel;\n // retrieve a scale and bias to F0. See [1], Figure 3\n let brdfSample = textureSampleLevel(\n pbr_brdfLUT,\n pbr_brdfLUTSampler,\n vec2f(pbrInfo.NdotV, 1.0 - pbrInfo.perceptualRoughness),\n 0.0\n );\n let diffuseSample = textureSampleLevel(\n pbr_diffuseEnvSampler,\n pbr_diffuseEnvSamplerSampler,\n environmentNormal,\n 0.0\n );\n var specularSample = textureSampleLevel(\n pbr_specularEnvSampler,\n pbr_specularEnvSamplerSampler,\n environmentReflection,\n 0.0\n );\n#ifdef USE_TEX_LOD\n specularSample = textureSampleLevel(\n pbr_specularEnvSampler,\n pbr_specularEnvSamplerSampler,\n environmentReflection,\n lod\n );\n#endif\n\n#ifdef USE_SCENE_ENVIRONMENT\n let brdf = brdfSample.rgb;\n let diffuseLight = diffuseSample.rgb;\n let specularLight = specularSample.rgb;\n#else\n let brdf = SRGBtoLINEAR(brdfSample).rgb;\n let diffuseLight = SRGBtoLINEAR(diffuseSample).rgb;\n let specularLight = SRGBtoLINEAR(specularSample).rgb;\n#endif\n\n let diffuse = diffuseLight * pbrInfo.diffuseColor * pbrMaterial.scaleIBLAmbient.x;\n let specular =\n specularLight * (pbrInfo.specularColor * brdf.x + brdf.y) * 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\nfn diffuse(pbrInfo: PBRInfo) -> vec3<f32> {\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\nfn specularReflection(pbrInfo: PBRInfo) -> vec3<f32> {\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].\nfn geometricOcclusion(pbrInfo: PBRInfo) -> f32 {\n let NdotL: f32 = pbrInfo.NdotL;\n let NdotV: f32 = pbrInfo.NdotV;\n let r: f32 = pbrInfo.alphaRoughness;\n\n let attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));\n let 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.\nfn microfacetDistribution(pbrInfo: PBRInfo) -> f32 {\n let roughnessSq = pbrInfo.alphaRoughness * pbrInfo.alphaRoughness;\n let f = (pbrInfo.NdotH * roughnessSq - pbrInfo.NdotH) * pbrInfo.NdotH + 1.0;\n return roughnessSq / (M_PI * f * f);\n}\n\nfn maxComponent(value: vec3f) -> f32 {\n return max(max(value.r, value.g), value.b);\n}\n\nfn getDielectricF0(ior: f32) -> f32 {\n let clampedIor = max(ior, 1.0);\n let ratio = (clampedIor - 1.0) / (clampedIor + 1.0);\n return ratio * ratio;\n}\n\nfn normalizeDirection(direction: vec2f) -> vec2f {\n let directionLength = length(direction);\n if (directionLength > 0.0001) {\n return direction / directionLength;\n }\n\n return vec2f(1.0, 0.0);\n}\n\nfn rotateDirection(direction: vec2f, rotation: f32) -> vec2f {\n let s = sin(rotation);\n let c = cos(rotation);\n return vec2f(direction.x * c - direction.y * s, direction.x * s + direction.y * c);\n}\n\nfn encodeLinearSRGB(linearColor: vec3f) -> vec3f {\n let positiveColor = max(linearColor, vec3f(0.0));\n return select(\n positiveColor * 12.92,\n 1.055 * pow(positiveColor, vec3f(1.0 / 2.4)) - 0.055,\n positiveColor > vec3f(0.0031308)\n );\n}\n\nfn toneMapKhronosPBRNeutral(inputColor: vec3f) -> vec3f {\n let startCompression = 0.76;\n let darkestChannel = min(inputColor.r, min(inputColor.g, inputColor.b));\n let offset = select(\n 0.04,\n darkestChannel - 6.25 * darkestChannel * darkestChannel,\n darkestChannel < 0.08\n );\n var color = inputColor - vec3f(offset);\n let peak = maxComponent(color);\n if (peak < startCompression) {\n return color;\n }\n\n let compressionRange = 1.0 - startCompression;\n let compressedPeak = 1.0 - compressionRange * compressionRange /\n (peak + compressionRange - startCompression);\n color *= compressedPeak / max(peak, 0.0001);\n let desaturation = 1.0 - 1.0 / (0.15 * (peak - compressedPeak) + 1.0);\n return mix(color, vec3f(compressedPeak), desaturation);\n}\n\nfn applySceneColorManagement(sceneColor: vec3f) -> vec3f {\n#ifdef USE_SCENE_COLOR_MANAGEMENT\n var color = max(sceneColor, vec3f(0.0)) * max(pbrScene.exposure, 0.0);\n if (pbrScene.toneMapMode == 1) {\n color /= vec3f(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 vec3f(0.0),\n vec3f(1.0)\n );\n }\n if (pbrScene.outputEncoding == 0) {\n return color;\n }\n return encodeLinearSRGB(color);\n#else\n return pow(max(sceneColor, vec3f(0.0)), vec3f(1.0 / 2.2));\n#endif\n}\n\nfn dielectricSchlick(reflectance: f32, cosine: f32) -> f32 {\n return reflectance + (1.0 - reflectance) * pow(clamp(1.0 - cosine, 0.0, 1.0), 5.0);\n}\n\nfn evaluateIridescenceSensitivity(opticalPathDifference: f32, phaseShift: vec3f) -> vec3f {\n let phase = 2.0 * M_PI * opticalPathDifference * 1.0e-9;\n let sensitivity = vec3f(5.4856e-13, 4.4201e-13, 5.2481e-13);\n let position = vec3f(1.6810e6, 1.7953e6, 2.2084e6);\n let variance = vec3f(4.3278e9, 9.3046e9, 6.6121e9);\n var 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 mat3x3f(\n vec3f(3.2404542, -0.9692660, 0.0556434),\n vec3f(-1.5371385, 1.8760108, -0.2040259),\n vec3f(-0.4985314, 0.0415560, 1.0572252)\n ) * xyz;\n}\n\nfn getIridescenceTint(\n iridescence: f32,\n thickness: f32,\n NdotV: f32,\n baseReflectance: vec3f\n) -> vec3f {\n if (iridescence <= 0.0 || thickness <= 0.0) {\n return baseReflectance;\n }\n\n let filmIor = max(pbrMaterial.iridescenceIor, 1.0);\n let sineSquared = (1.0 - NdotV * NdotV) / (filmIor * filmIor);\n let cosineSquared = 1.0 - sineSquared;\n if (cosineSquared <= 0.0) {\n return mix(baseReflectance, vec3f(1.0), iridescence);\n }\n let filmCosine = sqrt(cosineSquared);\n let firstInterfaceReflectance = dielectricSchlick(getDielectricF0(filmIor), NdotV);\n let transmittedEnergy = 1.0 - firstInterfaceReflectance;\n let squareRootReflectance = sqrt(clamp(baseReflectance, vec3f(0.0), vec3f(0.9999)));\n let baseIor = (vec3f(1.0) + squareRootReflectance) /\n (vec3f(1.0) - squareRootReflectance);\n var secondInterfaceF0 = (baseIor - vec3f(filmIor)) / (baseIor + vec3f(filmIor));\n secondInterfaceF0 *= secondInterfaceF0;\n let secondInterfaceReflectance = secondInterfaceF0 +\n (vec3f(1.0) - secondInterfaceF0) * pow(1.0 - filmCosine, 5.0);\n let phaseShift = vec3f(M_PI) + select(\n vec3f(0.0),\n vec3f(M_PI),\n baseIor < vec3f(filmIor)\n );\n let opticalPathDifference = 2.0 * filmIor * thickness * filmCosine;\n let combinedReflectance = clamp(\n firstInterfaceReflectance * secondInterfaceReflectance,\n vec3f(0.00001),\n vec3f(0.9999)\n );\n let recurringAmplitude = sqrt(combinedReflectance);\n let interfaceResponse = transmittedEnergy * transmittedEnergy * secondInterfaceReflectance /\n (vec3f(1.0) - combinedReflectance);\n var reflectedSpectrum = vec3f(firstInterfaceReflectance) + interfaceResponse;\n var harmonicAmplitude = interfaceResponse - vec3f(transmittedEnergy);\n for (var harmonic = 1; harmonic <= 2; harmonic++) {\n harmonicAmplitude *= recurringAmplitude;\n reflectedSpectrum += harmonicAmplitude * 2.0 * evaluateIridescenceSensitivity(\n f32(harmonic) * opticalPathDifference,\n f32(harmonic) * phaseShift\n );\n }\n return mix(baseReflectance, clamp(reflectedSpectrum, vec3f(0.0), vec3f(1.0)), iridescence);\n}\n\nfn getVolumeAttenuation(thickness: f32) -> vec3f {\n if (thickness <= 0.0) {\n return vec3f(1.0);\n }\n\n let attenuationCoefficient =\n -log(max(pbrMaterial.attenuationColor, vec3f(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.\nfn getDiffuseTransmissionAttenuation(\n pbrInfo: PBRInfo,\n multiscatterColor: vec3f,\n thickness: f32\n) -> vec3f {\n let volumeAttenuation = getVolumeAttenuation(thickness);\n let scatteringStrength = maxComponent(multiscatterColor);\n if (thickness <= 0.0 || scatteringStrength <= 0.0001) {\n return volumeAttenuation;\n }\n\n let anisotropy = clamp(pbrMaterial.scatterAnisotropy, -0.95, 0.95);\n let scatteringCosine = clamp(dot(-pbrInfo.v, pbrInfo.l), -1.0, 1.0);\n let phaseDenominator = max(\n 1.0 + anisotropy * anisotropy - 2.0 * anisotropy * scatteringCosine,\n 0.0001\n );\n let phaseWeight = clamp(\n (1.0 - anisotropy * anisotropy) / pow(phaseDenominator, 1.5),\n 0.0,\n 4.0\n );\n let scatteringDepth = thickness / max(pbrMaterial.attenuationDistance, 0.0001);\n let scatteringProbability = 1.0 - exp(-scatteringDepth);\n let scatteringColor = clamp(multiscatterColor, vec3f(0.0), vec3f(1.0));\n return mix(\n volumeAttenuation,\n volumeAttenuation * mix(vec3f(1.0), scatteringColor * phaseWeight, scatteringColor),\n scatteringProbability\n );\n}\n\nfn calculateDiffuseTransmissionLight(\n pbrInfo: PBRInfo,\n lightColor: vec3f,\n diffuseTransmissionColor: vec3f,\n diffuseTransmission: f32,\n multiscatterColor: vec3f,\n thickness: f32\n) -> vec3f {\n let oppositeHemisphere = max(dot(-pbrInfo.n, pbrInfo.l), 0.0);\n if (oppositeHemisphere <= 0.0 || diffuseTransmission <= 0.0) {\n return vec3f(0.0);\n }\n\n let nonReflectedEnergy = vec3f(1.0) - clamp(pbrInfo.reflectance0, vec3f(0.0), vec3f(1.0));\n let 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\nfn calculateDiffuseTransmissionIBL(\n pbrInfo: PBRInfo,\n diffuseTransmissionColor: vec3f,\n diffuseTransmission: f32,\n multiscatterColor: vec3f,\n thickness: f32\n) -> vec3f {\n if (diffuseTransmission <= 0.0) {\n return vec3f(0.0);\n }\n\n#ifdef USE_SCENE_ENVIRONMENT\n let rotationSine = sin(pbrScene.environmentRotation);\n let rotationCosine = cos(pbrScene.environmentRotation);\n let environmentRotation = mat2x2f(\n vec2f(rotationCosine, rotationSine),\n vec2f(-rotationSine, rotationCosine)\n );\n let rotatedNormal = environmentRotation * -pbrInfo.n.xz;\n let oppositeNormal = vec3f(rotatedNormal.x, -pbrInfo.n.y, rotatedNormal.y);\n let environmentColor = textureSampleLevel(\n pbr_diffuseEnvSampler,\n pbr_diffuseEnvSamplerSampler,\n oppositeNormal,\n 0.0\n ).rgb * max(pbrScene.environmentIntensity, 0.0);\n#else\n let environmentColor = SRGBtoLINEAR(\n textureSampleLevel(pbr_diffuseEnvSampler, pbr_diffuseEnvSamplerSampler, -pbrInfo.n, 0.0)\n ).rgb;\n#endif\n let nonReflectedEnergy = vec3f(1.0) - clamp(pbrInfo.reflectance0, vec3f(0.0), vec3f(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\nfn sampleTransmittedSceneColor(\n position: vec3f,\n normal: vec3f,\n viewDirection: vec3f,\n thickness: f32,\n perceptualRoughness: f32,\n indexOfRefraction: f32\n) -> vec3f {\n let refractionDirection = refract(\n -viewDirection,\n normal,\n 1.0 / max(indexOfRefraction, 1.0)\n );\n let refractedPosition = position + refractionDirection * thickness;\n let clipPosition = pbrScene.projectionMatrix *\n pbrScene.viewMatrix * vec4f(refractedPosition, 1.0);\n var textureCoordinate = clipPosition.xy / max(clipPosition.w, 0.0001) * 0.5 + 0.5;\n textureCoordinate.y = 1.0 - textureCoordinate.y;\n textureCoordinate = clamp(textureCoordinate, vec2f(0.001), vec2f(0.999));\n\n let blurRadius = perceptualRoughness * perceptualRoughness * 8.0 /\n max(pbrScene.framebufferSize, vec2f(1.0));\n var sceneColor = textureSampleLevel(\n pbr_transmissionFramebufferSampler,\n pbr_transmissionFramebufferSamplerSampler,\n textureCoordinate,\n 0.0\n ).rgb * 0.4;\n sceneColor += textureSampleLevel(\n pbr_transmissionFramebufferSampler,\n pbr_transmissionFramebufferSamplerSampler,\n textureCoordinate + vec2f(blurRadius.x, 0.0),\n 0.0\n ).rgb * 0.15;\n sceneColor += textureSampleLevel(\n pbr_transmissionFramebufferSampler,\n pbr_transmissionFramebufferSamplerSampler,\n textureCoordinate - vec2f(blurRadius.x, 0.0),\n 0.0\n ).rgb * 0.15;\n sceneColor += textureSampleLevel(\n pbr_transmissionFramebufferSampler,\n pbr_transmissionFramebufferSamplerSampler,\n textureCoordinate + vec2f(0.0, blurRadius.y),\n 0.0\n ).rgb * 0.15;\n sceneColor += textureSampleLevel(\n pbr_transmissionFramebufferSampler,\n pbr_transmissionFramebufferSamplerSampler,\n textureCoordinate - vec2f(0.0, blurRadius.y),\n 0.0\n ).rgb * 0.15;\n return max(sceneColor, vec3f(0.0));\n}\n\nfn getTransmittedSceneColor(\n position: vec3f,\n normal: vec3f,\n viewDirection: vec3f,\n thickness: f32,\n perceptualRoughness: f32\n) -> vec3f {\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 let halfSpread = (max(pbrMaterial.ior, 1.0) - 1.0) * 0.025 * pbrMaterial.dispersion;\n let indicesOfRefraction = max(\n vec3f(pbrMaterial.ior - halfSpread, pbrMaterial.ior, pbrMaterial.ior + halfSpread),\n vec3f(1.0)\n );\n return vec3f(\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\nfn createClearcoatPBRInfo(\n basePBRInfo: PBRInfo,\n clearcoatNormal: vec3f,\n clearcoatRoughness: f32\n) -> PBRInfo {\n let perceptualRoughness = clamp(clearcoatRoughness, c_MinRoughness, 1.0);\n let alphaRoughness = perceptualRoughness * perceptualRoughness;\n let 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 vec3f(0.04),\n vec3f(1.0),\n alphaRoughness,\n vec3f(0.0),\n vec3f(0.04),\n clearcoatNormal,\n basePBRInfo.v,\n basePBRInfo.l,\n basePBRInfo.h\n );\n}\n\nfn calculateClearcoatContribution(\n pbrInfo: PBRInfo,\n lightColor: vec3f,\n clearcoatNormal: vec3f,\n clearcoatFactor: f32,\n clearcoatRoughness: f32\n) -> vec3f {\n if (clearcoatFactor <= 0.0) {\n return vec3f(0.0);\n }\n\n let clearcoatPBRInfo = createClearcoatPBRInfo(pbrInfo, clearcoatNormal, clearcoatRoughness);\n return calculateFinalColor(clearcoatPBRInfo, lightColor) * clearcoatFactor;\n}\n\n#ifdef USE_IBL\nfn calculateClearcoatIBLContribution(\n pbrInfo: PBRInfo,\n clearcoatNormal: vec3f,\n reflection: vec3f,\n clearcoatFactor: f32,\n clearcoatRoughness: f32\n) -> vec3f {\n if (clearcoatFactor <= 0.0) {\n return vec3f(0.0);\n }\n\n let clearcoatPBRInfo = createClearcoatPBRInfo(pbrInfo, clearcoatNormal, clearcoatRoughness);\n return getIBLContribution(clearcoatPBRInfo, clearcoatNormal, reflection) * clearcoatFactor;\n}\n#endif\n\nfn calculateSheenContribution(\n pbrInfo: PBRInfo,\n lightColor: vec3f,\n sheenColor: vec3f,\n sheenRoughness: f32\n) -> vec3f {\n if (maxComponent(sheenColor) <= 0.0) {\n return vec3f(0.0);\n }\n\n let alpha = max(sheenRoughness * sheenRoughness, 0.0001);\n let inverseAlpha = 1.0 / alpha;\n let sineSquared = max(1.0 - pbrInfo.NdotH * pbrInfo.NdotH, 0.0);\n let distribution = (2.0 + inverseAlpha) * pow(sineSquared, inverseAlpha * 0.5) /\n (2.0 * M_PI);\n let 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\nfn calculateAnisotropicLightColor(\n pbrInfo: PBRInfo,\n lightColor: vec3f,\n anisotropyTangent: vec3f,\n anisotropyStrength: f32\n) -> vec3f {\n if (anisotropyStrength <= 0.0) {\n return calculateFinalColor(pbrInfo, lightColor);\n }\n\n let anisotropyBitangent = normalize(cross(pbrInfo.n, anisotropyTangent));\n let tangentRoughness = mix(\n pbrInfo.alphaRoughness,\n 1.0,\n anisotropyStrength * anisotropyStrength\n );\n let bitangentRoughness = clamp(pbrInfo.alphaRoughness, 0.001, 1.0);\n let roughnessProduct = tangentRoughness * bitangentRoughness;\n let distributionVector = vec3f(\n bitangentRoughness * dot(anisotropyTangent, pbrInfo.h),\n tangentRoughness * dot(anisotropyBitangent, pbrInfo.h),\n roughnessProduct * pbrInfo.NdotH\n );\n let distributionFactor = roughnessProduct /\n max(dot(distributionVector, distributionVector), 0.000001);\n let distribution = roughnessProduct * distributionFactor * distributionFactor / M_PI;\n let viewMask = pbrInfo.NdotL * length(vec3f(\n tangentRoughness * dot(anisotropyTangent, pbrInfo.v),\n bitangentRoughness * dot(anisotropyBitangent, pbrInfo.v),\n pbrInfo.NdotV\n ));\n let lightMask = pbrInfo.NdotV * length(vec3f(\n tangentRoughness * dot(anisotropyTangent, pbrInfo.l),\n bitangentRoughness * dot(anisotropyBitangent, pbrInfo.l),\n pbrInfo.NdotL\n ));\n let visibility = clamp(0.5 / max(viewMask + lightMask, 0.000001), 0.0, 1.0);\n let fresnel = specularReflection(pbrInfo);\n let diffuseContribution = (vec3f(1.0) - fresnel) * diffuse(pbrInfo);\n return pbrInfo.NdotL * lightColor *\n (diffuseContribution + fresnel * distribution * visibility);\n}\n\nfn getAnisotropicReflection(\n pbrInfo: PBRInfo,\n anisotropyTangent: vec3f,\n anisotropyStrength: f32\n) -> vec3f {\n if (anisotropyStrength <= 0.0) {\n return -normalize(reflect(pbrInfo.v, pbrInfo.n));\n }\n let anisotropyBitangent = normalize(cross(pbrInfo.n, anisotropyTangent));\n var anisotropicNormal = normalize(cross(anisotropyBitangent, pbrInfo.v));\n anisotropicNormal = normalize(cross(anisotropicNormal, anisotropyBitangent));\n let bend = anisotropyStrength * (1.0 - pbrInfo.perceptualRoughness);\n return -normalize(reflect(pbrInfo.v, normalize(mix(pbrInfo.n, anisotropicNormal, bend))));\n}\n\nfn calculateMaterialLightColor(\n pbrInfo: PBRInfo,\n lightColor: vec3f,\n clearcoatNormal: vec3f,\n clearcoatFactor: f32,\n clearcoatRoughness: f32,\n sheenColor: vec3f,\n sheenRoughness: f32,\n anisotropyTangent: vec3f,\n anisotropyStrength: f32\n) -> vec3f {\n var 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\nfn PBRInfo_setAmbientLight(pbrInfo: ptr<function, 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\nfn PBRInfo_setDirectionalLight(pbrInfo: ptr<function, PBRInfo>, lightDirection: vec3<f32>) {\n let n = (*pbrInfo).n;\n let v = (*pbrInfo).v;\n let l = normalize(lightDirection); // Vector from surface point to light\n let 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\nfn PBRInfo_setPointLight(pbrInfo: ptr<function, PBRInfo>, pointLight: PointLight) {\n let light_direction = normalize(pointLight.position - fragmentInputs.pbr_vPosition);\n PBRInfo_setDirectionalLight(pbrInfo, light_direction);\n}\n\nfn PBRInfo_setSpotLight(pbrInfo: ptr<function, PBRInfo>, spotLight: SpotLight) {\n let light_direction = normalize(spotLight.position - fragmentInputs.pbr_vPosition);\n PBRInfo_setDirectionalLight(pbrInfo, light_direction);\n}\n\nfn calculateFinalColor(pbrInfo: PBRInfo, lightColor: vec3<f32>) -> vec3<f32> {\n // Calculate the shading terms for the microfacet specular shading model\n let F = specularReflection(pbrInfo);\n let G = geometricOcclusion(pbrInfo);\n let D = microfacetDistribution(pbrInfo);\n\n // Calculation of analytical lighting contribution\n let diffuseContrib = (1.0 - F) * diffuse(pbrInfo);\n let 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.\nfn pbr_filterColorWithSpotShadows(vertexColor: vec4<f32>, spotVisibility: vec4f) -> vec4<f32> {\n let baseColorUV = getMaterialUV(pbrMaterial.baseColorUVSet, pbrMaterial.baseColorUVTransform);\n let metallicRoughnessUV = getMaterialUV(\n pbrMaterial.metallicRoughnessUVSet,\n pbrMaterial.metallicRoughnessUVTransform\n );\n let normalUV = getMaterialUV(pbrMaterial.normalUVSet, pbrMaterial.normalUVTransform);\n let occlusionUV = getMaterialUV(pbrMaterial.occlusionUVSet, pbrMaterial.occlusionUVTransform);\n let emissiveUV = getMaterialUV(pbrMaterial.emissiveUVSet, pbrMaterial.emissiveUVTransform);\n let lightmapUV = getMaterialUV(pbrMaterial.lightmapUVSet, pbrMaterial.lightmapUVTransform);\n let specularColorUV = getMaterialUV(\n pbrMaterial.specularColorUVSet,\n pbrMaterial.specularColorUVTransform\n );\n let specularIntensityUV = getMaterialUV(\n pbrMaterial.specularIntensityUVSet,\n pbrMaterial.specularIntensityUVTransform\n );\n let transmissionUV = getMaterialUV(\n pbrMaterial.transmissionUVSet,\n pbrMaterial.transmissionUVTransform\n );\n let thicknessUV = getMaterialUV(pbrMaterial.thicknessUVSet, pbrMaterial.thicknessUVTransform);\n let clearcoatUV = getMaterialUV(pbrMaterial.clearcoatUVSet, pbrMaterial.clearcoatUVTransform);\n let clearcoatRoughnessUV = getMaterialUV(\n pbrMaterial.clearcoatRoughnessUVSet,\n pbrMaterial.clearcoatRoughnessUVTransform\n );\n let clearcoatNormalUV = getMaterialUV(\n pbrMaterial.clearcoatNormalUVSet,\n pbrMaterial.clearcoatNormalUVTransform\n );\n let sheenColorUV = getMaterialUV(\n pbrMaterial.sheenColorUVSet,\n pbrMaterial.sheenColorUVTransform\n );\n let sheenRoughnessUV = getMaterialUV(\n pbrMaterial.sheenRoughnessUVSet,\n pbrMaterial.sheenRoughnessUVTransform\n );\n let iridescenceUV = getMaterialUV(\n pbrMaterial.iridescenceUVSet,\n pbrMaterial.iridescenceUVTransform\n );\n let iridescenceThicknessUV = getMaterialUV(\n pbrMaterial.iridescenceThicknessUVSet,\n pbrMaterial.iridescenceThicknessUVTransform\n );\n let anisotropyUV = getMaterialUV(\n pbrMaterial.anisotropyUVSet,\n pbrMaterial.anisotropyUVTransform\n );\n let diffuseTransmissionUV = getMaterialUV(\n pbrMaterial.diffuseTransmissionUVSet,\n pbrMaterial.diffuseTransmissionUVTransform\n );\n let diffuseTransmissionColorUV = getMaterialUV(\n pbrMaterial.diffuseTransmissionColorUVSet,\n pbrMaterial.diffuseTransmissionColorUVTransform\n );\n let 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 var baseColor: vec4<f32> = pbrMaterial.baseColorFactor * vertexColor;\n #ifdef HAS_BASECOLORMAP\n baseColor = SRGBtoLINEAR(\n textureSample(pbr_baseColorSampler, pbr_baseColorSamplerSampler, baseColorUV)\n ) * pbrMaterial.baseColorFactor * vertexColor;\n #endif\n\n #ifdef ALPHA_CUTOFF\n if (baseColor.a < pbrMaterial.alphaCutoff) {\n discard;\n }\n #endif\n\n var color = vec3<f32>(0.0, 0.0, 0.0);\n var transmission = 0.0;\n\n var lightmapIrradiance = vec3<f32>(0.0);\n #ifdef HAS_LIGHTMAP\n if (pbrMaterial.lightmapMapEnabled != 0u) {\n lightmapIrradiance = textureSample(pbr_lightmapSampler, pbr_lightmapSamplerSampler, lightmapUV).rgb * pbrMaterial.lightmapIntensity;\n }\n #endif\n\n if (pbrMaterial.unlit != 0u) {\n color = baseColor.rgb;\n #ifdef HAS_LIGHTMAP\n if (pbrMaterial.lightmapMapEnabled != 0u) {\n color *= lightmapIrradiance / M_PI;\n #ifdef HAS_OCCLUSIONMAP\n if (pbrMaterial.occlusionMapEnabled != 0) {\n let ao = textureSample(pbr_occlusionSampler, pbr_occlusionSamplerSampler, occlusionUV).r;\n color = mix(color, color * ao, pbrMaterial.occlusionStrength);\n }\n #endif\n }\n #endif\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 var perceptualRoughness = pbrMaterial.metallicRoughnessValues.y;\n var 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 let mrSample = textureSample(\n pbr_metallicRoughnessSampler,\n pbr_metallicRoughnessSamplerSampler,\n metallicRoughnessUV\n );\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 let tbn = getTBN(normalUV);\n let n = getNormal(tbn, normalUV); // normal at surface point\n perceptualRoughness = widenSpecularRoughness(perceptualRoughness, n);\n let v = normalize(pbrProjection.camera - fragmentInputs.pbr_vPosition); // Vector from surface point to camera\n let NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);\n var useExtendedPBR = false;\n #ifdef USE_MATERIAL_EXTENSIONS\n useExtendedPBR =\n pbrMaterial.specularColorMapEnabled != 0 ||\n pbrMaterial.specularIntensityMapEnabled != 0 ||\n abs(pbrMaterial.specularIntensityFactor - 1.0) > 0.0001 ||\n maxComponent(abs(pbrMaterial.specularColorFactor - vec3f(1.0))) > 0.0001 ||\n abs(pbrMaterial.ior - 1.5) > 0.0001 ||\n pbrMaterial.dispersion > 0.0001 ||\n pbrMaterial.transmissionMapEnabled != 0 ||\n pbrMaterial.transmissionFactor > 0.0001 ||\n pbrMaterial.diffuseTransmissionMapEnabled != 0 ||\n pbrMaterial.diffuseTransmissionColorMapEnabled != 0 ||\n pbrMaterial.diffuseTransmissionFactor > 0.0001 ||\n pbrMaterial.multiscatterColorMapEnabled != 0 ||\n maxComponent(pbrMaterial.multiscatterColorFactor) > 0.0001 ||\n pbrMaterial.clearcoatMapEnabled != 0 ||\n pbrMaterial.clearcoatRoughnessMapEnabled != 0 ||\n pbrMaterial.clearcoatFactor > 0.0001 ||\n pbrMaterial.clearcoatRoughnessFactor > 0.0001 ||\n pbrMaterial.sheenColorMapEnabled != 0 ||\n pbrMaterial.sheenRoughnessMapEnabled != 0 ||\n maxComponent(pbrMaterial.sheenColorFactor) > 0.0001 ||\n pbrMaterial.sheenRoughnessFactor > 0.0001 ||\n pbrMaterial.iridescenceMapEnabled != 0 ||\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 != 0 ||\n pbrMaterial.anisotropyStrength > 0.0001 ||\n abs(pbrMaterial.anisotropyRotation) > 0.0001 ||\n length(pbrMaterial.anisotropyDirection - vec2f(1.0, 0.0)) > 0.0001;\n #endif\n\n if (!useExtendedPBR) {\n let alphaRoughness = perceptualRoughness * perceptualRoughness;\n\n let f0 = vec3<f32>(0.04);\n var diffuseColor = baseColor.rgb * (vec3<f32>(1.0) - f0);\n diffuseColor *= 1.0 - metallic;\n let specularColor = mix(f0, baseColor.rgb, metallic);\n\n let reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n let reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);\n let specularEnvironmentR0 = specularColor;\n let specularEnvironmentR90 = vec3<f32>(1.0, 1.0, 1.0) * reflectance90;\n let reflection = -normalize(reflect(v, n));\n\n var 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 (var 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 (var i = 0; i < lighting.pointLightCount; i++) {\n if (i < lighting.pointLightCount) {\n PBRInfo_setPointLight(&pbrInfo, lighting_getPointLight(i));\n let attenuation = getPointLightAttenuation(\n lighting_getPointLight(i),\n distance(lighting_getPointLight(i).position, fragmentInputs.pbr_vPosition)\n );\n color += calculateFinalColor(pbrInfo, lighting_getPointLight(i).color / attenuation);\n }\n }\n\n for (var i = 0; i < lighting.spotLightCount; i++) {\n if (i < lighting.spotLightCount) {\n PBRInfo_setSpotLight(&pbrInfo, lighting_getSpotLight(i));\n let attenuation = getSpotLightAttenuation(\n lighting_getSpotLight(i),\n fragmentInputs.pbr_vPosition\n );\n color += calculateFinalColor(pbrInfo, lighting_getSpotLight(i).color * select(1.0, clamp(spotVisibility[min(i, 3)], 0.0, 1.0), i < 4) / attenuation);\n }\n }\n for (var areaIndex: i32 = 0; areaIndex < areaLighting_getLightCount(); areaIndex++) {\n#ifdef USE_AREA_LIGHT_LTC\n color += areaLTC_evaluate(areaIndex, fragmentInputs.pbr_vPosition, pbrInfo.n, pbrInfo.v, pbrInfo.perceptualRoughness, pbrInfo.diffuseColor, pbrInfo.reflectance0, pbrInfo.reflectance90);\n#else\n for (var sampleIndex: i32 = 0; sampleIndex < areaLighting.sampleCount; sampleIndex++) {\n let sampleLight = areaLighting_getSample(areaIndex, sampleIndex, fragmentInputs.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 != 0) {\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 != 0) {\n let ao = textureSample(pbr_occlusionSampler, pbr_occlusionSamplerSampler, occlusionUV).r;\n color = mix(color, color * ao, pbrMaterial.occlusionStrength);\n }\n #endif\n\n var emissive = pbrMaterial.emissiveFactor;\n #ifdef HAS_EMISSIVEMAP\n if (pbrMaterial.emissiveMapEnabled != 0u) {\n emissive *= SRGBtoLINEAR(\n textureSample(pbr_emissiveSampler, pbr_emissiveSamplerSampler, emissiveUV)\n ).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<f32>(metallic), pbrMaterial.scaleDiffBaseMR.z);\n color = mix(color, vec3<f32>(perceptualRoughness), pbrMaterial.scaleDiffBaseMR.w);\n #endif\n\n return vec4<f32>(applySceneColorManagement(color), baseColor.a);\n }\n\n var specularIntensity = pbrMaterial.specularIntensityFactor;\n #ifdef HAS_SPECULARINTENSITYMAP\n if (pbrMaterial.specularIntensityMapEnabled != 0) {\n specularIntensity *= textureSample(\n pbr_specularIntensitySampler,\n pbr_specularIntensitySamplerSampler,\n specularIntensityUV\n ).a;\n }\n #endif\n\n var specularFactor = pbrMaterial.specularColorFactor;\n #ifdef HAS_SPECULARCOLORMAP\n if (pbrMaterial.specularColorMapEnabled != 0) {\n specularFactor *= SRGBtoLINEAR(\n textureSample(\n pbr_specularColorSampler,\n pbr_specularColorSamplerSampler,\n specularColorUV\n )\n ).rgb;\n }\n #endif\n\n transmission = pbrMaterial.transmissionFactor;\n #ifdef HAS_TRANSMISSIONMAP\n if (pbrMaterial.transmissionMapEnabled != 0) {\n transmission *= textureSample(\n pbr_transmissionSampler,\n pbr_transmissionSamplerSampler,\n transmissionUV\n ).r;\n }\n #endif\n transmission = clamp(transmission * (1.0 - metallic), 0.0, 1.0);\n var thickness = max(pbrMaterial.thicknessFactor, 0.0);\n #ifdef HAS_THICKNESSMAP\n thickness *= textureSample(\n pbr_thicknessSampler,\n pbr_thicknessSamplerSampler,\n thicknessUV\n ).g;\n #endif\n\n var diffuseTransmission = clamp(pbrMaterial.diffuseTransmissionFactor, 0.0, 1.0);\n #ifdef HAS_DIFFUSETRANSMISSIONMAP\n if (pbrMaterial.diffuseTransmissionMapEnabled != 0) {\n diffuseTransmission *= textureSample(\n pbr_diffuseTransmissionSampler,\n pbr_diffuseTransmissionSamplerSampler,\n diffuseTransmissionUV\n ).a;\n }\n #endif\n diffuseTransmission *= (1.0 - metallic) * (1.0 - transmission);\n var diffuseTransmissionColor = pbrMaterial.diffuseTransmissionColorFactor;\n #ifdef HAS_DIFFUSETRANSMISSIONCOLORMAP\n if (pbrMaterial.diffuseTransmissionColorMapEnabled != 0) {\n diffuseTransmissionColor *= SRGBtoLINEAR(\n textureSample(\n pbr_diffuseTransmissionColorSampler,\n pbr_diffuseTransmissionColorSamplerSampler,\n diffuseTransmissionColorUV\n )\n ).rgb;\n }\n #endif\n var multiscatterColor = pbrMaterial.multiscatterColorFactor;\n #ifdef HAS_MULTISCATTERCOLORMAP\n if (pbrMaterial.multiscatterColorMapEnabled != 0) {\n multiscatterColor *= SRGBtoLINEAR(\n textureSample(\n pbr_multiscatterColorSampler,\n pbr_multiscatterColorSamplerSampler,\n multiscatterColorUV\n )\n ).rgb;\n }\n #endif\n\n let originalTransmission = transmission;\n var scatterReflection = 0.0;\n#ifdef HAS_MATERIAL_SCATTER\n if (thickness <= 0.0) {\n var strength = clamp(pbrMaterial.scatterStrengthFactor, 0.0, 1.0);\n#ifdef HAS_DIFFUSETRANSMISSIONMAP\n if (pbrMaterial.diffuseTransmissionMapEnabled != 0) {\n strength *= textureSample(\n pbr_diffuseTransmissionSampler,\n pbr_diffuseTransmissionSamplerSampler,\n diffuseTransmissionUV\n ).a;\n }\n#endif\n let 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 var clearcoatFactor = pbrMaterial.clearcoatFactor;\n var clearcoatRoughness = pbrMaterial.clearcoatRoughnessFactor;\n #ifdef HAS_CLEARCOATMAP\n if (pbrMaterial.clearcoatMapEnabled != 0) {\n clearcoatFactor *= textureSample(\n pbr_clearcoatSampler,\n pbr_clearcoatSamplerSampler,\n clearcoatUV\n ).r;\n }\n #endif\n #ifdef HAS_CLEARCOATROUGHNESSMAP\n if (pbrMaterial.clearcoatRoughnessMapEnabled != 0) {\n clearcoatRoughness *= textureSample(\n pbr_clearcoatRoughnessSampler,\n pbr_clearcoatRoughnessSamplerSampler,\n clearcoatRoughnessUV\n ).g;\n }\n #endif\n clearcoatFactor = clamp(clearcoatFactor, 0.0, 1.0);\n clearcoatRoughness = clamp(clearcoatRoughness, c_MinRoughness, 1.0);\n let clearcoatNormal = getClearcoatNormal(getTBN(clearcoatNormalUV), n, clearcoatNormalUV);\n clearcoatRoughness = widenSpecularRoughness(clearcoatRoughness, clearcoatNormal);\n\n var sheenColor = pbrMaterial.sheenColorFactor;\n var sheenRoughness = pbrMaterial.sheenRoughnessFactor;\n #ifdef HAS_SHEENCOLORMAP\n if (pbrMaterial.sheenColorMapEnabled != 0) {\n sheenColor *= SRGBtoLINEAR(\n textureSample(\n pbr_sheenColorSampler,\n pbr_sheenColorSamplerSampler,\n sheenColorUV\n )\n ).rgb;\n }\n #endif\n #ifdef HAS_SHEENROUGHNESSMAP\n if (pbrMaterial.sheenRoughnessMapEnabled != 0) {\n sheenRoughness *= textureSample(\n pbr_sheenRoughnessSampler,\n pbr_sheenRoughnessSamplerSampler,\n sheenRoughnessUV\n ).a;\n }\n #endif\n sheenRoughness = clamp(sheenRoughness, c_MinRoughness, 1.0);\n\n var iridescence = pbrMaterial.iridescenceFactor;\n #ifdef HAS_IRIDESCENCEMAP\n if (pbrMaterial.iridescenceMapEnabled != 0) {\n iridescence *= textureSample(\n pbr_iridescenceSampler,\n pbr_iridescenceSamplerSampler,\n iridescenceUV\n ).r;\n }\n #endif\n iridescence = clamp(iridescence, 0.0, 1.0);\n var 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 textureSample(\n pbr_iridescenceThicknessSampler,\n pbr_iridescenceThicknessSamplerSampler,\n iridescenceThicknessUV\n ).g\n );\n #endif\n\n var anisotropyStrength = clamp(pbrMaterial.anisotropyStrength, 0.0, 1.0);\n var anisotropyDirection = normalizeDirection(pbrMaterial.anisotropyDirection);\n #ifdef HAS_ANISOTROPYMAP\n if (pbrMaterial.anisotropyMapEnabled != 0) {\n let anisotropySample = textureSample(\n pbr_anisotropySampler,\n pbr_anisotropySamplerSampler,\n anisotropyUV\n ).rgb;\n anisotropyStrength *= anisotropySample.b;\n let 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 var anisotropyTangent =\n 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 let alphaRoughness = perceptualRoughness * perceptualRoughness;\n\n let dielectricF0 = getDielectricF0(pbrMaterial.ior);\n var dielectricSpecularF0 = min(\n vec3f(dielectricF0) * specularFactor * specularIntensity,\n vec3f(1.0)\n );\n dielectricSpecularF0 = getIridescenceTint(\n iridescence,\n iridescenceThickness,\n NdotV,\n dielectricSpecularF0\n );\n var diffuseColor = baseColor.rgb * (vec3f(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) * (vec3f(1.0) - dielectricSpecularF0);\n#endif\n var specularColor = mix(dielectricSpecularF0, baseColor.rgb, metallic);\n\n let clearcoatViewFresnel = dielectricSchlick(\n 0.04,\n clamp(abs(dot(clearcoatNormal, v)), 0.0, 1.0)\n );\n let sheenDirectionalAlbedo = maxComponent(sheenColor) *\n (0.157 + 0.343 * (1.0 - NdotV)) * (1.0 - sheenRoughness * 0.5);\n let 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 let 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 reflectance to 0%.\n let reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);\n let specularEnvironmentR0 = specularColor;\n let specularEnvironmentR90 = vec3<f32>(1.0, 1.0, 1.0) * reflectance90;\n let reflection = -normalize(reflect(v, n));\n\n var 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 // 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 (var 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 (var i = 0; i < lighting.pointLightCount; i++) {\n if (i < lighting.pointLightCount) {\n PBRInfo_setPointLight(&pbrInfo, lighting_getPointLight(i));\n let attenuation = getPointLightAttenuation(\n lighting_getPointLight(i),\n distance(lighting_getPointLight(i).position, fragmentInputs.pbr_vPosition)\n );\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 (var i = 0; i < lighting.spotLightCount; i++) {\n if (i < lighting.spotLightCount) {\n PBRInfo_setSpotLight(&pbrInfo, lighting_getSpotLight(i));\n let attenuation = getSpotLightAttenuation(lighting_getSpotLight(i), fragmentInputs.pbr_vPosition);\n color += calculateMaterialLightColor(\n pbrInfo,\n lighting_getSpotLight(i).color * select(1.0, clamp(spotVisibility[min(i, 3)], 0.0, 1.0), i < 4) / 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 * select(1.0, clamp(spotVisibility[min(i, 3)], 0.0, 1.0), i < 4) / attenuation,\n diffuseTransmissionColor,\n diffuseTransmission,\n multiscatterColor,\n thickness\n );\n }\n }\n for (var areaIndex: i32 = 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, fragmentInputs.pbr_vPosition, pbrInfo.n, pbrInfo.v, pbrInfo.perceptualRoughness, pbrInfo.diffuseColor, pbrInfo.reflectance0, pbrInfo.reflectance90);\n color += clearcoatFactor * areaLTC_specular(areaLighting_getLight(areaIndex), fragmentInputs.pbr_vPosition, clearcoatNormal, pbrInfo.v, clearcoatRoughness, vec3f(0.04), vec3f(1.0));\n } else {\n for (var sampleIndex: i32 = 0; sampleIndex < areaLighting.sampleCount; sampleIndex++) {\n let sampleLight = areaLighting_getSample(areaIndex, sampleIndex, fragmentInputs.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 (var sampleIndex: i32 = 0; sampleIndex < areaLighting.sampleCount; sampleIndex++) {\n let sampleLight = areaLighting_getSample(areaIndex, sampleIndex, fragmentInputs.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 != 0) {\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 != 0) {\n let ao = textureSample(pbr_occlusionSampler, pbr_occlusionSamplerSampler, occlusionUV).r;\n color = mix(color, color * ao, pbrMaterial.occlusionStrength);\n }\n #endif\n\n var emissive = pbrMaterial.emissiveFactor;\n #ifdef HAS_EMISSIVEMAP\n if (pbrMaterial.emissiveMapEnabled != 0u) {\n emissive *= SRGBtoLINEAR(\n textureSample(pbr_emissiveSampler, pbr_emissiveSamplerSampler, emissiveUV)\n ).rgb;\n }\n #endif\n color += emissive * pbrMaterial.emissiveStrength;\n\n if (transmission > 0.0) {\n #ifdef USE_TRANSMISSION_FRAMEBUFFER\n let dielectricFresnel = getDielectricF0(pbrMaterial.ior);\n let transmissionFresnel = dielectricFresnel +\n (1.0 - dielectricFresnel) * pow(1.0 - NdotV, 5.0);\n let transmittedColor = getTransmittedSceneColor(\n fragmentInputs.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<f32>(metallic), pbrMaterial.scaleDiffBaseMR.z);\n color = mix(color, vec3<f32>(perceptualRoughness), pbrMaterial.scaleDiffBaseMR.w);\n #endif\n }\n\n #ifdef USE_TRANSMISSION_FRAMEBUFFER\n let alpha = clamp(baseColor.a, 0.0, 1.0);\n #else\n let alpha = clamp(baseColor.a * (1.0 - transmission), 0.0, 1.0);\n #endif\n return vec4<f32>(applySceneColorManagement(color), alpha);\n}\n\nfn pbr_filterColor(vertexColor: vec4<f32>) -> vec4<f32> {\n return pbr_filterColorWithSpotShadows(vertexColor, vec4f(1.0));\n}\n"
uniforms
readonlyuniforms:PBRMaterialUniforms
uniformTypes
readonlyuniformTypes:object
uniformTypes.alphaCutoff
readonlyalphaCutoff:"f32"='f32'
uniformTypes.alphaCutoffEnabled
readonlyalphaCutoffEnabled:"i32"='i32'
uniformTypes.anisotropyDirection
readonlyanisotropyDirection:"vec2<f32>"='vec2<f32>'
uniformTypes.anisotropyMapEnabled
readonlyanisotropyMapEnabled:"i32"='i32'
uniformTypes.anisotropyRotation
readonlyanisotropyRotation:"f32"='f32'
uniformTypes.anisotropyStrength
readonlyanisotropyStrength:"f32"='f32'
uniformTypes.anisotropyUVSet
readonlyanisotropyUVSet:"i32"='i32'
uniformTypes.anisotropyUVTransform
readonlyanisotropyUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.attenuationColor
readonlyattenuationColor:"vec3<f32>"='vec3<f32>'
uniformTypes.attenuationDistance
readonlyattenuationDistance:"f32"='f32'
uniformTypes.baseColorFactor
readonlybaseColorFactor:"vec4<f32>"='vec4<f32>'
uniformTypes.baseColorMapEnabled
readonlybaseColorMapEnabled:"i32"='i32'
uniformTypes.baseColorUVSet
readonlybaseColorUVSet:"i32"='i32'
uniformTypes.baseColorUVTransform
readonlybaseColorUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.bumpFactor
readonlybumpFactor:"f32"='f32'
uniformTypes.bumpMapEnabled
readonlybumpMapEnabled:"i32"='i32'
uniformTypes.bumpUVSet
readonlybumpUVSet:"i32"='i32'
uniformTypes.bumpUVTransform
readonlybumpUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.clearcoatFactor
readonlyclearcoatFactor:"f32"='f32'
uniformTypes.clearcoatMapEnabled
readonlyclearcoatMapEnabled:"i32"='i32'
uniformTypes.clearcoatNormalUVSet
readonlyclearcoatNormalUVSet:"i32"='i32'
uniformTypes.clearcoatNormalUVTransform
readonlyclearcoatNormalUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.clearcoatRoughnessFactor
readonlyclearcoatRoughnessFactor:"f32"='f32'
uniformTypes.clearcoatRoughnessMapEnabled
readonlyclearcoatRoughnessMapEnabled:"i32"='i32'
uniformTypes.clearcoatRoughnessUVSet
readonlyclearcoatRoughnessUVSet:"i32"='i32'
uniformTypes.clearcoatRoughnessUVTransform
readonlyclearcoatRoughnessUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.clearcoatUVSet
readonlyclearcoatUVSet:"i32"='i32'
uniformTypes.clearcoatUVTransform
readonlyclearcoatUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.diffuseTransmissionColorFactor
readonlydiffuseTransmissionColorFactor:"vec3<f32>"='vec3<f32>'
uniformTypes.diffuseTransmissionColorMapEnabled
readonlydiffuseTransmissionColorMapEnabled:"i32"='i32'
uniformTypes.diffuseTransmissionColorUVSet
readonlydiffuseTransmissionColorUVSet:"i32"='i32'
uniformTypes.diffuseTransmissionColorUVTransform
readonlydiffuseTransmissionColorUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.diffuseTransmissionFactor
readonlydiffuseTransmissionFactor:"f32"='f32'
uniformTypes.diffuseTransmissionMapEnabled
readonlydiffuseTransmissionMapEnabled:"i32"='i32'
uniformTypes.diffuseTransmissionUVSet
readonlydiffuseTransmissionUVSet:"i32"='i32'
uniformTypes.diffuseTransmissionUVTransform
readonlydiffuseTransmissionUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.dispersion
readonlydispersion:"f32"='f32'
uniformTypes.emissiveFactor
readonlyemissiveFactor:"vec3<f32>"='vec3<f32>'
uniformTypes.emissiveMapEnabled
readonlyemissiveMapEnabled:"i32"='i32'
uniformTypes.emissiveStrength
readonlyemissiveStrength:"f32"='f32'
uniformTypes.emissiveUVSet
readonlyemissiveUVSet:"i32"='i32'
uniformTypes.emissiveUVTransform
readonlyemissiveUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.IBLenabled
readonlyIBLenabled:"i32"='i32'
uniformTypes.ior
readonlyior:"f32"='f32'
uniformTypes.iridescenceFactor
readonlyiridescenceFactor:"f32"='f32'
uniformTypes.iridescenceIor
readonlyiridescenceIor:"f32"='f32'
uniformTypes.iridescenceMapEnabled
readonlyiridescenceMapEnabled:"i32"='i32'
uniformTypes.iridescenceThicknessRange
readonlyiridescenceThicknessRange:"vec2<f32>"='vec2<f32>'
uniformTypes.iridescenceThicknessUVSet
readonlyiridescenceThicknessUVSet:"i32"='i32'
uniformTypes.iridescenceThicknessUVTransform
readonlyiridescenceThicknessUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.iridescenceUVSet
readonlyiridescenceUVSet:"i32"='i32'
uniformTypes.iridescenceUVTransform
readonlyiridescenceUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.lightmapIntensity
readonlylightmapIntensity:"f32"='f32'
uniformTypes.lightmapMapEnabled
readonlylightmapMapEnabled:"i32"='i32'
uniformTypes.lightmapUVSet
readonlylightmapUVSet:"i32"='i32'
uniformTypes.lightmapUVTransform
readonlylightmapUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.metallicRoughnessMapEnabled
readonlymetallicRoughnessMapEnabled:"i32"='i32'
uniformTypes.metallicRoughnessUVSet
readonlymetallicRoughnessUVSet:"i32"='i32'
uniformTypes.metallicRoughnessUVTransform
readonlymetallicRoughnessUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.metallicRoughnessValues
readonlymetallicRoughnessValues:"vec2<f32>"='vec2<f32>'
uniformTypes.multiscatterColorFactor
readonlymultiscatterColorFactor:"vec3<f32>"='vec3<f32>'
uniformTypes.multiscatterColorMapEnabled
readonlymultiscatterColorMapEnabled:"i32"='i32'
uniformTypes.multiscatterColorUVSet
readonlymultiscatterColorUVSet:"i32"='i32'
uniformTypes.multiscatterColorUVTransform
readonlymultiscatterColorUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.normalMapEnabled
readonlynormalMapEnabled:"i32"='i32'
uniformTypes.normalScale
readonlynormalScale:"f32"='f32'
uniformTypes.normalUVSet
readonlynormalUVSet:"i32"='i32'
uniformTypes.normalUVTransform
readonlynormalUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.occlusionMapEnabled
readonlyocclusionMapEnabled:"i32"='i32'
uniformTypes.occlusionStrength
readonlyocclusionStrength:"f32"='f32'
uniformTypes.occlusionUVSet
readonlyocclusionUVSet:"i32"='i32'
uniformTypes.occlusionUVTransform
readonlyocclusionUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.scaleDiffBaseMR
readonlyscaleDiffBaseMR:"vec4<f32>"='vec4<f32>'
uniformTypes.scaleFGDSpec
readonlyscaleFGDSpec:"vec4<f32>"='vec4<f32>'
uniformTypes.scaleIBLAmbient
readonlyscaleIBLAmbient:"vec2<f32>"='vec2<f32>'
uniformTypes.scatterAnisotropy
readonlyscatterAnisotropy:"f32"='f32'
uniformTypes.scatterStrengthFactor
readonlyscatterStrengthFactor:"f32"='f32'
uniformTypes.sheenColorFactor
readonlysheenColorFactor:"vec3<f32>"='vec3<f32>'
uniformTypes.sheenColorMapEnabled
readonlysheenColorMapEnabled:"i32"='i32'
uniformTypes.sheenColorUVSet
readonlysheenColorUVSet:"i32"='i32'
uniformTypes.sheenColorUVTransform
readonlysheenColorUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.sheenRoughnessFactor
readonlysheenRoughnessFactor:"f32"='f32'
uniformTypes.sheenRoughnessMapEnabled
readonlysheenRoughnessMapEnabled:"i32"='i32'
uniformTypes.sheenRoughnessUVSet
readonlysheenRoughnessUVSet:"i32"='i32'
uniformTypes.sheenRoughnessUVTransform
readonlysheenRoughnessUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.specularColorFactor
readonlyspecularColorFactor:"vec3<f32>"='vec3<f32>'
uniformTypes.specularColorMapEnabled
readonlyspecularColorMapEnabled:"i32"='i32'
uniformTypes.specularColorUVSet
readonlyspecularColorUVSet:"i32"='i32'
uniformTypes.specularColorUVTransform
readonlyspecularColorUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.specularIntensityFactor
readonlyspecularIntensityFactor:"f32"='f32'
uniformTypes.specularIntensityMapEnabled
readonlyspecularIntensityMapEnabled:"i32"='i32'
uniformTypes.specularIntensityUVSet
readonlyspecularIntensityUVSet:"i32"='i32'
uniformTypes.specularIntensityUVTransform
readonlyspecularIntensityUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.thicknessFactor
readonlythicknessFactor:"f32"='f32'
uniformTypes.thicknessUVSet
readonlythicknessUVSet:"i32"='i32'
uniformTypes.thicknessUVTransform
readonlythicknessUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.transmissionFactor
readonlytransmissionFactor:"f32"='f32'
uniformTypes.transmissionMapEnabled
readonlytransmissionMapEnabled:"i32"='i32'
uniformTypes.transmissionUVSet
readonlytransmissionUVSet:"i32"='i32'
uniformTypes.transmissionUVTransform
readonlytransmissionUVTransform:"mat3x3<f32>"='mat3x3<f32>'
uniformTypes.unlit
readonlyunlit:"i32"='i32'
vs
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"