@babylonjs/lite 1.11.0 → 1.13.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 (105) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/index.js +444 -368
  3. package/dist/index.js.map +1 -1
  4. package/index.d.ts +208 -6
  5. package/lib/asset-container.js.map +1 -1
  6. package/lib/audio/index.js +1 -0
  7. package/lib/audio/index.js.map +1 -1
  8. package/lib/audio/media-stream-output.js +44 -0
  9. package/lib/audio/media-stream-output.js.map +1 -0
  10. package/lib/engine/engine.js +1 -1
  11. package/lib/frame-graph/render-task.js +1 -1
  12. package/lib/frame-graph/render-task.js.map +1 -1
  13. package/lib/frame-graph/shadow-inputs.js +10 -1
  14. package/lib/frame-graph/shadow-inputs.js.map +1 -1
  15. package/lib/frame-graph/transmission.js +1 -16
  16. package/lib/frame-graph/transmission.js.map +1 -1
  17. package/lib/index.js +6 -3
  18. package/lib/index.js.map +1 -1
  19. package/lib/loader-gltf/gltf-json-asset.js +1 -1
  20. package/lib/loader-gltf/gltf-json-asset.js.map +1 -1
  21. package/lib/loader-gltf/gltf-multi-buffer.js +2 -10
  22. package/lib/loader-gltf/gltf-multi-buffer.js.map +1 -1
  23. package/lib/loader-gltf/gltf-pbr-builder-ext.js +4 -18
  24. package/lib/loader-gltf/gltf-pbr-builder-ext.js.map +1 -1
  25. package/lib/loader-gltf/gltf-pbr-builder.js +17 -14
  26. package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
  27. package/lib/loader-gltf/gltf-sampler-desc.js +3 -16
  28. package/lib/loader-gltf/gltf-sampler-desc.js.map +1 -1
  29. package/lib/material/node/blocks/ambient-occlusion-block.js +1 -4
  30. package/lib/material/node/blocks/ambient-occlusion-block.js.map +1 -1
  31. package/lib/material/node/blocks/biplanar-block.js +3 -6
  32. package/lib/material/node/blocks/biplanar-block.js.map +1 -1
  33. package/lib/material/node/blocks/image-source.js +2 -5
  34. package/lib/material/node/blocks/image-source.js.map +1 -1
  35. package/lib/material/node/blocks/input-block.js +5 -26
  36. package/lib/material/node/blocks/input-block.js.map +1 -1
  37. package/lib/material/node/blocks/pbr-mr-helper-full.js +5 -8
  38. package/lib/material/node/blocks/pbr-mr-helper-full.js.map +1 -1
  39. package/lib/material/node/blocks/reflection-texture-block.js +1 -4
  40. package/lib/material/node/blocks/reflection-texture-block.js.map +1 -1
  41. package/lib/material/node/blocks/texture-block.js +2 -5
  42. package/lib/material/node/blocks/texture-block.js.map +1 -1
  43. package/lib/material/node/blocks/triplanar-block.js +3 -6
  44. package/lib/material/node/blocks/triplanar-block.js.map +1 -1
  45. package/lib/material/node/node-emitter.js +24 -1
  46. package/lib/material/node/node-emitter.js.map +1 -1
  47. package/lib/material/node/node-geometry-renderable.js +2 -2
  48. package/lib/material/node/node-material.js +1 -22
  49. package/lib/material/node/node-material.js.map +1 -1
  50. package/lib/material/node/node-types.js.map +1 -1
  51. package/lib/material/pbr/fragments/shadow-only-fragment.js +68 -0
  52. package/lib/material/pbr/fragments/shadow-only-fragment.js.map +1 -0
  53. package/lib/material/pbr/pbr-flag-bits.js.map +1 -1
  54. package/lib/material/pbr/pbr-material.js.map +1 -1
  55. package/lib/material/pbr/pbr-primitive-resolver.js +2 -2
  56. package/lib/material/pbr/pbr-primitive-resolver.js.map +1 -1
  57. package/lib/material/pbr/pbr-renderable.js +3 -0
  58. package/lib/material/pbr/pbr-renderable.js.map +1 -1
  59. package/lib/material/pbr/pbr-template.js +1 -0
  60. package/lib/material/pbr/pbr-template.js.map +1 -1
  61. package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js +2 -8
  62. package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js.map +1 -1
  63. package/lib/mesh/get-mesh-geometry.js +24 -0
  64. package/lib/mesh/get-mesh-geometry.js.map +1 -0
  65. package/lib/mesh/mesh-dispose.js +2 -0
  66. package/lib/mesh/mesh-dispose.js.map +1 -1
  67. package/lib/mesh/mesh.js +2 -8
  68. package/lib/mesh/mesh.js.map +1 -1
  69. package/lib/mesh/thin-instance-cull-binding.js +54 -3
  70. package/lib/mesh/thin-instance-cull-binding.js.map +1 -1
  71. package/lib/mesh/thin-instance-gpu-culling.js +241 -24
  72. package/lib/mesh/thin-instance-gpu-culling.js.map +1 -1
  73. package/lib/mesh/thin-instance.js +112 -1
  74. package/lib/mesh/thin-instance.js.map +1 -1
  75. package/lib/picking/gpu-picker.js +4 -2
  76. package/lib/picking/gpu-picker.js.map +1 -1
  77. package/lib/picking/picking-pipeline.js +1 -1
  78. package/lib/picking/picking-pipeline.js.map +1 -1
  79. package/lib/picking/picking-shader.js +38 -16
  80. package/lib/picking/picking-shader.js.map +1 -1
  81. package/lib/scene/scene-core.js +7 -2
  82. package/lib/scene/scene-core.js.map +1 -1
  83. package/lib/scene/scene-node.js +2 -6
  84. package/lib/scene/scene-node.js.map +1 -1
  85. package/lib/scene/scene-remove.js +70 -1
  86. package/lib/scene/scene-remove.js.map +1 -1
  87. package/lib/scene/transform-node.js +3 -0
  88. package/lib/scene/transform-node.js.map +1 -1
  89. package/lib/scene/world-matrix-state.js +7 -1
  90. package/lib/scene/world-matrix-state.js.map +1 -1
  91. package/lib/shadow/csm-directional-shadow-generator.js +22 -1
  92. package/lib/shadow/csm-directional-shadow-generator.js.map +1 -1
  93. package/lib/shadow/csm-shadow-task-hooks.js +19 -11
  94. package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
  95. package/lib/shadow/esm-directional-shadow-generator.js +2 -51
  96. package/lib/shadow/esm-directional-shadow-generator.js.map +1 -1
  97. package/lib/shadow/pcf-directional-shadow-generator.js +2 -48
  98. package/lib/shadow/pcf-directional-shadow-generator.js.map +1 -1
  99. package/lib/shadow/shadow-base.js +48 -1
  100. package/lib/shadow/shadow-base.js.map +1 -1
  101. package/lib/text/text-renderable.js +2 -10
  102. package/lib/text/text-renderable.js.map +1 -1
  103. package/lib/texture/texture-array.js +96 -0
  104. package/lib/texture/texture-array.js.map +1 -0
  105. package/package.json +3 -3
