@babylonjs/lite 1.11.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/index.js +444 -368
  3. package/dist/index.js.map +1 -1
  4. package/index.d.ts +191 -4
  5. package/lib/audio/index.js +1 -0
  6. package/lib/audio/index.js.map +1 -1
  7. package/lib/audio/media-stream-output.js +44 -0
  8. package/lib/audio/media-stream-output.js.map +1 -0
  9. package/lib/engine/engine.js +1 -1
  10. package/lib/frame-graph/render-task.js +1 -1
  11. package/lib/frame-graph/render-task.js.map +1 -1
  12. package/lib/frame-graph/shadow-inputs.js +10 -1
  13. package/lib/frame-graph/shadow-inputs.js.map +1 -1
  14. package/lib/frame-graph/transmission.js +1 -16
  15. package/lib/frame-graph/transmission.js.map +1 -1
  16. package/lib/index.js +5 -3
  17. package/lib/index.js.map +1 -1
  18. package/lib/loader-gltf/gltf-json-asset.js +1 -1
  19. package/lib/loader-gltf/gltf-json-asset.js.map +1 -1
  20. package/lib/loader-gltf/gltf-multi-buffer.js +2 -10
  21. package/lib/loader-gltf/gltf-multi-buffer.js.map +1 -1
  22. package/lib/loader-gltf/gltf-pbr-builder-ext.js +4 -18
  23. package/lib/loader-gltf/gltf-pbr-builder-ext.js.map +1 -1
  24. package/lib/loader-gltf/gltf-pbr-builder.js +17 -14
  25. package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
  26. package/lib/loader-gltf/gltf-sampler-desc.js +3 -16
  27. package/lib/loader-gltf/gltf-sampler-desc.js.map +1 -1
  28. package/lib/material/node/blocks/ambient-occlusion-block.js +1 -4
  29. package/lib/material/node/blocks/ambient-occlusion-block.js.map +1 -1
  30. package/lib/material/node/blocks/biplanar-block.js +3 -6
  31. package/lib/material/node/blocks/biplanar-block.js.map +1 -1
  32. package/lib/material/node/blocks/image-source.js +2 -5
  33. package/lib/material/node/blocks/image-source.js.map +1 -1
  34. package/lib/material/node/blocks/input-block.js +5 -26
  35. package/lib/material/node/blocks/input-block.js.map +1 -1
  36. package/lib/material/node/blocks/pbr-mr-helper-full.js +5 -8
  37. package/lib/material/node/blocks/pbr-mr-helper-full.js.map +1 -1
  38. package/lib/material/node/blocks/reflection-texture-block.js +1 -4
  39. package/lib/material/node/blocks/reflection-texture-block.js.map +1 -1
  40. package/lib/material/node/blocks/texture-block.js +2 -5
  41. package/lib/material/node/blocks/texture-block.js.map +1 -1
  42. package/lib/material/node/blocks/triplanar-block.js +3 -6
  43. package/lib/material/node/blocks/triplanar-block.js.map +1 -1
  44. package/lib/material/node/node-emitter.js +24 -1
  45. package/lib/material/node/node-emitter.js.map +1 -1
  46. package/lib/material/node/node-geometry-renderable.js +2 -2
  47. package/lib/material/node/node-material.js +1 -22
  48. package/lib/material/node/node-material.js.map +1 -1
  49. package/lib/material/node/node-types.js.map +1 -1
  50. package/lib/material/pbr/fragments/shadow-only-fragment.js +68 -0
  51. package/lib/material/pbr/fragments/shadow-only-fragment.js.map +1 -0
  52. package/lib/material/pbr/pbr-flag-bits.js.map +1 -1
  53. package/lib/material/pbr/pbr-material.js.map +1 -1
  54. package/lib/material/pbr/pbr-renderable.js +3 -0
  55. package/lib/material/pbr/pbr-renderable.js.map +1 -1
  56. package/lib/material/pbr/pbr-template.js +1 -0
  57. package/lib/material/pbr/pbr-template.js.map +1 -1
  58. package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js +2 -8
  59. package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js.map +1 -1
  60. package/lib/mesh/mesh-dispose.js +2 -0
  61. package/lib/mesh/mesh-dispose.js.map +1 -1
  62. package/lib/mesh/mesh.js +2 -8
  63. package/lib/mesh/mesh.js.map +1 -1
  64. package/lib/mesh/thin-instance-cull-binding.js +54 -3
  65. package/lib/mesh/thin-instance-cull-binding.js.map +1 -1
  66. package/lib/mesh/thin-instance-gpu-culling.js +241 -24
  67. package/lib/mesh/thin-instance-gpu-culling.js.map +1 -1
  68. package/lib/mesh/thin-instance.js +112 -1
  69. package/lib/mesh/thin-instance.js.map +1 -1
  70. package/lib/picking/gpu-picker.js +4 -2
  71. package/lib/picking/gpu-picker.js.map +1 -1
  72. package/lib/picking/picking-pipeline.js +1 -1
  73. package/lib/picking/picking-pipeline.js.map +1 -1
  74. package/lib/picking/picking-shader.js +38 -16
  75. package/lib/picking/picking-shader.js.map +1 -1
  76. package/lib/scene/scene-core.js +3 -0
  77. package/lib/scene/scene-core.js.map +1 -1
  78. package/lib/scene/scene-node.js +2 -6
  79. package/lib/scene/scene-node.js.map +1 -1
  80. package/lib/scene/transform-node.js +3 -0
  81. package/lib/scene/transform-node.js.map +1 -1
  82. package/lib/scene/world-matrix-state.js +7 -1
  83. package/lib/scene/world-matrix-state.js.map +1 -1
  84. package/lib/shadow/csm-directional-shadow-generator.js +22 -1
  85. package/lib/shadow/csm-directional-shadow-generator.js.map +1 -1
  86. package/lib/shadow/csm-shadow-task-hooks.js +19 -11
  87. package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
  88. package/lib/shadow/esm-directional-shadow-generator.js +2 -51
  89. package/lib/shadow/esm-directional-shadow-generator.js.map +1 -1
  90. package/lib/shadow/pcf-directional-shadow-generator.js +2 -48
  91. package/lib/shadow/pcf-directional-shadow-generator.js.map +1 -1
  92. package/lib/shadow/shadow-base.js +48 -1
  93. package/lib/shadow/shadow-base.js.map +1 -1
  94. package/lib/text/text-renderable.js +2 -10
  95. package/lib/text/text-renderable.js.map +1 -1
  96. package/lib/texture/texture-array.js +96 -0
  97. package/lib/texture/texture-array.js.map +1 -0
  98. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"pbr-mr-helper-full.js","sources":["../../../../../src/material/node/blocks/pbr-mr-helper-full.ts"],"sourcesContent":["/** PBRMetallicRoughnessBlock — direct lighting + optional IBL + optional clearcoat + optional sheen.\n *\n * When the `reflection` input is connected (typically to a ReflectionBlock),\n * this emitter runs the GGX direct-lighting path PLUS a split-sum IBL\n * contribution (specular cube + BRDF LUT + SH irradiance).\n *\n * When the `clearcoat` input is connected (to a ClearCoatBlock), an extra\n * GGX clear-coat layer is added on top: per-light Schlick fresnel + Kelemen\n * visibility GGX specular, and the base layer (diffuse + specular + IBL)\n * is modulated by (1 - ccFresnel * ccIntensity).\n *\n * When the `sheen` input is connected (to a SheenBlock), an extra Charlie\n * NDF + Ashikhmin visibility cloth/velvet sheen layer is added: per-light\n * direct sheen contribution and a sheen IBL term that uses the BRDF LUT\n * blue channel for the sheen-roughness lookup.\n *\n * Outputs implemented (others stub to a zero vector):\n * - lighting / diffuseDir / specularDir / shadow / alpha\n * - diffuseInd / specularInd (only meaningful when IBL is on)\n */\n\nimport type { NodePbrMrHelperRequest } from \"../node-types.js\";\nimport { MAX_LIGHTS } from \"../../../light/types.js\";\n\nfunction ccDirectBlock(useClearcoat: boolean, useCcTint: boolean): string {\n if (!useClearcoat) {\n return \"\";\n }\n const Ncc = \"ccNormalW\";\n const NdotLcc = \"ccNdotL\";\n const declCcNdotL = `let ccNdotL = clamp(dot(ccNormalW, L), 0.0000001, 1.0);`;\n return `\n${declCcNdotL}\nif (${NdotLcc} > 0.0 && atten > 0.0) {\nlet ccH = normalize(V + L);\nlet ccNdotH = clamp(dot(${Ncc}, ccH), 0.0000001, 1.0);\nlet ccVdotH = saturate(dot(V, ccH));\nlet ccD = nme_pbr_distGGX(ccNdotH, ccAlphaG);\nlet ccVis = 0.25 / (ccVdotH * ccVdotH + 0.0000001);\nlet ccF_d = nme_pbr_ccSchlick(ccF0, ccVdotH);\nlet ccTerm = ccF_d * ccD * ccVis * ${NdotLcc};\nccDirectSpecAcc = ccDirectSpecAcc + v3(ccTerm) * color * atten * ccIntensity * sh;\nbaseLayerAtten = 1.0 - ccF_d * ccIntensity;\n${\n useCcTint\n ? `let ccLRefract = -refract(L, ${Ncc}, ccIorInv);\nlet ccNdotLRefract = clamp(dot(${Ncc}, ccLRefract), 0.0000001, 1.0);\nlet ccDirectAbsorption = nme_pbr_cocaLambert(ccAbsorptionColor, ccTintThickness * ((ccNdotLRefract + ccNdotVRefract) / (ccNdotLRefract * ccNdotVRefract)));\nbaseLayerAbsorption = mix(v3(1.0), ccDirectAbsorption, v3(ccIntensity));`\n : ``\n}\n}`;\n}\n\nfunction ccHemiBlock(useClearcoat: boolean, useCcTint: boolean): string {\n if (!useClearcoat) {\n return \"\";\n }\n const Ncc = \"ccNormalW\";\n return `\nlet ccNdotL_h = clamp(dot(${Ncc}, Ldir), 0.0000001, 1.0);\nif (nl > 0.0) {\nlet ccH_h = normalize(V + Ldir);\nlet ccNdotH_h = clamp(dot(${Ncc}, ccH_h), 0.0000001, 1.0);\nlet ccVdotH_h = saturate(dot(V, ccH_h));\nlet ccD_h = nme_pbr_distGGX(ccNdotH_h, ccAlphaG);\nlet ccVis_h = 0.25 / (ccVdotH_h * ccVdotH_h + 0.0000001);\nlet ccF_h = nme_pbr_ccSchlick(ccF0, ccVdotH_h);\nlet ccTerm_h = ccF_h * ccD_h * ccVis_h * ccNdotL_h;\nccDirectSpecAcc = ccDirectSpecAcc + v3(ccTerm_h) * entry.vLightDiffuse.rgb * ccIntensity * sh;\nbaseLayerAtten = 1.0 - ccF_h * ccIntensity;\n${\n useCcTint\n ? `let ccLRefract_h = -refract(Ldir, ${Ncc}, ccIorInv);\nlet ccNdotLRefract_h = clamp(dot(${Ncc}, ccLRefract_h), 0.0000001, 1.0);\nlet ccDirectAbsorption_h = nme_pbr_cocaLambert(ccAbsorptionColor, ccTintThickness * ((ccNdotLRefract_h + ccNdotVRefract) / (ccNdotLRefract_h * ccNdotVRefract)));\nbaseLayerAbsorption = mix(v3(1.0), ccDirectAbsorption_h, v3(ccIntensity));`\n : ``\n}\n}`;\n}\n\nfunction shDirectBlock(useSheen: boolean): string {\n if (!useSheen) {\n return \"\";\n }\n return `\nif (NdotL > 0.0 && atten > 0.0) {\nlet shH = normalize(V + L);\nlet shNdotH = clamp(dot(N, shH), 0.0000001, 1.0);\nlet shD = nme_pbr_charlieD(shNdotH, shAlphaG);\nlet shV = 1.0 / (4.0 * (NdotL + NdotV - NdotL * NdotV) + 0.0000001);\nshDirectAcc = shDirectAcc + shColorScaled * shD * shV * NdotL * color * atten * sh * baseLayerAtten;\n}`;\n}\n\nfunction shHemiBlock(useSheen: boolean): string {\n if (!useSheen) {\n return \"\";\n }\n return `\nif (nl > 0.0) {\nlet shH_h = normalize(V + Ldir);\nlet shNdotH_h = clamp(dot(N, shH_h), 0.0000001, 1.0);\nlet shD_h = nme_pbr_charlieD(shNdotH_h, shAlphaG);\nlet shV_h = 1.0 / (4.0 * (nl + NdotV - nl * NdotV) + 0.0000001);\nshDirectAcc = shDirectAcc + shColorScaled * shD_h * shV_h * nl * entry.vLightSpecular.rgb * sh * baseLayerAtten;\n}`;\n}\n\n/** Subsurface IBL block — runs inside the env IBL section. Computes refraction\n * (refract V through N, sample env at refractionLOD, apply Coca-Lambert tint\n * absorption + reflectance complement) and translucency (back-scattered SH\n * irradiance with Burley transmittance). Contributes:\n * - finalRefraction (vec3, added to lighting)\n * - refractionOpacity (f32, scales finalIrradiance: 1 - refrIntensity)\n * - mutates finalIrradiance to include refractionIrradiance + (1-translucency) scale.\n *\n * Always declares finalRefraction/refractionOpacity even when sub-features are\n * off so the downstream composition can reference them unconditionally. */\nfunction ssBlock(useSubsurface: boolean, useRefraction: boolean, useAnisotropy: boolean): string {\n if (!useSubsurface && !useRefraction) {\n return `let finalRefraction = v3(0.0);\nlet refractionOpacity = 1.0;\nlet ssRefractionIrradiance = v3(0.0);`;\n }\n const refrPart = useRefraction\n ? `// Refraction: refract V through N at IOR, sample env at refraction LOD.\n let refrIntensity = clamp(refrIntensityIn, 0.0, 1.0);\n let invIor = 1.0 / max(refrIor, 1.0001);\n let refrV_raw = refract(-V, ${useAnisotropy ? \"aniN\" : \"N\"}, invIor);\n let refrV = v3(refrV_raw.x * cosA + refrV_raw.z * sinA, refrV_raw.y, -refrV_raw.x * sinA + refrV_raw.z * cosA);\n let refrAlphaG = mix(alphaG, 0.0, clamp(invIor * 3.0 - 2.0, 0.0, 1.0));\n let refrLod = log2(cubemapDim * refrAlphaG) * sceneU.vImageInfos.z;\n let envRefr = textureSampleLevel(nmeIblTexture, nmeIblSampler, refrV, clamp(refrLod, 0.0, maxLod)).rgb;\n let volumeAlbedo = nme_pbr_colorAtDistance(ssTintColor, refrTintAtDistance);\n let refrTransmittance = v3(refrIntensity) * nme_pbr_cocaLambert(volumeAlbedo, ssThickness);\n let finalRefractionRaw = envRefr * refrTransmittance * (v3(1.0) - refractionSpecEnvReflectance);\n let refractionOpacity = 1.0 - refrIntensity;`\n : `let finalRefractionRaw = v3(0.0);\nlet refractionOpacity = 1.0;`;\n const ssPart = useSubsurface\n ? `// Translucency: back-scattered SH irradiance with Burley transmittance.\n let nN_raw = -N;\n let nN_env = v3(nN_raw.x * cosA + nN_raw.z * sinA, nN_raw.y, -nN_raw.x * sinA + nN_raw.z * cosA);\n let backIrradiance = (sceneU.vSphericalL00.xyz\n + sceneU.vSphericalL1_1.xyz * nN_env.y + sceneU.vSphericalL10.xyz * nN_env.z + sceneU.vSphericalL11.xyz * nN_env.x\n + sceneU.vSphericalL2_2.xyz * (nN_env.y * nN_env.x) + sceneU.vSphericalL2_1.xyz * (nN_env.y * nN_env.z)\n + sceneU.vSphericalL20.xyz * (3.0 * nN_env.z * nN_env.z - 1.0) + sceneU.vSphericalL21.xyz * (nN_env.z * nN_env.x)\n + sceneU.vSphericalL22.xyz * (nN_env.x * nN_env.x - nN_env.y * nN_env.y));\n let ssRefractionIrradiance = backIrradiance * ssTransmittance;\n finalIrradiance = finalIrradiance * refractionOpacity;\n finalIrradiance = finalIrradiance * (1.0 - translucencyIntensity);`\n : `let ssRefractionIrradiance = v3(0.0);\nfinalIrradiance = finalIrradiance * refractionOpacity;`;\n return `${refrPart}\n${ssPart}\nlet finalRefraction = finalRefractionRaw;`;\n}\n\nexport function buildPbrMrHelperFull(request: NodePbrMrHelperRequest): string {\n return HELPER_WGSL(\n request.useEnv,\n request.useClearcoat,\n request.useSheen,\n request.useRefraction,\n request.useSubsurface,\n request.useAnisotropy,\n request.useIridescence,\n request.useShAlbedoScaling,\n request.useCcBump,\n request.useCcTint,\n request.useSpecularAA,\n request.remapClearcoatF0\n );\n}\n\nfunction HELPER_WGSL(\n useEnv: boolean,\n useClearcoat: boolean,\n useSheen: boolean,\n useRefraction: boolean,\n useSubsurface: boolean,\n useAnisotropy: boolean,\n useIridescence: boolean,\n useShAlbedoScaling: boolean,\n useCcBump: boolean,\n useCcTint: boolean,\n useSpecularAA: boolean,\n remapClearcoatF0: boolean\n): string {\n const ccDecls = useClearcoat\n ? `let ccIntensity = clamp(ccIntensityIn, 0.0, 1.0);\nlet ccRough = clamp(ccRoughnessIn, 0.0, 1.0);\nlet ccF0_raw = (ccIor - 1.0) / (ccIor + 1.0);\nlet ccF0 = ccF0_raw * ccF0_raw;\nvar ccDirectSpecAcc = v3(0.0);`\n : `let ccDirectSpecAcc = v3(0.0);`;\n\n const ccAlphaSetup = useClearcoat\n ? `var ccAA_factor_y = 0.0;\n${\n useSpecularAA\n ? `{ let ccNdfdx_AA = dpdx(ccNormalW);\nlet ccNdfdy_AA = dpdy(ccNormalW);\nlet ccSlopeSquare_AA = max(dot(ccNdfdx_AA, ccNdfdx_AA), dot(ccNdfdy_AA, ccNdfdy_AA));\nccAA_factor_y = sqrt(ccSlopeSquare_AA) * 0.75; }`\n : ``\n}\nlet ccAlphaG = ccRough * ccRough + 0.0005 + ccAA_factor_y;`\n : ``;\n\n const ccNormalSetup = useClearcoat\n ? useCcBump\n ? `let ccNormalW = nme_perturbNormal(worldPos, Ng, ccBumpUv, ccBumpColor, 1.0);\nlet ccNdotV = abs(dot(ccNormalW, V)) + 0.0000001;${\n useCcTint\n ? `\nlet ccIorInv = 1.0 / max(ccIor, 1.0001);\nlet ccAbsorptionColor = nme_pbr_colorAtDistance(max(ccTintColor, v3(0.0000001)), max(ccTintAtDistance, 0.0000001));\nlet ccVRefract = refract(-V, ccNormalW, ccIorInv);\nlet ccNdotVRefract = abs(dot(ccNormalW, ccVRefract)) + 0.0000001;`\n : ``\n }`\n : `let ccNormalW = Ng;\nlet ccNdotV = abs(dot(ccNormalW, V)) + 0.0000001;${\n useCcTint\n ? `\nlet ccIorInv = 1.0 / max(ccIor, 1.0001);\nlet ccAbsorptionColor = nme_pbr_colorAtDistance(max(ccTintColor, v3(0.0000001)), max(ccTintAtDistance, 0.0000001));\nlet ccVRefract = refract(-V, ccNormalW, ccIorInv);\nlet ccNdotVRefract = abs(dot(ccNormalW, ccVRefract)) + 0.0000001;`\n : ``\n }`\n : `let ccNormalW = N;\nlet ccNdotV: f32 = 0.0;`;\n\n const shDecls = useSheen\n ? `let shIntensityRaw = clamp(shIntensityIn, 0.0, 1.0);\n${\n useShAlbedoScaling\n ? `let shIntensity = shIntensityRaw;`\n : `let reflectanceF0 = max(colorF0.r, max(colorF0.g, colorF0.b));\nlet shIntensity = shIntensityRaw * (1.0 - reflectanceF0);`\n}\nlet shRough = clamp(shRoughnessIn, 0.0, 1.0);\nlet shAlphaG = shRough * shRough + 0.0005;\nlet shColorScaled = shColorIn * shIntensity;\nvar shDirectAcc = v3(0.0);`\n : `let shDirectAcc = v3(0.0);`;\n\n const shIblTerm =\n useEnv && useSheen\n ? `let shSpecLod = log2(cubemapDim * shAlphaG) * sceneU.vImageInfos.z;\n let shEnvRadiance = textureSampleLevel(nmeIblTexture, nmeIblSampler, R, clamp(shSpecLod, 0.0, maxLod)).rgb;\n let shBrdfBlue = textureSample(nmeBrdfLUT, nmeBrdfSampler, v2(NdotV, shRough)).b;\n let shFinalIbl = shEnvRadiance * shColorScaled * shBrdfBlue * seo * eho;\n ${\n useShAlbedoScaling\n ? `// SHEEN_ALBEDOSCALING: surface albedo and base specular scale by (1 - shInt × max(shColor) × envSheenBrdf.b).\n let shAlbedoScaling = 1.0 - shIntensity * max(max(shColorIn.r, shColorIn.g), shColorIn.b) * shBrdfBlue;`\n : `let shAlbedoScaling: f32 = 1.0;`\n }`\n : `let shFinalIbl = v3(0.0);\nlet shAlbedoScaling: f32 = 1.0;`;\n\n const directSpecR0Decl =\n useClearcoat && remapClearcoatF0\n ? `let _directF0S = sqrt(max(colorF0, v3(0.0)));\nlet _directF0T = ((1.0 - ccIor) + (1.0 + ccIor) * _directF0S) / ((1.0 + ccIor) + (1.0 - ccIor) * _directF0S);\nlet directSpecR0 = mix(colorF0, clamp(_directF0T * _directF0T, v3(0.0), v3(1.0)), ccIntensity);`\n : `let directSpecR0 = colorF0;`;\n\n const shIblScale = useClearcoat ? ` * ccConsIBL${useCcTint ? \" * ccAbsorption\" : \"\"}` : \"\";\n const refrCcScale = useClearcoat ? \" * ccConsIBL\" : \"\";\n const ccIblPre = useClearcoat\n ? `let ccFresnelIBL = nme_pbr_ccSchlick(ccF0, ccNdotV);\n let ccConsIBL = 1.0 - ccFresnelIBL * ccIntensity;\n let ccBrdfSample = textureSample(nmeBrdfLUT, nmeBrdfSampler, v2(ccNdotV, ccRough)).rgb;\n let ccSpecEnvReflRaw = (v3(ccF0) * ccBrdfSample.y + (v3(1.0) - v3(ccF0)) * ccBrdfSample.x) * ccIntensity;\n let ccEnergyConservation = 1.0 + _coloredR0 * (1.0 / max(ccBrdfSample.y, 0.001) - 1.0);\n let ccEhoT = clamp(1.0 + 1.1 * dot(reflect(-V, ccNormalW), Ng), 0.0, 1.0);\n let ccSpecEnvRefl = ccSpecEnvReflRaw * (ccEhoT * ccEhoT);\n let ccSpecLod = log2(cubemapDim * ccAlphaG) * sceneU.vImageInfos.z;\n let ccR_raw = reflect(-V, ccNormalW);\n let ccR = v3(ccR_raw.x * cosA + ccR_raw.z * sinA, ccR_raw.y, -ccR_raw.x * sinA + ccR_raw.z * cosA);\n let ccEnvRadiance = textureSampleLevel(nmeIblTexture, nmeIblSampler, ccR, clamp(ccSpecLod, 0.0, maxLod)).rgb;\n ${\n useCcTint\n ? `// Clearcoat absorption: BJS Beer-Lambert path length through the coat.\n let ccAbsorption = mix(v3(1.0), nme_pbr_cocaLambert(ccAbsorptionColor, ccTintThickness * ((ccNdotVRefract + ccNdotVRefract) / (ccNdotVRefract * ccNdotVRefract))), v3(ccIntensity));`\n : `let ccAbsorption = v3(1.0);`\n }\n let ccFinalRadiance = ccEnvRadiance * ccSpecEnvRefl;`\n : ``;\n const ccTintScale = useCcTint ? \" * ccAbsorption\" : \"\";\n const ccIblFinal = useClearcoat\n ? `${ccIblPre}\n${shIblTerm}\nr.lighting = finalIrradiance * shAlbedoScaling * ccConsIBL${ccTintScale}\n+ finalRadianceScaled * shAlbedoScaling * ccConsIBL${ccTintScale}\n+ ssRefractionIrradiance * ao_c\n+ finalSpecularScaledDirect * shAlbedoScaling\n+ diffuseAcc * shAlbedoScaling\n+ diffuseTransmissionAcc\n+ ccDirectSpecAcc * ccEnergyConservation\n+ ccFinalRadiance\n+ shDirectAcc\n+ shFinalIbl${shIblScale}\n+ finalRefraction${refrCcScale}${ccTintScale};`\n : `${shIblTerm}\nr.lighting = finalIrradiance * shAlbedoScaling + ssRefractionIrradiance * ao_c + (finalRadianceScaled + finalSpecularScaledDirect + diffuseAcc) * shAlbedoScaling + diffuseTransmissionAcc + shDirectAcc + shFinalIbl + finalRefraction;`;\n\n const ccDirectFinal = useClearcoat\n ? `r.lighting = diffuseAcc + specAcc + diffuseTransmissionAcc + ccDirectSpecAcc + shDirectAcc;`\n : `r.lighting = diffuseAcc + diffuseTransmissionAcc + specAcc + shDirectAcc;`;\n\n const refractionSpecEnvReflectanceDecl = useRefraction ? `let refractionSpecEnvReflectance = baseSpecEnvReflectance;` : ``;\n\n const iblBlock = useEnv\n ? `\n let envRot = sceneU.envRotationY;\n let cosA = cos(envRot); let sinA = sin(envRot);\n let N_specSrc = ${useAnisotropy ? \"aniN\" : \"N\"};\n let R_raw = reflect(-V, N_specSrc);\n let R = v3(R_raw.x * cosA + R_raw.z * sinA, R_raw.y, -R_raw.x * sinA + R_raw.z * cosA);\n let N_env = v3(Ng.x * cosA + Ng.z * sinA, Ng.y, -Ng.x * sinA + Ng.z * cosA);\n let environmentIrradiance = (sceneU.vSphericalL00.xyz\n + sceneU.vSphericalL1_1.xyz * N_env.y + sceneU.vSphericalL10.xyz * N_env.z + sceneU.vSphericalL11.xyz * N_env.x\n + sceneU.vSphericalL2_2.xyz * (N_env.y * N_env.x) + sceneU.vSphericalL2_1.xyz * (N_env.y * N_env.z)\n + sceneU.vSphericalL20.xyz * (3.0 * N_env.z * N_env.z - 1.0) + sceneU.vSphericalL21.xyz * (N_env.z * N_env.x)\n + sceneU.vSphericalL22.xyz * (N_env.x * N_env.x - N_env.y * N_env.y));\n let brdfSample = textureSample(nmeBrdfLUT, nmeBrdfSampler, v2(NdotV, rough_c));\n let envBrdf = brdfSample.rgb;\n let reflectanceF0Scalar = max(colorF0.r, max(colorF0.g, colorF0.b));\n let baseSpecEnvReflectance = (colorF90 - v3(reflectanceF0Scalar)) * envBrdf.x + v3(reflectanceF0Scalar) * envBrdf.y;\n let seo = clamp((NdotVUnclamped + ao_c) * (NdotVUnclamped + ao_c) - 1.0 + ao_c, 0.0, 1.0);\n let _geoNF = select(-Ng, Ng, dot(Ng, V) > 0.0);\n let _ehoRefl = reflect(-V, N);\n let _ehoT = clamp(1.0 + 1.1 * dot(_ehoRefl, _geoNF), 0.0, 1.0);\n let eho = _ehoT * _ehoT;\n ${\n useClearcoat && remapClearcoatF0\n ? `let _f0S = sqrt(max(colorF0, v3(0.0)));\n let _f0T = ((1.0 - ccIor) + (1.0 + ccIor) * _f0S) / ((1.0 + ccIor) + (1.0 - ccIor) * _f0S);\n let _coloredR0 = mix(colorF0, clamp(_f0T * _f0T, v3(0.0), v3(1.0)), ccIntensity);`\n : `let _coloredR0 = colorF0;`\n }\n let colorSpecEnvReflectance = ((colorF90 - _coloredR0) * envBrdf.x + _coloredR0 * envBrdf.y) * seo * eho;\n let energyConservation = 1.0 + _coloredR0 * (1.0 / max(envBrdf.y, 0.001) - 1.0);\n let maxLod = f32(textureNumLevels(nmeIblTexture) - 1);\n let cubemapDim = f32(textureDimensions(nmeIblTexture).x);\n let specLod = log2(cubemapDim * alphaG) * sceneU.vImageInfos.z;\n var environmentRadiance = textureSampleLevel(nmeIblTexture, nmeIblSampler, R, clamp(specLod, 0.0, maxLod)).rgb;\n ${refractionSpecEnvReflectanceDecl}\n var finalIrradiance = environmentIrradiance * surfaceAlbedo;\n let finalRadianceScaled = environmentRadiance * colorSpecEnvReflectance * energyConservation;\n let finalSpecularScaledDirect = specAcc * energyConservation;\n ${ssBlock(useSubsurface, useRefraction, useAnisotropy)}\n finalIrradiance = finalIrradiance * ao_c;\n r.diffuseInd = finalIrradiance;\n r.specularInd = finalRadianceScaled;\n ${ccIblFinal}`\n : `\nr.diffuseInd = v3(0.0);\nr.specularInd = v3(0.0);\n${ccDirectFinal}`;\n\n const ccSchlickFn = useClearcoat\n ? `fn nme_pbr_ccSchlick(f0: f32, cosTheta: f32) -> f32 {\nlet t = 1.0 - cosTheta;\nlet t2 = t * t;\nreturn f0 + (1.0 - f0) * (t2 * t2 * t);\n}\n`\n : ``;\n\n const charlieFn = useSheen\n ? `fn nme_pbr_charlieD(NdotH: f32, alphaG: f32) -> f32 {\nlet invR = 1.0 / max(alphaG, 0.0005);\nlet cos2h = NdotH * NdotH;\nlet sin2h = 1.0 - cos2h;\nreturn (2.0 + invR) * pow(sin2h, invR * 0.5) / (2.0 * NME_PBR_PI);\n}\n`\n : ``;\n\n const anisoFns = useAnisotropy\n ? `fn nme_pbr_anisoRoughness(alphaG: f32, anisotropy: f32) -> v2 {\nlet alphaT = max(alphaG * (1.0 + anisotropy), 0.0005);\nlet alphaB = max(alphaG * (1.0 - anisotropy), 0.0005);\nreturn v2(alphaT, alphaB);\n}\nfn nme_pbr_anisoBentNormal(T: v3, B: v3, N: v3, V: v3, anisotropy: f32) -> v3 {\nvar anisotropicFrameDirection = B;\nif (anisotropy < 0.0) {\nanisotropicFrameDirection = T;\n}\nlet anisoTan = cross(normalize(anisotropicFrameDirection), V);\nlet anisoNormal = cross(anisoTan, anisotropicFrameDirection);\nreturn normalize(mix(N, anisoNormal, abs(anisotropy)));\n}\nfn nme_pbr_burleyAnisoD(NdotH: f32, TdotH: f32, BdotH: f32, alphaTB: v2) -> f32 {\nlet a2 = alphaTB.x * alphaTB.y;\nlet v = v3(alphaTB.y * TdotH, alphaTB.x * BdotH, a2 * NdotH);\nlet v2 = dot(v, v);\nlet w2 = a2 / max(v2, 0.0000001);\nreturn a2 * w2 * w2 * (1.0 / NME_PBR_PI);\n}\nfn nme_pbr_visAnisoSmith(NdotL: f32, NdotV: f32, TdotV: f32, BdotV: f32, TdotL: f32, BdotL: f32, alphaTB: v2) -> f32 {\nlet lambdaV = NdotL * length(v3(alphaTB.x * TdotV, alphaTB.y * BdotV, NdotV));\nlet lambdaL = NdotV * length(v3(alphaTB.x * TdotL, alphaTB.y * BdotL, NdotL));\nreturn 0.5 / max(lambdaV + lambdaL, 0.0000001);\n}\n`\n : ``;\n\n const ssFns =\n useSubsurface || useRefraction || useCcTint\n ? `fn nme_pbr_transmittanceBurley(tintColor: v3, diffusionDist: v3, thickness: f32) -> v3 {\nlet S = v3(1.0) / max(diffusionDist, v3(0.0000001));\nlet temp = exp(-0.333333333 * thickness * S);\nreturn tintColor * 0.25 * (temp * temp * temp + 3.0 * temp);\n}\nfn nme_pbr_cocaLambert(volumeAlbedo: v3, distance: f32) -> v3 {\nreturn exp(-volumeAlbedo * distance);\n}\nfn nme_pbr_colorAtDistance(color: v3, distance: f32) -> v3 {\nreturn -log(color) / distance;\n}\n`\n : ``;\n\n const anisoSetup = useAnisotropy\n ? `let _adp1 = dpdx(worldPos);\nlet _adp2 = -dpdy(worldPos);\nlet _aduv1 = dpdx(anisoUv);\nlet _aduv2 = -dpdy(anisoUv);\nlet _adp2perp = cross(_adp2, Ng);\nlet _adp1perp = cross(Ng, _adp1);\nlet _atan = _adp2perp * _aduv1.x + _adp1perp * _aduv2.x;\nlet _abit = _adp2perp * _aduv1.y + _adp1perp * _aduv2.y;\nlet _adet = max(dot(_atan, _atan), dot(_abit, _abit));\nlet _ainvmax = select(0.0, inverseSqrt(_adet), _adet > 0.0);\nlet _aTBN0 = normalize(_atan * _ainvmax);\nlet _aTBN1 = normalize(_abit * _ainvmax);\nlet anisoIntensity = clamp(anisoIntensityIn, -1.0, 1.0);\nlet anisoDir = v3(anisoDirection, 0.0);\nlet anisoT_raw = _aTBN0 * anisoDir.x + _aTBN1 * anisoDir.y;\nlet anisoT = normalize(anisoT_raw);\nlet anisoB = normalize(cross(Ng, anisoT));\nlet aniAlphaTB = nme_pbr_anisoRoughness(alphaG, anisoIntensity);\nlet aniN = nme_pbr_anisoBentNormal(anisoT, anisoB, N, V, anisoIntensity);`\n : `let anisoT = v3(1.0, 0.0, 0.0);\nlet anisoB = v3(0.0, 0.0, 1.0);\nlet aniAlphaTB = v2(alphaG, alphaG);\nlet aniN = N;`;\n\n const specularAABlock = useSpecularAA\n ? `var AA_factor_x = 0.0;\nvar AA_factor_y = 0.0;\n{ let nDfdx_AA = dpdx(N);\nlet nDfdy_AA = dpdy(N);\nlet slopeSquare_AA = max(dot(nDfdx_AA, nDfdx_AA), dot(nDfdy_AA, nDfdy_AA));\nAA_factor_x = pow(saturate(slopeSquare_AA), 0.333);\nAA_factor_y = sqrt(slopeSquare_AA) * 0.75;\nalphaG = alphaG + AA_factor_y; }`\n : `let AA_factor_x = 0.0;\nlet AA_factor_y = 0.0;`;\n\n return `alias v2 = vec2<f32>;\nalias v3 = vec3<f32>;\nalias v4 = vec4<f32>;\nstruct NmePbrMrResult {\nlighting: v3,\ndiffuseDir: v3,\nspecularDir: v3,\ndiffuseInd: v3,\nspecularInd: v3,\nshadow: f32,\nlumOverAlpha: f32,\n};\nconst NME_PBR_PI: f32 = 3.14159265358979323846;\nfn nme_pbr_distGGX(NdotH: f32, alphaG: f32) -> f32 {\nlet a2 = alphaG * alphaG;\nlet d = NdotH * NdotH * (a2 - 1.0) + 1.0;\nreturn a2 / (NME_PBR_PI * d * d);\n}\nfn nme_pbr_geomGGX(NdotL: f32, NdotV: f32, alphaG: f32) -> f32 {\nlet a2 = alphaG * alphaG;\nlet gl = NdotL * sqrt(NdotV * (NdotV - a2 * NdotV) + a2);\nlet gv = NdotV * sqrt(NdotL * (NdotL - a2 * NdotL) + a2);\nreturn 0.5 / max(gl + gv, 0.00001);\n}\nfn nme_pbr_fresSchlick(c: f32, F0: v3, F90: v3) -> v3 {\nlet t = 1.0 - c;\nlet t2 = t * t;\nreturn F0 + (F90 - F0) * (t2 * t2 * t);\n}\nfn nme_pbr_diffuseEON(albedo: v3, sigma: f32, NdotL: f32, NdotV: f32, LdotV: f32) -> v3 {\nreturn albedo * (1.0 / NME_PBR_PI);\n}\n${ccSchlickFn}${charlieFn}${anisoFns}${ssFns}fn nme_pbr_mr_compute(\n worldPos: v3, geometricNormal: v3, worldNormal: v3, cameraPos: v3,\n baseColor: v3, metallic: f32, roughness: f32, ao: f32,\n ccIntensityIn: f32, ccRoughnessIn: f32, ccIor: f32,\n ccBumpColor: v3, ccBumpUv: v2,\n ccTintColor: v3, ccTintAtDistance: f32, ccTintThickness: f32,\n shIntensityIn: f32, shColorIn: v3, shRoughnessIn: f32,\n baseIor: f32,\n refrIntensityIn: f32, refrIor: f32, refrTintAtDistance: f32,\n ssTintColor: v3, ssThickness: f32,\n ssTranslucencyIntensityIn: f32, ssDiffusionDist: v3,\n anisoIntensityIn: f32, anisoDirection: v2, anisoUv: v2,\n iridescenceIntensityIn: f32, iridescenceIorIn: f32, iridescenceThicknessIn: f32,\n shadowFactors: array<f32, ${MAX_LIGHTS}>\n) -> NmePbrMrResult {\n var r: NmePbrMrResult;\n let Ng = normalize(geometricNormal);\n let N = normalize(worldNormal);\n let V = normalize(cameraPos - worldPos);\n let NdotVUnclamped = dot(N, V);\n let NdotV = abs(NdotVUnclamped) + 0.0000001;\n let metallic_c = clamp(metallic, 0.0, 1.0);\n let rough_c = clamp(roughness, 0.0, 1.0);\n var alphaG = rough_c * rough_c + 0.0005;\n ${specularAABlock}\n let dielectricF0Raw = (baseIor - 1.0) / (baseIor + 1.0);\n let dielectricF0Scalar = dielectricF0Raw * dielectricF0Raw;\n let dielectricF0 = v3(dielectricF0Scalar);\n var surfaceAlbedo = baseColor * (1.0 - metallic_c) * (1.0 - dielectricF0Scalar);\n let colorF0Base = mix(dielectricF0, baseColor, metallic_c);\n let colorF0 = ${\n useIridescence\n ? `mix(colorF0Base, nme_pbr_evalIridescence(1.0, max(iridescenceIorIn, 1.0001), NdotV, max(iridescenceThicknessIn, 0.0), colorF0Base), clamp(iridescenceIntensityIn, 0.0, 1.0))`\n : `colorF0Base`\n };\n let colorF90 = v3(1.0);\n let ao_c = clamp(ao, 0.0, 1.0);\n let directRoughness = max(rough_c, AA_factor_x);\n let directAlphaG = directRoughness * directRoughness + 0.0005;\n ${anisoSetup}\n ${ccDecls}\n ${directSpecR0Decl}\n ${ccNormalSetup}\n ${ccAlphaSetup}\n ${shDecls}\n let translucencyIntensity = ${useSubsurface ? \"clamp(ssTranslucencyIntensityIn, 0.0, 1.0)\" : \"0.0\"};\n let ssTransmittance = ${useSubsurface ? \"nme_pbr_transmittanceBurley(ssTintColor, ssDiffusionDist, max(ssThickness, 0.0000001)) * translucencyIntensity\" : \"v3(0.0)\"};\n let directDiffuseTranslucencyScale = 1.0 - translucencyIntensity;\n ${\n useRefraction\n ? `// LEGACY_SPECULAR_ENERGY_CONSERVATION is on for BJS NME PBR-MR. When refraction\n let _refractionOpacityPre = 1.0 - clamp(refrIntensityIn, 0.0, 1.0);\n surfaceAlbedo = surfaceAlbedo * _refractionOpacityPre;`\n : ``\n }\n var diffuseAcc = v3(0.0);\n var diffuseTransmissionAcc = v3(0.0);\n var specAcc = v3(0.0);\n var aggShadow: f32 = 0.0;\n var nLights: f32 = 0.0;\n let lc = min(meshU.lc, ${MAX_LIGHTS}u);\n for (var i: u32 = 0u; i < lc; i = i + 1u) {\n let lightIndex = nli(i);\n let entry = nmeLights.lights[lightIndex];\n let t = u32(entry.vLightData.w);\n let sh = shadowFactors[lightIndex];\n if (t == 3u) {\n let Ldir = normalize(entry.vLightData.xyz);\n let nl = clamp(0.5 + 0.5 * dot(N, Ldir), 0.0000001, 1.0);\n let groundSky = mix(entry.vLightDirection.xyz, entry.vLightDiffuse.rgb, nl);\n var baseLayerAtten: f32 = 1.0;\n var baseLayerAbsorption = v3(1.0);${ccHemiBlock(useClearcoat, useCcTint)}\n let H_h = normalize(V + Ldir);\n let NdotH_h = clamp(dot(N, H_h), 0.0000001, 1.0);\n let VdotH_h = saturate(dot(V, H_h));\n let cF_h = nme_pbr_fresSchlick(VdotH_h, directSpecR0, colorF90);\n ${\n useAnisotropy\n ? `let TdotH_h = dot(anisoT, H_h);\n let BdotH_h = dot(anisoB, H_h);\n let TdotV_h = dot(anisoT, V);\n let BdotV_h = dot(anisoB, V);\n let TdotL_h = dot(anisoT, Ldir);\n let BdotL_h = dot(anisoB, Ldir);\n let D_h = nme_pbr_burleyAnisoD(NdotH_h, TdotH_h, BdotH_h, aniAlphaTB);\n let Vis_h = nme_pbr_visAnisoSmith(nl, NdotV, TdotV_h, BdotV_h, TdotL_h, BdotL_h, aniAlphaTB);\n specAcc = specAcc + cF_h * D_h * Vis_h * nl * entry.vLightDiffuse.rgb * sh * baseLayerAtten * baseLayerAbsorption;`\n : `let D_h = nme_pbr_distGGX(NdotH_h, directAlphaG);\n let G_h = nme_pbr_geomGGX(nl, NdotV, directAlphaG);\n specAcc = specAcc + cF_h * D_h * G_h * nl * entry.vLightDiffuse.rgb * sh * baseLayerAtten * baseLayerAbsorption;`\n }\n diffuseAcc = diffuseAcc + groundSky * surfaceAlbedo * sh * baseLayerAtten * baseLayerAbsorption;${shHemiBlock(useSheen)}\n aggShadow = aggShadow + sh;\n nLights = nLights + 1.0;\n continue;\n }\n var L: v3;\n var atten: f32 = 1.0;\n let color = entry.vLightDiffuse.rgb;\n if (t == 1u) {\n L = normalize(-entry.vLightData.xyz);\n } else {\n let toL = entry.vLightData.xyz - worldPos;\n let d2 = dot(toL, toL);\n let dist = sqrt(d2);\n L = toL / max(dist, 0.0001);\n let range = entry.vLightDiffuse.a;\n if (t == 2u) {\n let invD2 = 1.0 / max(d2, 0.0000001);\n let cosHalfAngle = entry.vLightDirection.w;\n let kappa = 6.64385618977 / max(1.0 - cosHalfAngle, 0.0001);\n let cd = dot(-entry.vLightDirection.xyz, L);\n let dirFall = exp2(kappa * (cd - 1.0));\n atten = invD2 * dirFall;\n } else {\n atten = 1.0 / max(d2, 0.0000001);\n }\n }\n let NdotLUnclamped = dot(N, L);\n let NdotL = clamp(NdotLUnclamped, 0.0000001, 1.0);\n var baseLayerAtten: f32 = 1.0;\n var baseLayerAbsorption = v3(1.0);${ccDirectBlock(useClearcoat, useCcTint)}\n let _LdotV = select(0.0, dot(L, V), t == 1u);\n let _eonDiffuse = nme_pbr_diffuseEON(surfaceAlbedo, 0.0, NdotL, NdotV, _LdotV);\n diffuseAcc = diffuseAcc + _eonDiffuse * directDiffuseTranslucencyScale * NdotL * color * atten * sh * baseLayerAtten * baseLayerAbsorption;\n if (NdotLUnclamped < 0.0 && translucencyIntensity > 0.0) {\n let _trNdotL = abs(NdotLUnclamped) + 0.0000001;\n let _wrapW = 0.02;\n let _wrapT = 1.0 + _wrapW;\n let _wrapNdotL = clamp((_trNdotL + _wrapW) / (_wrapT * _wrapT), 0.0, 1.0);\n let _clampedAlbT = clamp(surfaceAlbedo, v3(0.1), v3(1.0));\n let _eonTransmit = nme_pbr_diffuseEON(_clampedAlbT, 0.0, max(NdotL, 0.0000001), NdotV, _LdotV) / _clampedAlbT;\n diffuseTransmissionAcc = diffuseTransmissionAcc + _eonTransmit * (ssTransmittance * _wrapNdotL) * color * atten * sh * baseLayerAtten * baseLayerAbsorption;\n }\n if (NdotL > 0.0 && atten > 0.0) {\n let H = normalize(V + L);\n let NdotH = clamp(dot(N, H), 0.0000001, 1.0);\n let VdotH = saturate(dot(V, H));\n let cF = nme_pbr_fresSchlick(VdotH, directSpecR0, colorF90);\n ${\n useAnisotropy\n ? `let TdotH = dot(anisoT, H);\n let BdotH = dot(anisoB, H);\n let TdotV = dot(anisoT, V);\n let BdotV = dot(anisoB, V);\n let TdotL = dot(anisoT, L);\n let BdotL = dot(anisoB, L);\n let D = nme_pbr_burleyAnisoD(NdotH, TdotH, BdotH, aniAlphaTB);\n let Vis = nme_pbr_visAnisoSmith(NdotL, NdotV, TdotV, BdotV, TdotL, BdotL, aniAlphaTB);\n specAcc = specAcc + cF * D * Vis * NdotL * color * atten * sh * baseLayerAtten * baseLayerAbsorption;`\n : `let D = nme_pbr_distGGX(NdotH, directAlphaG);\n let G = nme_pbr_geomGGX(NdotL, NdotV, directAlphaG);\n specAcc = specAcc + cF * D * G * NdotL * color * atten * sh * baseLayerAtten * baseLayerAbsorption;`\n }\n }${shDirectBlock(useSheen)}\n aggShadow = aggShadow + sh;\n nLights = nLights + 1.0;\n }\n r.diffuseDir = diffuseAcc;\n r.specularDir = specAcc;\n${iblBlock}\n ${\n useEnv\n ? `let _radLum = clamp(dot(finalRadianceScaled * shAlbedoScaling${useClearcoat ? ` * ccConsIBL${ccTintScale}` : ``}, v3(0.2126, 0.7152, 0.0722)), 0.0, 1.0);\n let _specLum = clamp(dot(finalSpecularScaledDirect * shAlbedoScaling, v3(0.2126, 0.7152, 0.0722)), 0.0, 1.0);${\n useClearcoat\n ? `\n let _ccLum = clamp(dot(ccFinalRadiance, v3(0.2126, 0.7152, 0.0722)), 0.0, 1.0);\n r.lumOverAlpha = _radLum + _specLum + _ccLum;`\n : `\n r.lumOverAlpha = _radLum + _specLum;`\n }`\n : `let _specLum = clamp(dot(specAcc, v3(0.2126, 0.7152, 0.0722)), 0.0, 1.0);\n r.lumOverAlpha = _specLum;`\n }\n var colorOut = max(r.lighting, v3(0.0)) * sceneU.vImageInfos.x;\n if (sceneU.vImageInfos.w > 0.5) {\n colorOut = 1.0 - exp2(-1.590579 * colorOut);\n }\n colorOut = pow(max(colorOut, v3(0.0)), v3(0.45454545));\n colorOut = clamp(colorOut, v3(0.0), v3(1.0));\n let highContrast = colorOut * colorOut * (v3(3.0) - colorOut * 2.0);\n if (sceneU.vImageInfos.y < 1.0) {\n colorOut = mix(v3(0.5), colorOut, sceneU.vImageInfos.y);\n } else {\n colorOut = mix(colorOut, highContrast, sceneU.vImageInfos.y - 1.0);\n }\n r.lighting = max(colorOut, v3(0.0));\n if (nLights > 0.0) { r.shadow = aggShadow / nLights; } else { r.shadow = 1.0; }\n return r;\n}\n`;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pbr-mr-helper-full.js","sources":["../../../../../src/material/node/blocks/pbr-mr-helper-full.ts"],"sourcesContent":["/** PBRMetallicRoughnessBlock — direct lighting + optional IBL + optional clearcoat + optional sheen.\n *\n * When the `reflection` input is connected (typically to a ReflectionBlock),\n * this emitter runs the GGX direct-lighting path PLUS a split-sum IBL\n * contribution (specular cube + BRDF LUT + SH irradiance).\n *\n * When the `clearcoat` input is connected (to a ClearCoatBlock), an extra\n * GGX clear-coat layer is added on top: per-light Schlick fresnel + Kelemen\n * visibility GGX specular, and the base layer (diffuse + specular + IBL)\n * is modulated by (1 - ccFresnel * ccIntensity).\n *\n * When the `sheen` input is connected (to a SheenBlock), an extra Charlie\n * NDF + Ashikhmin visibility cloth/velvet sheen layer is added: per-light\n * direct sheen contribution and a sheen IBL term that uses the BRDF LUT\n * blue channel for the sheen-roughness lookup.\n *\n * Outputs implemented (others stub to a zero vector):\n * - lighting / diffuseDir / specularDir / shadow / alpha\n * - diffuseInd / specularInd (only meaningful when IBL is on)\n */\n\nimport type { NodePbrMrHelperRequest } from \"../node-types.js\";\nimport { MAX_LIGHTS } from \"../../../light/types.js\";\n\nfunction ccDirectBlock(useClearcoat: boolean, useCcTint: boolean): string {\n if (!useClearcoat) {\n return \"\";\n }\n const Ncc = \"ccNormalW\";\n const NdotLcc = \"ccNdotL\";\n const declCcNdotL = `let ccNdotL = clamp(dot(ccNormalW, L), 0.0000001, 1.0);`;\n return `\n${declCcNdotL}\nif (${NdotLcc} > 0.0 && atten > 0.0) {\nlet ccH = normalize(V + L);\nlet ccNdotH = clamp(dot(${Ncc}, ccH), 0.0000001, 1.0);\nlet ccVdotH = saturate(dot(V, ccH));\nlet ccD = nme_pbr_distGGX(ccNdotH, ccAlphaG);\nlet ccVis = 0.25 / (ccVdotH * ccVdotH + 0.0000001);\nlet ccF_d = nme_pbr_ccSchlick(ccF0, ccVdotH);\nlet ccTerm = ccF_d * ccD * ccVis * ${NdotLcc};\nccDirectSpecAcc = ccDirectSpecAcc + v3(ccTerm) * color * atten * ccIntensity * sh;\nbaseLayerAtten = 1.0 - ccF_d * ccIntensity;\n${\n useCcTint\n ? `let ccLRefract = -refract(L, ${Ncc}, ccIorInv);\nlet ccNdotLRefract = clamp(dot(${Ncc}, ccLRefract), 0.0000001, 1.0);\nlet ccDirectAbsorption = nme_pbr_cocaLambert(ccAbsorptionColor, ccTintThickness * ((ccNdotLRefract + ccNdotVRefract) / (ccNdotLRefract * ccNdotVRefract)));\nbaseLayerAbsorption = mix(v3(1.0), ccDirectAbsorption, v3(ccIntensity));`\n : ``\n}\n}`;\n}\n\nfunction ccHemiBlock(useClearcoat: boolean, useCcTint: boolean): string {\n if (!useClearcoat) {\n return \"\";\n }\n const Ncc = \"ccNormalW\";\n return `\nlet ccNdotL_h = clamp(dot(${Ncc}, Ldir), 0.0000001, 1.0);\nif (nl > 0.0) {\nlet ccH_h = normalize(V + Ldir);\nlet ccNdotH_h = clamp(dot(${Ncc}, ccH_h), 0.0000001, 1.0);\nlet ccVdotH_h = saturate(dot(V, ccH_h));\nlet ccD_h = nme_pbr_distGGX(ccNdotH_h, ccAlphaG);\nlet ccVis_h = 0.25 / (ccVdotH_h * ccVdotH_h + 0.0000001);\nlet ccF_h = nme_pbr_ccSchlick(ccF0, ccVdotH_h);\nlet ccTerm_h = ccF_h * ccD_h * ccVis_h * ccNdotL_h;\nccDirectSpecAcc = ccDirectSpecAcc + v3(ccTerm_h) * entry.vLightDiffuse.rgb * ccIntensity * sh;\nbaseLayerAtten = 1.0 - ccF_h * ccIntensity;\n${\n useCcTint\n ? `let ccLRefract_h = -refract(Ldir, ${Ncc}, ccIorInv);\nlet ccNdotLRefract_h = clamp(dot(${Ncc}, ccLRefract_h), 0.0000001, 1.0);\nlet ccDirectAbsorption_h = nme_pbr_cocaLambert(ccAbsorptionColor, ccTintThickness * ((ccNdotLRefract_h + ccNdotVRefract) / (ccNdotLRefract_h * ccNdotVRefract)));\nbaseLayerAbsorption = mix(v3(1.0), ccDirectAbsorption_h, v3(ccIntensity));`\n : ``\n}\n}`;\n}\n\nfunction shDirectBlock(useSheen: boolean): string {\n if (!useSheen) {\n return \"\";\n }\n return `\nif (NdotL > 0.0 && atten > 0.0) {\nlet shH = normalize(V + L);\nlet shNdotH = clamp(dot(N, shH), 0.0000001, 1.0);\nlet shD = nme_pbr_charlieD(shNdotH, shAlphaG);\nlet shV = 1.0 / (4.0 * (NdotL + NdotV - NdotL * NdotV) + 0.0000001);\nshDirectAcc = shDirectAcc + shColorScaled * shD * shV * NdotL * color * atten * sh * baseLayerAtten;\n}`;\n}\n\nfunction shHemiBlock(useSheen: boolean): string {\n if (!useSheen) {\n return \"\";\n }\n return `\nif (nl > 0.0) {\nlet shH_h = normalize(V + Ldir);\nlet shNdotH_h = clamp(dot(N, shH_h), 0.0000001, 1.0);\nlet shD_h = nme_pbr_charlieD(shNdotH_h, shAlphaG);\nlet shV_h = 1.0 / (4.0 * (nl + NdotV - nl * NdotV) + 0.0000001);\nshDirectAcc = shDirectAcc + shColorScaled * shD_h * shV_h * nl * entry.vLightSpecular.rgb * sh * baseLayerAtten;\n}`;\n}\n\n/** Subsurface IBL block — runs inside the env IBL section. Computes refraction\n * (refract V through N, sample env at refractionLOD, apply Coca-Lambert tint\n * absorption + reflectance complement) and translucency (back-scattered SH\n * irradiance with Burley transmittance). Contributes:\n * - finalRefraction (vec3, added to lighting)\n * - refractionOpacity (f32, scales finalIrradiance: 1 - refrIntensity)\n * - mutates finalIrradiance to include refractionIrradiance + (1-translucency) scale.\n *\n * Always declares finalRefraction/refractionOpacity even when sub-features are\n * off so the downstream composition can reference them unconditionally. */\nfunction ssBlock(useSubsurface: boolean, useRefraction: boolean, useAnisotropy: boolean): string {\n if (!useSubsurface && !useRefraction) {\n return `let finalRefraction = v3(0.0);\nlet refractionOpacity = 1.0;\nlet ssRefractionIrradiance = v3(0.0);`;\n }\n const refrPart = useRefraction\n ? `// Refraction: refract V through N at IOR, sample env at refraction LOD.\n let refrIntensity = clamp(refrIntensityIn, 0.0, 1.0);\n let invIor = 1.0 / max(refrIor, 1.0001);\n let refrV_raw = refract(-V, ${useAnisotropy ? \"aniN\" : \"N\"}, invIor);\n let refrV = v3(refrV_raw.x * cosA + refrV_raw.z * sinA, refrV_raw.y, -refrV_raw.x * sinA + refrV_raw.z * cosA);\n let refrAlphaG = mix(alphaG, 0.0, clamp(invIor * 3.0 - 2.0, 0.0, 1.0));\n let refrLod = log2(cubemapDim * refrAlphaG) * sceneU.vImageInfos.z;\n let envRefr = textureSampleLevel(nmeIblTexture, nmeIblSampler, refrV, clamp(refrLod, 0.0, maxLod)).rgb;\n let volumeAlbedo = nme_pbr_colorAtDistance(ssTintColor, refrTintAtDistance);\n let refrTransmittance = v3(refrIntensity) * nme_pbr_cocaLambert(volumeAlbedo, ssThickness);\n let finalRefractionRaw = envRefr * refrTransmittance * (v3(1.0) - refractionSpecEnvReflectance);\n let refractionOpacity = 1.0 - refrIntensity;`\n : `let finalRefractionRaw = v3(0.0);\nlet refractionOpacity = 1.0;`;\n const ssPart = useSubsurface\n ? `// Translucency: back-scattered SH irradiance with Burley transmittance.\n let nN_raw = -N;\n let nN_env = v3(nN_raw.x * cosA + nN_raw.z * sinA, nN_raw.y, -nN_raw.x * sinA + nN_raw.z * cosA);\n let backIrradiance = (sceneU.vSphericalL00.xyz\n + sceneU.vSphericalL1_1.xyz * nN_env.y + sceneU.vSphericalL10.xyz * nN_env.z + sceneU.vSphericalL11.xyz * nN_env.x\n + sceneU.vSphericalL2_2.xyz * (nN_env.y * nN_env.x) + sceneU.vSphericalL2_1.xyz * (nN_env.y * nN_env.z)\n + sceneU.vSphericalL20.xyz * (3.0 * nN_env.z * nN_env.z - 1.0) + sceneU.vSphericalL21.xyz * (nN_env.z * nN_env.x)\n + sceneU.vSphericalL22.xyz * (nN_env.x * nN_env.x - nN_env.y * nN_env.y));\n let ssRefractionIrradiance = backIrradiance * ssTransmittance;\n finalIrradiance = finalIrradiance * refractionOpacity;\n finalIrradiance = finalIrradiance * (1.0 - translucencyIntensity);`\n : `let ssRefractionIrradiance = v3(0.0);\nfinalIrradiance = finalIrradiance * refractionOpacity;`;\n return `${refrPart}\n${ssPart}\nlet finalRefraction = finalRefractionRaw;`;\n}\n\nexport function buildPbrMrHelperFull(request: NodePbrMrHelperRequest): string {\n return HELPER_WGSL(\n request.useEnv,\n request.useClearcoat,\n request.useSheen,\n request.useRefraction,\n request.useSubsurface,\n request.useAnisotropy,\n request.useIridescence,\n request.useShAlbedoScaling,\n request.useCcBump,\n request.useCcTint,\n request.useSpecularAA,\n request.remapClearcoatF0\n );\n}\n\nfunction HELPER_WGSL(\n useEnv: boolean,\n useClearcoat: boolean,\n useSheen: boolean,\n useRefraction: boolean,\n useSubsurface: boolean,\n useAnisotropy: boolean,\n useIridescence: boolean,\n useShAlbedoScaling: boolean,\n useCcBump: boolean,\n useCcTint: boolean,\n useSpecularAA: boolean,\n remapClearcoatF0: boolean\n): string {\n const ccDecls = useClearcoat\n ? `let ccIntensity = clamp(ccIntensityIn, 0.0, 1.0);\nlet ccRough = clamp(ccRoughnessIn, 0.0, 1.0);\nlet ccF0_raw = (ccIor - 1.0) / (ccIor + 1.0);\nlet ccF0 = ccF0_raw * ccF0_raw;\nvar ccDirectSpecAcc = v3(0.0);`\n : `let ccDirectSpecAcc = v3(0.0);`;\n\n const ccAlphaSetup = useClearcoat\n ? `var ccAA_factor_y = 0.0;\n${\n useSpecularAA\n ? `{ let ccNdfdx_AA = dpdx(ccNormalW);\nlet ccNdfdy_AA = dpdy(ccNormalW);\nlet ccSlopeSquare_AA = max(dot(ccNdfdx_AA, ccNdfdx_AA), dot(ccNdfdy_AA, ccNdfdy_AA));\nccAA_factor_y = sqrt(ccSlopeSquare_AA) * 0.75; }`\n : ``\n}\nlet ccAlphaG = ccRough * ccRough + 0.0005 + ccAA_factor_y;`\n : ``;\n\n const ccTintViewSetup = useCcTint\n ? `\nlet ccIorInv = 1.0 / max(ccIor, 1.0001);\nlet ccAbsorptionColor = nme_pbr_colorAtDistance(max(ccTintColor, v3(0.0000001)), max(ccTintAtDistance, 0.0000001));\nlet ccVRefract = refract(-V, ccNormalW, ccIorInv);\nlet ccNdotVRefract = abs(dot(ccNormalW, ccVRefract)) + 0.0000001;`\n : ``;\n\n const ccNormalSetup = useClearcoat\n ? useCcBump\n ? `let ccNormalW = nme_perturbNormal(worldPos, Ng, ccBumpUv, ccBumpColor, 1.0);\nlet ccNdotV = abs(dot(ccNormalW, V)) + 0.0000001;${ccTintViewSetup}`\n : `let ccNormalW = Ng;\nlet ccNdotV = abs(dot(ccNormalW, V)) + 0.0000001;${ccTintViewSetup}`\n : `let ccNormalW = N;\nlet ccNdotV: f32 = 0.0;`;\n\n const shDecls = useSheen\n ? `let shIntensityRaw = clamp(shIntensityIn, 0.0, 1.0);\n${\n useShAlbedoScaling\n ? `let shIntensity = shIntensityRaw;`\n : `let reflectanceF0 = max(colorF0.r, max(colorF0.g, colorF0.b));\nlet shIntensity = shIntensityRaw * (1.0 - reflectanceF0);`\n}\nlet shRough = clamp(shRoughnessIn, 0.0, 1.0);\nlet shAlphaG = shRough * shRough + 0.0005;\nlet shColorScaled = shColorIn * shIntensity;\nvar shDirectAcc = v3(0.0);`\n : `let shDirectAcc = v3(0.0);`;\n\n const shIblTerm =\n useEnv && useSheen\n ? `let shSpecLod = log2(cubemapDim * shAlphaG) * sceneU.vImageInfos.z;\n let shEnvRadiance = textureSampleLevel(nmeIblTexture, nmeIblSampler, R, clamp(shSpecLod, 0.0, maxLod)).rgb;\n let shBrdfBlue = textureSample(nmeBrdfLUT, nmeBrdfSampler, v2(NdotV, shRough)).b;\n let shFinalIbl = shEnvRadiance * shColorScaled * shBrdfBlue * seo * eho;\n ${\n useShAlbedoScaling\n ? `// SHEEN_ALBEDOSCALING: surface albedo and base specular scale by (1 - shInt × max(shColor) × envSheenBrdf.b).\n let shAlbedoScaling = 1.0 - shIntensity * max(max(shColorIn.r, shColorIn.g), shColorIn.b) * shBrdfBlue;`\n : `let shAlbedoScaling: f32 = 1.0;`\n }`\n : `let shFinalIbl = v3(0.0);\nlet shAlbedoScaling: f32 = 1.0;`;\n\n const directSpecR0Decl =\n useClearcoat && remapClearcoatF0\n ? `let _directF0S = sqrt(max(colorF0, v3(0.0)));\nlet _directF0T = ((1.0 - ccIor) + (1.0 + ccIor) * _directF0S) / ((1.0 + ccIor) + (1.0 - ccIor) * _directF0S);\nlet directSpecR0 = mix(colorF0, clamp(_directF0T * _directF0T, v3(0.0), v3(1.0)), ccIntensity);`\n : `let directSpecR0 = colorF0;`;\n\n const shIblScale = useClearcoat ? ` * ccConsIBL${useCcTint ? \" * ccAbsorption\" : \"\"}` : \"\";\n const refrCcScale = useClearcoat ? \" * ccConsIBL\" : \"\";\n const ccIblPre = useClearcoat\n ? `let ccFresnelIBL = nme_pbr_ccSchlick(ccF0, ccNdotV);\n let ccConsIBL = 1.0 - ccFresnelIBL * ccIntensity;\n let ccBrdfSample = textureSample(nmeBrdfLUT, nmeBrdfSampler, v2(ccNdotV, ccRough)).rgb;\n let ccSpecEnvReflRaw = (v3(ccF0) * ccBrdfSample.y + (v3(1.0) - v3(ccF0)) * ccBrdfSample.x) * ccIntensity;\n let ccEnergyConservation = 1.0 + _coloredR0 * (1.0 / max(ccBrdfSample.y, 0.001) - 1.0);\n let ccEhoT = clamp(1.0 + 1.1 * dot(reflect(-V, ccNormalW), Ng), 0.0, 1.0);\n let ccSpecEnvRefl = ccSpecEnvReflRaw * (ccEhoT * ccEhoT);\n let ccSpecLod = log2(cubemapDim * ccAlphaG) * sceneU.vImageInfos.z;\n let ccR_raw = reflect(-V, ccNormalW);\n let ccR = v3(ccR_raw.x * cosA + ccR_raw.z * sinA, ccR_raw.y, -ccR_raw.x * sinA + ccR_raw.z * cosA);\n let ccEnvRadiance = textureSampleLevel(nmeIblTexture, nmeIblSampler, ccR, clamp(ccSpecLod, 0.0, maxLod)).rgb;\n ${\n useCcTint\n ? `// Clearcoat absorption: BJS Beer-Lambert path length through the coat.\n let ccAbsorption = mix(v3(1.0), nme_pbr_cocaLambert(ccAbsorptionColor, ccTintThickness * ((ccNdotVRefract + ccNdotVRefract) / (ccNdotVRefract * ccNdotVRefract))), v3(ccIntensity));`\n : `let ccAbsorption = v3(1.0);`\n }\n let ccFinalRadiance = ccEnvRadiance * ccSpecEnvRefl;`\n : ``;\n const ccTintScale = useCcTint ? \" * ccAbsorption\" : \"\";\n const ccIblFinal = useClearcoat\n ? `${ccIblPre}\n${shIblTerm}\nr.lighting = finalIrradiance * shAlbedoScaling * ccConsIBL${ccTintScale}\n+ finalRadianceScaled * shAlbedoScaling * ccConsIBL${ccTintScale}\n+ ssRefractionIrradiance * ao_c\n+ finalSpecularScaledDirect * shAlbedoScaling\n+ diffuseAcc * shAlbedoScaling\n+ diffuseTransmissionAcc\n+ ccDirectSpecAcc * ccEnergyConservation\n+ ccFinalRadiance\n+ shDirectAcc\n+ shFinalIbl${shIblScale}\n+ finalRefraction${refrCcScale}${ccTintScale};`\n : `${shIblTerm}\nr.lighting = finalIrradiance * shAlbedoScaling + ssRefractionIrradiance * ao_c + (finalRadianceScaled + finalSpecularScaledDirect + diffuseAcc) * shAlbedoScaling + diffuseTransmissionAcc + shDirectAcc + shFinalIbl + finalRefraction;`;\n\n const ccDirectFinal = useClearcoat\n ? `r.lighting = diffuseAcc + specAcc + diffuseTransmissionAcc + ccDirectSpecAcc + shDirectAcc;`\n : `r.lighting = diffuseAcc + diffuseTransmissionAcc + specAcc + shDirectAcc;`;\n\n const refractionSpecEnvReflectanceDecl = useRefraction ? `let refractionSpecEnvReflectance = baseSpecEnvReflectance;` : ``;\n\n const iblBlock = useEnv\n ? `\n let envRot = sceneU.envRotationY;\n let cosA = cos(envRot); let sinA = sin(envRot);\n let N_specSrc = ${useAnisotropy ? \"aniN\" : \"N\"};\n let R_raw = reflect(-V, N_specSrc);\n let R = v3(R_raw.x * cosA + R_raw.z * sinA, R_raw.y, -R_raw.x * sinA + R_raw.z * cosA);\n let N_env = v3(Ng.x * cosA + Ng.z * sinA, Ng.y, -Ng.x * sinA + Ng.z * cosA);\n let environmentIrradiance = (sceneU.vSphericalL00.xyz\n + sceneU.vSphericalL1_1.xyz * N_env.y + sceneU.vSphericalL10.xyz * N_env.z + sceneU.vSphericalL11.xyz * N_env.x\n + sceneU.vSphericalL2_2.xyz * (N_env.y * N_env.x) + sceneU.vSphericalL2_1.xyz * (N_env.y * N_env.z)\n + sceneU.vSphericalL20.xyz * (3.0 * N_env.z * N_env.z - 1.0) + sceneU.vSphericalL21.xyz * (N_env.z * N_env.x)\n + sceneU.vSphericalL22.xyz * (N_env.x * N_env.x - N_env.y * N_env.y));\n let brdfSample = textureSample(nmeBrdfLUT, nmeBrdfSampler, v2(NdotV, rough_c));\n let envBrdf = brdfSample.rgb;\n let reflectanceF0Scalar = max(colorF0.r, max(colorF0.g, colorF0.b));\n let baseSpecEnvReflectance = (colorF90 - v3(reflectanceF0Scalar)) * envBrdf.x + v3(reflectanceF0Scalar) * envBrdf.y;\n let seo = clamp((NdotVUnclamped + ao_c) * (NdotVUnclamped + ao_c) - 1.0 + ao_c, 0.0, 1.0);\n let _geoNF = select(-Ng, Ng, dot(Ng, V) > 0.0);\n let _ehoRefl = reflect(-V, N);\n let _ehoT = clamp(1.0 + 1.1 * dot(_ehoRefl, _geoNF), 0.0, 1.0);\n let eho = _ehoT * _ehoT;\n ${\n useClearcoat && remapClearcoatF0\n ? `let _f0S = sqrt(max(colorF0, v3(0.0)));\n let _f0T = ((1.0 - ccIor) + (1.0 + ccIor) * _f0S) / ((1.0 + ccIor) + (1.0 - ccIor) * _f0S);\n let _coloredR0 = mix(colorF0, clamp(_f0T * _f0T, v3(0.0), v3(1.0)), ccIntensity);`\n : `let _coloredR0 = colorF0;`\n }\n let colorSpecEnvReflectance = ((colorF90 - _coloredR0) * envBrdf.x + _coloredR0 * envBrdf.y) * seo * eho;\n let energyConservation = 1.0 + _coloredR0 * (1.0 / max(envBrdf.y, 0.001) - 1.0);\n let maxLod = f32(textureNumLevels(nmeIblTexture) - 1);\n let cubemapDim = f32(textureDimensions(nmeIblTexture).x);\n let specLod = log2(cubemapDim * alphaG) * sceneU.vImageInfos.z;\n var environmentRadiance = textureSampleLevel(nmeIblTexture, nmeIblSampler, R, clamp(specLod, 0.0, maxLod)).rgb;\n ${refractionSpecEnvReflectanceDecl}\n var finalIrradiance = environmentIrradiance * surfaceAlbedo;\n let finalRadianceScaled = environmentRadiance * colorSpecEnvReflectance * energyConservation;\n let finalSpecularScaledDirect = specAcc * energyConservation;\n ${ssBlock(useSubsurface, useRefraction, useAnisotropy)}\n finalIrradiance = finalIrradiance * ao_c;\n r.diffuseInd = finalIrradiance;\n r.specularInd = finalRadianceScaled;\n ${ccIblFinal}`\n : `\nr.diffuseInd = v3(0.0);\nr.specularInd = v3(0.0);\n${ccDirectFinal}`;\n\n const ccSchlickFn = useClearcoat\n ? `fn nme_pbr_ccSchlick(f0: f32, cosTheta: f32) -> f32 {\nlet t = 1.0 - cosTheta;\nlet t2 = t * t;\nreturn f0 + (1.0 - f0) * (t2 * t2 * t);\n}\n`\n : ``;\n\n const charlieFn = useSheen\n ? `fn nme_pbr_charlieD(NdotH: f32, alphaG: f32) -> f32 {\nlet invR = 1.0 / max(alphaG, 0.0005);\nlet cos2h = NdotH * NdotH;\nlet sin2h = 1.0 - cos2h;\nreturn (2.0 + invR) * pow(sin2h, invR * 0.5) / (2.0 * NME_PBR_PI);\n}\n`\n : ``;\n\n const anisoFns = useAnisotropy\n ? `fn nme_pbr_anisoRoughness(alphaG: f32, anisotropy: f32) -> v2 {\nlet alphaT = max(alphaG * (1.0 + anisotropy), 0.0005);\nlet alphaB = max(alphaG * (1.0 - anisotropy), 0.0005);\nreturn v2(alphaT, alphaB);\n}\nfn nme_pbr_anisoBentNormal(T: v3, B: v3, N: v3, V: v3, anisotropy: f32) -> v3 {\nvar anisotropicFrameDirection = B;\nif (anisotropy < 0.0) {\nanisotropicFrameDirection = T;\n}\nlet anisoTan = cross(normalize(anisotropicFrameDirection), V);\nlet anisoNormal = cross(anisoTan, anisotropicFrameDirection);\nreturn normalize(mix(N, anisoNormal, abs(anisotropy)));\n}\nfn nme_pbr_burleyAnisoD(NdotH: f32, TdotH: f32, BdotH: f32, alphaTB: v2) -> f32 {\nlet a2 = alphaTB.x * alphaTB.y;\nlet v = v3(alphaTB.y * TdotH, alphaTB.x * BdotH, a2 * NdotH);\nlet v2 = dot(v, v);\nlet w2 = a2 / max(v2, 0.0000001);\nreturn a2 * w2 * w2 * (1.0 / NME_PBR_PI);\n}\nfn nme_pbr_visAnisoSmith(NdotL: f32, NdotV: f32, TdotV: f32, BdotV: f32, TdotL: f32, BdotL: f32, alphaTB: v2) -> f32 {\nlet lambdaV = NdotL * length(v3(alphaTB.x * TdotV, alphaTB.y * BdotV, NdotV));\nlet lambdaL = NdotV * length(v3(alphaTB.x * TdotL, alphaTB.y * BdotL, NdotL));\nreturn 0.5 / max(lambdaV + lambdaL, 0.0000001);\n}\n`\n : ``;\n\n const ssFns =\n useSubsurface || useRefraction || useCcTint\n ? `fn nme_pbr_transmittanceBurley(tintColor: v3, diffusionDist: v3, thickness: f32) -> v3 {\nlet S = v3(1.0) / max(diffusionDist, v3(0.0000001));\nlet temp = exp(-0.333333333 * thickness * S);\nreturn tintColor * 0.25 * (temp * temp * temp + 3.0 * temp);\n}\nfn nme_pbr_cocaLambert(volumeAlbedo: v3, distance: f32) -> v3 {\nreturn exp(-volumeAlbedo * distance);\n}\nfn nme_pbr_colorAtDistance(color: v3, distance: f32) -> v3 {\nreturn -log(color) / distance;\n}\n`\n : ``;\n\n const anisoSetup = useAnisotropy\n ? `let _adp1 = dpdx(worldPos);\nlet _adp2 = -dpdy(worldPos);\nlet _aduv1 = dpdx(anisoUv);\nlet _aduv2 = -dpdy(anisoUv);\nlet _adp2perp = cross(_adp2, Ng);\nlet _adp1perp = cross(Ng, _adp1);\nlet _atan = _adp2perp * _aduv1.x + _adp1perp * _aduv2.x;\nlet _abit = _adp2perp * _aduv1.y + _adp1perp * _aduv2.y;\nlet _adet = max(dot(_atan, _atan), dot(_abit, _abit));\nlet _ainvmax = select(0.0, inverseSqrt(_adet), _adet > 0.0);\nlet _aTBN0 = normalize(_atan * _ainvmax);\nlet _aTBN1 = normalize(_abit * _ainvmax);\nlet anisoIntensity = clamp(anisoIntensityIn, -1.0, 1.0);\nlet anisoDir = v3(anisoDirection, 0.0);\nlet anisoT_raw = _aTBN0 * anisoDir.x + _aTBN1 * anisoDir.y;\nlet anisoT = normalize(anisoT_raw);\nlet anisoB = normalize(cross(Ng, anisoT));\nlet aniAlphaTB = nme_pbr_anisoRoughness(alphaG, anisoIntensity);\nlet aniN = nme_pbr_anisoBentNormal(anisoT, anisoB, N, V, anisoIntensity);`\n : `let anisoT = v3(1.0, 0.0, 0.0);\nlet anisoB = v3(0.0, 0.0, 1.0);\nlet aniAlphaTB = v2(alphaG, alphaG);\nlet aniN = N;`;\n\n const specularAABlock = useSpecularAA\n ? `var AA_factor_x = 0.0;\nvar AA_factor_y = 0.0;\n{ let nDfdx_AA = dpdx(N);\nlet nDfdy_AA = dpdy(N);\nlet slopeSquare_AA = max(dot(nDfdx_AA, nDfdx_AA), dot(nDfdy_AA, nDfdy_AA));\nAA_factor_x = pow(saturate(slopeSquare_AA), 0.333);\nAA_factor_y = sqrt(slopeSquare_AA) * 0.75;\nalphaG = alphaG + AA_factor_y; }`\n : `let AA_factor_x = 0.0;\nlet AA_factor_y = 0.0;`;\n\n return `alias v2 = vec2<f32>;\nalias v3 = vec3<f32>;\nalias v4 = vec4<f32>;\nstruct NmePbrMrResult {\nlighting: v3,\ndiffuseDir: v3,\nspecularDir: v3,\ndiffuseInd: v3,\nspecularInd: v3,\nshadow: f32,\nlumOverAlpha: f32,\n};\nconst NME_PBR_PI: f32 = 3.14159265358979323846;\nfn nme_pbr_distGGX(NdotH: f32, alphaG: f32) -> f32 {\nlet a2 = alphaG * alphaG;\nlet d = NdotH * NdotH * (a2 - 1.0) + 1.0;\nreturn a2 / (NME_PBR_PI * d * d);\n}\nfn nme_pbr_geomGGX(NdotL: f32, NdotV: f32, alphaG: f32) -> f32 {\nlet a2 = alphaG * alphaG;\nlet gl = NdotL * sqrt(NdotV * (NdotV - a2 * NdotV) + a2);\nlet gv = NdotV * sqrt(NdotL * (NdotL - a2 * NdotL) + a2);\nreturn 0.5 / max(gl + gv, 0.00001);\n}\nfn nme_pbr_fresSchlick(c: f32, F0: v3, F90: v3) -> v3 {\nlet t = 1.0 - c;\nlet t2 = t * t;\nreturn F0 + (F90 - F0) * (t2 * t2 * t);\n}\nfn nme_pbr_diffuseEON(albedo: v3, sigma: f32, NdotL: f32, NdotV: f32, LdotV: f32) -> v3 {\nreturn albedo * (1.0 / NME_PBR_PI);\n}\n${ccSchlickFn}${charlieFn}${anisoFns}${ssFns}fn nme_pbr_mr_compute(\n worldPos: v3, geometricNormal: v3, worldNormal: v3, cameraPos: v3,\n baseColor: v3, metallic: f32, roughness: f32, ao: f32,\n ccIntensityIn: f32, ccRoughnessIn: f32, ccIor: f32,\n ccBumpColor: v3, ccBumpUv: v2,\n ccTintColor: v3, ccTintAtDistance: f32, ccTintThickness: f32,\n shIntensityIn: f32, shColorIn: v3, shRoughnessIn: f32,\n baseIor: f32,\n refrIntensityIn: f32, refrIor: f32, refrTintAtDistance: f32,\n ssTintColor: v3, ssThickness: f32,\n ssTranslucencyIntensityIn: f32, ssDiffusionDist: v3,\n anisoIntensityIn: f32, anisoDirection: v2, anisoUv: v2,\n iridescenceIntensityIn: f32, iridescenceIorIn: f32, iridescenceThicknessIn: f32,\n shadowFactors: array<f32, ${MAX_LIGHTS}>\n) -> NmePbrMrResult {\n var r: NmePbrMrResult;\n let Ng = normalize(geometricNormal);\n let N = normalize(worldNormal);\n let V = normalize(cameraPos - worldPos);\n let NdotVUnclamped = dot(N, V);\n let NdotV = abs(NdotVUnclamped) + 0.0000001;\n let metallic_c = clamp(metallic, 0.0, 1.0);\n let rough_c = clamp(roughness, 0.0, 1.0);\n var alphaG = rough_c * rough_c + 0.0005;\n ${specularAABlock}\n let dielectricF0Raw = (baseIor - 1.0) / (baseIor + 1.0);\n let dielectricF0Scalar = dielectricF0Raw * dielectricF0Raw;\n let dielectricF0 = v3(dielectricF0Scalar);\n var surfaceAlbedo = baseColor * (1.0 - metallic_c) * (1.0 - dielectricF0Scalar);\n let colorF0Base = mix(dielectricF0, baseColor, metallic_c);\n let colorF0 = ${\n useIridescence\n ? `mix(colorF0Base, nme_pbr_evalIridescence(1.0, max(iridescenceIorIn, 1.0001), NdotV, max(iridescenceThicknessIn, 0.0), colorF0Base), clamp(iridescenceIntensityIn, 0.0, 1.0))`\n : `colorF0Base`\n };\n let colorF90 = v3(1.0);\n let ao_c = clamp(ao, 0.0, 1.0);\n let directRoughness = max(rough_c, AA_factor_x);\n let directAlphaG = directRoughness * directRoughness + 0.0005;\n ${anisoSetup}\n ${ccDecls}\n ${directSpecR0Decl}\n ${ccNormalSetup}\n ${ccAlphaSetup}\n ${shDecls}\n let translucencyIntensity = ${useSubsurface ? \"clamp(ssTranslucencyIntensityIn, 0.0, 1.0)\" : \"0.0\"};\n let ssTransmittance = ${useSubsurface ? \"nme_pbr_transmittanceBurley(ssTintColor, ssDiffusionDist, max(ssThickness, 0.0000001)) * translucencyIntensity\" : \"v3(0.0)\"};\n let directDiffuseTranslucencyScale = 1.0 - translucencyIntensity;\n ${\n useRefraction\n ? `// LEGACY_SPECULAR_ENERGY_CONSERVATION is on for BJS NME PBR-MR. When refraction\n let _refractionOpacityPre = 1.0 - clamp(refrIntensityIn, 0.0, 1.0);\n surfaceAlbedo = surfaceAlbedo * _refractionOpacityPre;`\n : ``\n }\n var diffuseAcc = v3(0.0);\n var diffuseTransmissionAcc = v3(0.0);\n var specAcc = v3(0.0);\n var aggShadow: f32 = 0.0;\n var nLights: f32 = 0.0;\n let lc = min(meshU.lc, ${MAX_LIGHTS}u);\n for (var i: u32 = 0u; i < lc; i = i + 1u) {\n let lightIndex = nli(i);\n let entry = nmeLights.lights[lightIndex];\n let t = u32(entry.vLightData.w);\n let sh = shadowFactors[lightIndex];\n if (t == 3u) {\n let Ldir = normalize(entry.vLightData.xyz);\n let nl = clamp(0.5 + 0.5 * dot(N, Ldir), 0.0000001, 1.0);\n let groundSky = mix(entry.vLightDirection.xyz, entry.vLightDiffuse.rgb, nl);\n var baseLayerAtten: f32 = 1.0;\n var baseLayerAbsorption = v3(1.0);${ccHemiBlock(useClearcoat, useCcTint)}\n let H_h = normalize(V + Ldir);\n let NdotH_h = clamp(dot(N, H_h), 0.0000001, 1.0);\n let VdotH_h = saturate(dot(V, H_h));\n let cF_h = nme_pbr_fresSchlick(VdotH_h, directSpecR0, colorF90);\n ${\n useAnisotropy\n ? `let TdotH_h = dot(anisoT, H_h);\n let BdotH_h = dot(anisoB, H_h);\n let TdotV_h = dot(anisoT, V);\n let BdotV_h = dot(anisoB, V);\n let TdotL_h = dot(anisoT, Ldir);\n let BdotL_h = dot(anisoB, Ldir);\n let D_h = nme_pbr_burleyAnisoD(NdotH_h, TdotH_h, BdotH_h, aniAlphaTB);\n let Vis_h = nme_pbr_visAnisoSmith(nl, NdotV, TdotV_h, BdotV_h, TdotL_h, BdotL_h, aniAlphaTB);\n specAcc = specAcc + cF_h * D_h * Vis_h * nl * entry.vLightDiffuse.rgb * sh * baseLayerAtten * baseLayerAbsorption;`\n : `let D_h = nme_pbr_distGGX(NdotH_h, directAlphaG);\n let G_h = nme_pbr_geomGGX(nl, NdotV, directAlphaG);\n specAcc = specAcc + cF_h * D_h * G_h * nl * entry.vLightDiffuse.rgb * sh * baseLayerAtten * baseLayerAbsorption;`\n }\n diffuseAcc = diffuseAcc + groundSky * surfaceAlbedo * sh * baseLayerAtten * baseLayerAbsorption;${shHemiBlock(useSheen)}\n aggShadow = aggShadow + sh;\n nLights = nLights + 1.0;\n continue;\n }\n var L: v3;\n var atten: f32 = 1.0;\n let color = entry.vLightDiffuse.rgb;\n if (t == 1u) {\n L = normalize(-entry.vLightData.xyz);\n } else {\n let toL = entry.vLightData.xyz - worldPos;\n let d2 = dot(toL, toL);\n let dist = sqrt(d2);\n L = toL / max(dist, 0.0001);\n let range = entry.vLightDiffuse.a;\n if (t == 2u) {\n let invD2 = 1.0 / max(d2, 0.0000001);\n let cosHalfAngle = entry.vLightDirection.w;\n let kappa = 6.64385618977 / max(1.0 - cosHalfAngle, 0.0001);\n let cd = dot(-entry.vLightDirection.xyz, L);\n let dirFall = exp2(kappa * (cd - 1.0));\n atten = invD2 * dirFall;\n } else {\n atten = 1.0 / max(d2, 0.0000001);\n }\n }\n let NdotLUnclamped = dot(N, L);\n let NdotL = clamp(NdotLUnclamped, 0.0000001, 1.0);\n var baseLayerAtten: f32 = 1.0;\n var baseLayerAbsorption = v3(1.0);${ccDirectBlock(useClearcoat, useCcTint)}\n let _LdotV = select(0.0, dot(L, V), t == 1u);\n let _eonDiffuse = nme_pbr_diffuseEON(surfaceAlbedo, 0.0, NdotL, NdotV, _LdotV);\n diffuseAcc = diffuseAcc + _eonDiffuse * directDiffuseTranslucencyScale * NdotL * color * atten * sh * baseLayerAtten * baseLayerAbsorption;\n if (NdotLUnclamped < 0.0 && translucencyIntensity > 0.0) {\n let _trNdotL = abs(NdotLUnclamped) + 0.0000001;\n let _wrapW = 0.02;\n let _wrapT = 1.0 + _wrapW;\n let _wrapNdotL = clamp((_trNdotL + _wrapW) / (_wrapT * _wrapT), 0.0, 1.0);\n let _clampedAlbT = clamp(surfaceAlbedo, v3(0.1), v3(1.0));\n let _eonTransmit = nme_pbr_diffuseEON(_clampedAlbT, 0.0, max(NdotL, 0.0000001), NdotV, _LdotV) / _clampedAlbT;\n diffuseTransmissionAcc = diffuseTransmissionAcc + _eonTransmit * (ssTransmittance * _wrapNdotL) * color * atten * sh * baseLayerAtten * baseLayerAbsorption;\n }\n if (NdotL > 0.0 && atten > 0.0) {\n let H = normalize(V + L);\n let NdotH = clamp(dot(N, H), 0.0000001, 1.0);\n let VdotH = saturate(dot(V, H));\n let cF = nme_pbr_fresSchlick(VdotH, directSpecR0, colorF90);\n ${\n useAnisotropy\n ? `let TdotH = dot(anisoT, H);\n let BdotH = dot(anisoB, H);\n let TdotV = dot(anisoT, V);\n let BdotV = dot(anisoB, V);\n let TdotL = dot(anisoT, L);\n let BdotL = dot(anisoB, L);\n let D = nme_pbr_burleyAnisoD(NdotH, TdotH, BdotH, aniAlphaTB);\n let Vis = nme_pbr_visAnisoSmith(NdotL, NdotV, TdotV, BdotV, TdotL, BdotL, aniAlphaTB);\n specAcc = specAcc + cF * D * Vis * NdotL * color * atten * sh * baseLayerAtten * baseLayerAbsorption;`\n : `let D = nme_pbr_distGGX(NdotH, directAlphaG);\n let G = nme_pbr_geomGGX(NdotL, NdotV, directAlphaG);\n specAcc = specAcc + cF * D * G * NdotL * color * atten * sh * baseLayerAtten * baseLayerAbsorption;`\n }\n }${shDirectBlock(useSheen)}\n aggShadow = aggShadow + sh;\n nLights = nLights + 1.0;\n }\n r.diffuseDir = diffuseAcc;\n r.specularDir = specAcc;\n${iblBlock}\n ${\n useEnv\n ? `let _radLum = clamp(dot(finalRadianceScaled * shAlbedoScaling${useClearcoat ? ` * ccConsIBL${ccTintScale}` : ``}, v3(0.2126, 0.7152, 0.0722)), 0.0, 1.0);\n let _specLum = clamp(dot(finalSpecularScaledDirect * shAlbedoScaling, v3(0.2126, 0.7152, 0.0722)), 0.0, 1.0);${\n useClearcoat\n ? `\n let _ccLum = clamp(dot(ccFinalRadiance, v3(0.2126, 0.7152, 0.0722)), 0.0, 1.0);\n r.lumOverAlpha = _radLum + _specLum + _ccLum;`\n : `\n r.lumOverAlpha = _radLum + _specLum;`\n }`\n : `let _specLum = clamp(dot(specAcc, v3(0.2126, 0.7152, 0.0722)), 0.0, 1.0);\n r.lumOverAlpha = _specLum;`\n }\n var colorOut = max(r.lighting, v3(0.0)) * sceneU.vImageInfos.x;\n if (sceneU.vImageInfos.w > 0.5) {\n colorOut = 1.0 - exp2(-1.590579 * colorOut);\n }\n colorOut = pow(max(colorOut, v3(0.0)), v3(0.45454545));\n colorOut = clamp(colorOut, v3(0.0), v3(1.0));\n let highContrast = colorOut * colorOut * (v3(3.0) - colorOut * 2.0);\n if (sceneU.vImageInfos.y < 1.0) {\n colorOut = mix(v3(0.5), colorOut, sceneU.vImageInfos.y);\n } else {\n colorOut = mix(colorOut, highContrast, sceneU.vImageInfos.y - 1.0);\n }\n r.lighting = max(colorOut, v3(0.0));\n if (nLights > 0.0) { r.shadow = aggShadow / nLights; } else { r.shadow = 1.0; }\n return r;\n}\n`;\n}\n"],"names":[],"mappings":"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"}