@@ -1,23 +1,5 @@
1
1
  import { WGSL } from '../node-types.js';
2
2
 
3
- function bjsTypeToNodeType(t) {
4
- if (t === 1 || t === 2) {
5
- return "f32";
6
- }
7
- if (t === 4) {
8
- return "vec2f";
9
- }
10
- if (t === 8 || t === 32) {
11
- return "vec3f";
12
- }
13
- if (t === 16 || t === 64) {
14
- return "vec4f";
15
- }
16
- if (t === 128) {
17
- return "mat4f";
18
- }
19
- throw new Error(`InputBlock: unsupported BJS connection point type 0x${t.toString(16)}`);
20
- }
21
3
  const ATTRIBUTE_TYPES = {
22
4
  position: "vec3f",
23
5
  normal: "vec3f",
@@ -78,21 +60,18 @@ function emitSystemValue(block, stage, state) {
78
60
  throw new Error(`InputBlock: unsupported systemValue ${sv} on block "${block.name}"`);
79
61
  }
80
62
  }
81
- function emitUniform(block, state) {
63
+ function emitUniform(block, state, ctx) {
82
64
  const portType = block.serialized["type"] ?? 16;
83
- const type = bjsTypeToNodeType(portType);
84
- const fieldName = sanitize(block.name || `input${block.id}`);
65
+ const type = ctx.bjsTypeToNodeType(portType, "InputBlock");
66
+ const fieldName = ctx.sanitize(block.name || `input${block.id}`);
85
67
  if (!state.nodeUboFields.find((f) => f._name === fieldName)) {
86
68
  state.nodeUboFields.push({ _name: fieldName, _type: WGSL[type] });
87
69
  }
88
70
  return { expr: `nodeU.${fieldName}`, type };
89
71
  }
90
- function sanitize(name) {
91
- return name.replace(/[^A-Za-z0-9_]/g, "_");
92
- }
93
72
  const emitter = {
94
73
  className: "InputBlock",
95
- emit(block, _outputName, stage, state, _ctx) {
74
+ emit(block, _outputName, stage, state, ctx) {
96
75
  const mode = block.serialized["mode"] ?? block.serialized["_mode"];
97
76
  if (mode === 1) {
98
77
  return emitAttribute(block, stage, state);
@@ -101,7 +80,7 @@ const emitter = {
101
80
  if (typeof sv === "number") {
102
81
  return emitSystemValue(block);
103
82
  }
104
- return emitUniform(block, state);
83
+ return emitUniform(block, state, ctx);
105
84
  }
106
85
  };
107
86
 
@@ -1 +1 @@
1
- {"version":3,"file":"input-block.js","sources":["../../../../../src/material/node/blocks/input-block.ts"],"sourcesContent":["/** InputBlock emitter.\n *\n * Three modes (BJS NodeMaterialBlockConnectionPointMode):\n * 0 = Uniform — inline value becomes a field in the node UBO.\n * 1 = Attribute — bound to a vertex attribute (position/normal/uv/...).\n * 2 = Varying — interpolated from a system/pre-existing varying.\n *\n * For attributes we declare the vertex attribute (dedup by name) and, if the\n * value is consumed in fragment stage, a varying to carry it across.\n */\n\nimport type { BlockEmitter, NodeBuildState, NodeExpr, NodeValueType, Stage, NodeBlock } from \"../node-types.js\";\nimport { WGSL } from \"../node-types.js\";\n\ntype BjsType = number; // NodeMaterialBlockConnectionPointTypes\n\nfunction bjsTypeToNodeType(t: BjsType): NodeValueType {\n // bitflags: 0x1=Float, 0x4=Vec2, 0x8=Vec3, 0x10=Vec4, 0x20=Color3, 0x40=Color4\n if (t === 0x1 || t === 0x2) {\n return \"f32\";\n }\n if (t === 0x4) {\n return \"vec2f\";\n }\n if (t === 0x8 || t === 0x20) {\n return \"vec3f\";\n }\n if (t === 0x10 || t === 0x40) {\n return \"vec4f\";\n }\n if (t === 0x80) {\n return \"mat4f\";\n }\n throw new Error(`InputBlock: unsupported BJS connection point type 0x${t.toString(16)}`);\n}\n\nfunction wgslLiteral(value: unknown, type: NodeValueType): string {\n if (type === \"f32\") {\n const f = typeof value === \"number\" ? value : 0;\n return formatFloat(f);\n }\n if (Array.isArray(value)) {\n const parts = value.map((v) => formatFloat(typeof v === \"number\" ? v : 0)).join(\", \");\n return `${WGSL[type]}(${parts})`;\n }\n // Fallback to zero.\n if (type === \"vec2f\") {\n return \"vec2<f32>(0.0, 0.0)\";\n }\n if (type === \"vec3f\") {\n return \"vec3<f32>(0.0, 0.0, 0.0)\";\n }\n if (type === \"vec4f\") {\n return \"vec4<f32>(0.0, 0.0, 0.0, 0.0)\";\n }\n return \"0.0\";\n}\n\nfunction formatFloat(n: number): string {\n if (Number.isInteger(n)) {\n return `${n}.0`;\n }\n return `${n}`;\n}\n\n// Known mesh attributes — maps InputBlock.name → WGSL type.\nconst ATTRIBUTE_TYPES: Record<string, NodeValueType> = {\n position: \"vec3f\",\n normal: \"vec3f\",\n tangent: \"vec4f\",\n uv: \"vec2f\",\n uv2: \"vec2f\",\n color: \"vec4f\",\n matricesIndices: \"vec4f\",\n matricesWeights: \"vec4f\",\n matricesIndicesExtra: \"vec4f\",\n matricesWeightsExtra: \"vec4f\",\n};\n\nfunction emitAttribute(block: NodeBlock, stage: Stage, state: NodeBuildState): NodeExpr {\n const attrName = block.name;\n const type = ATTRIBUTE_TYPES[attrName];\n if (!type) {\n throw new Error(`InputBlock: unknown mesh attribute \"${attrName}\"`);\n }\n const wgslType = WGSL[type];\n // Dedup vertex attribute.\n if (!state.vertexAttributes.find((a) => a._name === attrName)) {\n state.vertexAttributes.push({\n _name: attrName,\n _type: wgslType,\n _gpuFormat: type === \"vec2f\" ? \"float32x2\" : type === \"vec3f\" ? \"float32x3\" : \"float32x4\",\n _arrayStride: (type === \"vec2f\" ? 2 : type === \"vec3f\" ? 3 : 4) * 4,\n });\n }\n if (stage === \"vertex\") {\n return { expr: `in.${attrName}`, type };\n }\n // In fragment stage — bridge through a varying (idempotent).\n const vname = `v_attr_${attrName}`;\n if (!state.varyings.find((v) => v._name === vname)) {\n state.varyings.push({ _name: vname, _type: wgslType });\n state.vertex.body.push(`out.${vname} = in.${attrName};`);\n }\n return { expr: `in.${vname}`, type };\n}\n\n// BJS NodeMaterialSystemValues enum (Babylon.js master).\n// We map the commonly used ones to WGSL expressions sourced from scene/mesh UBOs.\n// For matrices not present in Lite's scene UBO (`projection` alone), we fall\n// back to the closest valid expression (or throw — caller decides).\nfunction emitSystemValue(block: NodeBlock, stage: Stage, state: NodeBuildState): NodeExpr {\n const sv = block.serialized[\"systemValue\"] as number | undefined;\n // Only sensible in the vertex stage for matrix types; for CameraPosition/FogColor either stage is fine.\n switch (sv) {\n case 1: // World\n return { expr: \"meshU.world\", type: \"mat4f\" };\n case 2: // View\n return { expr: \"sceneU.view\", type: \"mat4f\" };\n case 3: // Projection\n return { expr: \"sceneU.projection\", type: \"mat4f\" };\n case 4: // ViewProjection\n return { expr: \"sceneU.viewProjection\", type: \"mat4f\" };\n case 5: // WorldView\n return { expr: \"(sceneU.view * meshU.world)\", type: \"mat4f\" };\n case 6: // WorldViewProjection\n return { expr: \"(sceneU.viewProjection * meshU.world)\", type: \"mat4f\" };\n case 7: // CameraPosition\n return { expr: \"sceneU.vEyePosition.xyz\", type: \"vec3f\" };\n case 8: // FogColor\n return { expr: \"sceneU.vFogColor.xyz\", type: \"vec3f\" };\n default:\n throw new Error(`InputBlock: unsupported systemValue ${sv} on block \"${block.name}\"`);\n }\n void stage;\n void state;\n}\n\nfunction emitUniform(block: NodeBlock, state: NodeBuildState): NodeExpr {\n // Determine the WGSL type. BJS serializes the port type under `type`.\n const portType = (block.serialized[\"type\"] as BjsType | undefined) ?? 0x10;\n const type = bjsTypeToNodeType(portType);\n // UBO field name — use block name (must be unique; parser enforces via namedInputs key).\n const fieldName = sanitize(block.name || `input${block.id}`);\n // Dedup.\n if (!state.nodeUboFields.find((f) => f._name === fieldName)) {\n state.nodeUboFields.push({ _name: fieldName, _type: WGSL[type] as any });\n // If this is a literal value (no override yet), it will be written into the\n // UBO at material-build time; for shader generation we just reference the field.\n // We ignore the inline literal here — the UBO write path handles that.\n }\n void wgslLiteral; // reserved for future default-literal constant-fold optimization\n return { expr: `nodeU.${fieldName}`, type };\n}\n\nfunction sanitize(name: string): string {\n return name.replace(/[^A-Za-z0-9_]/g, \"_\");\n}\n\nexport const emitter: BlockEmitter = {\n className: \"InputBlock\",\n emit(block, _outputName, stage, state, _ctx) {\n const mode = (block.serialized[\"mode\"] ?? block.serialized[\"_mode\"]) as number | undefined;\n if (mode === 1) {\n return emitAttribute(block, stage, state);\n }\n // System-value uniforms (World, WVP, CameraPosition, …) come from scene/mesh UBOs\n // rather than the material's node UBO, so they never appear in `nodeUboFields`.\n const sv = block.serialized[\"systemValue\"];\n if (typeof sv === \"number\") {\n return emitSystemValue(block, stage, state);\n }\n // Default to Uniform (mode 0 or unspecified).\n return emitUniform(block, state);\n },\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"input-block.js","sources":["../../../../../src/material/node/blocks/input-block.ts"],"sourcesContent":["/** InputBlock emitter.\n *\n * Three modes (BJS NodeMaterialBlockConnectionPointMode):\n * 0 = Uniform — inline value becomes a field in the node UBO.\n * 1 = Attribute — bound to a vertex attribute (position/normal/uv/...).\n * 2 = Varying — interpolated from a system/pre-existing varying.\n *\n * For attributes we declare the vertex attribute (dedup by name) and, if the\n * value is consumed in fragment stage, a varying to carry it across.\n */\n\nimport type { BlockEmitter, NodeBuildState, NodeEmitContext, NodeExpr, NodeValueType, Stage, NodeBlock } from \"../node-types.js\";\nimport { WGSL } from \"../node-types.js\";\n\ntype BjsType = number; // NodeMaterialBlockConnectionPointTypes\n\nfunction wgslLiteral(value: unknown, type: NodeValueType): string {\n if (type === \"f32\") {\n const f = typeof value === \"number\" ? value : 0;\n return formatFloat(f);\n }\n if (Array.isArray(value)) {\n const parts = value.map((v) => formatFloat(typeof v === \"number\" ? v : 0)).join(\", \");\n return `${WGSL[type]}(${parts})`;\n }\n // Fallback to zero.\n if (type === \"vec2f\") {\n return \"vec2<f32>(0.0, 0.0)\";\n }\n if (type === \"vec3f\") {\n return \"vec3<f32>(0.0, 0.0, 0.0)\";\n }\n if (type === \"vec4f\") {\n return \"vec4<f32>(0.0, 0.0, 0.0, 0.0)\";\n }\n return \"0.0\";\n}\n\nfunction formatFloat(n: number): string {\n if (Number.isInteger(n)) {\n return `${n}.0`;\n }\n return `${n}`;\n}\n\n// Known mesh attributes — maps InputBlock.name → WGSL type.\nconst ATTRIBUTE_TYPES: Record<string, NodeValueType> = {\n position: \"vec3f\",\n normal: \"vec3f\",\n tangent: \"vec4f\",\n uv: \"vec2f\",\n uv2: \"vec2f\",\n color: \"vec4f\",\n matricesIndices: \"vec4f\",\n matricesWeights: \"vec4f\",\n matricesIndicesExtra: \"vec4f\",\n matricesWeightsExtra: \"vec4f\",\n};\n\nfunction emitAttribute(block: NodeBlock, stage: Stage, state: NodeBuildState): NodeExpr {\n const attrName = block.name;\n const type = ATTRIBUTE_TYPES[attrName];\n if (!type) {\n throw new Error(`InputBlock: unknown mesh attribute \"${attrName}\"`);\n }\n const wgslType = WGSL[type];\n // Dedup vertex attribute.\n if (!state.vertexAttributes.find((a) => a._name === attrName)) {\n state.vertexAttributes.push({\n _name: attrName,\n _type: wgslType,\n _gpuFormat: type === \"vec2f\" ? \"float32x2\" : type === \"vec3f\" ? \"float32x3\" : \"float32x4\",\n _arrayStride: (type === \"vec2f\" ? 2 : type === \"vec3f\" ? 3 : 4) * 4,\n });\n }\n if (stage === \"vertex\") {\n return { expr: `in.${attrName}`, type };\n }\n // In fragment stage — bridge through a varying (idempotent).\n const vname = `v_attr_${attrName}`;\n if (!state.varyings.find((v) => v._name === vname)) {\n state.varyings.push({ _name: vname, _type: wgslType });\n state.vertex.body.push(`out.${vname} = in.${attrName};`);\n }\n return { expr: `in.${vname}`, type };\n}\n\n// BJS NodeMaterialSystemValues enum (Babylon.js master).\n// We map the commonly used ones to WGSL expressions sourced from scene/mesh UBOs.\n// For matrices not present in Lite's scene UBO (`projection` alone), we fall\n// back to the closest valid expression (or throw — caller decides).\nfunction emitSystemValue(block: NodeBlock, stage: Stage, state: NodeBuildState): NodeExpr {\n const sv = block.serialized[\"systemValue\"] as number | undefined;\n // Only sensible in the vertex stage for matrix types; for CameraPosition/FogColor either stage is fine.\n switch (sv) {\n case 1: // World\n return { expr: \"meshU.world\", type: \"mat4f\" };\n case 2: // View\n return { expr: \"sceneU.view\", type: \"mat4f\" };\n case 3: // Projection\n return { expr: \"sceneU.projection\", type: \"mat4f\" };\n case 4: // ViewProjection\n return { expr: \"sceneU.viewProjection\", type: \"mat4f\" };\n case 5: // WorldView\n return { expr: \"(sceneU.view * meshU.world)\", type: \"mat4f\" };\n case 6: // WorldViewProjection\n return { expr: \"(sceneU.viewProjection * meshU.world)\", type: \"mat4f\" };\n case 7: // CameraPosition\n return { expr: \"sceneU.vEyePosition.xyz\", type: \"vec3f\" };\n case 8: // FogColor\n return { expr: \"sceneU.vFogColor.xyz\", type: \"vec3f\" };\n default:\n throw new Error(`InputBlock: unsupported systemValue ${sv} on block \"${block.name}\"`);\n }\n void stage;\n void state;\n}\n\nfunction emitUniform(block: NodeBlock, state: NodeBuildState, ctx: NodeEmitContext): NodeExpr {\n // Determine the WGSL type. BJS serializes the port type under `type`.\n const portType = (block.serialized[\"type\"] as BjsType | undefined) ?? 0x10;\n const type = ctx.bjsTypeToNodeType(portType, \"InputBlock\");\n // UBO field name — use block name (must be unique; parser enforces via namedInputs key).\n const fieldName = ctx.sanitize(block.name || `input${block.id}`);\n // Dedup.\n if (!state.nodeUboFields.find((f) => f._name === fieldName)) {\n state.nodeUboFields.push({ _name: fieldName, _type: WGSL[type] as any });\n // If this is a literal value (no override yet), it will be written into the\n // UBO at material-build time; for shader generation we just reference the field.\n // We ignore the inline literal here — the UBO write path handles that.\n }\n void wgslLiteral; // reserved for future default-literal constant-fold optimization\n return { expr: `nodeU.${fieldName}`, type };\n}\n\nexport const emitter: BlockEmitter = {\n className: \"InputBlock\",\n emit(block, _outputName, stage, state, ctx) {\n const mode = (block.serialized[\"mode\"] ?? block.serialized[\"_mode\"]) as number | undefined;\n if (mode === 1) {\n return emitAttribute(block, stage, state);\n }\n // System-value uniforms (World, WVP, CameraPosition, …) come from scene/mesh UBOs\n // rather than the material's node UBO, so they never appear in `nodeUboFields`.\n const sv = block.serialized[\"systemValue\"];\n if (typeof sv === \"number\") {\n return emitSystemValue(block, stage, state);\n }\n // Default to Uniform (mode 0 or unspecified).\n return emitUniform(block, state, ctx);\n },\n};\n"],"names":[],"mappings":"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"}
@@ -137,17 +137,14 @@ let ccNdfdy_AA = dpdy(ccNormalW);
137
137
  let ccSlopeSquare_AA = max(dot(ccNdfdx_AA, ccNdfdx_AA), dot(ccNdfdy_AA, ccNdfdy_AA));
138
138
  ccAA_factor_y = sqrt(ccSlopeSquare_AA) * 0.75; }` : ``}
139
139
  let ccAlphaG = ccRough * ccRough + 0.0005 + ccAA_factor_y;` : ``;
140
- const ccNormalSetup = useClearcoat ? useCcBump ? `let ccNormalW = nme_perturbNormal(worldPos, Ng, ccBumpUv, ccBumpColor, 1.0);
141
- let ccNdotV = abs(dot(ccNormalW, V)) + 0.0000001;${useCcTint ? `
140
+ const ccTintViewSetup = useCcTint ? `
142
141
  let ccIorInv = 1.0 / max(ccIor, 1.0001);
143
142
  let ccAbsorptionColor = nme_pbr_colorAtDistance(max(ccTintColor, v3(0.0000001)), max(ccTintAtDistance, 0.0000001));
144
143
  let ccVRefract = refract(-V, ccNormalW, ccIorInv);
145
- let ccNdotVRefract = abs(dot(ccNormalW, ccVRefract)) + 0.0000001;` : ``}` : `let ccNormalW = Ng;
146
- let ccNdotV = abs(dot(ccNormalW, V)) + 0.0000001;${useCcTint ? `
147
- let ccIorInv = 1.0 / max(ccIor, 1.0001);
148
- let ccAbsorptionColor = nme_pbr_colorAtDistance(max(ccTintColor, v3(0.0000001)), max(ccTintAtDistance, 0.0000001));
149
- let ccVRefract = refract(-V, ccNormalW, ccIorInv);
150
- let ccNdotVRefract = abs(dot(ccNormalW, ccVRefract)) + 0.0000001;` : ``}` : `let ccNormalW = N;
144
+ let ccNdotVRefract = abs(dot(ccNormalW, ccVRefract)) + 0.0000001;` : ``;
145
+ const ccNormalSetup = useClearcoat ? useCcBump ? `let ccNormalW = nme_perturbNormal(worldPos, Ng, ccBumpUv, ccBumpColor, 1.0);
146
+ let ccNdotV = abs(dot(ccNormalW, V)) + 0.0000001;${ccTintViewSetup}` : `let ccNormalW = Ng;
147
+ let ccNdotV = abs(dot(ccNormalW, V)) + 0.0000001;${ccTintViewSetup}` : `let ccNormalW = N;
151
148
  let ccNdotV: f32 = 0.0;`;
152
149
  const shDecls = useSheen ? `let shIntensityRaw = clamp(shIntensityIn, 0.0, 1.0);
153
150
  ${useShAlbedoScaling ? `let shIntensity = shIntensityRaw;` : `let reflectanceF0 = max(colorF0.r, max(colorF0.g, colorF0.b));
@@ -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