@@ -1,9 +1,6 @@
1
1
  const EQUIRECTANGULAR_MODE = 7;
2
2
  const RECIPROCAL_PI2 = "0.15915494309189535";
3
3
  const RECIPROCAL_PI = "0.3183098861837907";
4
- function sanitize(name) {
5
- return name.replace(/[^A-Za-z0-9_]/g, "_");
6
- }
7
4
  const OUTPUTS = {
8
5
  rgb: { swizzle: "", type: "vec3f" },
9
6
  r: { swizzle: ".x", type: "f32" },
@@ -18,7 +15,7 @@ const emitter = {
18
15
  if (mode !== EQUIRECTANGULAR_MODE) {
19
16
  throw new Error(`ReflectionTextureBlock: coordinatesMode ${mode} not supported (only EQUIRECTANGULAR_MODE=7)`);
20
17
  }
21
- const bindingName = sanitize(block.name || `reflection${block.id}`);
18
+ const bindingName = ctx.sanitize(block.name || `reflection${block.id}`);
22
19
  if (!state.textures.find((t) => t.name === bindingName)) {
23
20
  state.textures.push({ name: bindingName, kind: "texture2d", texture: null });
24
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"reflection-texture-block.js","sources":["../../../../../src/material/node/blocks/reflection-texture-block.ts"],"sourcesContent":["/** ReflectionTextureBlock — environment reflection sampling.\n *\n * Inputs: `position` (local-space), `worldPosition`, `worldNormal`, `world`\n * (mat4), `cameraPosition`, `view` (mat4).\n * Outputs: `rgb` (vec3), `r`/`g`/`b`/`a` (f32), `reflectionCoords` (vec3).\n *\n * Current support: coordinatesMode = EQUIRECTANGULAR_MODE (7) with a 2D input\n * texture. Other modes (CUBIC, SPHERICAL, PLANAR, PROJECTION, SKYBOX,\n * EQUIRECTANGULAR_FIXED) throw at parse-time so the failure is loud.\n *\n * The embedded texture data (base64 PNG in the snippet) is decoded by the\n * scene side and supplied via `parseNodeMaterialFromSnippet(..., { textures })`\n * using the block's sanitized name as the key — same pattern as TextureBlock.\n *\n * Gamma handling: when `gammaSpace: true` (typical for PNG environments stored\n * in sRGB), the sampled colour is linearized via `pow(rgb, 2.2)` before being\n * exposed on the `rgb`/`r`/`g`/`b` outputs.\n */\n\nimport type { BlockEmitter, NodeExpr } from \"../node-types.js\";\n\nconst EQUIRECTANGULAR_MODE = 7;\n\nconst RECIPROCAL_PI2 = \"0.15915494309189535\";\nconst RECIPROCAL_PI = \"0.3183098861837907\";\n\nfunction sanitize(name: string): string {\n return name.replace(/[^A-Za-z0-9_]/g, \"_\");\n}\n\nconst OUTPUTS: Record<string, { swizzle: string; type: \"vec3f\" | \"f32\" }> = {\n rgb: { swizzle: \"\", type: \"vec3f\" },\n r: { swizzle: \".x\", type: \"f32\" },\n g: { swizzle: \".y\", type: \"f32\" },\n b: { swizzle: \".z\", type: \"f32\" },\n};\n\nexport const emitter: BlockEmitter = {\n className: \"ReflectionTextureBlock\",\n stage: \"fragment\",\n emit(block, outputName, stage, state, ctx) {\n const mode = (block.serialized[\"coordinatesMode\"] as number | undefined) ?? EQUIRECTANGULAR_MODE;\n if (mode !== EQUIRECTANGULAR_MODE) {\n throw new Error(`ReflectionTextureBlock: coordinatesMode ${mode} not supported (only EQUIRECTANGULAR_MODE=7)`);\n }\n\n const bindingName = sanitize(block.name || `reflection${block.id}`);\n if (!state.textures.find((t) => t.name === bindingName)) {\n state.textures.push({ name: bindingName, kind: \"texture2d\", texture: null });\n }\n\n const memoKey = `_refl_${block.id}_rgb`;\n let sample = state.fragment.memo.get(memoKey);\n if (!sample) {\n const wp = block.inputs.get(\"worldPosition\")?.source ? ctx.cast(ctx.resolve(block, \"worldPosition\", stage, state), \"vec3f\").expr : `vec3<f32>(0.0)`;\n const wn = block.inputs.get(\"worldNormal\")?.source ? ctx.cast(ctx.resolve(block, \"worldNormal\", stage, state), \"vec3f\").expr : `vec3<f32>(0.0, 1.0, 0.0)`;\n const cp = block.inputs.get(\"cameraPosition\")?.source ? ctx.cast(ctx.resolve(block, \"cameraPosition\", stage, state), \"vec3f\").expr : `_NME_CAMERA_POS_`;\n\n const t = ctx.temp(state, \"refl\");\n const body: string[] = [\n `let _v${t} = normalize(${cp} - ${wp});`,\n `let _r${t} = reflect(-_v${t}, normalize(${wn}));`,\n // BJS flips the V coordinate after computing equirectangular UVs.\n `let _uv${t} = vec2<f32>(atan2(_r${t}.z, _r${t}.x) * ${RECIPROCAL_PI2} + 0.5, 1.0 - acos(clamp(_r${t}.y, -1.0, 1.0)) * ${RECIPROCAL_PI});`,\n `let _s${t} = textureSample(nodeTex_${bindingName}, nodeSamp_${bindingName}, _uv${t});`,\n ];\n // BJS's NME ReflectionTextureBlock does NOT apply gamma conversion\n // in the shader — it samples and uses raw values regardless of gammaSpace.\n // The NME expression graph operates in gamma space (textures are non-sRGB),\n // so the reflection must stay in gamma space too.\n state.fragment.body.push(body.join(\"\\n\"));\n sample = { expr: `_s${t}.xyz`, type: \"vec3f\" };\n state.fragment.memo.set(memoKey, sample);\n }\n\n if (outputName === \"a\") {\n return { expr: \"1.0\", type: \"f32\" };\n }\n if (outputName === \"reflectionCoords\") {\n // Seldom used by graphs; return the reflection vector as a placeholder.\n return { expr: sample.expr, type: \"vec3f\" };\n }\n const out = OUTPUTS[outputName] ?? OUTPUTS.rgb!;\n if (out.swizzle === \"\") {\n return sample as NodeExpr;\n }\n return { expr: `${sample.expr}${out.swizzle}`, type: out.type };\n },\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reflection-texture-block.js","sources":["../../../../../src/material/node/blocks/reflection-texture-block.ts"],"sourcesContent":["/** ReflectionTextureBlock — environment reflection sampling.\n *\n * Inputs: `position` (local-space), `worldPosition`, `worldNormal`, `world`\n * (mat4), `cameraPosition`, `view` (mat4).\n * Outputs: `rgb` (vec3), `r`/`g`/`b`/`a` (f32), `reflectionCoords` (vec3).\n *\n * Current support: coordinatesMode = EQUIRECTANGULAR_MODE (7) with a 2D input\n * texture. Other modes (CUBIC, SPHERICAL, PLANAR, PROJECTION, SKYBOX,\n * EQUIRECTANGULAR_FIXED) throw at parse-time so the failure is loud.\n *\n * The embedded texture data (base64 PNG in the snippet) is decoded by the\n * scene side and supplied via `parseNodeMaterialFromSnippet(..., { textures })`\n * using the block's sanitized name as the key — same pattern as TextureBlock.\n *\n * Gamma handling: when `gammaSpace: true` (typical for PNG environments stored\n * in sRGB), the sampled colour is linearized via `pow(rgb, 2.2)` before being\n * exposed on the `rgb`/`r`/`g`/`b` outputs.\n */\n\nimport type { BlockEmitter, NodeExpr } from \"../node-types.js\";\n\nconst EQUIRECTANGULAR_MODE = 7;\n\nconst RECIPROCAL_PI2 = \"0.15915494309189535\";\nconst RECIPROCAL_PI = \"0.3183098861837907\";\n\nconst OUTPUTS: Record<string, { swizzle: string; type: \"vec3f\" | \"f32\" }> = {\n rgb: { swizzle: \"\", type: \"vec3f\" },\n r: { swizzle: \".x\", type: \"f32\" },\n g: { swizzle: \".y\", type: \"f32\" },\n b: { swizzle: \".z\", type: \"f32\" },\n};\n\nexport const emitter: BlockEmitter = {\n className: \"ReflectionTextureBlock\",\n stage: \"fragment\",\n emit(block, outputName, stage, state, ctx) {\n const mode = (block.serialized[\"coordinatesMode\"] as number | undefined) ?? EQUIRECTANGULAR_MODE;\n if (mode !== EQUIRECTANGULAR_MODE) {\n throw new Error(`ReflectionTextureBlock: coordinatesMode ${mode} not supported (only EQUIRECTANGULAR_MODE=7)`);\n }\n\n const bindingName = ctx.sanitize(block.name || `reflection${block.id}`);\n if (!state.textures.find((t) => t.name === bindingName)) {\n state.textures.push({ name: bindingName, kind: \"texture2d\", texture: null });\n }\n\n const memoKey = `_refl_${block.id}_rgb`;\n let sample = state.fragment.memo.get(memoKey);\n if (!sample) {\n const wp = block.inputs.get(\"worldPosition\")?.source ? ctx.cast(ctx.resolve(block, \"worldPosition\", stage, state), \"vec3f\").expr : `vec3<f32>(0.0)`;\n const wn = block.inputs.get(\"worldNormal\")?.source ? ctx.cast(ctx.resolve(block, \"worldNormal\", stage, state), \"vec3f\").expr : `vec3<f32>(0.0, 1.0, 0.0)`;\n const cp = block.inputs.get(\"cameraPosition\")?.source ? ctx.cast(ctx.resolve(block, \"cameraPosition\", stage, state), \"vec3f\").expr : `_NME_CAMERA_POS_`;\n\n const t = ctx.temp(state, \"refl\");\n const body: string[] = [\n `let _v${t} = normalize(${cp} - ${wp});`,\n `let _r${t} = reflect(-_v${t}, normalize(${wn}));`,\n // BJS flips the V coordinate after computing equirectangular UVs.\n `let _uv${t} = vec2<f32>(atan2(_r${t}.z, _r${t}.x) * ${RECIPROCAL_PI2} + 0.5, 1.0 - acos(clamp(_r${t}.y, -1.0, 1.0)) * ${RECIPROCAL_PI});`,\n `let _s${t} = textureSample(nodeTex_${bindingName}, nodeSamp_${bindingName}, _uv${t});`,\n ];\n // BJS's NME ReflectionTextureBlock does NOT apply gamma conversion\n // in the shader — it samples and uses raw values regardless of gammaSpace.\n // The NME expression graph operates in gamma space (textures are non-sRGB),\n // so the reflection must stay in gamma space too.\n state.fragment.body.push(body.join(\"\\n\"));\n sample = { expr: `_s${t}.xyz`, type: \"vec3f\" };\n state.fragment.memo.set(memoKey, sample);\n }\n\n if (outputName === \"a\") {\n return { expr: \"1.0\", type: \"f32\" };\n }\n if (outputName === \"reflectionCoords\") {\n // Seldom used by graphs; return the reflection vector as a placeholder.\n return { expr: sample.expr, type: \"vec3f\" };\n }\n const out = OUTPUTS[outputName] ?? OUTPUTS.rgb!;\n if (out.swizzle === \"\") {\n return sample as NodeExpr;\n }\n return { expr: `${sample.expr}${out.swizzle}`, type: out.type };\n },\n};\n"],"names":[],"mappings":"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"}
@@ -22,9 +22,6 @@ function applyColorSpace(expr, outputName, convertToLinear, convertToGamma) {
22
22
  }
23
23
  return expr;
24
24
  }
25
- function sanitize(name) {
26
- return name.replace(/[^A-Za-z0-9_]/g, "_");
27
- }
28
25
  const emitter = {
29
26
  className: "TextureBlock",
30
27
  emit(block, outputName, stage, state, ctx) {
@@ -32,9 +29,9 @@ const emitter = {
32
29
  const source = block.inputs.get("source");
33
30
  if (source?.source) {
34
31
  const producer = ctx.graph.blocks.get(source.source.blockId);
35
- bindingName = sanitize(producer?.name || `tex${block.id}`);
32
+ bindingName = ctx.sanitize(producer?.name || `tex${block.id}`);
36
33
  } else {
37
- bindingName = sanitize(block.name || `tex${block.id}`);
34
+ bindingName = ctx.sanitize(block.name || `tex${block.id}`);
38
35
  }
39
36
  if (!state.textures.find((t) => t.name === bindingName)) {
40
37
  state.textures.push({ name: bindingName, kind: "texture2d", texture: null });
@@ -1 +1 @@
1
- {"version":3,"file":"texture-block.js","sources":["../../../../../src/material/node/blocks/texture-block.ts"],"sourcesContent":["/** TextureBlock — samples a 2D texture.\n *\n * Inputs:\n * - `uv`: vec2 texture coordinates.\n * - `source` (optional): ImageSourceBlock.output that names the binding. When\n * absent, this block owns its own binding named after itself.\n * Outputs: `rgba`, `rgb`, `r`, `g`, `b`, `a`, `level`.\n */\n\nimport type { BlockEmitter, NodeExpr, NodeValueType } from \"../node-types.js\";\n\nconst OUTPUT: Record<string, { swizzle: string; type: NodeValueType }> = {\n rgba: { swizzle: \"\", type: \"vec4f\" },\n rgb: { swizzle: \".xyz\", type: \"vec3f\" },\n r: { swizzle: \".x\", type: \"f32\" },\n g: { swizzle: \".y\", type: \"f32\" },\n b: { swizzle: \".z\", type: \"f32\" },\n a: { swizzle: \".w\", type: \"f32\" },\n};\n\nfunction applyColorSpace(expr: string, outputName: string, convertToLinear: boolean, convertToGamma: boolean): string {\n if (!convertToLinear && !convertToGamma) {\n return expr;\n }\n const power = convertToLinear ? \"2.2\" : \"0.45454545\";\n if (outputName === \"rgba\") {\n return `vec4<f32>(pow(max(${expr}.xyz, vec3<f32>(0.0)), vec3<f32>(${power})), ${expr}.w)`;\n }\n if (outputName === \"rgb\") {\n return `pow(max(${expr}.xyz, vec3<f32>(0.0)), vec3<f32>(${power}))`;\n }\n if (outputName === \"r\" || outputName === \"g\" || outputName === \"b\") {\n return `pow(max(${expr}${OUTPUT[outputName]!.swizzle}, 0.0), ${power})`;\n }\n return expr;\n}\n\nfunction sanitize(name: string): string {\n return name.replace(/[^A-Za-z0-9_]/g, \"_\");\n}\n\nexport const emitter: BlockEmitter = {\n className: \"TextureBlock\",\n emit(block, outputName, stage, state, ctx) {\n // Resolve source binding: if `source` input is connected, use that producer's name;\n // otherwise name the binding after this block.\n let bindingName: string;\n const source = block.inputs.get(\"source\");\n if (source?.source) {\n const producer = ctx.graph.blocks.get(source.source.blockId);\n bindingName = sanitize(producer?.name || `tex${block.id}`);\n } else {\n bindingName = sanitize(block.name || `tex${block.id}`);\n }\n\n // Dedup binding.\n if (!state.textures.find((t) => t.name === bindingName)) {\n state.textures.push({ name: bindingName, kind: \"texture2d\", texture: null });\n }\n\n // Resolve UV.\n const uvInput = block.inputs.get(\"uv\");\n let uv: NodeExpr;\n if (uvInput?.source) {\n uv = ctx.cast(ctx.resolve(block, \"uv\", stage, state), \"vec2f\");\n } else {\n // Fallback: a zero UV so shader still compiles (matches BJS behaviour when unhooked).\n uv = { expr: \"vec2<f32>(0.0, 0.0)\", type: \"vec2f\" };\n }\n\n // Memoize the full sample per-stage so rgba/rgb/r/... share one textureSample call.\n const memoKey = `_tex_${block.id}_sample`;\n const stageState = stage === \"vertex\" ? state.vertex : state.fragment;\n let sampleExpr = stageState.memo.get(memoKey);\n if (!sampleExpr) {\n const sampleVar = `_s${ctx.temp(state, \"tex\")}`;\n stageState.body.push(`let ${sampleVar} = textureSample(nodeTex_${bindingName}, nodeSamp_${bindingName}, ${uv.expr});`);\n sampleExpr = { expr: sampleVar, type: \"vec4f\" };\n stageState.memo.set(memoKey, sampleExpr);\n }\n\n // Special case: `level` output returns a pseudo-f32 (0.0 for now — proper LOD calc TBD).\n if (outputName === \"level\") {\n return { expr: \"0.0\", type: \"f32\" };\n }\n\n const out = OUTPUT[outputName] ?? OUTPUT.rgba!;\n const serialized = block.serialized as { convertToLinearSpace?: boolean; convertToGammaSpace?: boolean };\n const expr = applyColorSpace(sampleExpr.expr, outputName, serialized.convertToLinearSpace === true, serialized.convertToGammaSpace === true);\n return { expr: expr === sampleExpr.expr ? `${sampleExpr.expr}${out.swizzle}` : expr, type: out.type };\n },\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"texture-block.js","sources":["../../../../../src/material/node/blocks/texture-block.ts"],"sourcesContent":["/** TextureBlock — samples a 2D texture.\n *\n * Inputs:\n * - `uv`: vec2 texture coordinates.\n * - `source` (optional): ImageSourceBlock.output that names the binding. When\n * absent, this block owns its own binding named after itself.\n * Outputs: `rgba`, `rgb`, `r`, `g`, `b`, `a`, `level`.\n */\n\nimport type { BlockEmitter, NodeExpr, NodeValueType } from \"../node-types.js\";\n\nconst OUTPUT: Record<string, { swizzle: string; type: NodeValueType }> = {\n rgba: { swizzle: \"\", type: \"vec4f\" },\n rgb: { swizzle: \".xyz\", type: \"vec3f\" },\n r: { swizzle: \".x\", type: \"f32\" },\n g: { swizzle: \".y\", type: \"f32\" },\n b: { swizzle: \".z\", type: \"f32\" },\n a: { swizzle: \".w\", type: \"f32\" },\n};\n\nfunction applyColorSpace(expr: string, outputName: string, convertToLinear: boolean, convertToGamma: boolean): string {\n if (!convertToLinear && !convertToGamma) {\n return expr;\n }\n const power = convertToLinear ? \"2.2\" : \"0.45454545\";\n if (outputName === \"rgba\") {\n return `vec4<f32>(pow(max(${expr}.xyz, vec3<f32>(0.0)), vec3<f32>(${power})), ${expr}.w)`;\n }\n if (outputName === \"rgb\") {\n return `pow(max(${expr}.xyz, vec3<f32>(0.0)), vec3<f32>(${power}))`;\n }\n if (outputName === \"r\" || outputName === \"g\" || outputName === \"b\") {\n return `pow(max(${expr}${OUTPUT[outputName]!.swizzle}, 0.0), ${power})`;\n }\n return expr;\n}\n\nexport const emitter: BlockEmitter = {\n className: \"TextureBlock\",\n emit(block, outputName, stage, state, ctx) {\n // Resolve source binding: if `source` input is connected, use that producer's name;\n // otherwise name the binding after this block.\n let bindingName: string;\n const source = block.inputs.get(\"source\");\n if (source?.source) {\n const producer = ctx.graph.blocks.get(source.source.blockId);\n bindingName = ctx.sanitize(producer?.name || `tex${block.id}`);\n } else {\n bindingName = ctx.sanitize(block.name || `tex${block.id}`);\n }\n\n // Dedup binding.\n if (!state.textures.find((t) => t.name === bindingName)) {\n state.textures.push({ name: bindingName, kind: \"texture2d\", texture: null });\n }\n\n // Resolve UV.\n const uvInput = block.inputs.get(\"uv\");\n let uv: NodeExpr;\n if (uvInput?.source) {\n uv = ctx.cast(ctx.resolve(block, \"uv\", stage, state), \"vec2f\");\n } else {\n // Fallback: a zero UV so shader still compiles (matches BJS behaviour when unhooked).\n uv = { expr: \"vec2<f32>(0.0, 0.0)\", type: \"vec2f\" };\n }\n\n // Memoize the full sample per-stage so rgba/rgb/r/... share one textureSample call.\n const memoKey = `_tex_${block.id}_sample`;\n const stageState = stage === \"vertex\" ? state.vertex : state.fragment;\n let sampleExpr = stageState.memo.get(memoKey);\n if (!sampleExpr) {\n const sampleVar = `_s${ctx.temp(state, \"tex\")}`;\n stageState.body.push(`let ${sampleVar} = textureSample(nodeTex_${bindingName}, nodeSamp_${bindingName}, ${uv.expr});`);\n sampleExpr = { expr: sampleVar, type: \"vec4f\" };\n stageState.memo.set(memoKey, sampleExpr);\n }\n\n // Special case: `level` output returns a pseudo-f32 (0.0 for now — proper LOD calc TBD).\n if (outputName === \"level\") {\n return { expr: \"0.0\", type: \"f32\" };\n }\n\n const out = OUTPUT[outputName] ?? OUTPUT.rgba!;\n const serialized = block.serialized as { convertToLinearSpace?: boolean; convertToGammaSpace?: boolean };\n const expr = applyColorSpace(sampleExpr.expr, outputName, serialized.convertToLinearSpace === true, serialized.convertToGammaSpace === true);\n return { expr: expr === sampleExpr.expr ? `${sampleExpr.expr}${out.swizzle}` : expr, type: out.type };\n },\n};\n"],"names":[],"mappings":"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"}
@@ -6,9 +6,6 @@ const OUTPUT = {
6
6
  b: { swizzle: ".z", type: "f32" },
7
7
  a: { swizzle: ".w", type: "f32" }
8
8
  };
9
- function sanitize(name) {
10
- return name.replace(/[^A-Za-z0-9_]/g, "_");
11
- }
12
9
  function formatFloat(value) {
13
10
  if (Number.isInteger(value)) {
14
11
  return `${value}.0`;
@@ -36,9 +33,9 @@ function bindingName(block, inputName, ctx, fallback) {
36
33
  const input = block.inputs.get(inputName);
37
34
  if (input?.source) {
38
35
  const producer = ctx.graph.blocks.get(input.source.blockId);
39
- return sanitize(producer?.name || fallback);
36
+ return ctx.sanitize(producer?.name || fallback);
40
37
  }
41
- return sanitize(fallback);
38
+ return ctx.sanitize(fallback);
42
39
  }
43
40
  function ensureBinding(state, name) {
44
41
  if (!state.textures.find((t) => t.name === name)) {
@@ -71,7 +68,7 @@ function emitTriPlanarSample(block, stage, state, ctx) {
71
68
  if (memo) {
72
69
  return memo;
73
70
  }
74
- const baseName = sanitize(block.name || `triPlanar${block.id}`);
71
+ const baseName = ctx.sanitize(block.name || `triPlanar${block.id}`);
75
72
  const texX = bindingName(block, "source", ctx, baseName);
76
73
  const texY = bindingName(block, "sourceY", ctx, texX);
77
74
  const texZ = bindingName(block, "sourceZ", ctx, texX);
@@ -1 +1 @@
1
- {"version":3,"file":"triplanar-block.js","sources":["../../../../../src/material/node/blocks/triplanar-block.ts"],"sourcesContent":["/** TriPlanarBlock — texture projection from position/normal.\n *\n * Implements the Babylon.js WGSL math for the common texture-source path:\n * uvx = position.yz, uvy = position.zx, uvz = position.xy\n * optional cube-facing flips\n * sample X/Y/Z projections\n * blend by pow(abs(normal), sharpness)\n *\n * Texture transform/level defaults are identity/1.0 unless serialized on the\n * block's embedded texture. Runtime ImageSource texture transforms are not part\n * of Lite's NME binding ABI today, so Scene 81 uses default transforms.\n */\n\nimport type { BlockEmitter, NodeBlock, NodeBuildState, NodeEmitContext, NodeExpr, NodeValueType, Stage } from \"../node-types.js\";\n\nconst OUTPUT: Record<string, { swizzle: string; type: NodeValueType }> = {\n rgba: { swizzle: \"\", type: \"vec4f\" },\n rgb: { swizzle: \".xyz\", type: \"vec3f\" },\n r: { swizzle: \".x\", type: \"f32\" },\n g: { swizzle: \".y\", type: \"f32\" },\n b: { swizzle: \".z\", type: \"f32\" },\n a: { swizzle: \".w\", type: \"f32\" },\n};\n\ninterface TextureTransform {\n readonly level: number;\n readonly uAng: number;\n readonly vAng: number;\n readonly wAng: number;\n readonly uOffset: number;\n readonly vOffset: number;\n readonly uScale: number;\n readonly vScale: number;\n}\n\nfunction sanitize(name: string): string {\n return name.replace(/[^A-Za-z0-9_]/g, \"_\");\n}\n\nfunction formatFloat(value: number): string {\n if (Number.isInteger(value)) {\n return `${value}.0`;\n }\n return `${value}`;\n}\n\nfunction textureTransform(block: NodeBlock): TextureTransform {\n const tex = block.serialized[\"texture\"] as Record<string, unknown> | null | undefined;\n const num = (name: string, fallback: number): number => {\n const value = tex?.[name];\n return typeof value === \"number\" ? value : fallback;\n };\n return {\n level: num(\"level\", 1),\n uAng: num(\"uAng\", 0),\n vAng: num(\"vAng\", 0),\n wAng: num(\"wAng\", 0),\n uOffset: num(\"uOffset\", 0),\n vOffset: num(\"vOffset\", 0),\n uScale: num(\"uScale\", 1),\n vScale: num(\"vScale\", 1),\n };\n}\n\nfunction bindingName(block: NodeBlock, inputName: string, ctx: NodeEmitContext, fallback: string): string {\n const input = block.inputs.get(inputName);\n if (input?.source) {\n const producer = ctx.graph.blocks.get(input.source.blockId);\n return sanitize(producer?.name || fallback);\n }\n return sanitize(fallback);\n}\n\nfunction ensureBinding(state: NodeBuildState, name: string): void {\n if (!state.textures.find((t) => t.name === name)) {\n state.textures.push({ name, kind: \"texture2d\", texture: null });\n }\n}\n\nfunction applyColorSpace(expr: string, outputName: string, convertToLinear: boolean, convertToGamma: boolean): string {\n if (!convertToLinear && !convertToGamma) {\n return expr;\n }\n const power = convertToLinear ? \"2.2\" : \"0.45454545\";\n if (outputName === \"rgba\") {\n return `vec4<f32>(pow(max(${expr}.xyz, vec3<f32>(0.0)), vec3<f32>(${power})), ${expr}.w)`;\n }\n if (outputName === \"rgb\") {\n return `pow(max(${expr}.xyz, vec3<f32>(0.0)), vec3<f32>(${power}))`;\n }\n if (outputName === \"r\" || outputName === \"g\" || outputName === \"b\") {\n return `pow(max(${expr}${OUTPUT[outputName]!.swizzle}, 0.0), ${power})`;\n }\n return expr;\n}\n\nfunction emitTriPlanarSample(block: NodeBlock, stage: Stage, state: NodeBuildState, ctx: NodeEmitContext): NodeExpr {\n if (stage !== \"fragment\") {\n throw new Error(\"TriPlanarBlock: texture projection is supported only in the fragment stage\");\n }\n\n const stageState = state.fragment;\n const memoKey = `_triplanar_${block.id}_sample`;\n const memo = stageState.memo.get(memoKey);\n if (memo) {\n return memo;\n }\n\n const baseName = sanitize(block.name || `triPlanar${block.id}`);\n const texX = bindingName(block, \"source\", ctx, baseName);\n const texY = bindingName(block, \"sourceY\", ctx, texX);\n const texZ = bindingName(block, \"sourceZ\", ctx, texX);\n ensureBinding(state, texX);\n ensureBinding(state, texY);\n ensureBinding(state, texZ);\n\n const position = ctx.cast(ctx.resolve(block, \"position\", stage, state), \"vec3f\");\n const normal = ctx.cast(ctx.resolve(block, \"normal\", stage, state), \"vec3f\");\n const sharpnessInput = block.inputs.get(\"sharpness\")?.source ? ctx.cast(ctx.resolve(block, \"sharpness\", stage, state), \"f32\").expr : \"1.0\";\n const transform = textureTransform(block);\n\n const temp = ctx.temp(state, \"tri\");\n const n = `_n${temp}`;\n const uvx = `_uvx${temp}`;\n const uvy = `_uvy${temp}`;\n const uvz = `_uvz${temp}`;\n const x = `_x${temp}`;\n const y = `_y${temp}`;\n const z = `_z${temp}`;\n const w = `_w${temp}`;\n const sample = `_sample${temp}`;\n\n stageState.body.push(`let ${n} = ${normal.expr};`);\n stageState.body.push(`var ${uvx} = (${position.expr}).yz;`);\n stageState.body.push(`var ${uvy} = (${position.expr}).zx;`);\n stageState.body.push(`var ${uvz} = (${position.expr}).xy;`);\n if (block.serialized[\"projectAsCube\"] === true) {\n stageState.body.push(`${uvx} = (${uvx}).yx;`);\n stageState.body.push(`if (${n}.x >= 0.0) { ${uvx}.x = -${uvx}.x; }`);\n stageState.body.push(`if (${n}.y < 0.0) { ${uvy}.y = -${uvy}.y; }`);\n stageState.body.push(`if (${n}.z < 0.0) { ${uvz}.x = -${uvz}.x; }`);\n }\n stageState.body.push(`let _cU${temp} = cos(${formatFloat(transform.uAng)});`);\n stageState.body.push(`let _sU${temp} = sin(${formatFloat(transform.uAng)});`);\n stageState.body.push(`${uvx} = mat2x2<f32>(_cU${temp}, -_sU${temp}, _sU${temp}, _cU${temp}) * ${uvx};`);\n stageState.body.push(`let _cV${temp} = cos(${formatFloat(transform.vAng)});`);\n stageState.body.push(`let _sV${temp} = sin(${formatFloat(transform.vAng)});`);\n stageState.body.push(`${uvy} = mat2x2<f32>(_cV${temp}, _sV${temp}, -_sV${temp}, _cV${temp}) * ${uvy};`);\n stageState.body.push(`let _cW${temp} = cos(${formatFloat(transform.wAng)});`);\n stageState.body.push(`let _sW${temp} = sin(${formatFloat(transform.wAng)});`);\n stageState.body.push(`${uvz} = mat2x2<f32>(_cW${temp}, -_sW${temp}, _sW${temp}, _cW${temp}) * ${uvz};`);\n stageState.body.push(`let _scale${temp} = vec2<f32>(${formatFloat(transform.uScale)}, ${formatFloat(transform.vScale)});`);\n stageState.body.push(`let _offset${temp} = vec2<f32>(${formatFloat(transform.uOffset)}, ${formatFloat(transform.vOffset)});`);\n stageState.body.push(`${uvx} = ${uvx} * _scale${temp} + _offset${temp};`);\n stageState.body.push(`${uvy} = ${uvy} * _scale${temp} + _offset${temp};`);\n stageState.body.push(`${uvz} = ${uvz} * _scale${temp} + _offset${temp};`);\n stageState.body.push(`let ${x} = textureSample(nodeTex_${texX}, nodeSamp_${texX}, ${uvx});`);\n stageState.body.push(`let ${y} = textureSample(nodeTex_${texY}, nodeSamp_${texY}, ${uvy});`);\n stageState.body.push(`let ${z} = textureSample(nodeTex_${texZ}, nodeSamp_${texZ}, ${uvz});`);\n stageState.body.push(`let ${w} = pow(abs(${n}), vec3<f32>(${sharpnessInput}));`);\n stageState.body.push(\n `let ${sample} = ((${x} * ${w}.x + ${y} * ${w}.y + ${z} * ${w}.z) / (${w}.x + ${w}.y + ${w}.z)) * ${formatFloat(block.serialized[\"disableLevelMultiplication\"] === true ? 1 : transform.level)};`\n );\n\n const result = { expr: sample, type: \"vec4f\" } as const;\n stageState.memo.set(memoKey, result);\n return result;\n}\n\nexport const emitter: BlockEmitter = {\n className: \"TriPlanarBlock\",\n emit(block, outputName, stage, state, ctx) {\n if (outputName === \"level\") {\n const transform = textureTransform(block);\n return { expr: formatFloat(transform.level), type: \"f32\" };\n }\n const sample = emitTriPlanarSample(block, stage, state, ctx);\n const out = OUTPUT[outputName] ?? OUTPUT.rgba!;\n const serialized = block.serialized as { convertToLinearSpace?: boolean; convertToGammaSpace?: boolean };\n const converted = applyColorSpace(sample.expr, outputName, serialized.convertToLinearSpace === true, serialized.convertToGammaSpace === true);\n return { expr: converted === sample.expr ? `${sample.expr}${out.swizzle}` : converted, type: out.type };\n },\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"triplanar-block.js","sources":["../../../../../src/material/node/blocks/triplanar-block.ts"],"sourcesContent":["/** TriPlanarBlock — texture projection from position/normal.\n *\n * Implements the Babylon.js WGSL math for the common texture-source path:\n * uvx = position.yz, uvy = position.zx, uvz = position.xy\n * optional cube-facing flips\n * sample X/Y/Z projections\n * blend by pow(abs(normal), sharpness)\n *\n * Texture transform/level defaults are identity/1.0 unless serialized on the\n * block's embedded texture. Runtime ImageSource texture transforms are not part\n * of Lite's NME binding ABI today, so Scene 81 uses default transforms.\n */\n\nimport type { BlockEmitter, NodeBlock, NodeBuildState, NodeEmitContext, NodeExpr, NodeValueType, Stage } from \"../node-types.js\";\n\nconst OUTPUT: Record<string, { swizzle: string; type: NodeValueType }> = {\n rgba: { swizzle: \"\", type: \"vec4f\" },\n rgb: { swizzle: \".xyz\", type: \"vec3f\" },\n r: { swizzle: \".x\", type: \"f32\" },\n g: { swizzle: \".y\", type: \"f32\" },\n b: { swizzle: \".z\", type: \"f32\" },\n a: { swizzle: \".w\", type: \"f32\" },\n};\n\ninterface TextureTransform {\n readonly level: number;\n readonly uAng: number;\n readonly vAng: number;\n readonly wAng: number;\n readonly uOffset: number;\n readonly vOffset: number;\n readonly uScale: number;\n readonly vScale: number;\n}\n\nfunction formatFloat(value: number): string {\n if (Number.isInteger(value)) {\n return `${value}.0`;\n }\n return `${value}`;\n}\n\nfunction textureTransform(block: NodeBlock): TextureTransform {\n const tex = block.serialized[\"texture\"] as Record<string, unknown> | null | undefined;\n const num = (name: string, fallback: number): number => {\n const value = tex?.[name];\n return typeof value === \"number\" ? value : fallback;\n };\n return {\n level: num(\"level\", 1),\n uAng: num(\"uAng\", 0),\n vAng: num(\"vAng\", 0),\n wAng: num(\"wAng\", 0),\n uOffset: num(\"uOffset\", 0),\n vOffset: num(\"vOffset\", 0),\n uScale: num(\"uScale\", 1),\n vScale: num(\"vScale\", 1),\n };\n}\n\nfunction bindingName(block: NodeBlock, inputName: string, ctx: NodeEmitContext, fallback: string): string {\n const input = block.inputs.get(inputName);\n if (input?.source) {\n const producer = ctx.graph.blocks.get(input.source.blockId);\n return ctx.sanitize(producer?.name || fallback);\n }\n return ctx.sanitize(fallback);\n}\n\nfunction ensureBinding(state: NodeBuildState, name: string): void {\n if (!state.textures.find((t) => t.name === name)) {\n state.textures.push({ name, kind: \"texture2d\", texture: null });\n }\n}\n\nfunction applyColorSpace(expr: string, outputName: string, convertToLinear: boolean, convertToGamma: boolean): string {\n if (!convertToLinear && !convertToGamma) {\n return expr;\n }\n const power = convertToLinear ? \"2.2\" : \"0.45454545\";\n if (outputName === \"rgba\") {\n return `vec4<f32>(pow(max(${expr}.xyz, vec3<f32>(0.0)), vec3<f32>(${power})), ${expr}.w)`;\n }\n if (outputName === \"rgb\") {\n return `pow(max(${expr}.xyz, vec3<f32>(0.0)), vec3<f32>(${power}))`;\n }\n if (outputName === \"r\" || outputName === \"g\" || outputName === \"b\") {\n return `pow(max(${expr}${OUTPUT[outputName]!.swizzle}, 0.0), ${power})`;\n }\n return expr;\n}\n\nfunction emitTriPlanarSample(block: NodeBlock, stage: Stage, state: NodeBuildState, ctx: NodeEmitContext): NodeExpr {\n if (stage !== \"fragment\") {\n throw new Error(\"TriPlanarBlock: texture projection is supported only in the fragment stage\");\n }\n\n const stageState = state.fragment;\n const memoKey = `_triplanar_${block.id}_sample`;\n const memo = stageState.memo.get(memoKey);\n if (memo) {\n return memo;\n }\n\n const baseName = ctx.sanitize(block.name || `triPlanar${block.id}`);\n const texX = bindingName(block, \"source\", ctx, baseName);\n const texY = bindingName(block, \"sourceY\", ctx, texX);\n const texZ = bindingName(block, \"sourceZ\", ctx, texX);\n ensureBinding(state, texX);\n ensureBinding(state, texY);\n ensureBinding(state, texZ);\n\n const position = ctx.cast(ctx.resolve(block, \"position\", stage, state), \"vec3f\");\n const normal = ctx.cast(ctx.resolve(block, \"normal\", stage, state), \"vec3f\");\n const sharpnessInput = block.inputs.get(\"sharpness\")?.source ? ctx.cast(ctx.resolve(block, \"sharpness\", stage, state), \"f32\").expr : \"1.0\";\n const transform = textureTransform(block);\n\n const temp = ctx.temp(state, \"tri\");\n const n = `_n${temp}`;\n const uvx = `_uvx${temp}`;\n const uvy = `_uvy${temp}`;\n const uvz = `_uvz${temp}`;\n const x = `_x${temp}`;\n const y = `_y${temp}`;\n const z = `_z${temp}`;\n const w = `_w${temp}`;\n const sample = `_sample${temp}`;\n\n stageState.body.push(`let ${n} = ${normal.expr};`);\n stageState.body.push(`var ${uvx} = (${position.expr}).yz;`);\n stageState.body.push(`var ${uvy} = (${position.expr}).zx;`);\n stageState.body.push(`var ${uvz} = (${position.expr}).xy;`);\n if (block.serialized[\"projectAsCube\"] === true) {\n stageState.body.push(`${uvx} = (${uvx}).yx;`);\n stageState.body.push(`if (${n}.x >= 0.0) { ${uvx}.x = -${uvx}.x; }`);\n stageState.body.push(`if (${n}.y < 0.0) { ${uvy}.y = -${uvy}.y; }`);\n stageState.body.push(`if (${n}.z < 0.0) { ${uvz}.x = -${uvz}.x; }`);\n }\n stageState.body.push(`let _cU${temp} = cos(${formatFloat(transform.uAng)});`);\n stageState.body.push(`let _sU${temp} = sin(${formatFloat(transform.uAng)});`);\n stageState.body.push(`${uvx} = mat2x2<f32>(_cU${temp}, -_sU${temp}, _sU${temp}, _cU${temp}) * ${uvx};`);\n stageState.body.push(`let _cV${temp} = cos(${formatFloat(transform.vAng)});`);\n stageState.body.push(`let _sV${temp} = sin(${formatFloat(transform.vAng)});`);\n stageState.body.push(`${uvy} = mat2x2<f32>(_cV${temp}, _sV${temp}, -_sV${temp}, _cV${temp}) * ${uvy};`);\n stageState.body.push(`let _cW${temp} = cos(${formatFloat(transform.wAng)});`);\n stageState.body.push(`let _sW${temp} = sin(${formatFloat(transform.wAng)});`);\n stageState.body.push(`${uvz} = mat2x2<f32>(_cW${temp}, -_sW${temp}, _sW${temp}, _cW${temp}) * ${uvz};`);\n stageState.body.push(`let _scale${temp} = vec2<f32>(${formatFloat(transform.uScale)}, ${formatFloat(transform.vScale)});`);\n stageState.body.push(`let _offset${temp} = vec2<f32>(${formatFloat(transform.uOffset)}, ${formatFloat(transform.vOffset)});`);\n stageState.body.push(`${uvx} = ${uvx} * _scale${temp} + _offset${temp};`);\n stageState.body.push(`${uvy} = ${uvy} * _scale${temp} + _offset${temp};`);\n stageState.body.push(`${uvz} = ${uvz} * _scale${temp} + _offset${temp};`);\n stageState.body.push(`let ${x} = textureSample(nodeTex_${texX}, nodeSamp_${texX}, ${uvx});`);\n stageState.body.push(`let ${y} = textureSample(nodeTex_${texY}, nodeSamp_${texY}, ${uvy});`);\n stageState.body.push(`let ${z} = textureSample(nodeTex_${texZ}, nodeSamp_${texZ}, ${uvz});`);\n stageState.body.push(`let ${w} = pow(abs(${n}), vec3<f32>(${sharpnessInput}));`);\n stageState.body.push(\n `let ${sample} = ((${x} * ${w}.x + ${y} * ${w}.y + ${z} * ${w}.z) / (${w}.x + ${w}.y + ${w}.z)) * ${formatFloat(block.serialized[\"disableLevelMultiplication\"] === true ? 1 : transform.level)};`\n );\n\n const result = { expr: sample, type: \"vec4f\" } as const;\n stageState.memo.set(memoKey, result);\n return result;\n}\n\nexport const emitter: BlockEmitter = {\n className: \"TriPlanarBlock\",\n emit(block, outputName, stage, state, ctx) {\n if (outputName === \"level\") {\n const transform = textureTransform(block);\n return { expr: formatFloat(transform.level), type: \"f32\" };\n }\n const sample = emitTriPlanarSample(block, stage, state, ctx);\n const out = OUTPUT[outputName] ?? OUTPUT.rgba!;\n const serialized = block.serialized as { convertToLinearSpace?: boolean; convertToGammaSpace?: boolean };\n const converted = applyColorSpace(sample.expr, outputName, serialized.convertToLinearSpace === true, serialized.convertToGammaSpace === true);\n return { expr: converted === sample.expr ? `${sample.expr}${out.swizzle}` : converted, type: out.type };\n },\n};\n"],"names":[],"mappings":"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"}
@@ -77,12 +77,35 @@ function castExpr(value, target) {
77
77
  }
78
78
  throw new Error(`NodeMaterial: cannot cast ${value.type} to ${target} for expression \`${value.expr}\``);
79
79
  }
80
+ function sanitize(name) {
81
+ return name.replace(/[^A-Za-z0-9_]/g, "_");
82
+ }
83
+ function bjsTypeToNodeType(type, source = "NodeMaterial") {
84
+ if (type === 1 || type === 2) {
85
+ return "f32";
86
+ }
87
+ if (type === 4) {
88
+ return "vec2f";
89
+ }
90
+ if (type === 8 || type === 32) {
91
+ return "vec3f";
92
+ }
93
+ if (type === 16 || type === 64) {
94
+ return "vec4f";
95
+ }
96
+ if (type === 128) {
97
+ return "mat4f";
98
+ }
99
+ throw new Error(`${source}: unsupported BJS connection point type 0x${type.toString(16)}`);
100
+ }
80
101
  function makeContext(graph, loadedEmitters) {
81
102
  const ctx = {
82
103
  graph,
83
104
  _loadedEmitters: loadedEmitters,
84
105
  temp: (state, prefix) => mintTemp(state, prefix),
85
106
  cast: castExpr,
107
+ sanitize,
108
+ bjsTypeToNodeType,
86
109
  resolve: (block, inputName, stage, state) => {
87
110
  const input = block.inputs.get(inputName);
88
111
  if (!input) {
@@ -218,5 +241,5 @@ function composeStage(state, stage) {
218
241
  return s.body.join("\n");
219
242
  }
220
243
 
221
- export { castExpr, createBuildState, emitGraph, loadGraphEmitters, mintTemp };
244
+ export { bjsTypeToNodeType, castExpr, createBuildState, emitGraph, loadGraphEmitters, mintTemp, sanitize };
222
245
  //# sourceMappingURL=node-emitter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"node-emitter.js","sources":["../../../../src/material/node/node-emitter.ts"],"sourcesContent":["/** Node Material — WGSL emitter core.\n *\n * Given a parsed NodeGraph, walk it topologically from the FragmentOutput +\n * VertexOutput roots, calling each block's emitter to emit WGSL. The emitter\n * API guarantees that every (blockId, outputName) is emitted at most once per\n * stage (memoization), so downstream consumers share the same SSA temp.\n *\n * The result is a pair of WGSL source strings (vertex + fragment) plus the\n * accumulated UBO fields, attributes, varyings, samplers, and texture bindings\n * needed by the pipeline builder. This module intentionally has no WGSL of its\n * own beyond empty scaffolding — every shader string comes from a block emitter\n * so each block tree-shakes independently.\n */\n\nimport type { NodeBlock, NodeBuildState, NodeEmitContext, NodeExpr, NodeGraph, NodeValueType, Stage, StageState, BlockEmitter } from \"./node-types.js\";\nimport { WGSL } from \"./node-types.js\";\n\n// ─── Build-state construction ───────────────────────────────────────\n\nfunction newStageState(): StageState {\n return {\n helpers: new Map(),\n body: [],\n memo: new Map(),\n };\n}\n\nexport function createBuildState(): NodeBuildState {\n return {\n vertex: newStageState(),\n fragment: newStageState(),\n vertexAttributes: [],\n varyings: [],\n nodeUboFields: [],\n bindings: [],\n textures: [],\n pbrMrHelperRequests: [],\n loopVariables: new Map(),\n nextTemp: 0,\n usesLightsUbo: false,\n usesScreenSize: false,\n usesFragDepth: false,\n usesClipPlanes: false,\n usesMeshAttributeExists: false,\n usesMorphTargets: false,\n usesEnv: false,\n usesClearcoat: false,\n usesSheen: false,\n usesAnisotropy: false,\n usesIridescence: false,\n usesSubsurface: false,\n shadowLights: [],\n hasSkeleton: false,\n hasInstances: false,\n };\n}\n\n// ─── Emitter context ────────────────────────────────────────────────\n\nfunction memoKey(blockId: number, outputName: string): string {\n return `${blockId}|${outputName}`;\n}\n\nfunction stageOf(state: NodeBuildState, stage: Stage): StageState {\n return stage === \"vertex\" ? state.vertex : state.fragment;\n}\n\n/** Mint a fresh SSA temp name. */\nexport function mintTemp(state: NodeBuildState, prefix = \"t\"): string {\n const id = state.nextTemp++;\n return `_${prefix}${id}`;\n}\n\n/** Cast a typed WGSL expression to a target type. Throws if no cast is known.\n * Handles the common vector-widen/narrow cases that NME graphs actually use. */\nexport function castExpr(value: NodeExpr, target: NodeValueType): NodeExpr {\n if (value.type === target) {\n return value;\n }\n const t = WGSL[target];\n // Narrowing: vec4 -> vec3/vec2/f32 via .xyz/.xy/.x\n if (value.type === \"vec4f\" && target === \"vec3f\") {\n return { expr: `(${value.expr}).xyz`, type: target };\n }\n if (value.type === \"vec4f\" && target === \"vec2f\") {\n return { expr: `(${value.expr}).xy`, type: target };\n }\n if (value.type === \"vec3f\" && target === \"vec2f\") {\n return { expr: `(${value.expr}).xy`, type: target };\n }\n if ((value.type === \"vec4f\" || value.type === \"vec3f\" || value.type === \"vec2f\") && target === \"f32\") {\n return { expr: `(${value.expr}).x`, type: target };\n }\n // Widening: f32 -> vecN, vec3 -> vec4 (w=1)\n if (value.type === \"f32\" && (target === \"vec2f\" || target === \"vec3f\" || target === \"vec4f\")) {\n return { expr: `${t}(${value.expr})`, type: target };\n }\n if (value.type === \"vec3f\" && target === \"vec4f\") {\n return { expr: `vec4<f32>(${value.expr}, 1.0)`, type: target };\n }\n if (value.type === \"vec2f\" && target === \"vec4f\") {\n return { expr: `vec4<f32>(${value.expr}, 0.0, 1.0)`, type: target };\n }\n if (value.type === \"vec2f\" && target === \"vec3f\") {\n return { expr: `vec3<f32>(${value.expr}, 0.0)`, type: target };\n }\n throw new Error(`NodeMaterial: cannot cast ${value.type} to ${target} for expression \\`${value.expr}\\``);\n}\n\nfunction makeContext(graph: NodeGraph, loadedEmitters: Map<string, BlockEmitter>): NodeEmitContext {\n const ctx: NodeEmitContext = {\n graph,\n _loadedEmitters: loadedEmitters,\n temp: (state, prefix) => mintTemp(state, prefix),\n cast: castExpr,\n resolve: (block, inputName, stage, state) => {\n const input = block.inputs.get(inputName);\n if (!input) {\n throw new Error(`NodeMaterial: block \"${block.className}\" (id=${block.id}) has no input \"${inputName}\"`);\n }\n if (!input.source) {\n throw new Error(`NodeMaterial: block \"${block.className}\" (id=${block.id}) input \"${inputName}\" is not connected`);\n }\n const producer = graph.blocks.get(input.source.blockId);\n if (!producer) {\n throw new Error(`NodeMaterial: dangling connection ${block.id}.${inputName} -> block ${input.source.blockId}`);\n }\n return ctx.resolveOutput(producer, input.source.outputName, stage, state);\n },\n resolveOutput: (producer, outputName, stage, state) => {\n const stageState = stageOf(state, stage);\n const key = memoKey(producer.id, outputName);\n const existing = stageState.memo.get(key);\n if (existing) {\n return existing;\n }\n const emitter = loadedEmitters.get(producer.className);\n if (!emitter) {\n throw new Error(`NodeMaterial: no emitter loaded for block \"${producer.className}\"`);\n }\n // Blocks that declare a stage preference override the requested stage.\n const targetStage = emitter.stage ?? stage;\n const result = emitter.emit(producer, outputName, targetStage, state, ctx);\n // If the producer ran in a different stage, bridge via varying.\n if (targetStage !== stage) {\n const vname = `v_${producer.id}_${outputName}`;\n bridgeVarying(state, vname, result, targetStage, stage);\n const bridged: NodeExpr = { expr: `in.${vname}`, type: result.type };\n stageState.memo.set(key, bridged);\n return bridged;\n }\n stageState.memo.set(key, result);\n return result;\n },\n };\n return ctx;\n}\n\nfunction bridgeVarying(state: NodeBuildState, varyingName: string, value: NodeExpr, from: Stage, to: Stage): void {\n if (from !== \"vertex\" || to !== \"fragment\") {\n throw new Error(\"NodeMaterial: only vertex->fragment varyings are supported\");\n }\n const already = state.varyings.find((v) => v._name === varyingName);\n if (!already) {\n state.varyings.push({ _name: varyingName, _type: WGSL[value.type] });\n state.vertex.body.push(`out.${varyingName} = ${value.expr};`);\n }\n}\n\n// ─── Emitter dispatch ───────────────────────────────────────────────\n\n/** Load all emitters referenced by the graph in a single parallel batch. */\nlet defaultRegistry: Promise<typeof import(\"./node-registry.js\")> | null = null;\nasync function defaultBlockLoader(className: string): Promise<BlockEmitter> {\n defaultRegistry ??= import(\"./node-registry.js\");\n return (await defaultRegistry).loadBlockEmitter(className);\n}\n\nfunction pbrMrBlockNeedsFullEmitter(block: NodeBlock): boolean {\n return (\n (block.serialized as { enableSpecularAntiAliasing?: boolean }).enableSpecularAntiAliasing === true ||\n !!block.inputs.get(\"clearcoat\")?.source ||\n !!block.inputs.get(\"sheen\")?.source ||\n !!block.inputs.get(\"subsurface\")?.source ||\n !!block.inputs.get(\"anisotropy\")?.source ||\n !!block.inputs.get(\"iridescence\")?.source\n );\n}\n\nfunction graphNeedsFullPbrMrEmitter(graph: NodeGraph): boolean {\n for (const block of graph.blocks.values()) {\n if (block.className === \"PBRMetallicRoughnessBlock\" && pbrMrBlockNeedsFullEmitter(block)) {\n return true;\n }\n }\n return false;\n}\n\nexport async function loadGraphEmitters(graph: NodeGraph, blockLoader: (className: string) => Promise<BlockEmitter> = defaultBlockLoader): Promise<Map<string, BlockEmitter>> {\n const classNames = new Set<string>();\n for (const b of graph.blocks.values()) {\n classNames.add(b.className);\n }\n const map = new Map<string, BlockEmitter>();\n const useFullPbrMrEmitter = blockLoader === defaultBlockLoader && graphNeedsFullPbrMrEmitter(graph);\n await Promise.all(\n Array.from(classNames).map(async (className) => {\n const loaderKey = className === \"PBRMetallicRoughnessBlock\" && useFullPbrMrEmitter ? \"PBRMetallicRoughnessBlock__full\" : className;\n const e = await blockLoader(loaderKey);\n map.set(className, e);\n })\n );\n return map;\n}\n\n// ─── Public entry ───────────────────────────────────────────────────\n\nexport interface EmitResult {\n readonly vertexWgsl: string;\n readonly fragmentWgsl: string;\n readonly state: NodeBuildState;\n}\n\n/** Walk the graph from the given root (a FragmentOutput or VertexOutput block)\n * and emit the pair of WGSL shader strings. The caller is responsible for\n * wrapping the result with the pipeline's bind-group / entry-point scaffolding\n * (done by `node-pipeline.ts`). */\nexport function emitGraph(\n graph: NodeGraph,\n loadedEmitters: Map<string, BlockEmitter>,\n fragmentRootId: number,\n vertexRootId: number | null,\n shadowLights?: readonly { lightIndex: number; shadowType: \"esm\" | \"pcf\" }[],\n meshCaps?: { hasSkeleton?: boolean; hasInstances?: boolean }\n): EmitResult {\n const state = createBuildState();\n if (shadowLights) {\n for (const sl of shadowLights) {\n state.shadowLights.push(sl);\n }\n }\n if (meshCaps) {\n if (meshCaps.hasSkeleton) {\n state.hasSkeleton = true;\n }\n if (meshCaps.hasInstances) {\n state.hasInstances = true;\n }\n }\n const ctx = makeContext(graph, loadedEmitters);\n\n // Emit fragment root.\n const fragRoot = graph.blocks.get(fragmentRootId);\n if (!fragRoot) {\n throw new Error(`NodeMaterial: fragment root block ${fragmentRootId} not found`);\n }\n const fragEmitter = loadedEmitters.get(fragRoot.className);\n if (!fragEmitter) {\n throw new Error(`NodeMaterial: no emitter for fragment root \"${fragRoot.className}\"`);\n }\n fragEmitter.emit(fragRoot, \"\", \"fragment\", state, ctx);\n\n if (vertexRootId !== null) {\n const vertRoot = graph.blocks.get(vertexRootId);\n if (!vertRoot) {\n throw new Error(`NodeMaterial: vertex root block ${vertexRootId} not found`);\n }\n const vertEmitter = loadedEmitters.get(vertRoot.className);\n if (!vertEmitter) {\n throw new Error(`NodeMaterial: no emitter for vertex root \"${vertRoot.className}\"`);\n }\n vertEmitter.emit(vertRoot, \"\", \"vertex\", state, ctx);\n }\n\n // Force-emit side-effect blocks (e.g. DiscardBlock) that have no outputs\n // the graph walk would visit. Each such emitter is expected to guard its\n // own body via a memo key so multiple calls are idempotent.\n for (const block of graph.blocks.values()) {\n const e = loadedEmitters.get(block.className);\n if (e?.sideEffect) {\n e.emit(block, \"\", e.stage ?? \"fragment\", state, ctx);\n }\n }\n\n return {\n vertexWgsl: composeStage(state, \"vertex\"),\n fragmentWgsl: composeStage(state, \"fragment\"),\n state,\n };\n}\n\nfunction composeStage(state: NodeBuildState, stage: Stage): string {\n // Helpers are emitted at module scope by the pipeline builder, NOT inside main.\n // composeStage returns only the statements that belong inside the entry point.\n const s = stageOf(state, stage);\n return s.body.join(\"\\n\");\n}\n"],"names":[],"mappings":";;AAmBA,SAAS,aAAA,GAA4B;AACjC,EAAA,OAAO;AAAA,IACH,OAAA,sBAAa,GAAA,EAAI;AAAA,IACjB,MAAM,EAAC;AAAA,IACP,IAAA,sBAAU,GAAA;AAAI,GAClB;AACJ;AAEO,SAAS,gBAAA,GAAmC;AAC/C,EAAA,OAAO;AAAA,IACH,QAAQ,aAAA,EAAc;AAAA,IACtB,UAAU,aAAA,EAAc;AAAA,IACxB,kBAAkB,EAAC;AAAA,IACnB,UAAU,EAAC;AAAA,IACX,eAAe,EAAC;AAAA,IAChB,UAAU,EAAC;AAAA,IACX,UAAU,EAAC;AAAA,IACX,qBAAqB,EAAC;AAAA,IACtB,aAAA,sBAAmB,GAAA,EAAI;AAAA,IACvB,QAAA,EAAU,CAAA;AAAA,IACV,aAAA,EAAe,KAAA;AAAA,IACf,cAAA,EAAgB,KAAA;AAAA,IAChB,aAAA,EAAe,KAAA;AAAA,IACf,cAAA,EAAgB,KAAA;AAAA,IAChB,uBAAA,EAAyB,KAAA;AAAA,IACzB,gBAAA,EAAkB,KAAA;AAAA,IAClB,OAAA,EAAS,KAAA;AAAA,IACT,aAAA,EAAe,KAAA;AAAA,IACf,SAAA,EAAW,KAAA;AAAA,IACX,cAAA,EAAgB,KAAA;AAAA,IAChB,eAAA,EAAiB,KAAA;AAAA,IACjB,cAAA,EAAgB,KAAA;AAAA,IAChB,cAAc,EAAC;AAAA,IACf,WAAA,EAAa,KAAA;AAAA,IACb,YAAA,EAAc;AAAA,GAClB;AACJ;AAIA,SAAS,OAAA,CAAQ,SAAiB,UAAA,EAA4B;AAC1D,EAAA,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA;AACnC;AAEA,SAAS,OAAA,CAAQ,OAAuB,KAAA,EAA0B;AAC9D,EAAA,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,CAAM,MAAA,GAAS,KAAA,CAAM,QAAA;AACrD;AAGO,SAAS,QAAA,CAAS,KAAA,EAAuB,MAAA,GAAS,GAAA,EAAa;AAClE,EAAA,MAAM,KAAK,KAAA,CAAM,QAAA,EAAA;AACjB,EAAA,OAAO,CAAA,CAAA,EAAI,MAAM,CAAA,EAAG,EAAE,CAAA,CAAA;AAC1B;AAIO,SAAS,QAAA,CAAS,OAAiB,MAAA,EAAiC;AACvE,EAAA,IAAI,KAAA,CAAM,SAAS,MAAA,EAAQ;AACvB,IAAA,OAAO,KAAA;AAAA,EACX;AACA,EAAA,MAAM,CAAA,GAAI,KAAK,MAAM,CAAA;AAErB,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,CAAA,EAAI,MAAM,IAAI,CAAA,KAAA,CAAA,EAAS,MAAM,MAAA,EAAO;AAAA,EACvD;AACA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,CAAA,EAAI,MAAM,IAAI,CAAA,IAAA,CAAA,EAAQ,MAAM,MAAA,EAAO;AAAA,EACtD;AACA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,CAAA,EAAI,MAAM,IAAI,CAAA,IAAA,CAAA,EAAQ,MAAM,MAAA,EAAO;AAAA,EACtD;AACA,EAAA,IAAA,CAAK,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,KAAA,CAAM,IAAA,KAAS,WAAW,KAAA,CAAM,IAAA,KAAS,OAAA,KAAY,MAAA,KAAW,KAAA,EAAO;AAClG,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,CAAA,EAAI,MAAM,IAAI,CAAA,GAAA,CAAA,EAAO,MAAM,MAAA,EAAO;AAAA,EACrD;AAEA,EAAA,IAAI,KAAA,CAAM,SAAS,KAAA,KAAU,MAAA,KAAW,WAAW,MAAA,KAAW,OAAA,IAAW,WAAW,OAAA,CAAA,EAAU;AAC1F,IAAA,OAAO,EAAE,MAAM,CAAA,EAAG,CAAC,IAAI,KAAA,CAAM,IAAI,CAAA,CAAA,CAAA,EAAK,IAAA,EAAM,MAAA,EAAO;AAAA,EACvD;AACA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,UAAA,EAAa,MAAM,IAAI,CAAA,MAAA,CAAA,EAAU,MAAM,MAAA,EAAO;AAAA,EACjE;AACA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,UAAA,EAAa,MAAM,IAAI,CAAA,WAAA,CAAA,EAAe,MAAM,MAAA,EAAO;AAAA,EACtE;AACA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,UAAA,EAAa,MAAM,IAAI,CAAA,MAAA,CAAA,EAAU,MAAM,MAAA,EAAO;AAAA,EACjE;AACA,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,KAAA,CAAM,IAAI,OAAO,MAAM,CAAA,kBAAA,EAAqB,KAAA,CAAM,IAAI,CAAA,EAAA,CAAI,CAAA;AAC3G;AAEA,SAAS,WAAA,CAAY,OAAkB,cAAA,EAA4D;AAC/F,EAAA,MAAM,GAAA,GAAuB;AAAA,IACzB,KAAA;AAAA,IACA,eAAA,EAAiB,cAAA;AAAA,IACjB,MAAM,CAAC,KAAA,EAAO,MAAA,KAAW,QAAA,CAAS,OAAO,MAAM,CAAA;AAAA,IAC/C,IAAA,EAAM,QAAA;AAAA,IACN,OAAA,EAAS,CAAC,KAAA,EAAO,SAAA,EAAW,OAAO,KAAA,KAAU;AACzC,MAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,SAAS,CAAA;AACxC,MAAA,IAAI,CAAC,KAAA,EAAO;AACR,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,KAAA,CAAM,SAAS,SAAS,KAAA,CAAM,EAAE,CAAA,gBAAA,EAAmB,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,MAC3G;AACA,MAAA,IAAI,CAAC,MAAM,MAAA,EAAQ;AACf,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,KAAA,CAAM,SAAS,SAAS,KAAA,CAAM,EAAE,CAAA,SAAA,EAAY,SAAS,CAAA,kBAAA,CAAoB,CAAA;AAAA,MACrH;AACA,MAAA,MAAM,WAAW,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,KAAA,CAAM,OAAO,OAAO,CAAA;AACtD,MAAA,IAAI,CAAC,QAAA,EAAU;AACX,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,KAAA,CAAM,EAAE,CAAA,CAAA,EAAI,SAAS,CAAA,UAAA,EAAa,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,CAAE,CAAA;AAAA,MACjH;AACA,MAAA,OAAO,IAAI,aAAA,CAAc,QAAA,EAAU,MAAM,MAAA,CAAO,UAAA,EAAY,OAAO,KAAK,CAAA;AAAA,IAC5E,CAAA;AAAA,IACA,aAAA,EAAe,CAAC,QAAA,EAAU,UAAA,EAAY,OAAO,KAAA,KAAU;AACnD,MAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,KAAA,EAAO,KAAK,CAAA;AACvC,MAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,QAAA,CAAS,EAAA,EAAI,UAAU,CAAA;AAC3C,MAAA,MAAM,QAAA,GAAW,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AACxC,MAAA,IAAI,QAAA,EAAU;AACV,QAAA,OAAO,QAAA;AAAA,MACX;AACA,MAAA,MAAM,OAAA,GAAU,cAAA,CAAe,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA;AACrD,MAAA,IAAI,CAAC,OAAA,EAAS;AACV,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2CAAA,EAA8C,QAAA,CAAS,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,MACvF;AAEA,MAAA,MAAM,WAAA,GAAc,QAAQ,KAAA,IAAS,KAAA;AACrC,MAAA,MAAM,SAAS,OAAA,CAAQ,IAAA,CAAK,UAAU,UAAA,EAAY,WAAA,EAAa,OAAO,GAAG,CAAA;AAEzE,MAAA,IAAI,gBAAgB,KAAA,EAAO;AACvB,QAAA,MAAM,KAAA,GAAQ,CAAA,EAAA,EAAK,QAAA,CAAS,EAAE,IAAI,UAAU,CAAA,CAAA;AAC5C,QAAA,aAAA,CAAc,KAAA,EAAO,KAAA,EAAO,MAAA,EAAQ,WAAA,EAAa,KAAK,CAAA;AACtD,QAAA,MAAM,OAAA,GAAoB,EAAE,IAAA,EAAM,CAAA,GAAA,EAAM,KAAK,CAAA,CAAA,EAAI,IAAA,EAAM,OAAO,IAAA,EAAK;AACnE,QAAA,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,OAAO,CAAA;AAChC,QAAA,OAAO,OAAA;AAAA,MACX;AACA,MAAA,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,MAAM,CAAA;AAC/B,MAAA,OAAO,MAAA;AAAA,IACX;AAAA,GACJ;AACA,EAAA,OAAO,GAAA;AACX;AAEA,SAAS,aAAA,CAAc,KAAA,EAAuB,WAAA,EAAqB,KAAA,EAAiB,MAAa,EAAA,EAAiB;AAC9G,EAAA,IAAI,IAAA,KAAS,QAAA,IAAY,EAAA,KAAO,UAAA,EAAY;AACxC,IAAA,MAAM,IAAI,MAAM,4DAA4D,CAAA;AAAA,EAChF;AACA,EAAA,MAAM,OAAA,GAAU,MAAM,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,WAAW,CAAA;AAClE,EAAA,IAAI,CAAC,OAAA,EAAS;AACV,IAAA,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,OAAO,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,EAAG,CAAA;AACnE,IAAA,KAAA,CAAM,MAAA,CAAO,KAAK,IAAA,CAAK,CAAA,IAAA,EAAO,WAAW,CAAA,GAAA,EAAM,KAAA,CAAM,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,EAChE;AACJ;AAKA,IAAI,eAAA,GAAuE,IAAA;AAC3E,eAAe,mBAAmB,SAAA,EAA0C;AACxE,EAAA,eAAA,KAAoB,OAAO,oBAAoB,CAAA;AAC/C,EAAA,OAAA,CAAQ,MAAM,eAAA,EAAiB,gBAAA,CAAiB,SAAS,CAAA;AAC7D;AAEA,SAAS,2BAA2B,KAAA,EAA2B;AAC3D,EAAA,OACK,MAAM,UAAA,CAAwD,0BAAA,KAA+B,QAC9F,CAAC,CAAC,MAAM,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA,EAAG,MAAA,IACjC,CAAC,CAAC,KAAA,CAAM,OAAO,GAAA,CAAI,OAAO,GAAG,MAAA,IAC7B,CAAC,CAAC,KAAA,CAAM,OAAO,GAAA,CAAI,YAAY,GAAG,MAAA,IAClC,CAAC,CAAC,KAAA,CAAM,MAAA,CAAO,IAAI,YAAY,CAAA,EAAG,UAClC,CAAC,CAAC,MAAM,MAAA,CAAO,GAAA,CAAI,aAAa,CAAA,EAAG,MAAA;AAE3C;AAEA,SAAS,2BAA2B,KAAA,EAA2B;AAC3D,EAAA,KAAA,MAAW,KAAA,IAAS,KAAA,CAAM,MAAA,CAAO,MAAA,EAAO,EAAG;AACvC,IAAA,IAAI,KAAA,CAAM,SAAA,KAAc,2BAAA,IAA+B,0BAAA,CAA2B,KAAK,CAAA,EAAG;AACtF,MAAA,OAAO,IAAA;AAAA,IACX;AAAA,EACJ;AACA,EAAA,OAAO,KAAA;AACX;AAEA,eAAsB,iBAAA,CAAkB,KAAA,EAAkB,WAAA,GAA4D,kBAAA,EAAwD;AAC1K,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAY;AACnC,EAAA,KAAA,MAAW,CAAA,IAAK,KAAA,CAAM,MAAA,CAAO,MAAA,EAAO,EAAG;AACnC,IAAA,UAAA,CAAW,GAAA,CAAI,EAAE,SAAS,CAAA;AAAA,EAC9B;AACA,EAAA,MAAM,GAAA,uBAAU,GAAA,EAA0B;AAC1C,EAAA,MAAM,mBAAA,GAAsB,WAAA,KAAgB,kBAAA,IAAsB,0BAAA,CAA2B,KAAK,CAAA;AAClG,EAAA,MAAM,OAAA,CAAQ,GAAA;AAAA,IACV,MAAM,IAAA,CAAK,UAAU,CAAA,CAAE,GAAA,CAAI,OAAO,SAAA,KAAc;AAC5C,MAAA,MAAM,SAAA,GAAY,SAAA,KAAc,2BAAA,IAA+B,mBAAA,GAAsB,iCAAA,GAAoC,SAAA;AACzH,MAAA,MAAM,CAAA,GAAI,MAAM,WAAA,CAAY,SAAS,CAAA;AACrC,MAAA,GAAA,CAAI,GAAA,CAAI,WAAW,CAAC,CAAA;AAAA,IACxB,CAAC;AAAA,GACL;AACA,EAAA,OAAO,GAAA;AACX;AAcO,SAAS,UACZ,KAAA,EACA,cAAA,EACA,cAAA,EACA,YAAA,EACA,cACA,QAAA,EACU;AACV,EAAA,MAAM,QAAQ,gBAAA,EAAiB;AAC/B,EAAA,IAAI,YAAA,EAAc;AACd,IAAA,KAAA,MAAW,MAAM,YAAA,EAAc;AAC3B,MAAA,KAAA,CAAM,YAAA,CAAa,KAAK,EAAE,CAAA;AAAA,IAC9B;AAAA,EACJ;AACA,EAAA,IAAI,QAAA,EAAU;AACV,IAAA,IAAI,SAAS,WAAA,EAAa;AACtB,MAAA,KAAA,CAAM,WAAA,GAAc,IAAA;AAAA,IACxB;AACA,IAAA,IAAI,SAAS,YAAA,EAAc;AACvB,MAAA,KAAA,CAAM,YAAA,GAAe,IAAA;AAAA,IACzB;AAAA,EACJ;AACA,EAAA,MAAM,GAAA,GAAM,WAAA,CAAY,KAAA,EAAO,cAAc,CAAA;AAG7C,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,cAAc,CAAA;AAChD,EAAA,IAAI,CAAC,QAAA,EAAU;AACX,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,cAAc,CAAA,UAAA,CAAY,CAAA;AAAA,EACnF;AACA,EAAA,MAAM,WAAA,GAAc,cAAA,CAAe,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA;AACzD,EAAA,IAAI,CAAC,WAAA,EAAa;AACd,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,4CAAA,EAA+C,QAAA,CAAS,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,EACxF;AACA,EAAA,WAAA,CAAY,IAAA,CAAK,QAAA,EAAU,EAAA,EAAI,UAAA,EAAY,OAAO,GAAG,CAAA;AAErD,EAAA,IAAI,iBAAiB,IAAA,EAAM;AACvB,IAAA,MAAM,QAAA,GAAW,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,YAAY,CAAA;AAC9C,IAAA,IAAI,CAAC,QAAA,EAAU;AACX,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gCAAA,EAAmC,YAAY,CAAA,UAAA,CAAY,CAAA;AAAA,IAC/E;AACA,IAAA,MAAM,WAAA,GAAc,cAAA,CAAe,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA;AACzD,IAAA,IAAI,CAAC,WAAA,EAAa;AACd,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0CAAA,EAA6C,QAAA,CAAS,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,IACtF;AACA,IAAA,WAAA,CAAY,IAAA,CAAK,QAAA,EAAU,EAAA,EAAI,QAAA,EAAU,OAAO,GAAG,CAAA;AAAA,EACvD;AAKA,EAAA,KAAA,MAAW,KAAA,IAAS,KAAA,CAAM,MAAA,CAAO,MAAA,EAAO,EAAG;AACvC,IAAA,MAAM,CAAA,GAAI,cAAA,CAAe,GAAA,CAAI,KAAA,CAAM,SAAS,CAAA;AAC5C,IAAA,IAAI,GAAG,UAAA,EAAY;AACf,MAAA,CAAA,CAAE,KAAK,KAAA,EAAO,EAAA,EAAI,EAAE,KAAA,IAAS,UAAA,EAAY,OAAO,GAAG,CAAA;AAAA,IACvD;AAAA,EACJ;AAEA,EAAA,OAAO;AAAA,IACH,UAAA,EAAY,YAAA,CAAa,KAAA,EAAO,QAAQ,CAAA;AAAA,IACxC,YAAA,EAAc,YAAA,CAAa,KAAA,EAAO,UAAU,CAAA;AAAA,IAC5C;AAAA,GACJ;AACJ;AAEA,SAAS,YAAA,CAAa,OAAuB,KAAA,EAAsB;AAG/D,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,KAAA,EAAO,KAAK,CAAA;AAC9B,EAAA,OAAO,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,IAAI,CAAA;AAC3B;;;;"}
1
+ {"version":3,"file":"node-emitter.js","sources":["../../../../src/material/node/node-emitter.ts"],"sourcesContent":["/** Node Material — WGSL emitter core.\n *\n * Given a parsed NodeGraph, walk it topologically from the FragmentOutput +\n * VertexOutput roots, calling each block's emitter to emit WGSL. The emitter\n * API guarantees that every (blockId, outputName) is emitted at most once per\n * stage (memoization), so downstream consumers share the same SSA temp.\n *\n * The result is a pair of WGSL source strings (vertex + fragment) plus the\n * accumulated UBO fields, attributes, varyings, samplers, and texture bindings\n * needed by the pipeline builder. This module intentionally has no WGSL of its\n * own beyond empty scaffolding — every shader string comes from a block emitter\n * so each block tree-shakes independently.\n */\n\nimport type { NodeBlock, NodeBuildState, NodeEmitContext, NodeExpr, NodeGraph, NodeValueType, Stage, StageState, BlockEmitter } from \"./node-types.js\";\nimport { WGSL } from \"./node-types.js\";\n\n// ─── Build-state construction ───────────────────────────────────────\n\nfunction newStageState(): StageState {\n return {\n helpers: new Map(),\n body: [],\n memo: new Map(),\n };\n}\n\nexport function createBuildState(): NodeBuildState {\n return {\n vertex: newStageState(),\n fragment: newStageState(),\n vertexAttributes: [],\n varyings: [],\n nodeUboFields: [],\n bindings: [],\n textures: [],\n pbrMrHelperRequests: [],\n loopVariables: new Map(),\n nextTemp: 0,\n usesLightsUbo: false,\n usesScreenSize: false,\n usesFragDepth: false,\n usesClipPlanes: false,\n usesMeshAttributeExists: false,\n usesMorphTargets: false,\n usesEnv: false,\n usesClearcoat: false,\n usesSheen: false,\n usesAnisotropy: false,\n usesIridescence: false,\n usesSubsurface: false,\n shadowLights: [],\n hasSkeleton: false,\n hasInstances: false,\n };\n}\n\n// ─── Emitter context ────────────────────────────────────────────────\n\nfunction memoKey(blockId: number, outputName: string): string {\n return `${blockId}|${outputName}`;\n}\n\nfunction stageOf(state: NodeBuildState, stage: Stage): StageState {\n return stage === \"vertex\" ? state.vertex : state.fragment;\n}\n\n/** Mint a fresh SSA temp name. */\nexport function mintTemp(state: NodeBuildState, prefix = \"t\"): string {\n const id = state.nextTemp++;\n return `_${prefix}${id}`;\n}\n\n/** Cast a typed WGSL expression to a target type. Throws if no cast is known.\n * Handles the common vector-widen/narrow cases that NME graphs actually use. */\nexport function castExpr(value: NodeExpr, target: NodeValueType): NodeExpr {\n if (value.type === target) {\n return value;\n }\n const t = WGSL[target];\n // Narrowing: vec4 -> vec3/vec2/f32 via .xyz/.xy/.x\n if (value.type === \"vec4f\" && target === \"vec3f\") {\n return { expr: `(${value.expr}).xyz`, type: target };\n }\n if (value.type === \"vec4f\" && target === \"vec2f\") {\n return { expr: `(${value.expr}).xy`, type: target };\n }\n if (value.type === \"vec3f\" && target === \"vec2f\") {\n return { expr: `(${value.expr}).xy`, type: target };\n }\n if ((value.type === \"vec4f\" || value.type === \"vec3f\" || value.type === \"vec2f\") && target === \"f32\") {\n return { expr: `(${value.expr}).x`, type: target };\n }\n // Widening: f32 -> vecN, vec3 -> vec4 (w=1)\n if (value.type === \"f32\" && (target === \"vec2f\" || target === \"vec3f\" || target === \"vec4f\")) {\n return { expr: `${t}(${value.expr})`, type: target };\n }\n if (value.type === \"vec3f\" && target === \"vec4f\") {\n return { expr: `vec4<f32>(${value.expr}, 1.0)`, type: target };\n }\n if (value.type === \"vec2f\" && target === \"vec4f\") {\n return { expr: `vec4<f32>(${value.expr}, 0.0, 1.0)`, type: target };\n }\n if (value.type === \"vec2f\" && target === \"vec3f\") {\n return { expr: `vec3<f32>(${value.expr}, 0.0)`, type: target };\n }\n throw new Error(`NodeMaterial: cannot cast ${value.type} to ${target} for expression \\`${value.expr}\\``);\n}\n\n/** @internal Sanitize a block/input name for use as a WGSL identifier. */\nexport function sanitize(name: string): string {\n return name.replace(/[^A-Za-z0-9_]/g, \"_\");\n}\n\n/** @internal Map Babylon.js connection-point flags to Lite's node value types. */\nexport function bjsTypeToNodeType(type: number, source = \"NodeMaterial\"): NodeValueType {\n if (type === 0x1 || type === 0x2) {\n return \"f32\";\n }\n if (type === 0x4) {\n return \"vec2f\";\n }\n if (type === 0x8 || type === 0x20) {\n return \"vec3f\";\n }\n if (type === 0x10 || type === 0x40) {\n return \"vec4f\";\n }\n if (type === 0x80) {\n return \"mat4f\";\n }\n throw new Error(`${source}: unsupported BJS connection point type 0x${type.toString(16)}`);\n}\n\nfunction makeContext(graph: NodeGraph, loadedEmitters: Map<string, BlockEmitter>): NodeEmitContext {\n const ctx: NodeEmitContext = {\n graph,\n _loadedEmitters: loadedEmitters,\n temp: (state, prefix) => mintTemp(state, prefix),\n cast: castExpr,\n sanitize,\n bjsTypeToNodeType,\n resolve: (block, inputName, stage, state) => {\n const input = block.inputs.get(inputName);\n if (!input) {\n throw new Error(`NodeMaterial: block \"${block.className}\" (id=${block.id}) has no input \"${inputName}\"`);\n }\n if (!input.source) {\n throw new Error(`NodeMaterial: block \"${block.className}\" (id=${block.id}) input \"${inputName}\" is not connected`);\n }\n const producer = graph.blocks.get(input.source.blockId);\n if (!producer) {\n throw new Error(`NodeMaterial: dangling connection ${block.id}.${inputName} -> block ${input.source.blockId}`);\n }\n return ctx.resolveOutput(producer, input.source.outputName, stage, state);\n },\n resolveOutput: (producer, outputName, stage, state) => {\n const stageState = stageOf(state, stage);\n const key = memoKey(producer.id, outputName);\n const existing = stageState.memo.get(key);\n if (existing) {\n return existing;\n }\n const emitter = loadedEmitters.get(producer.className);\n if (!emitter) {\n throw new Error(`NodeMaterial: no emitter loaded for block \"${producer.className}\"`);\n }\n // Blocks that declare a stage preference override the requested stage.\n const targetStage = emitter.stage ?? stage;\n const result = emitter.emit(producer, outputName, targetStage, state, ctx);\n // If the producer ran in a different stage, bridge via varying.\n if (targetStage !== stage) {\n const vname = `v_${producer.id}_${outputName}`;\n bridgeVarying(state, vname, result, targetStage, stage);\n const bridged: NodeExpr = { expr: `in.${vname}`, type: result.type };\n stageState.memo.set(key, bridged);\n return bridged;\n }\n stageState.memo.set(key, result);\n return result;\n },\n };\n return ctx;\n}\n\nfunction bridgeVarying(state: NodeBuildState, varyingName: string, value: NodeExpr, from: Stage, to: Stage): void {\n if (from !== \"vertex\" || to !== \"fragment\") {\n throw new Error(\"NodeMaterial: only vertex->fragment varyings are supported\");\n }\n const already = state.varyings.find((v) => v._name === varyingName);\n if (!already) {\n state.varyings.push({ _name: varyingName, _type: WGSL[value.type] });\n state.vertex.body.push(`out.${varyingName} = ${value.expr};`);\n }\n}\n\n// ─── Emitter dispatch ───────────────────────────────────────────────\n\n/** Load all emitters referenced by the graph in a single parallel batch. */\nlet defaultRegistry: Promise<typeof import(\"./node-registry.js\")> | null = null;\nasync function defaultBlockLoader(className: string): Promise<BlockEmitter> {\n defaultRegistry ??= import(\"./node-registry.js\");\n return (await defaultRegistry).loadBlockEmitter(className);\n}\n\nfunction pbrMrBlockNeedsFullEmitter(block: NodeBlock): boolean {\n return (\n (block.serialized as { enableSpecularAntiAliasing?: boolean }).enableSpecularAntiAliasing === true ||\n !!block.inputs.get(\"clearcoat\")?.source ||\n !!block.inputs.get(\"sheen\")?.source ||\n !!block.inputs.get(\"subsurface\")?.source ||\n !!block.inputs.get(\"anisotropy\")?.source ||\n !!block.inputs.get(\"iridescence\")?.source\n );\n}\n\nfunction graphNeedsFullPbrMrEmitter(graph: NodeGraph): boolean {\n for (const block of graph.blocks.values()) {\n if (block.className === \"PBRMetallicRoughnessBlock\" && pbrMrBlockNeedsFullEmitter(block)) {\n return true;\n }\n }\n return false;\n}\n\nexport async function loadGraphEmitters(graph: NodeGraph, blockLoader: (className: string) => Promise<BlockEmitter> = defaultBlockLoader): Promise<Map<string, BlockEmitter>> {\n const classNames = new Set<string>();\n for (const b of graph.blocks.values()) {\n classNames.add(b.className);\n }\n const map = new Map<string, BlockEmitter>();\n const useFullPbrMrEmitter = blockLoader === defaultBlockLoader && graphNeedsFullPbrMrEmitter(graph);\n await Promise.all(\n Array.from(classNames).map(async (className) => {\n const loaderKey = className === \"PBRMetallicRoughnessBlock\" && useFullPbrMrEmitter ? \"PBRMetallicRoughnessBlock__full\" : className;\n const e = await blockLoader(loaderKey);\n map.set(className, e);\n })\n );\n return map;\n}\n\n// ─── Public entry ───────────────────────────────────────────────────\n\nexport interface EmitResult {\n readonly vertexWgsl: string;\n readonly fragmentWgsl: string;\n readonly state: NodeBuildState;\n}\n\n/** Walk the graph from the given root (a FragmentOutput or VertexOutput block)\n * and emit the pair of WGSL shader strings. The caller is responsible for\n * wrapping the result with the pipeline's bind-group / entry-point scaffolding\n * (done by `node-pipeline.ts`). */\nexport function emitGraph(\n graph: NodeGraph,\n loadedEmitters: Map<string, BlockEmitter>,\n fragmentRootId: number,\n vertexRootId: number | null,\n shadowLights?: readonly { lightIndex: number; shadowType: \"esm\" | \"pcf\" }[],\n meshCaps?: { hasSkeleton?: boolean; hasInstances?: boolean }\n): EmitResult {\n const state = createBuildState();\n if (shadowLights) {\n for (const sl of shadowLights) {\n state.shadowLights.push(sl);\n }\n }\n if (meshCaps) {\n if (meshCaps.hasSkeleton) {\n state.hasSkeleton = true;\n }\n if (meshCaps.hasInstances) {\n state.hasInstances = true;\n }\n }\n const ctx = makeContext(graph, loadedEmitters);\n\n // Emit fragment root.\n const fragRoot = graph.blocks.get(fragmentRootId);\n if (!fragRoot) {\n throw new Error(`NodeMaterial: fragment root block ${fragmentRootId} not found`);\n }\n const fragEmitter = loadedEmitters.get(fragRoot.className);\n if (!fragEmitter) {\n throw new Error(`NodeMaterial: no emitter for fragment root \"${fragRoot.className}\"`);\n }\n fragEmitter.emit(fragRoot, \"\", \"fragment\", state, ctx);\n\n if (vertexRootId !== null) {\n const vertRoot = graph.blocks.get(vertexRootId);\n if (!vertRoot) {\n throw new Error(`NodeMaterial: vertex root block ${vertexRootId} not found`);\n }\n const vertEmitter = loadedEmitters.get(vertRoot.className);\n if (!vertEmitter) {\n throw new Error(`NodeMaterial: no emitter for vertex root \"${vertRoot.className}\"`);\n }\n vertEmitter.emit(vertRoot, \"\", \"vertex\", state, ctx);\n }\n\n // Force-emit side-effect blocks (e.g. DiscardBlock) that have no outputs\n // the graph walk would visit. Each such emitter is expected to guard its\n // own body via a memo key so multiple calls are idempotent.\n for (const block of graph.blocks.values()) {\n const e = loadedEmitters.get(block.className);\n if (e?.sideEffect) {\n e.emit(block, \"\", e.stage ?? \"fragment\", state, ctx);\n }\n }\n\n return {\n vertexWgsl: composeStage(state, \"vertex\"),\n fragmentWgsl: composeStage(state, \"fragment\"),\n state,\n };\n}\n\nfunction composeStage(state: NodeBuildState, stage: Stage): string {\n // Helpers are emitted at module scope by the pipeline builder, NOT inside main.\n // composeStage returns only the statements that belong inside the entry point.\n const s = stageOf(state, stage);\n return s.body.join(\"\\n\");\n}\n"],"names":[],"mappings":"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"}
@@ -5,10 +5,10 @@ import { writeMeshLightSelection } from '../../render/lights-ubo.js';
5
5
  import { MAX_LIGHTS } from '../../light/types.js';
6
6
  import { packMat4IntoF32 } from '../../math/pack-mat4-into-f32.js';
7
7
  import { GeometryTextureType } from '../../frame-graph/geometry-types.js';
8
- import { emitGraph } from './node-emitter.js';
8
+ import { emitGraph, sanitize, bjsTypeToNodeType } from './node-emitter.js';
9
9
  import { findBlockByClassName } from './node-parser.js';
10
10
  import { compileNodePipeline } from './node-pipeline.js';
11
- import { sanitize, bjsTypeToNodeType, extractDefault, floatCount } from './node-material.js';
11
+ import { extractDefault, floatCount } from './node-material.js';
12
12
  import { getAttrBuffer, writeAttributeFlags } from './node-renderable.js';
13
13
 
14
14
  let _nodeGeometryGroupBuilder = null;