@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.
- package/CHANGELOG.md +35 -0
- package/dist/index.js +444 -368
- package/dist/index.js.map +1 -1
- package/index.d.ts +208 -6
- package/lib/asset-container.js.map +1 -1
- package/lib/audio/index.js +1 -0
- package/lib/audio/index.js.map +1 -1
- package/lib/audio/media-stream-output.js +44 -0
- package/lib/audio/media-stream-output.js.map +1 -0
- package/lib/engine/engine.js +1 -1
- package/lib/frame-graph/render-task.js +1 -1
- package/lib/frame-graph/render-task.js.map +1 -1
- package/lib/frame-graph/shadow-inputs.js +10 -1
- package/lib/frame-graph/shadow-inputs.js.map +1 -1
- package/lib/frame-graph/transmission.js +1 -16
- package/lib/frame-graph/transmission.js.map +1 -1
- package/lib/index.js +6 -3
- package/lib/index.js.map +1 -1
- package/lib/loader-gltf/gltf-json-asset.js +1 -1
- package/lib/loader-gltf/gltf-json-asset.js.map +1 -1
- package/lib/loader-gltf/gltf-multi-buffer.js +2 -10
- package/lib/loader-gltf/gltf-multi-buffer.js.map +1 -1
- package/lib/loader-gltf/gltf-pbr-builder-ext.js +4 -18
- package/lib/loader-gltf/gltf-pbr-builder-ext.js.map +1 -1
- package/lib/loader-gltf/gltf-pbr-builder.js +17 -14
- package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
- package/lib/loader-gltf/gltf-sampler-desc.js +3 -16
- package/lib/loader-gltf/gltf-sampler-desc.js.map +1 -1
- package/lib/material/node/blocks/ambient-occlusion-block.js +1 -4
- package/lib/material/node/blocks/ambient-occlusion-block.js.map +1 -1
- package/lib/material/node/blocks/biplanar-block.js +3 -6
- package/lib/material/node/blocks/biplanar-block.js.map +1 -1
- package/lib/material/node/blocks/image-source.js +2 -5
- package/lib/material/node/blocks/image-source.js.map +1 -1
- package/lib/material/node/blocks/input-block.js +5 -26
- package/lib/material/node/blocks/input-block.js.map +1 -1
- package/lib/material/node/blocks/pbr-mr-helper-full.js +5 -8
- package/lib/material/node/blocks/pbr-mr-helper-full.js.map +1 -1
- package/lib/material/node/blocks/reflection-texture-block.js +1 -4
- package/lib/material/node/blocks/reflection-texture-block.js.map +1 -1
- package/lib/material/node/blocks/texture-block.js +2 -5
- package/lib/material/node/blocks/texture-block.js.map +1 -1
- package/lib/material/node/blocks/triplanar-block.js +3 -6
- package/lib/material/node/blocks/triplanar-block.js.map +1 -1
- package/lib/material/node/node-emitter.js +24 -1
- package/lib/material/node/node-emitter.js.map +1 -1
- package/lib/material/node/node-geometry-renderable.js +2 -2
- package/lib/material/node/node-material.js +1 -22
- package/lib/material/node/node-material.js.map +1 -1
- package/lib/material/node/node-types.js.map +1 -1
- package/lib/material/pbr/fragments/shadow-only-fragment.js +68 -0
- package/lib/material/pbr/fragments/shadow-only-fragment.js.map +1 -0
- package/lib/material/pbr/pbr-flag-bits.js.map +1 -1
- package/lib/material/pbr/pbr-material.js.map +1 -1
- package/lib/material/pbr/pbr-primitive-resolver.js +2 -2
- package/lib/material/pbr/pbr-primitive-resolver.js.map +1 -1
- package/lib/material/pbr/pbr-renderable.js +3 -0
- package/lib/material/pbr/pbr-renderable.js.map +1 -1
- package/lib/material/pbr/pbr-template.js +1 -0
- package/lib/material/pbr/pbr-template.js.map +1 -1
- package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js +2 -8
- package/lib/mesh/GaussianSplatting/gaussian-splatting-mesh.js.map +1 -1
- package/lib/mesh/get-mesh-geometry.js +24 -0
- package/lib/mesh/get-mesh-geometry.js.map +1 -0
- package/lib/mesh/mesh-dispose.js +2 -0
- package/lib/mesh/mesh-dispose.js.map +1 -1
- package/lib/mesh/mesh.js +2 -8
- package/lib/mesh/mesh.js.map +1 -1
- package/lib/mesh/thin-instance-cull-binding.js +54 -3
- package/lib/mesh/thin-instance-cull-binding.js.map +1 -1
- package/lib/mesh/thin-instance-gpu-culling.js +241 -24
- package/lib/mesh/thin-instance-gpu-culling.js.map +1 -1
- package/lib/mesh/thin-instance.js +112 -1
- package/lib/mesh/thin-instance.js.map +1 -1
- package/lib/picking/gpu-picker.js +4 -2
- package/lib/picking/gpu-picker.js.map +1 -1
- package/lib/picking/picking-pipeline.js +1 -1
- package/lib/picking/picking-pipeline.js.map +1 -1
- package/lib/picking/picking-shader.js +38 -16
- package/lib/picking/picking-shader.js.map +1 -1
- package/lib/scene/scene-core.js +7 -2
- package/lib/scene/scene-core.js.map +1 -1
- package/lib/scene/scene-node.js +2 -6
- package/lib/scene/scene-node.js.map +1 -1
- package/lib/scene/scene-remove.js +70 -1
- package/lib/scene/scene-remove.js.map +1 -1
- package/lib/scene/transform-node.js +3 -0
- package/lib/scene/transform-node.js.map +1 -1
- package/lib/scene/world-matrix-state.js +7 -1
- package/lib/scene/world-matrix-state.js.map +1 -1
- package/lib/shadow/csm-directional-shadow-generator.js +22 -1
- package/lib/shadow/csm-directional-shadow-generator.js.map +1 -1
- package/lib/shadow/csm-shadow-task-hooks.js +19 -11
- package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
- package/lib/shadow/esm-directional-shadow-generator.js +2 -51
- package/lib/shadow/esm-directional-shadow-generator.js.map +1 -1
- package/lib/shadow/pcf-directional-shadow-generator.js +2 -48
- package/lib/shadow/pcf-directional-shadow-generator.js.map +1 -1
- package/lib/shadow/shadow-base.js +48 -1
- package/lib/shadow/shadow-base.js.map +1 -1
- package/lib/text/text-renderable.js +2 -10
- package/lib/text/text-renderable.js.map +1 -1
- package/lib/texture/texture-array.js +96 -0
- package/lib/texture/texture-array.js.map +1 -0
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-emitter.js","sources":["../../../../src/material/node/node-emitter.ts"],"sourcesContent":["/** Node Material — WGSL emitter core.\n *\n * Given a parsed NodeGraph, walk it topologically from the FragmentOutput +\n * VertexOutput roots, calling each block's emitter to emit WGSL. The emitter\n * API guarantees that every (blockId, outputName) is emitted at most once per\n * stage (memoization), so downstream consumers share the same SSA temp.\n *\n * The result is a pair of WGSL source strings (vertex + fragment) plus the\n * accumulated UBO fields, attributes, varyings, samplers, and texture bindings\n * needed by the pipeline builder. This module intentionally has no WGSL of its\n * own beyond empty scaffolding — every shader string comes from a block emitter\n * so each block tree-shakes independently.\n */\n\nimport type { NodeBlock, NodeBuildState, NodeEmitContext, NodeExpr, NodeGraph, NodeValueType, Stage, StageState, BlockEmitter } from \"./node-types.js\";\nimport { WGSL } from \"./node-types.js\";\n\n// ─── Build-state construction ───────────────────────────────────────\n\nfunction newStageState(): StageState {\n return {\n helpers: new Map(),\n body: [],\n memo: new Map(),\n };\n}\n\nexport function createBuildState(): NodeBuildState {\n return {\n vertex: newStageState(),\n fragment: newStageState(),\n vertexAttributes: [],\n varyings: [],\n nodeUboFields: [],\n bindings: [],\n textures: [],\n pbrMrHelperRequests: [],\n loopVariables: new Map(),\n nextTemp: 0,\n usesLightsUbo: false,\n usesScreenSize: false,\n usesFragDepth: false,\n usesClipPlanes: false,\n usesMeshAttributeExists: false,\n usesMorphTargets: false,\n usesEnv: false,\n usesClearcoat: false,\n usesSheen: false,\n usesAnisotropy: false,\n usesIridescence: false,\n usesSubsurface: false,\n shadowLights: [],\n hasSkeleton: false,\n hasInstances: false,\n };\n}\n\n// ─── Emitter context ────────────────────────────────────────────────\n\nfunction memoKey(blockId: number, outputName: string): string {\n return `${blockId}|${outputName}`;\n}\n\nfunction stageOf(state: NodeBuildState, stage: Stage): StageState {\n return stage === \"vertex\" ? state.vertex : state.fragment;\n}\n\n/** Mint a fresh SSA temp name. */\nexport function mintTemp(state: NodeBuildState, prefix = \"t\"): string {\n const id = state.nextTemp++;\n return `_${prefix}${id}`;\n}\n\n/** Cast a typed WGSL expression to a target type. Throws if no cast is known.\n * Handles the common vector-widen/narrow cases that NME graphs actually use. */\nexport function castExpr(value: NodeExpr, target: NodeValueType): NodeExpr {\n if (value.type === target) {\n return value;\n }\n const t = WGSL[target];\n // Narrowing: vec4 -> vec3/vec2/f32 via .xyz/.xy/.x\n if (value.type === \"vec4f\" && target === \"vec3f\") {\n return { expr: `(${value.expr}).xyz`, type: target };\n }\n if (value.type === \"vec4f\" && target === \"vec2f\") {\n return { expr: `(${value.expr}).xy`, type: target };\n }\n if (value.type === \"vec3f\" && target === \"vec2f\") {\n return { expr: `(${value.expr}).xy`, type: target };\n }\n if ((value.type === \"vec4f\" || value.type === \"vec3f\" || value.type === \"vec2f\") && target === \"f32\") {\n return { expr: `(${value.expr}).x`, type: target };\n }\n // Widening: f32 -> vecN, vec3 -> vec4 (w=1)\n if (value.type === \"f32\" && (target === \"vec2f\" || target === \"vec3f\" || target === \"vec4f\")) {\n return { expr: `${t}(${value.expr})`, type: target };\n }\n if (value.type === \"vec3f\" && target === \"vec4f\") {\n return { expr: `vec4<f32>(${value.expr}, 1.0)`, type: target };\n }\n if (value.type === \"vec2f\" && target === \"vec4f\") {\n return { expr: `vec4<f32>(${value.expr}, 0.0, 1.0)`, type: target };\n }\n if (value.type === \"vec2f\" && target === \"vec3f\") {\n return { expr: `vec3<f32>(${value.expr}, 0.0)`, type: target };\n }\n throw new Error(`NodeMaterial: cannot cast ${value.type} to ${target} for expression \\`${value.expr}\\``);\n}\n\nfunction makeContext(graph: NodeGraph, loadedEmitters: Map<string, BlockEmitter>): NodeEmitContext {\n const ctx: NodeEmitContext = {\n graph,\n _loadedEmitters: loadedEmitters,\n temp: (state, prefix) => mintTemp(state, prefix),\n cast: castExpr,\n resolve: (block, inputName, stage, state) => {\n const input = block.inputs.get(inputName);\n if (!input) {\n throw new Error(`NodeMaterial: block \"${block.className}\" (id=${block.id}) has no input \"${inputName}\"`);\n }\n if (!input.source) {\n throw new Error(`NodeMaterial: block \"${block.className}\" (id=${block.id}) input \"${inputName}\" is not connected`);\n }\n const producer = graph.blocks.get(input.source.blockId);\n if (!producer) {\n throw new Error(`NodeMaterial: dangling connection ${block.id}.${inputName} -> block ${input.source.blockId}`);\n }\n return ctx.resolveOutput(producer, input.source.outputName, stage, state);\n },\n resolveOutput: (producer, outputName, stage, state) => {\n const stageState = stageOf(state, stage);\n const key = memoKey(producer.id, outputName);\n const existing = stageState.memo.get(key);\n if (existing) {\n return existing;\n }\n const emitter = loadedEmitters.get(producer.className);\n if (!emitter) {\n throw new Error(`NodeMaterial: no emitter loaded for block \"${producer.className}\"`);\n }\n // Blocks that declare a stage preference override the requested stage.\n const targetStage = emitter.stage ?? stage;\n const result = emitter.emit(producer, outputName, targetStage, state, ctx);\n // If the producer ran in a different stage, bridge via varying.\n if (targetStage !== stage) {\n const vname = `v_${producer.id}_${outputName}`;\n bridgeVarying(state, vname, result, targetStage, stage);\n const bridged: NodeExpr = { expr: `in.${vname}`, type: result.type };\n stageState.memo.set(key, bridged);\n return bridged;\n }\n stageState.memo.set(key, result);\n return result;\n },\n };\n return ctx;\n}\n\nfunction bridgeVarying(state: NodeBuildState, varyingName: string, value: NodeExpr, from: Stage, to: Stage): void {\n if (from !== \"vertex\" || to !== \"fragment\") {\n throw new Error(\"NodeMaterial: only vertex->fragment varyings are supported\");\n }\n const already = state.varyings.find((v) => v._name === varyingName);\n if (!already) {\n state.varyings.push({ _name: varyingName, _type: WGSL[value.type] });\n state.vertex.body.push(`out.${varyingName} = ${value.expr};`);\n }\n}\n\n// ─── Emitter dispatch ───────────────────────────────────────────────\n\n/** Load all emitters referenced by the graph in a single parallel batch. */\nlet defaultRegistry: Promise<typeof import(\"./node-registry.js\")> | null = null;\nasync function defaultBlockLoader(className: string): Promise<BlockEmitter> {\n defaultRegistry ??= import(\"./node-registry.js\");\n return (await defaultRegistry).loadBlockEmitter(className);\n}\n\nfunction pbrMrBlockNeedsFullEmitter(block: NodeBlock): boolean {\n return (\n (block.serialized as { enableSpecularAntiAliasing?: boolean }).enableSpecularAntiAliasing === true ||\n !!block.inputs.get(\"clearcoat\")?.source ||\n !!block.inputs.get(\"sheen\")?.source ||\n !!block.inputs.get(\"subsurface\")?.source ||\n !!block.inputs.get(\"anisotropy\")?.source ||\n !!block.inputs.get(\"iridescence\")?.source\n );\n}\n\nfunction graphNeedsFullPbrMrEmitter(graph: NodeGraph): boolean {\n for (const block of graph.blocks.values()) {\n if (block.className === \"PBRMetallicRoughnessBlock\" && pbrMrBlockNeedsFullEmitter(block)) {\n return true;\n }\n }\n return false;\n}\n\nexport async function loadGraphEmitters(graph: NodeGraph, blockLoader: (className: string) => Promise<BlockEmitter> = defaultBlockLoader): Promise<Map<string, BlockEmitter>> {\n const classNames = new Set<string>();\n for (const b of graph.blocks.values()) {\n classNames.add(b.className);\n }\n const map = new Map<string, BlockEmitter>();\n const useFullPbrMrEmitter = blockLoader === defaultBlockLoader && graphNeedsFullPbrMrEmitter(graph);\n await Promise.all(\n Array.from(classNames).map(async (className) => {\n const loaderKey = className === \"PBRMetallicRoughnessBlock\" && useFullPbrMrEmitter ? \"PBRMetallicRoughnessBlock__full\" : className;\n const e = await blockLoader(loaderKey);\n map.set(className, e);\n })\n );\n return map;\n}\n\n// ─── Public entry ───────────────────────────────────────────────────\n\nexport interface EmitResult {\n readonly vertexWgsl: string;\n readonly fragmentWgsl: string;\n readonly state: NodeBuildState;\n}\n\n/** Walk the graph from the given root (a FragmentOutput or VertexOutput block)\n * and emit the pair of WGSL shader strings. The caller is responsible for\n * wrapping the result with the pipeline's bind-group / entry-point scaffolding\n * (done by `node-pipeline.ts`). */\nexport function emitGraph(\n graph: NodeGraph,\n loadedEmitters: Map<string, BlockEmitter>,\n fragmentRootId: number,\n vertexRootId: number | null,\n shadowLights?: readonly { lightIndex: number; shadowType: \"esm\" | \"pcf\" }[],\n meshCaps?: { hasSkeleton?: boolean; hasInstances?: boolean }\n): EmitResult {\n const state = createBuildState();\n if (shadowLights) {\n for (const sl of shadowLights) {\n state.shadowLights.push(sl);\n }\n }\n if (meshCaps) {\n if (meshCaps.hasSkeleton) {\n state.hasSkeleton = true;\n }\n if (meshCaps.hasInstances) {\n state.hasInstances = true;\n }\n }\n const ctx = makeContext(graph, loadedEmitters);\n\n // Emit fragment root.\n const fragRoot = graph.blocks.get(fragmentRootId);\n if (!fragRoot) {\n throw new Error(`NodeMaterial: fragment root block ${fragmentRootId} not found`);\n }\n const fragEmitter = loadedEmitters.get(fragRoot.className);\n if (!fragEmitter) {\n throw new Error(`NodeMaterial: no emitter for fragment root \"${fragRoot.className}\"`);\n }\n fragEmitter.emit(fragRoot, \"\", \"fragment\", state, ctx);\n\n if (vertexRootId !== null) {\n const vertRoot = graph.blocks.get(vertexRootId);\n if (!vertRoot) {\n throw new Error(`NodeMaterial: vertex root block ${vertexRootId} not found`);\n }\n const vertEmitter = loadedEmitters.get(vertRoot.className);\n if (!vertEmitter) {\n throw new Error(`NodeMaterial: no emitter for vertex root \"${vertRoot.className}\"`);\n }\n vertEmitter.emit(vertRoot, \"\", \"vertex\", state, ctx);\n }\n\n // Force-emit side-effect blocks (e.g. DiscardBlock) that have no outputs\n // the graph walk would visit. Each such emitter is expected to guard its\n // own body via a memo key so multiple calls are idempotent.\n for (const block of graph.blocks.values()) {\n const e = loadedEmitters.get(block.className);\n if (e?.sideEffect) {\n e.emit(block, \"\", e.stage ?? \"fragment\", state, ctx);\n }\n }\n\n return {\n vertexWgsl: composeStage(state, \"vertex\"),\n fragmentWgsl: composeStage(state, \"fragment\"),\n state,\n };\n}\n\nfunction composeStage(state: NodeBuildState, stage: Stage): string {\n // Helpers are emitted at module scope by the pipeline builder, NOT inside main.\n // composeStage returns only the statements that belong inside the entry point.\n const s = stageOf(state, stage);\n return s.body.join(\"\\n\");\n}\n"],"names":[],"mappings":";;AAmBA,SAAS,aAAA,GAA4B;AACjC,EAAA,OAAO;AAAA,IACH,OAAA,sBAAa,GAAA,EAAI;AAAA,IACjB,MAAM,EAAC;AAAA,IACP,IAAA,sBAAU,GAAA;AAAI,GAClB;AACJ;AAEO,SAAS,gBAAA,GAAmC;AAC/C,EAAA,OAAO;AAAA,IACH,QAAQ,aAAA,EAAc;AAAA,IACtB,UAAU,aAAA,EAAc;AAAA,IACxB,kBAAkB,EAAC;AAAA,IACnB,UAAU,EAAC;AAAA,IACX,eAAe,EAAC;AAAA,IAChB,UAAU,EAAC;AAAA,IACX,UAAU,EAAC;AAAA,IACX,qBAAqB,EAAC;AAAA,IACtB,aAAA,sBAAmB,GAAA,EAAI;AAAA,IACvB,QAAA,EAAU,CAAA;AAAA,IACV,aAAA,EAAe,KAAA;AAAA,IACf,cAAA,EAAgB,KAAA;AAAA,IAChB,aAAA,EAAe,KAAA;AAAA,IACf,cAAA,EAAgB,KAAA;AAAA,IAChB,uBAAA,EAAyB,KAAA;AAAA,IACzB,gBAAA,EAAkB,KAAA;AAAA,IAClB,OAAA,EAAS,KAAA;AAAA,IACT,aAAA,EAAe,KAAA;AAAA,IACf,SAAA,EAAW,KAAA;AAAA,IACX,cAAA,EAAgB,KAAA;AAAA,IAChB,eAAA,EAAiB,KAAA;AAAA,IACjB,cAAA,EAAgB,KAAA;AAAA,IAChB,cAAc,EAAC;AAAA,IACf,WAAA,EAAa,KAAA;AAAA,IACb,YAAA,EAAc;AAAA,GAClB;AACJ;AAIA,SAAS,OAAA,CAAQ,SAAiB,UAAA,EAA4B;AAC1D,EAAA,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA;AACnC;AAEA,SAAS,OAAA,CAAQ,OAAuB,KAAA,EAA0B;AAC9D,EAAA,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,CAAM,MAAA,GAAS,KAAA,CAAM,QAAA;AACrD;AAGO,SAAS,QAAA,CAAS,KAAA,EAAuB,MAAA,GAAS,GAAA,EAAa;AAClE,EAAA,MAAM,KAAK,KAAA,CAAM,QAAA,EAAA;AACjB,EAAA,OAAO,CAAA,CAAA,EAAI,MAAM,CAAA,EAAG,EAAE,CAAA,CAAA;AAC1B;AAIO,SAAS,QAAA,CAAS,OAAiB,MAAA,EAAiC;AACvE,EAAA,IAAI,KAAA,CAAM,SAAS,MAAA,EAAQ;AACvB,IAAA,OAAO,KAAA;AAAA,EACX;AACA,EAAA,MAAM,CAAA,GAAI,KAAK,MAAM,CAAA;AAErB,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,CAAA,EAAI,MAAM,IAAI,CAAA,KAAA,CAAA,EAAS,MAAM,MAAA,EAAO;AAAA,EACvD;AACA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,CAAA,EAAI,MAAM,IAAI,CAAA,IAAA,CAAA,EAAQ,MAAM,MAAA,EAAO;AAAA,EACtD;AACA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,CAAA,EAAI,MAAM,IAAI,CAAA,IAAA,CAAA,EAAQ,MAAM,MAAA,EAAO;AAAA,EACtD;AACA,EAAA,IAAA,CAAK,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,KAAA,CAAM,IAAA,KAAS,WAAW,KAAA,CAAM,IAAA,KAAS,OAAA,KAAY,MAAA,KAAW,KAAA,EAAO;AAClG,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,CAAA,EAAI,MAAM,IAAI,CAAA,GAAA,CAAA,EAAO,MAAM,MAAA,EAAO;AAAA,EACrD;AAEA,EAAA,IAAI,KAAA,CAAM,SAAS,KAAA,KAAU,MAAA,KAAW,WAAW,MAAA,KAAW,OAAA,IAAW,WAAW,OAAA,CAAA,EAAU;AAC1F,IAAA,OAAO,EAAE,MAAM,CAAA,EAAG,CAAC,IAAI,KAAA,CAAM,IAAI,CAAA,CAAA,CAAA,EAAK,IAAA,EAAM,MAAA,EAAO;AAAA,EACvD;AACA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,UAAA,EAAa,MAAM,IAAI,CAAA,MAAA,CAAA,EAAU,MAAM,MAAA,EAAO;AAAA,EACjE;AACA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,UAAA,EAAa,MAAM,IAAI,CAAA,WAAA,CAAA,EAAe,MAAM,MAAA,EAAO;AAAA,EACtE;AACA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,MAAA,KAAW,OAAA,EAAS;AAC9C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,UAAA,EAAa,MAAM,IAAI,CAAA,MAAA,CAAA,EAAU,MAAM,MAAA,EAAO;AAAA,EACjE;AACA,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,KAAA,CAAM,IAAI,OAAO,MAAM,CAAA,kBAAA,EAAqB,KAAA,CAAM,IAAI,CAAA,EAAA,CAAI,CAAA;AAC3G;AAEA,SAAS,WAAA,CAAY,OAAkB,cAAA,EAA4D;AAC/F,EAAA,MAAM,GAAA,GAAuB;AAAA,IACzB,KAAA;AAAA,IACA,eAAA,EAAiB,cAAA;AAAA,IACjB,MAAM,CAAC,KAAA,EAAO,MAAA,KAAW,QAAA,CAAS,OAAO,MAAM,CAAA;AAAA,IAC/C,IAAA,EAAM,QAAA;AAAA,IACN,OAAA,EAAS,CAAC,KAAA,EAAO,SAAA,EAAW,OAAO,KAAA,KAAU;AACzC,MAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,SAAS,CAAA;AACxC,MAAA,IAAI,CAAC,KAAA,EAAO;AACR,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,KAAA,CAAM,SAAS,SAAS,KAAA,CAAM,EAAE,CAAA,gBAAA,EAAmB,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,MAC3G;AACA,MAAA,IAAI,CAAC,MAAM,MAAA,EAAQ;AACf,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,KAAA,CAAM,SAAS,SAAS,KAAA,CAAM,EAAE,CAAA,SAAA,EAAY,SAAS,CAAA,kBAAA,CAAoB,CAAA;AAAA,MACrH;AACA,MAAA,MAAM,WAAW,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,KAAA,CAAM,OAAO,OAAO,CAAA;AACtD,MAAA,IAAI,CAAC,QAAA,EAAU;AACX,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,KAAA,CAAM,EAAE,CAAA,CAAA,EAAI,SAAS,CAAA,UAAA,EAAa,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,CAAE,CAAA;AAAA,MACjH;AACA,MAAA,OAAO,IAAI,aAAA,CAAc,QAAA,EAAU,MAAM,MAAA,CAAO,UAAA,EAAY,OAAO,KAAK,CAAA;AAAA,IAC5E,CAAA;AAAA,IACA,aAAA,EAAe,CAAC,QAAA,EAAU,UAAA,EAAY,OAAO,KAAA,KAAU;AACnD,MAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,KAAA,EAAO,KAAK,CAAA;AACvC,MAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,QAAA,CAAS,EAAA,EAAI,UAAU,CAAA;AAC3C,MAAA,MAAM,QAAA,GAAW,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AACxC,MAAA,IAAI,QAAA,EAAU;AACV,QAAA,OAAO,QAAA;AAAA,MACX;AACA,MAAA,MAAM,OAAA,GAAU,cAAA,CAAe,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA;AACrD,MAAA,IAAI,CAAC,OAAA,EAAS;AACV,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2CAAA,EAA8C,QAAA,CAAS,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,MACvF;AAEA,MAAA,MAAM,WAAA,GAAc,QAAQ,KAAA,IAAS,KAAA;AACrC,MAAA,MAAM,SAAS,OAAA,CAAQ,IAAA,CAAK,UAAU,UAAA,EAAY,WAAA,EAAa,OAAO,GAAG,CAAA;AAEzE,MAAA,IAAI,gBAAgB,KAAA,EAAO;AACvB,QAAA,MAAM,KAAA,GAAQ,CAAA,EAAA,EAAK,QAAA,CAAS,EAAE,IAAI,UAAU,CAAA,CAAA;AAC5C,QAAA,aAAA,CAAc,KAAA,EAAO,KAAA,EAAO,MAAA,EAAQ,WAAA,EAAa,KAAK,CAAA;AACtD,QAAA,MAAM,OAAA,GAAoB,EAAE,IAAA,EAAM,CAAA,GAAA,EAAM,KAAK,CAAA,CAAA,EAAI,IAAA,EAAM,OAAO,IAAA,EAAK;AACnE,QAAA,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,OAAO,CAAA;AAChC,QAAA,OAAO,OAAA;AAAA,MACX;AACA,MAAA,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,MAAM,CAAA;AAC/B,MAAA,OAAO,MAAA;AAAA,IACX;AAAA,GACJ;AACA,EAAA,OAAO,GAAA;AACX;AAEA,SAAS,aAAA,CAAc,KAAA,EAAuB,WAAA,EAAqB,KAAA,EAAiB,MAAa,EAAA,EAAiB;AAC9G,EAAA,IAAI,IAAA,KAAS,QAAA,IAAY,EAAA,KAAO,UAAA,EAAY;AACxC,IAAA,MAAM,IAAI,MAAM,4DAA4D,CAAA;AAAA,EAChF;AACA,EAAA,MAAM,OAAA,GAAU,MAAM,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,WAAW,CAAA;AAClE,EAAA,IAAI,CAAC,OAAA,EAAS;AACV,IAAA,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,EAAE,KAAA,EAAO,WAAA,EAAa,OAAO,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,EAAG,CAAA;AACnE,IAAA,KAAA,CAAM,MAAA,CAAO,KAAK,IAAA,CAAK,CAAA,IAAA,EAAO,WAAW,CAAA,GAAA,EAAM,KAAA,CAAM,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,EAChE;AACJ;AAKA,IAAI,eAAA,GAAuE,IAAA;AAC3E,eAAe,mBAAmB,SAAA,EAA0C;AACxE,EAAA,eAAA,KAAoB,OAAO,oBAAoB,CAAA;AAC/C,EAAA,OAAA,CAAQ,MAAM,eAAA,EAAiB,gBAAA,CAAiB,SAAS,CAAA;AAC7D;AAEA,SAAS,2BAA2B,KAAA,EAA2B;AAC3D,EAAA,OACK,MAAM,UAAA,CAAwD,0BAAA,KAA+B,QAC9F,CAAC,CAAC,MAAM,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA,EAAG,MAAA,IACjC,CAAC,CAAC,KAAA,CAAM,OAAO,GAAA,CAAI,OAAO,GAAG,MAAA,IAC7B,CAAC,CAAC,KAAA,CAAM,OAAO,GAAA,CAAI,YAAY,GAAG,MAAA,IAClC,CAAC,CAAC,KAAA,CAAM,MAAA,CAAO,IAAI,YAAY,CAAA,EAAG,UAClC,CAAC,CAAC,MAAM,MAAA,CAAO,GAAA,CAAI,aAAa,CAAA,EAAG,MAAA;AAE3C;AAEA,SAAS,2BAA2B,KAAA,EAA2B;AAC3D,EAAA,KAAA,MAAW,KAAA,IAAS,KAAA,CAAM,MAAA,CAAO,MAAA,EAAO,EAAG;AACvC,IAAA,IAAI,KAAA,CAAM,SAAA,KAAc,2BAAA,IAA+B,0BAAA,CAA2B,KAAK,CAAA,EAAG;AACtF,MAAA,OAAO,IAAA;AAAA,IACX;AAAA,EACJ;AACA,EAAA,OAAO,KAAA;AACX;AAEA,eAAsB,iBAAA,CAAkB,KAAA,EAAkB,WAAA,GAA4D,kBAAA,EAAwD;AAC1K,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAY;AACnC,EAAA,KAAA,MAAW,CAAA,IAAK,KAAA,CAAM,MAAA,CAAO,MAAA,EAAO,EAAG;AACnC,IAAA,UAAA,CAAW,GAAA,CAAI,EAAE,SAAS,CAAA;AAAA,EAC9B;AACA,EAAA,MAAM,GAAA,uBAAU,GAAA,EAA0B;AAC1C,EAAA,MAAM,mBAAA,GAAsB,WAAA,KAAgB,kBAAA,IAAsB,0BAAA,CAA2B,KAAK,CAAA;AAClG,EAAA,MAAM,OAAA,CAAQ,GAAA;AAAA,IACV,MAAM,IAAA,CAAK,UAAU,CAAA,CAAE,GAAA,CAAI,OAAO,SAAA,KAAc;AAC5C,MAAA,MAAM,SAAA,GAAY,SAAA,KAAc,2BAAA,IAA+B,mBAAA,GAAsB,iCAAA,GAAoC,SAAA;AACzH,MAAA,MAAM,CAAA,GAAI,MAAM,WAAA,CAAY,SAAS,CAAA;AACrC,MAAA,GAAA,CAAI,GAAA,CAAI,WAAW,CAAC,CAAA;AAAA,IACxB,CAAC;AAAA,GACL;AACA,EAAA,OAAO,GAAA;AACX;AAcO,SAAS,UACZ,KAAA,EACA,cAAA,EACA,cAAA,EACA,YAAA,EACA,cACA,QAAA,EACU;AACV,EAAA,MAAM,QAAQ,gBAAA,EAAiB;AAC/B,EAAA,IAAI,YAAA,EAAc;AACd,IAAA,KAAA,MAAW,MAAM,YAAA,EAAc;AAC3B,MAAA,KAAA,CAAM,YAAA,CAAa,KAAK,EAAE,CAAA;AAAA,IAC9B;AAAA,EACJ;AACA,EAAA,IAAI,QAAA,EAAU;AACV,IAAA,IAAI,SAAS,WAAA,EAAa;AACtB,MAAA,KAAA,CAAM,WAAA,GAAc,IAAA;AAAA,IACxB;AACA,IAAA,IAAI,SAAS,YAAA,EAAc;AACvB,MAAA,KAAA,CAAM,YAAA,GAAe,IAAA;AAAA,IACzB;AAAA,EACJ;AACA,EAAA,MAAM,GAAA,GAAM,WAAA,CAAY,KAAA,EAAO,cAAc,CAAA;AAG7C,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,cAAc,CAAA;AAChD,EAAA,IAAI,CAAC,QAAA,EAAU;AACX,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,cAAc,CAAA,UAAA,CAAY,CAAA;AAAA,EACnF;AACA,EAAA,MAAM,WAAA,GAAc,cAAA,CAAe,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA;AACzD,EAAA,IAAI,CAAC,WAAA,EAAa;AACd,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,4CAAA,EAA+C,QAAA,CAAS,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,EACxF;AACA,EAAA,WAAA,CAAY,IAAA,CAAK,QAAA,EAAU,EAAA,EAAI,UAAA,EAAY,OAAO,GAAG,CAAA;AAErD,EAAA,IAAI,iBAAiB,IAAA,EAAM;AACvB,IAAA,MAAM,QAAA,GAAW,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,YAAY,CAAA;AAC9C,IAAA,IAAI,CAAC,QAAA,EAAU;AACX,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gCAAA,EAAmC,YAAY,CAAA,UAAA,CAAY,CAAA;AAAA,IAC/E;AACA,IAAA,MAAM,WAAA,GAAc,cAAA,CAAe,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA;AACzD,IAAA,IAAI,CAAC,WAAA,EAAa;AACd,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0CAAA,EAA6C,QAAA,CAAS,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,IACtF;AACA,IAAA,WAAA,CAAY,IAAA,CAAK,QAAA,EAAU,EAAA,EAAI,QAAA,EAAU,OAAO,GAAG,CAAA;AAAA,EACvD;AAKA,EAAA,KAAA,MAAW,KAAA,IAAS,KAAA,CAAM,MAAA,CAAO,MAAA,EAAO,EAAG;AACvC,IAAA,MAAM,CAAA,GAAI,cAAA,CAAe,GAAA,CAAI,KAAA,CAAM,SAAS,CAAA;AAC5C,IAAA,IAAI,GAAG,UAAA,EAAY;AACf,MAAA,CAAA,CAAE,KAAK,KAAA,EAAO,EAAA,EAAI,EAAE,KAAA,IAAS,UAAA,EAAY,OAAO,GAAG,CAAA;AAAA,IACvD;AAAA,EACJ;AAEA,EAAA,OAAO;AAAA,IACH,UAAA,EAAY,YAAA,CAAa,KAAA,EAAO,QAAQ,CAAA;AAAA,IACxC,YAAA,EAAc,YAAA,CAAa,KAAA,EAAO,UAAU,CAAA;AAAA,IAC5C;AAAA,GACJ;AACJ;AAEA,SAAS,YAAA,CAAa,OAAuB,KAAA,EAAsB;AAG/D,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,KAAA,EAAO,KAAK,CAAA;AAC9B,EAAA,OAAO,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,IAAI,CAAA;AAC3B;;;;"}
|
|
1
|
+
{"version":3,"file":"node-emitter.js","sources":["../../../../src/material/node/node-emitter.ts"],"sourcesContent":["/** Node Material — WGSL emitter core.\n *\n * Given a parsed NodeGraph, walk it topologically from the FragmentOutput +\n * VertexOutput roots, calling each block's emitter to emit WGSL. The emitter\n * API guarantees that every (blockId, outputName) is emitted at most once per\n * stage (memoization), so downstream consumers share the same SSA temp.\n *\n * The result is a pair of WGSL source strings (vertex + fragment) plus the\n * accumulated UBO fields, attributes, varyings, samplers, and texture bindings\n * needed by the pipeline builder. This module intentionally has no WGSL of its\n * own beyond empty scaffolding — every shader string comes from a block emitter\n * so each block tree-shakes independently.\n */\n\nimport type { NodeBlock, NodeBuildState, NodeEmitContext, NodeExpr, NodeGraph, NodeValueType, Stage, StageState, BlockEmitter } from \"./node-types.js\";\nimport { WGSL } from \"./node-types.js\";\n\n// ─── Build-state construction ───────────────────────────────────────\n\nfunction newStageState(): StageState {\n return {\n helpers: new Map(),\n body: [],\n memo: new Map(),\n };\n}\n\nexport function createBuildState(): NodeBuildState {\n return {\n vertex: newStageState(),\n fragment: newStageState(),\n vertexAttributes: [],\n varyings: [],\n nodeUboFields: [],\n bindings: [],\n textures: [],\n pbrMrHelperRequests: [],\n loopVariables: new Map(),\n nextTemp: 0,\n usesLightsUbo: false,\n usesScreenSize: false,\n usesFragDepth: false,\n usesClipPlanes: false,\n usesMeshAttributeExists: false,\n usesMorphTargets: false,\n usesEnv: false,\n usesClearcoat: false,\n usesSheen: false,\n usesAnisotropy: false,\n usesIridescence: false,\n usesSubsurface: false,\n shadowLights: [],\n hasSkeleton: false,\n hasInstances: false,\n };\n}\n\n// ─── Emitter context ────────────────────────────────────────────────\n\nfunction memoKey(blockId: number, outputName: string): string {\n return `${blockId}|${outputName}`;\n}\n\nfunction stageOf(state: NodeBuildState, stage: Stage): StageState {\n return stage === \"vertex\" ? state.vertex : state.fragment;\n}\n\n/** Mint a fresh SSA temp name. */\nexport function mintTemp(state: NodeBuildState, prefix = \"t\"): string {\n const id = state.nextTemp++;\n return `_${prefix}${id}`;\n}\n\n/** Cast a typed WGSL expression to a target type. Throws if no cast is known.\n * Handles the common vector-widen/narrow cases that NME graphs actually use. */\nexport function castExpr(value: NodeExpr, target: NodeValueType): NodeExpr {\n if (value.type === target) {\n return value;\n }\n const t = WGSL[target];\n // Narrowing: vec4 -> vec3/vec2/f32 via .xyz/.xy/.x\n if (value.type === \"vec4f\" && target === \"vec3f\") {\n return { expr: `(${value.expr}).xyz`, type: target };\n }\n if (value.type === \"vec4f\" && target === \"vec2f\") {\n return { expr: `(${value.expr}).xy`, type: target };\n }\n if (value.type === \"vec3f\" && target === \"vec2f\") {\n return { expr: `(${value.expr}).xy`, type: target };\n }\n if ((value.type === \"vec4f\" || value.type === \"vec3f\" || value.type === \"vec2f\") && target === \"f32\") {\n return { expr: `(${value.expr}).x`, type: target };\n }\n // Widening: f32 -> vecN, vec3 -> vec4 (w=1)\n if (value.type === \"f32\" && (target === \"vec2f\" || target === \"vec3f\" || target === \"vec4f\")) {\n return { expr: `${t}(${value.expr})`, type: target };\n }\n if (value.type === \"vec3f\" && target === \"vec4f\") {\n return { expr: `vec4<f32>(${value.expr}, 1.0)`, type: target };\n }\n if (value.type === \"vec2f\" && target === \"vec4f\") {\n return { expr: `vec4<f32>(${value.expr}, 0.0, 1.0)`, type: target };\n }\n if (value.type === \"vec2f\" && target === \"vec3f\") {\n return { expr: `vec3<f32>(${value.expr}, 0.0)`, type: target };\n }\n throw new Error(`NodeMaterial: cannot cast ${value.type} to ${target} for expression \\`${value.expr}\\``);\n}\n\n/** @internal Sanitize a block/input name for use as a WGSL identifier. */\nexport function sanitize(name: string): string {\n return name.replace(/[^A-Za-z0-9_]/g, \"_\");\n}\n\n/** @internal Map Babylon.js connection-point flags to Lite's node value types. */\nexport function bjsTypeToNodeType(type: number, source = \"NodeMaterial\"): NodeValueType {\n if (type === 0x1 || type === 0x2) {\n return \"f32\";\n }\n if (type === 0x4) {\n return \"vec2f\";\n }\n if (type === 0x8 || type === 0x20) {\n return \"vec3f\";\n }\n if (type === 0x10 || type === 0x40) {\n return \"vec4f\";\n }\n if (type === 0x80) {\n return \"mat4f\";\n }\n throw new Error(`${source}: unsupported BJS connection point type 0x${type.toString(16)}`);\n}\n\nfunction makeContext(graph: NodeGraph, loadedEmitters: Map<string, BlockEmitter>): NodeEmitContext {\n const ctx: NodeEmitContext = {\n graph,\n _loadedEmitters: loadedEmitters,\n temp: (state, prefix) => mintTemp(state, prefix),\n cast: castExpr,\n sanitize,\n bjsTypeToNodeType,\n resolve: (block, inputName, stage, state) => {\n const input = block.inputs.get(inputName);\n if (!input) {\n throw new Error(`NodeMaterial: block \"${block.className}\" (id=${block.id}) has no input \"${inputName}\"`);\n }\n if (!input.source) {\n throw new Error(`NodeMaterial: block \"${block.className}\" (id=${block.id}) input \"${inputName}\" is not connected`);\n }\n const producer = graph.blocks.get(input.source.blockId);\n if (!producer) {\n throw new Error(`NodeMaterial: dangling connection ${block.id}.${inputName} -> block ${input.source.blockId}`);\n }\n return ctx.resolveOutput(producer, input.source.outputName, stage, state);\n },\n resolveOutput: (producer, outputName, stage, state) => {\n const stageState = stageOf(state, stage);\n const key = memoKey(producer.id, outputName);\n const existing = stageState.memo.get(key);\n if (existing) {\n return existing;\n }\n const emitter = loadedEmitters.get(producer.className);\n if (!emitter) {\n throw new Error(`NodeMaterial: no emitter loaded for block \"${producer.className}\"`);\n }\n // Blocks that declare a stage preference override the requested stage.\n const targetStage = emitter.stage ?? stage;\n const result = emitter.emit(producer, outputName, targetStage, state, ctx);\n // If the producer ran in a different stage, bridge via varying.\n if (targetStage !== stage) {\n const vname = `v_${producer.id}_${outputName}`;\n bridgeVarying(state, vname, result, targetStage, stage);\n const bridged: NodeExpr = { expr: `in.${vname}`, type: result.type };\n stageState.memo.set(key, bridged);\n return bridged;\n }\n stageState.memo.set(key, result);\n return result;\n },\n };\n return ctx;\n}\n\nfunction bridgeVarying(state: NodeBuildState, varyingName: string, value: NodeExpr, from: Stage, to: Stage): void {\n if (from !== \"vertex\" || to !== \"fragment\") {\n throw new Error(\"NodeMaterial: only vertex->fragment varyings are supported\");\n }\n const already = state.varyings.find((v) => v._name === varyingName);\n if (!already) {\n state.varyings.push({ _name: varyingName, _type: WGSL[value.type] });\n state.vertex.body.push(`out.${varyingName} = ${value.expr};`);\n }\n}\n\n// ─── Emitter dispatch ───────────────────────────────────────────────\n\n/** Load all emitters referenced by the graph in a single parallel batch. */\nlet defaultRegistry: Promise<typeof import(\"./node-registry.js\")> | null = null;\nasync function defaultBlockLoader(className: string): Promise<BlockEmitter> {\n defaultRegistry ??= import(\"./node-registry.js\");\n return (await defaultRegistry).loadBlockEmitter(className);\n}\n\nfunction pbrMrBlockNeedsFullEmitter(block: NodeBlock): boolean {\n return (\n (block.serialized as { enableSpecularAntiAliasing?: boolean }).enableSpecularAntiAliasing === true ||\n !!block.inputs.get(\"clearcoat\")?.source ||\n !!block.inputs.get(\"sheen\")?.source ||\n !!block.inputs.get(\"subsurface\")?.source ||\n !!block.inputs.get(\"anisotropy\")?.source ||\n !!block.inputs.get(\"iridescence\")?.source\n );\n}\n\nfunction graphNeedsFullPbrMrEmitter(graph: NodeGraph): boolean {\n for (const block of graph.blocks.values()) {\n if (block.className === \"PBRMetallicRoughnessBlock\" && pbrMrBlockNeedsFullEmitter(block)) {\n return true;\n }\n }\n return false;\n}\n\nexport async function loadGraphEmitters(graph: NodeGraph, blockLoader: (className: string) => Promise<BlockEmitter> = defaultBlockLoader): Promise<Map<string, BlockEmitter>> {\n const classNames = new Set<string>();\n for (const b of graph.blocks.values()) {\n classNames.add(b.className);\n }\n const map = new Map<string, BlockEmitter>();\n const useFullPbrMrEmitter = blockLoader === defaultBlockLoader && graphNeedsFullPbrMrEmitter(graph);\n await Promise.all(\n Array.from(classNames).map(async (className) => {\n const loaderKey = className === \"PBRMetallicRoughnessBlock\" && useFullPbrMrEmitter ? \"PBRMetallicRoughnessBlock__full\" : className;\n const e = await blockLoader(loaderKey);\n map.set(className, e);\n })\n );\n return map;\n}\n\n// ─── Public entry ───────────────────────────────────────────────────\n\nexport interface EmitResult {\n readonly vertexWgsl: string;\n readonly fragmentWgsl: string;\n readonly state: NodeBuildState;\n}\n\n/** Walk the graph from the given root (a FragmentOutput or VertexOutput block)\n * and emit the pair of WGSL shader strings. The caller is responsible for\n * wrapping the result with the pipeline's bind-group / entry-point scaffolding\n * (done by `node-pipeline.ts`). */\nexport function emitGraph(\n graph: NodeGraph,\n loadedEmitters: Map<string, BlockEmitter>,\n fragmentRootId: number,\n vertexRootId: number | null,\n shadowLights?: readonly { lightIndex: number; shadowType: \"esm\" | \"pcf\" }[],\n meshCaps?: { hasSkeleton?: boolean; hasInstances?: boolean }\n): EmitResult {\n const state = createBuildState();\n if (shadowLights) {\n for (const sl of shadowLights) {\n state.shadowLights.push(sl);\n }\n }\n if (meshCaps) {\n if (meshCaps.hasSkeleton) {\n state.hasSkeleton = true;\n }\n if (meshCaps.hasInstances) {\n state.hasInstances = true;\n }\n }\n const ctx = makeContext(graph, loadedEmitters);\n\n // Emit fragment root.\n const fragRoot = graph.blocks.get(fragmentRootId);\n if (!fragRoot) {\n throw new Error(`NodeMaterial: fragment root block ${fragmentRootId} not found`);\n }\n const fragEmitter = loadedEmitters.get(fragRoot.className);\n if (!fragEmitter) {\n throw new Error(`NodeMaterial: no emitter for fragment root \"${fragRoot.className}\"`);\n }\n fragEmitter.emit(fragRoot, \"\", \"fragment\", state, ctx);\n\n if (vertexRootId !== null) {\n const vertRoot = graph.blocks.get(vertexRootId);\n if (!vertRoot) {\n throw new Error(`NodeMaterial: vertex root block ${vertexRootId} not found`);\n }\n const vertEmitter = loadedEmitters.get(vertRoot.className);\n if (!vertEmitter) {\n throw new Error(`NodeMaterial: no emitter for vertex root \"${vertRoot.className}\"`);\n }\n vertEmitter.emit(vertRoot, \"\", \"vertex\", state, ctx);\n }\n\n // Force-emit side-effect blocks (e.g. DiscardBlock) that have no outputs\n // the graph walk would visit. Each such emitter is expected to guard its\n // own body via a memo key so multiple calls are idempotent.\n for (const block of graph.blocks.values()) {\n const e = loadedEmitters.get(block.className);\n if (e?.sideEffect) {\n e.emit(block, \"\", e.stage ?? \"fragment\", state, ctx);\n }\n }\n\n return {\n vertexWgsl: composeStage(state, \"vertex\"),\n fragmentWgsl: composeStage(state, \"fragment\"),\n state,\n };\n}\n\nfunction composeStage(state: NodeBuildState, stage: Stage): string {\n // Helpers are emitted at module scope by the pipeline builder, NOT inside main.\n // composeStage returns only the statements that belong inside the entry point.\n const s = stageOf(state, stage);\n return s.body.join(\"\\n\");\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -5,10 +5,10 @@ import { writeMeshLightSelection } from '../../render/lights-ubo.js';
|
|
|
5
5
|
import { MAX_LIGHTS } from '../../light/types.js';
|
|
6
6
|
import { packMat4IntoF32 } from '../../math/pack-mat4-into-f32.js';
|
|
7
7
|
import { GeometryTextureType } from '../../frame-graph/geometry-types.js';
|
|
8
|
-
import { emitGraph } from './node-emitter.js';
|
|
8
|
+
import { emitGraph, sanitize, bjsTypeToNodeType } from './node-emitter.js';
|
|
9
9
|
import { findBlockByClassName } from './node-parser.js';
|
|
10
10
|
import { compileNodePipeline } from './node-pipeline.js';
|
|
11
|
-
import {
|
|
11
|
+
import { extractDefault, floatCount } from './node-material.js';
|
|
12
12
|
import { getAttrBuffer, writeAttributeFlags } from './node-renderable.js';
|
|
13
13
|
|
|
14
14
|
let _nodeGeometryGroupBuilder = null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { F32 } from '../../engine/typed-arrays.js';
|
|
2
2
|
import { parseNodeMaterialSource, findBlockByClassName } from './node-parser.js';
|
|
3
|
-
import { loadGraphEmitters, emitGraph } from './node-emitter.js';
|
|
3
|
+
import { loadGraphEmitters, emitGraph, sanitize, bjsTypeToNodeType } from './node-emitter.js';
|
|
4
4
|
import { compileNodePipeline } from './node-pipeline.js';
|
|
5
5
|
|
|
6
6
|
async function parseNodeMaterialFromSnippet(engine, snippetId, options = {}) {
|
|
@@ -167,27 +167,6 @@ async function resolvePbrMrHelpers(state) {
|
|
|
167
167
|
state.fragment.helpers.set(request.key, core.buildPbrMrHelperCore(request));
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
-
function sanitize(name) {
|
|
171
|
-
return name.replace(/[^A-Za-z0-9_]/g, "_");
|
|
172
|
-
}
|
|
173
|
-
function bjsTypeToNodeType(t) {
|
|
174
|
-
if (t === 1 || t === 2) {
|
|
175
|
-
return "f32";
|
|
176
|
-
}
|
|
177
|
-
if (t === 4) {
|
|
178
|
-
return "vec2f";
|
|
179
|
-
}
|
|
180
|
-
if (t === 8 || t === 32) {
|
|
181
|
-
return "vec3f";
|
|
182
|
-
}
|
|
183
|
-
if (t === 16 || t === 64) {
|
|
184
|
-
return "vec4f";
|
|
185
|
-
}
|
|
186
|
-
if (t === 128) {
|
|
187
|
-
return "mat4f";
|
|
188
|
-
}
|
|
189
|
-
throw new Error(`NodeMaterial: unsupported BJS connection point type 0x${t.toString(16)}`);
|
|
190
|
-
}
|
|
191
170
|
function floatCount(type) {
|
|
192
171
|
switch (type) {
|
|
193
172
|
case "f32":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-material.js","sources":["../../../../src/material/node/node-material.ts"],"sourcesContent":["/** Node Material — public API (real implementation).\n *\n * Scenes that don't reference these exports tree-shake the entire\n * `material/node/` subtree to zero bytes.\n *\n * Flow: `parseNodeMaterialFromSnippet`\n * → fetch or inline JSON\n * → parse (`parseNodeMaterialSource`)\n * → load referenced emitters (lazy per-block)\n * → emit WGSL bodies (`emitGraph`)\n * → wrap + compile GPU pipeline (`compileNodePipeline`)\n * → return NodeMaterial with `inputs` map + `_buildGroup` dispatcher.\n */\n\nimport { F32 } from \"../../engine/typed-arrays.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { Texture2D } from \"../../texture/texture-2d.js\";\nimport type { MeshGroupBuilder, MeshGroupBuildResult } from \"../../render/renderable.js\";\nimport { parseNodeMaterialSource, findBlockByClassName } from \"./node-parser.js\";\nimport { loadGraphEmitters, emitGraph } from \"./node-emitter.js\";\nimport type { BlockEmitter, NodeBuildState, NodeGraph, NodeValueType } from \"./node-types.js\";\nimport type { Material } from \"../material.js\";\nimport { compileNodePipeline, type NodeCompileResult } from \"./node-pipeline.js\";\nimport type * as NodeEnv from \"./node-env.js\";\n\n// ─── Public API types ───────────────────────────────────────────────\n\n/** A compiled Node Material (Babylon NME graph). Exposes an `inputs` map of\n * named handles for live uniform/texture updates, and dispatches rendering\n * through the inherited `_buildGroup` hook. */\nexport interface NodeMaterial extends Material {\n readonly inputs: Record<string, NodeInputHandle>;\n /** @internal */\n readonly _compile: NodeCompileResult;\n /** @internal */\n readonly _state: NodeBuildState;\n /** @internal */\n readonly _graph: NodeGraph;\n /** @internal */\n readonly _vertexBody: string;\n /** @internal */\n readonly _fragmentBody: string;\n /** @internal Ordered list of vertex attribute names that the pipeline's vertex buffers expect. */\n readonly _vertexAttrNames: readonly string[];\n /** @internal */\n readonly _shadowGenerators: readonly import(\"../../shadow/shadow-generator.js\").ShadowGenerator[];\n /** @internal Whether this material requires alpha blending (derived from graph + JSON flags). */\n readonly _needsAlphaBlending: boolean;\n /** @internal */\n _nodeUBO: GPUBuffer | null;\n /** @internal */\n _uboDirty: boolean;\n /** @internal */\n _uniformValues: Map<string, UniformSlot>;\n /** @internal Per-texture-binding Texture2D slot (populated from options.textures and/or inputs.*.texture). */\n _textureSlots: Map<string, { current: Texture2D | null }>;\n /** @internal Pre-loaded env helpers (only populated when state.usesEnv was set during emitGraph).\n * Forwarded to the renderable so it doesn't have to dynamic-import again. */\n _envHelpers: typeof NodeEnv | null;\n /** @internal ESM shadow depth code emitted from the node graph (when shadow generators are present). */\n readonly _esmShadowDepthCode?: string;\n /** @internal ESM shadow params UBO buffer. */\n readonly _esmShadowParamsUBO?: GPUBuffer;\n /** @internal Loaded block emitters (className → emitter). Retained so the\n * geometry-renderer pass can re-walk the graph from a\n * GeometryTextureOutputBlock terminal without re-loading emitters. */\n readonly _emitters: ReadonlyMap<string, BlockEmitter>;\n /** @internal Mesh capability flags captured at parse time, forwarded to the\n * geometry-pass re-emit so BonesBlock / InstancesBlock behave identically. */\n readonly _hasSkeleton: boolean;\n /** @internal */\n readonly _hasInstances: boolean;\n}\n\n/** A live handle to one named Node Material input (uniform or texture). Set\n * `value` for scalar/vector inputs or `texture` for `texture2d` inputs; writes\n * flag the material UBO dirty so the change is uploaded next frame. */\nexport interface NodeInputHandle {\n readonly type: \"f32\" | \"vec2f\" | \"vec3f\" | \"vec4f\" | \"texture2d\";\n value?: number | number[];\n texture?: Texture2D | null;\n}\n\n/** Options for `parseNodeMaterialFromSnippet()`. */\nexport interface ParseNodeMaterialOptions {\n readonly snippetServer?: string;\n /** Pre-resolved JSON (object or string). When provided, bypasses the network. */\n readonly json?: string | object;\n /** Texture overrides keyed by TextureBlock / ImageSourceBlock name. */\n readonly textures?: Readonly<Record<string, Texture2D>>;\n /** Shadow generators to integrate into the material. Each contributes\n * one shadow-light slot whose lightIndex is the position of its light in\n * `scene.lights` at the time of rendering. Materials built without this\n * option have zero shadow bindings / zero shadow WGSL. */\n readonly shadowGenerators?: readonly import(\"../../shadow/shadow-generator.js\").ShadowGenerator[];\n /** For each entry in shadowGenerators, the index of the owning light in\n * scene.lights. When omitted, defaults to [0, 1, …] (first N lights). */\n readonly shadowLightIndices?: readonly number[];\n /** When true, BonesBlock produces a skinned world matrix (requires all\n * meshes using this material to have a skeleton). Default false. */\n readonly hasSkeleton?: boolean;\n /** When true, InstancesBlock wires per-instance attributes. Default false. */\n readonly hasInstances?: boolean;\n /** Optional graph-specific block loader. Avoids the full default registry when callers know the exact block set. */\n readonly blockLoader?: (className: string) => Promise<BlockEmitter>;\n}\n\n// ─── Internal shape (what the renderable + updater read) ────────────\n\n/** @internal */\ninterface UniformSlot {\n readonly _name: string;\n readonly _type: NodeValueType;\n readonly _offsetBytes: number;\n readonly _values: Float32Array;\n}\n\n// ─── Parse entry point ──────────────────────────────────────────────\n\n/** Parse a Babylon NME graph (by snippet ID or inline JSON), emit WGSL, compile\n * the GPU pipeline, and return a ready-to-render `NodeMaterial`.\n * @param engine - Engine context.\n * @param snippetId - Snippet server ID; ignored when `options.json` is supplied.\n * @param options - Inline JSON, texture overrides, shadow generators, and graph flags.\n * @returns A promise resolving to the compiled `NodeMaterial`. */\nexport async function parseNodeMaterialFromSnippet(engine: EngineContext, snippetId: string, options: ParseNodeMaterialOptions = {}): Promise<NodeMaterial> {\n const source =\n options.json !== undefined\n ? typeof options.json === \"string\"\n ? JSON.parse(options.json)\n : options.json\n : await (await import(\"./node-snippet.js\")).fetchSnippetSource(snippetId, options.snippetServer);\n\n const graph = parseNodeMaterialSource(source);\n const emitters = await loadGraphEmitters(graph, options.blockLoader);\n\n const fragRoot = findBlockByClassName(graph, \"FragmentOutputBlock\");\n if (!fragRoot) {\n throw new Error(\"NodeMaterial: graph has no FragmentOutputBlock\");\n }\n const vertRoot = findBlockByClassName(graph, \"VertexOutputBlock\");\n\n // Pre-populate shadow metadata BEFORE emitGraph so LightBlock can dispatch\n // to nme_computeShadowFactors(...) during emission. When no shadow\n // generators are supplied, state.shadowLights stays empty and zero shadow\n // WGSL / zero shadow bindings are emitted (tree-shakable).\n const shadowLightsPre: { lightIndex: number; shadowType: \"esm\" | \"pcf\" }[] = [];\n if (options.shadowGenerators && options.shadowGenerators.length > 0) {\n const defaultIdx = options.shadowGenerators.map((_, i) => i);\n const indices = options.shadowLightIndices ?? defaultIdx;\n for (let i = 0; i < options.shadowGenerators.length; i++) {\n // v1: CSM is a Standard-material-only receiver. Node materials never have a CSM light in any\n // current scene, so the cast is safe and keeps this block byte-identical to baseline.\n shadowLightsPre.push({ lightIndex: indices[i]!, shadowType: options.shadowGenerators[i]!._shadowType as \"esm\" | \"pcf\" });\n }\n }\n\n const { vertexWgsl, fragmentWgsl, state } = emitGraph(graph, emitters, fragRoot.id, vertRoot ? vertRoot.id : null, shadowLightsPre, {\n hasSkeleton: options.hasSkeleton ?? false,\n hasInstances: options.hasInstances ?? false,\n });\n await resolvePbrMrHelpers(state);\n\n // Dynamic import: env IBL helpers in node-env.ts are only loaded when the\n // graph emitted state.usesEnv. Scenes without ReflectionBlock+PBR-MR never\n // bundle this module.\n let envHelpers: typeof import(\"./node-env.js\") | null = null;\n let _envEmitter: typeof import(\"./node-env.js\").emitEnv | undefined;\n if (state.usesEnv) {\n envHelpers = await import(\"./node-env.js\");\n _envEmitter = envHelpers.emitEnv;\n }\n\n // Dynamic import: the PCF/ESM WGSL helpers live in node-shadow.ts and\n // are only loaded when the caller supplied shadowGenerators. Scenes\n // without shadows never bundle this module.\n let _shadowEmitter: typeof import(\"./node-shadow.js\").emitShadow | undefined;\n if (options.shadowGenerators && options.shadowGenerators.length > 0) {\n _shadowEmitter = (await import(\"./node-shadow.js\")).emitShadow;\n }\n\n const compile = compileNodePipeline(state, vertexWgsl, fragmentWgsl, {\n _engine: engine,\n _format: engine.format,\n _msaaSamples: engine.msaaSamples,\n _backFaceCulling: graph.backFaceCulling,\n _alphaMode: graph.needsAlphaBlending ? graph.alphaMode : 0,\n _envEmitter,\n _shadowEmitter,\n });\n\n // Build the `inputs` map: one NodeInputHandle per named uniform.\n const inputs: Record<string, NodeInputHandle> = {};\n const uniformValues = new Map<string, UniformSlot>();\n for (const [name, blockId] of graph.namedInputs) {\n const block = graph.blocks.get(blockId)!;\n const _name = sanitize(block.name || `input${block.id}`);\n const _offsetBytes = compile._nodeUboOffsets.get(_name);\n if (_offsetBytes === undefined) {\n continue;\n }\n const _type = bjsTypeToNodeType((block.serialized[\"type\"] as number | undefined) ?? 0x10);\n if (_type === \"mat4f\") {\n continue;\n }\n const len = floatCount(_type);\n const defaultValues = extractDefault(block.serialized[\"value\"], _type);\n const _values = new F32(len);\n _values.set(defaultValues);\n const slot: UniformSlot = { _name, _type, _offsetBytes, _values };\n uniformValues.set(_name, slot);\n\n const handleType = handleTypeOf(_type);\n // capture material so the setter can mark it dirty.\n const setDirty = () => {\n material._uboDirty = true;\n };\n const handle: NodeInputHandle = {\n type: handleType,\n get value(): number | number[] {\n return handleType === \"f32\" ? slot._values[0]! : Array.from(slot._values);\n },\n set value(v: number | number[]) {\n if (typeof v === \"number\") {\n slot._values[0] = v;\n } else {\n slot._values.set(v);\n }\n setDirty();\n },\n } as NodeInputHandle;\n inputs[name] = handle;\n }\n\n // Second pass: write defaults for unnamed / constant InputBlocks whose\n // values exist in the UBO but were skipped by the namedInputs loop above\n // (e.g. blocks with empty names or isConstant=true).\n for (const block of graph.blocks.values()) {\n if (block.className !== \"InputBlock\") {\n continue;\n }\n const _name = sanitize(block.name || `input${block.id}`);\n if (uniformValues.has(_name)) {\n continue;\n } // already handled above\n const _offsetBytes = compile._nodeUboOffsets.get(_name);\n if (_offsetBytes === undefined) {\n continue;\n }\n const _type = bjsTypeToNodeType((block.serialized[\"type\"] as number | undefined) ?? 0x10);\n if (_type === \"mat4f\") {\n continue;\n }\n const len = floatCount(_type);\n const defaultValues = extractDefault(block.serialized[\"value\"], _type);\n const _values = new F32(len);\n _values.set(defaultValues);\n uniformValues.set(_name, { _name, _type, _offsetBytes, _values });\n }\n\n const attrNames = state.vertexAttributes.map((a) => a._name);\n\n // Per-texture handles (populated from options.textures, then exposed via inputs).\n const textureSlots = new Map<string, { current: Texture2D | null }>();\n for (const tb of compile._textureBindings) {\n const slot = { current: options.textures?.[tb._name] ?? null };\n textureSlots.set(tb._name, slot);\n const handle: NodeInputHandle = {\n type: \"texture2d\",\n get texture(): Texture2D | null {\n return slot.current;\n },\n set texture(v: Texture2D | null) {\n slot.current = v;\n },\n } as NodeInputHandle;\n inputs[tb._name] = handle;\n }\n\n const _buildGroup: MeshGroupBuilder = async (scene, meshes): Promise<MeshGroupBuildResult> => {\n const { buildNodeMeshRenderables } = await import(\"./node-renderable.js\");\n const result = buildNodeMeshRenderables(scene, meshes);\n _buildGroup._rebuildSingle = result.rebuildSingle;\n return result;\n };\n _buildGroup._materialFamily = \"node\";\n\n const material: NodeMaterial = {\n inputs,\n _renderFeatures: { features: 0 },\n _buildGroup,\n _uboVersion: 0,\n _compile: compile,\n _state: state,\n _graph: graph,\n _vertexBody: vertexWgsl,\n _fragmentBody: fragmentWgsl,\n _vertexAttrNames: attrNames,\n _shadowGenerators: options.shadowGenerators ?? [],\n _needsAlphaBlending: graph.needsAlphaBlending,\n _nodeUBO: null,\n _uboDirty: false,\n _uniformValues: uniformValues,\n _textureSlots: textureSlots,\n _envHelpers: envHelpers,\n _emitters: emitters,\n _hasSkeleton: options.hasSkeleton ?? false,\n _hasInstances: options.hasInstances ?? false,\n };\n return material;\n}\n\nfunction isCorePbrMrRequest(request: import(\"./node-types.js\").NodePbrMrHelperRequest): boolean {\n return (\n !request.useClearcoat &&\n !request.useSheen &&\n !request.useRefraction &&\n !request.useSubsurface &&\n !request.useAnisotropy &&\n !request.useShAlbedoScaling &&\n !request.useCcBump &&\n !request.useCcTint &&\n !request.useSpecularAA &&\n !request.remapClearcoatF0\n );\n}\n\nasync function resolvePbrMrHelpers(state: NodeBuildState): Promise<void> {\n if (state.pbrMrHelperRequests.length === 0) {\n return;\n }\n if (state.pbrMrHelperRequests.some((request) => !isCorePbrMrRequest(request))) {\n throw new Error(\"NodeMaterial: advanced PBR-MR helper request must be emitted by the full PBR-MR block\");\n }\n const core = await import(\"./blocks/pbr-mr-helper-core.js\");\n for (const request of state.pbrMrHelperRequests) {\n state.fragment.helpers.set(request.key, core.buildPbrMrHelperCore(request));\n }\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────\n\n/** @internal Exported only so the lazily-imported geometry renderable\n * (`node-geometry-renderable.ts`) can reuse it without re-bundling — already\n * retained here by the parser/UBO writers, so the export costs zero\n * always-loaded bytes. */\nexport function sanitize(name: string): string {\n return name.replace(/[^A-Za-z0-9_]/g, \"_\");\n}\n\n/** @internal See {@link sanitize} — exported for the lazy geometry renderable. */\nexport function bjsTypeToNodeType(t: number): NodeValueType {\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(`NodeMaterial: unsupported BJS connection point type 0x${t.toString(16)}`);\n}\n\n/** @internal See {@link sanitize} — exported for the lazy geometry renderable. */\nexport function floatCount(type: NodeValueType): number {\n switch (type) {\n case \"f32\":\n return 1;\n case \"vec2f\":\n return 2;\n case \"vec3f\":\n return 3;\n case \"vec4f\":\n return 4;\n case \"mat4f\":\n return 16;\n default:\n return 0;\n }\n}\n\nfunction handleTypeOf(t: NodeValueType): NodeInputHandle[\"type\"] {\n if (t === \"mat4f\" || t === \"texture2d\" || t === \"textureCube\") {\n return \"vec4f\";\n }\n return t;\n}\n\n/** @internal See {@link sanitize} — exported for the lazy geometry renderable. */\nexport function extractDefault(raw: unknown, type: NodeValueType): number[] {\n const n = floatCount(type);\n if (typeof raw === \"number\") {\n return [raw];\n }\n if (Array.isArray(raw)) {\n const out = raw.slice(0, n).map((v) => (typeof v === \"number\" ? v : 0));\n while (out.length < n) {\n out.push(0);\n }\n return out;\n }\n if (raw && typeof raw === \"object\") {\n const obj = raw as Record<string, number>;\n const picks: number[] = [];\n for (const k of [\"x\", \"y\", \"z\", \"w\"]) {\n if (typeof obj[k] === \"number\") {\n picks.push(obj[k]);\n }\n }\n if (picks.length > 0) {\n while (picks.length < n) {\n picks.push(0);\n }\n return picks.slice(0, n);\n }\n const rgba: number[] = [];\n for (const k of [\"r\", \"g\", \"b\", \"a\"]) {\n if (typeof obj[k] === \"number\") {\n rgba.push(obj[k]);\n }\n }\n if (rgba.length > 0) {\n while (rgba.length < n) {\n rgba.push(1);\n }\n return rgba.slice(0, n);\n }\n }\n return new Array(n).fill(0);\n}\n\n// ─── UBO writer ─────────────────────────────────────────────────────\n\nexport function writeNodeUBO(engine: EngineContext, buffer: GPUBuffer, material: NodeMaterial): void {\n const size = material._compile._nodeUboSize;\n if (size === 0) {\n return;\n }\n const scratch = new F32(size / 4);\n for (const slot of material._uniformValues.values()) {\n const dstIdx = slot._offsetBytes >> 2;\n scratch.set(slot._values, dstIdx);\n }\n engine._device.queue.writeBuffer(buffer, 0, scratch);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"node-material.js","sources":["../../../../src/material/node/node-material.ts"],"sourcesContent":["/** Node Material — public API (real implementation).\n *\n * Scenes that don't reference these exports tree-shake the entire\n * `material/node/` subtree to zero bytes.\n *\n * Flow: `parseNodeMaterialFromSnippet`\n * → fetch or inline JSON\n * → parse (`parseNodeMaterialSource`)\n * → load referenced emitters (lazy per-block)\n * → emit WGSL bodies (`emitGraph`)\n * → wrap + compile GPU pipeline (`compileNodePipeline`)\n * → return NodeMaterial with `inputs` map + `_buildGroup` dispatcher.\n */\n\nimport { F32 } from \"../../engine/typed-arrays.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { Texture2D } from \"../../texture/texture-2d.js\";\nimport type { MeshGroupBuilder, MeshGroupBuildResult } from \"../../render/renderable.js\";\nimport { parseNodeMaterialSource, findBlockByClassName } from \"./node-parser.js\";\nimport { bjsTypeToNodeType, loadGraphEmitters, emitGraph, sanitize } from \"./node-emitter.js\";\nimport type { BlockEmitter, NodeBuildState, NodeGraph, NodeValueType } from \"./node-types.js\";\nimport type { Material } from \"../material.js\";\nimport { compileNodePipeline, type NodeCompileResult } from \"./node-pipeline.js\";\nimport type * as NodeEnv from \"./node-env.js\";\n\nexport { bjsTypeToNodeType, sanitize } from \"./node-emitter.js\";\n\n// ─── Public API types ───────────────────────────────────────────────\n\n/** A compiled Node Material (Babylon NME graph). Exposes an `inputs` map of\n * named handles for live uniform/texture updates, and dispatches rendering\n * through the inherited `_buildGroup` hook. */\nexport interface NodeMaterial extends Material {\n readonly inputs: Record<string, NodeInputHandle>;\n /** @internal */\n readonly _compile: NodeCompileResult;\n /** @internal */\n readonly _state: NodeBuildState;\n /** @internal */\n readonly _graph: NodeGraph;\n /** @internal */\n readonly _vertexBody: string;\n /** @internal */\n readonly _fragmentBody: string;\n /** @internal Ordered list of vertex attribute names that the pipeline's vertex buffers expect. */\n readonly _vertexAttrNames: readonly string[];\n /** @internal */\n readonly _shadowGenerators: readonly import(\"../../shadow/shadow-generator.js\").ShadowGenerator[];\n /** @internal Whether this material requires alpha blending (derived from graph + JSON flags). */\n readonly _needsAlphaBlending: boolean;\n /** @internal */\n _nodeUBO: GPUBuffer | null;\n /** @internal */\n _uboDirty: boolean;\n /** @internal */\n _uniformValues: Map<string, UniformSlot>;\n /** @internal Per-texture-binding Texture2D slot (populated from options.textures and/or inputs.*.texture). */\n _textureSlots: Map<string, { current: Texture2D | null }>;\n /** @internal Pre-loaded env helpers (only populated when state.usesEnv was set during emitGraph).\n * Forwarded to the renderable so it doesn't have to dynamic-import again. */\n _envHelpers: typeof NodeEnv | null;\n /** @internal ESM shadow depth code emitted from the node graph (when shadow generators are present). */\n readonly _esmShadowDepthCode?: string;\n /** @internal ESM shadow params UBO buffer. */\n readonly _esmShadowParamsUBO?: GPUBuffer;\n /** @internal Loaded block emitters (className → emitter). Retained so the\n * geometry-renderer pass can re-walk the graph from a\n * GeometryTextureOutputBlock terminal without re-loading emitters. */\n readonly _emitters: ReadonlyMap<string, BlockEmitter>;\n /** @internal Mesh capability flags captured at parse time, forwarded to the\n * geometry-pass re-emit so BonesBlock / InstancesBlock behave identically. */\n readonly _hasSkeleton: boolean;\n /** @internal */\n readonly _hasInstances: boolean;\n}\n\n/** A live handle to one named Node Material input (uniform or texture). Set\n * `value` for scalar/vector inputs or `texture` for `texture2d` inputs; writes\n * flag the material UBO dirty so the change is uploaded next frame. */\nexport interface NodeInputHandle {\n readonly type: \"f32\" | \"vec2f\" | \"vec3f\" | \"vec4f\" | \"texture2d\";\n value?: number | number[];\n texture?: Texture2D | null;\n}\n\n/** Options for `parseNodeMaterialFromSnippet()`. */\nexport interface ParseNodeMaterialOptions {\n readonly snippetServer?: string;\n /** Pre-resolved JSON (object or string). When provided, bypasses the network. */\n readonly json?: string | object;\n /** Texture overrides keyed by TextureBlock / ImageSourceBlock name. */\n readonly textures?: Readonly<Record<string, Texture2D>>;\n /** Shadow generators to integrate into the material. Each contributes\n * one shadow-light slot whose lightIndex is the position of its light in\n * `scene.lights` at the time of rendering. Materials built without this\n * option have zero shadow bindings / zero shadow WGSL. */\n readonly shadowGenerators?: readonly import(\"../../shadow/shadow-generator.js\").ShadowGenerator[];\n /** For each entry in shadowGenerators, the index of the owning light in\n * scene.lights. When omitted, defaults to [0, 1, …] (first N lights). */\n readonly shadowLightIndices?: readonly number[];\n /** When true, BonesBlock produces a skinned world matrix (requires all\n * meshes using this material to have a skeleton). Default false. */\n readonly hasSkeleton?: boolean;\n /** When true, InstancesBlock wires per-instance attributes. Default false. */\n readonly hasInstances?: boolean;\n /** Optional graph-specific block loader. Avoids the full default registry when callers know the exact block set. */\n readonly blockLoader?: (className: string) => Promise<BlockEmitter>;\n}\n\n// ─── Internal shape (what the renderable + updater read) ────────────\n\n/** @internal */\ninterface UniformSlot {\n readonly _name: string;\n readonly _type: NodeValueType;\n readonly _offsetBytes: number;\n readonly _values: Float32Array;\n}\n\n// ─── Parse entry point ──────────────────────────────────────────────\n\n/** Parse a Babylon NME graph (by snippet ID or inline JSON), emit WGSL, compile\n * the GPU pipeline, and return a ready-to-render `NodeMaterial`.\n * @param engine - Engine context.\n * @param snippetId - Snippet server ID; ignored when `options.json` is supplied.\n * @param options - Inline JSON, texture overrides, shadow generators, and graph flags.\n * @returns A promise resolving to the compiled `NodeMaterial`. */\nexport async function parseNodeMaterialFromSnippet(engine: EngineContext, snippetId: string, options: ParseNodeMaterialOptions = {}): Promise<NodeMaterial> {\n const source =\n options.json !== undefined\n ? typeof options.json === \"string\"\n ? JSON.parse(options.json)\n : options.json\n : await (await import(\"./node-snippet.js\")).fetchSnippetSource(snippetId, options.snippetServer);\n\n const graph = parseNodeMaterialSource(source);\n const emitters = await loadGraphEmitters(graph, options.blockLoader);\n\n const fragRoot = findBlockByClassName(graph, \"FragmentOutputBlock\");\n if (!fragRoot) {\n throw new Error(\"NodeMaterial: graph has no FragmentOutputBlock\");\n }\n const vertRoot = findBlockByClassName(graph, \"VertexOutputBlock\");\n\n // Pre-populate shadow metadata BEFORE emitGraph so LightBlock can dispatch\n // to nme_computeShadowFactors(...) during emission. When no shadow\n // generators are supplied, state.shadowLights stays empty and zero shadow\n // WGSL / zero shadow bindings are emitted (tree-shakable).\n const shadowLightsPre: { lightIndex: number; shadowType: \"esm\" | \"pcf\" }[] = [];\n if (options.shadowGenerators && options.shadowGenerators.length > 0) {\n const defaultIdx = options.shadowGenerators.map((_, i) => i);\n const indices = options.shadowLightIndices ?? defaultIdx;\n for (let i = 0; i < options.shadowGenerators.length; i++) {\n // v1: CSM is a Standard-material-only receiver. Node materials never have a CSM light in any\n // current scene, so the cast is safe and keeps this block byte-identical to baseline.\n shadowLightsPre.push({ lightIndex: indices[i]!, shadowType: options.shadowGenerators[i]!._shadowType as \"esm\" | \"pcf\" });\n }\n }\n\n const { vertexWgsl, fragmentWgsl, state } = emitGraph(graph, emitters, fragRoot.id, vertRoot ? vertRoot.id : null, shadowLightsPre, {\n hasSkeleton: options.hasSkeleton ?? false,\n hasInstances: options.hasInstances ?? false,\n });\n await resolvePbrMrHelpers(state);\n\n // Dynamic import: env IBL helpers in node-env.ts are only loaded when the\n // graph emitted state.usesEnv. Scenes without ReflectionBlock+PBR-MR never\n // bundle this module.\n let envHelpers: typeof import(\"./node-env.js\") | null = null;\n let _envEmitter: typeof import(\"./node-env.js\").emitEnv | undefined;\n if (state.usesEnv) {\n envHelpers = await import(\"./node-env.js\");\n _envEmitter = envHelpers.emitEnv;\n }\n\n // Dynamic import: the PCF/ESM WGSL helpers live in node-shadow.ts and\n // are only loaded when the caller supplied shadowGenerators. Scenes\n // without shadows never bundle this module.\n let _shadowEmitter: typeof import(\"./node-shadow.js\").emitShadow | undefined;\n if (options.shadowGenerators && options.shadowGenerators.length > 0) {\n _shadowEmitter = (await import(\"./node-shadow.js\")).emitShadow;\n }\n\n const compile = compileNodePipeline(state, vertexWgsl, fragmentWgsl, {\n _engine: engine,\n _format: engine.format,\n _msaaSamples: engine.msaaSamples,\n _backFaceCulling: graph.backFaceCulling,\n _alphaMode: graph.needsAlphaBlending ? graph.alphaMode : 0,\n _envEmitter,\n _shadowEmitter,\n });\n\n // Build the `inputs` map: one NodeInputHandle per named uniform.\n const inputs: Record<string, NodeInputHandle> = {};\n const uniformValues = new Map<string, UniformSlot>();\n for (const [name, blockId] of graph.namedInputs) {\n const block = graph.blocks.get(blockId)!;\n const _name = sanitize(block.name || `input${block.id}`);\n const _offsetBytes = compile._nodeUboOffsets.get(_name);\n if (_offsetBytes === undefined) {\n continue;\n }\n const _type = bjsTypeToNodeType((block.serialized[\"type\"] as number | undefined) ?? 0x10);\n if (_type === \"mat4f\") {\n continue;\n }\n const len = floatCount(_type);\n const defaultValues = extractDefault(block.serialized[\"value\"], _type);\n const _values = new F32(len);\n _values.set(defaultValues);\n const slot: UniformSlot = { _name, _type, _offsetBytes, _values };\n uniformValues.set(_name, slot);\n\n const handleType = handleTypeOf(_type);\n // capture material so the setter can mark it dirty.\n const setDirty = () => {\n material._uboDirty = true;\n };\n const handle: NodeInputHandle = {\n type: handleType,\n get value(): number | number[] {\n return handleType === \"f32\" ? slot._values[0]! : Array.from(slot._values);\n },\n set value(v: number | number[]) {\n if (typeof v === \"number\") {\n slot._values[0] = v;\n } else {\n slot._values.set(v);\n }\n setDirty();\n },\n } as NodeInputHandle;\n inputs[name] = handle;\n }\n\n // Second pass: write defaults for unnamed / constant InputBlocks whose\n // values exist in the UBO but were skipped by the namedInputs loop above\n // (e.g. blocks with empty names or isConstant=true).\n for (const block of graph.blocks.values()) {\n if (block.className !== \"InputBlock\") {\n continue;\n }\n const _name = sanitize(block.name || `input${block.id}`);\n if (uniformValues.has(_name)) {\n continue;\n } // already handled above\n const _offsetBytes = compile._nodeUboOffsets.get(_name);\n if (_offsetBytes === undefined) {\n continue;\n }\n const _type = bjsTypeToNodeType((block.serialized[\"type\"] as number | undefined) ?? 0x10);\n if (_type === \"mat4f\") {\n continue;\n }\n const len = floatCount(_type);\n const defaultValues = extractDefault(block.serialized[\"value\"], _type);\n const _values = new F32(len);\n _values.set(defaultValues);\n uniformValues.set(_name, { _name, _type, _offsetBytes, _values });\n }\n\n const attrNames = state.vertexAttributes.map((a) => a._name);\n\n // Per-texture handles (populated from options.textures, then exposed via inputs).\n const textureSlots = new Map<string, { current: Texture2D | null }>();\n for (const tb of compile._textureBindings) {\n const slot = { current: options.textures?.[tb._name] ?? null };\n textureSlots.set(tb._name, slot);\n const handle: NodeInputHandle = {\n type: \"texture2d\",\n get texture(): Texture2D | null {\n return slot.current;\n },\n set texture(v: Texture2D | null) {\n slot.current = v;\n },\n } as NodeInputHandle;\n inputs[tb._name] = handle;\n }\n\n const _buildGroup: MeshGroupBuilder = async (scene, meshes): Promise<MeshGroupBuildResult> => {\n const { buildNodeMeshRenderables } = await import(\"./node-renderable.js\");\n const result = buildNodeMeshRenderables(scene, meshes);\n _buildGroup._rebuildSingle = result.rebuildSingle;\n return result;\n };\n _buildGroup._materialFamily = \"node\";\n\n const material: NodeMaterial = {\n inputs,\n _renderFeatures: { features: 0 },\n _buildGroup,\n _uboVersion: 0,\n _compile: compile,\n _state: state,\n _graph: graph,\n _vertexBody: vertexWgsl,\n _fragmentBody: fragmentWgsl,\n _vertexAttrNames: attrNames,\n _shadowGenerators: options.shadowGenerators ?? [],\n _needsAlphaBlending: graph.needsAlphaBlending,\n _nodeUBO: null,\n _uboDirty: false,\n _uniformValues: uniformValues,\n _textureSlots: textureSlots,\n _envHelpers: envHelpers,\n _emitters: emitters,\n _hasSkeleton: options.hasSkeleton ?? false,\n _hasInstances: options.hasInstances ?? false,\n };\n return material;\n}\n\nfunction isCorePbrMrRequest(request: import(\"./node-types.js\").NodePbrMrHelperRequest): boolean {\n return (\n !request.useClearcoat &&\n !request.useSheen &&\n !request.useRefraction &&\n !request.useSubsurface &&\n !request.useAnisotropy &&\n !request.useShAlbedoScaling &&\n !request.useCcBump &&\n !request.useCcTint &&\n !request.useSpecularAA &&\n !request.remapClearcoatF0\n );\n}\n\nasync function resolvePbrMrHelpers(state: NodeBuildState): Promise<void> {\n if (state.pbrMrHelperRequests.length === 0) {\n return;\n }\n if (state.pbrMrHelperRequests.some((request) => !isCorePbrMrRequest(request))) {\n throw new Error(\"NodeMaterial: advanced PBR-MR helper request must be emitted by the full PBR-MR block\");\n }\n const core = await import(\"./blocks/pbr-mr-helper-core.js\");\n for (const request of state.pbrMrHelperRequests) {\n state.fragment.helpers.set(request.key, core.buildPbrMrHelperCore(request));\n }\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────\n\n/** @internal See {@link sanitize} — exported for the lazy geometry renderable. */\nexport function floatCount(type: NodeValueType): number {\n switch (type) {\n case \"f32\":\n return 1;\n case \"vec2f\":\n return 2;\n case \"vec3f\":\n return 3;\n case \"vec4f\":\n return 4;\n case \"mat4f\":\n return 16;\n default:\n return 0;\n }\n}\n\nfunction handleTypeOf(t: NodeValueType): NodeInputHandle[\"type\"] {\n if (t === \"mat4f\" || t === \"texture2d\" || t === \"textureCube\") {\n return \"vec4f\";\n }\n return t;\n}\n\n/** @internal See {@link sanitize} — exported for the lazy geometry renderable. */\nexport function extractDefault(raw: unknown, type: NodeValueType): number[] {\n const n = floatCount(type);\n if (typeof raw === \"number\") {\n return [raw];\n }\n if (Array.isArray(raw)) {\n const out = raw.slice(0, n).map((v) => (typeof v === \"number\" ? v : 0));\n while (out.length < n) {\n out.push(0);\n }\n return out;\n }\n if (raw && typeof raw === \"object\") {\n const obj = raw as Record<string, number>;\n const picks: number[] = [];\n for (const k of [\"x\", \"y\", \"z\", \"w\"]) {\n if (typeof obj[k] === \"number\") {\n picks.push(obj[k]);\n }\n }\n if (picks.length > 0) {\n while (picks.length < n) {\n picks.push(0);\n }\n return picks.slice(0, n);\n }\n const rgba: number[] = [];\n for (const k of [\"r\", \"g\", \"b\", \"a\"]) {\n if (typeof obj[k] === \"number\") {\n rgba.push(obj[k]);\n }\n }\n if (rgba.length > 0) {\n while (rgba.length < n) {\n rgba.push(1);\n }\n return rgba.slice(0, n);\n }\n }\n return new Array(n).fill(0);\n}\n\n// ─── UBO writer ─────────────────────────────────────────────────────\n\nexport function writeNodeUBO(engine: EngineContext, buffer: GPUBuffer, material: NodeMaterial): void {\n const size = material._compile._nodeUboSize;\n if (size === 0) {\n return;\n }\n const scratch = new F32(size / 4);\n for (const slot of material._uniformValues.values()) {\n const dstIdx = slot._offsetBytes >> 2;\n scratch.set(slot._values, dstIdx);\n }\n engine._device.queue.writeBuffer(buffer, 0, scratch);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-types.js","sources":["../../../../src/material/node/node-types.ts"],"sourcesContent":["/** Node Material — internal graph + emitter types.\n *\n * All types here are pure data. Block emitters are pure functions imported lazily\n * from `./blocks/*` via the registry. No module-level state lives here.\n */\n\nimport type { Texture2D } from \"../../texture/texture-2d.js\";\nimport type { UboField, BindingDecl, VertexAttribute, Varying } from \"../../shader/fragment-types.js\";\nimport type { GeometryTextureType } from \"../../frame-graph/geometry-types.js\";\n\n// ─── Graph (parser output) ───────────────────────────────────────────\n\n/** A single connection point on a block — input only.\n * Output connection types are resolved by the emitter at graph-walk time. */\nexport interface NodeConnection {\n /** Connection name on the owning block (e.g. \"rgb\", \"uv\", \"color\"). */\n readonly name: string;\n /** For inputs only: the upstream block id + output name. Null if unconnected. */\n readonly source: NodeConnectionRef | null;\n}\n\nexport interface NodeConnectionRef {\n readonly blockId: number;\n readonly outputName: string;\n}\n\n/** Parsed block in the graph. */\nexport interface NodeBlock {\n readonly id: number;\n /** BJS class name (e.g. \"InputBlock\", \"TransformBlock\", \"FragmentOutputBlock\"). */\n readonly className: string;\n /** Author-provided block name. */\n readonly name: string;\n /** Inputs by name. */\n readonly inputs: ReadonlyMap<string, NodeConnection>;\n /** Output names (type is resolved by the emitter). */\n readonly outputs: ReadonlySet<string>;\n /** Original serialized JSON for emitters that need extra fields (mode, value, etc.). */\n readonly serialized: Readonly<Record<string, unknown>>;\n}\n\n/** Parsed graph. Roots are FragmentOutputBlock + VertexOutputBlock (located by className). */\nexport interface NodeGraph {\n readonly blocks: ReadonlyMap<number, NodeBlock>;\n /** Named overridable inputs (uniform InputBlocks) — name → block id. */\n readonly namedInputs: ReadonlyMap<string, number>;\n /** BJS alpha mode (0=DISABLE, 2=COMBINE, …). Determines the GPU blend equation. */\n readonly alphaMode: number;\n /** Whether the material requires alpha blending at runtime.\n * Derived from the graph (FragmentOutputBlock.a is connected) plus\n * JSON-level overrides (`_needAlphaBlending`, `forceAlphaBlending`). */\n readonly needsAlphaBlending: boolean;\n /** Babylon.js material back-face culling flag. */\n readonly backFaceCulling: boolean;\n}\n\nexport interface NodePbrMrHelperRequest {\n readonly key: string;\n readonly useEnv: boolean;\n readonly useClearcoat: boolean;\n readonly useSheen: boolean;\n readonly useRefraction: boolean;\n readonly useSubsurface: boolean;\n readonly useAnisotropy: boolean;\n readonly useIridescence: boolean;\n readonly useShAlbedoScaling: boolean;\n readonly useCcBump: boolean;\n readonly useCcTint: boolean;\n readonly useSpecularAA: boolean;\n readonly remapClearcoatF0: boolean;\n}\n\n// ─── WGSL value types ───────────────────────────────────────────────\n\nexport type NodeValueType = \"f32\" | \"vec2f\" | \"vec3f\" | \"vec4f\" | \"mat4f\" | \"texture2d\" | \"textureCube\";\n\n/** Typed WGSL expression produced by an emitter. */\nexport interface NodeExpr {\n readonly expr: string;\n readonly type: NodeValueType;\n}\n\nexport const WGSL: Readonly<Record<NodeValueType, string>> = {\n f32: \"f32\",\n vec2f: \"vec2<f32>\",\n vec3f: \"vec3<f32>\",\n vec4f: \"vec4<f32>\",\n mat4f: \"mat4x4<f32>\",\n texture2d: \"texture_2d<f32>\",\n textureCube: \"texture_cube<f32>\",\n};\n\n// ─── Shader stage ───────────────────────────────────────────────────\n\n/** Which shader stage an emitter writes into. Neutral blocks can run in either;\n * the walker places them in the stage of their consumer (fragment by default). */\nexport type Stage = \"vertex\" | \"fragment\";\n\n// ─── Emitter API ────────────────────────────────────────────────────\n\n/** Accumulators for a single shader stage. */\nexport interface StageState {\n /** Top-level helper declarations (functions, constants) keyed by canonical id. */\n readonly helpers: Map<string, string>;\n /** Statements emitted inside main(). */\n readonly body: string[];\n /** Memoized (blockId, outputName) → expr for already-emitted values in this stage. */\n readonly memo: Map<string, NodeExpr>;\n}\n\nexport interface NodeLoopVariable {\n readonly valueVar: string;\n readonly valueType: NodeValueType;\n readonly indexVar: string;\n}\n\n/** Build state threaded through every emit call. */\nexport interface NodeBuildState {\n readonly vertex: StageState;\n readonly fragment: StageState;\n // Shared across stages:\n readonly vertexAttributes: VertexAttribute[];\n readonly varyings: Varying[];\n readonly nodeUboFields: UboField[];\n readonly bindings: BindingDecl[];\n readonly textures: NodeTextureBinding[];\n /** PBRMetallicRoughnessBlock helper bodies are large, so the block records\n * feature-specific helper requests here and node-material resolves them\n * through dynamic imports after graph emission. */\n readonly pbrMrHelperRequests: NodePbrMrHelperRequest[];\n /** Active LoopBlock storage variables keyed by `${stage}|${blockId}` while\n * the loop body is being emitted. StorageReadBlock/StorageWriteBlock use\n * this to route their loopID object connection to the mutable WGSL var. */\n readonly loopVariables: Map<string, NodeLoopVariable>;\n /** Monotonic counter for SSA temp names, shared across stages. */\n nextTemp: number;\n /** Set by any block that references the scene lights UBO (LightBlock,\n * LightInformationBlock, …). The pipeline builder allocates a binding +\n * struct decls + BGL entry when true. */\n usesLightsUbo: boolean;\n /** Set by ScreenSizeBlock. The pipeline exposes the current canvas size via\n * spare base scene-UBO scalars (no extra bindings / no per-graph UBO size change). */\n usesScreenSize: boolean;\n /** Set by FragDepthBlock. The pipeline switches the fragment return type\n * from a bare color to a `color+@builtin(frag_depth)` output struct. */\n usesFragDepth: boolean;\n usesClipPlanes: boolean;\n usesMeshAttributeExists: boolean;\n /** Set by MorphTargetsBlock. The pipeline allocates two vertex-only\n * bindings (morph texture + morph UBO), declares the struct, and adds\n * a `@builtin(vertex_index)` param to vs_main. */\n usesMorphTargets: boolean;\n /** Set by parseNodeMaterialFromSnippet when shadowGenerators are supplied.\n * The pipeline allocates shadow bindings (texture + sampler + UBO) per\n * shadow-casting light, emits light-space varyings in vs_main, and injects\n * a `nme_computeShadowFactors` helper that LightBlock calls before the\n * lighting loop. Zero entries = no bindings, no WGSL — invisible to scenes\n * without shadows. */\n shadowLights: { lightIndex: number; shadowType: \"esm\" | \"pcf\" }[];\n /** Set by ReflectionBlock or any block that needs scene env textures\n * (specular cube + BRDF LUT + SH irradiance). The pipeline allocates\n * 4 group-1 bindings (env_iblTexture/sampler + env_brdfLUT/sampler) and\n * reads SH coefficients + envRotationY + lodGenerationScale from the\n * canonical frame-graph scene UBO. Materials without env\n * pay zero — empty default. */\n usesEnv: boolean;\n /** Set by ClearCoatBlock; tells PBRMetallicRoughnessBlock to walk into\n * the connected ClearCoatBlock and emit the clear-coat layer code path\n * (extra GGX layer + Fresnel modulation of the base specular). */\n usesClearcoat: boolean;\n /** Set by SheenBlock; tells PBRMetallicRoughnessBlock to add the Charlie\n * NDF + Ashikhmin visibility sheen layer (cloth/velvet look). */\n usesSheen: boolean;\n /** Set by AnisotropyBlock; reserved for future anisotropic GGX path.\n * Currently used only to validate marker plumbing in scene 70 — at\n * intensity=0 the BJS anisotropic path reduces to standard GGX. */\n usesAnisotropy: boolean;\n /** Set by IridescenceBlock; tells PBRMetallicRoughnessBlock to replace the\n * base-layer F0 by the thin-film interference Fresnel color before direct\n * and IBL specular evaluation. */\n usesIridescence: boolean;\n /** Set by SubSurfaceBlock; reserved for future SS path. Marker only. */\n usesSubsurface: boolean;\n /** When false (default), BonesBlock emits a pass-through of its `world`\n * input — no skeleton binding is required. Set to true only when every\n * mesh using this material has a skeleton. */\n hasSkeleton: boolean;\n /** When false (default), InstancesBlock passes through the uniform world\n * matrix. Set to true when thin-instance attributes are bound. */\n hasInstances: boolean;\n /** @internal Populated by {@link GeometryTextureOutputBlock} during a\n * geometry-pass re-emit (see node-geometry-view.ts). Maps each CONNECTED\n * geometry input to its already-resolved WGSL expression so the node\n * pipeline can write the multi-attachment `FragmentOutput`. Absent\n * (undefined) for the normal colour pass, keeping zero footprint on\n * non-geometry node scenes. */\n _geometryInputs?: Map<GeometryTextureType, NodeExpr>;\n}\n\nexport interface NodeTextureBinding {\n readonly name: string;\n readonly kind: \"texture2d\" | \"textureCube\";\n readonly texture: Texture2D | null;\n}\n\n/** A block emitter — pure functions, no per-instance state. */\nexport interface BlockEmitter {\n /** Class name this emitter handles (e.g. \"InputBlock\"). */\n readonly className: string;\n /** Which shader stage this block produces into. Defaults to \"fragment\". */\n readonly stage?: Stage;\n /** Terminal \"side-effect\" block that has no outputs the graph reads (e.g.\n * DiscardBlock). emitGraph force-emits these after the root walk so they\n * participate even without a downstream consumer. */\n readonly sideEffect?: boolean;\n /** Emit the value of `outputName` for `block`, returning a typed WGSL expression. */\n emit(block: NodeBlock, outputName: string, stage: Stage, state: NodeBuildState, ctx: NodeEmitContext): NodeExpr;\n}\n\nexport interface NodeEmitContext {\n /** Resolve an input → WGSL expression (handles memoization + recursive walk). */\n readonly resolve: (block: NodeBlock, inputName: string, stage: Stage, state: NodeBuildState) => NodeExpr;\n /** Resolve a specific (producerBlock, outputName) — used when one block reads another directly. */\n readonly resolveOutput: (producer: NodeBlock, outputName: string, stage: Stage, state: NodeBuildState) => NodeExpr;\n /** Mint a fresh SSA temp name. */\n readonly temp: (state: NodeBuildState, prefix?: string) => string;\n /** Cast a typed expression to a target WGSL type when the shapes differ. */\n readonly cast: (value: NodeExpr, target: NodeValueType) => NodeExpr;\n /** Access the surrounding graph (so emitters can find upstream blocks). */\n readonly graph: NodeGraph;\n /** @internal */\n readonly _loadedEmitters: Map<string, BlockEmitter>;\n}\n"],"names":[],"mappings":"AAkFO,MAAM,IAAA,GAAgD;AAAA,EACzD,GAAA,EAAK,KAAA;AAAA,EACL,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,aAAA;AAAA,EACP,SAAA,EAAW,iBAAA;AAAA,EACX,WAAA,EAAa;AACjB;;;;"}
|
|
1
|
+
{"version":3,"file":"node-types.js","sources":["../../../../src/material/node/node-types.ts"],"sourcesContent":["/** Node Material — internal graph + emitter types.\n *\n * All types here are pure data. Block emitters are pure functions imported lazily\n * from `./blocks/*` via the registry. No module-level state lives here.\n */\n\nimport type { Texture2D } from \"../../texture/texture-2d.js\";\nimport type { UboField, BindingDecl, VertexAttribute, Varying } from \"../../shader/fragment-types.js\";\nimport type { GeometryTextureType } from \"../../frame-graph/geometry-types.js\";\n\n// ─── Graph (parser output) ───────────────────────────────────────────\n\n/** A single connection point on a block — input only.\n * Output connection types are resolved by the emitter at graph-walk time. */\nexport interface NodeConnection {\n /** Connection name on the owning block (e.g. \"rgb\", \"uv\", \"color\"). */\n readonly name: string;\n /** For inputs only: the upstream block id + output name. Null if unconnected. */\n readonly source: NodeConnectionRef | null;\n}\n\nexport interface NodeConnectionRef {\n readonly blockId: number;\n readonly outputName: string;\n}\n\n/** Parsed block in the graph. */\nexport interface NodeBlock {\n readonly id: number;\n /** BJS class name (e.g. \"InputBlock\", \"TransformBlock\", \"FragmentOutputBlock\"). */\n readonly className: string;\n /** Author-provided block name. */\n readonly name: string;\n /** Inputs by name. */\n readonly inputs: ReadonlyMap<string, NodeConnection>;\n /** Output names (type is resolved by the emitter). */\n readonly outputs: ReadonlySet<string>;\n /** Original serialized JSON for emitters that need extra fields (mode, value, etc.). */\n readonly serialized: Readonly<Record<string, unknown>>;\n}\n\n/** Parsed graph. Roots are FragmentOutputBlock + VertexOutputBlock (located by className). */\nexport interface NodeGraph {\n readonly blocks: ReadonlyMap<number, NodeBlock>;\n /** Named overridable inputs (uniform InputBlocks) — name → block id. */\n readonly namedInputs: ReadonlyMap<string, number>;\n /** BJS alpha mode (0=DISABLE, 2=COMBINE, …). Determines the GPU blend equation. */\n readonly alphaMode: number;\n /** Whether the material requires alpha blending at runtime.\n * Derived from the graph (FragmentOutputBlock.a is connected) plus\n * JSON-level overrides (`_needAlphaBlending`, `forceAlphaBlending`). */\n readonly needsAlphaBlending: boolean;\n /** Babylon.js material back-face culling flag. */\n readonly backFaceCulling: boolean;\n}\n\nexport interface NodePbrMrHelperRequest {\n readonly key: string;\n readonly useEnv: boolean;\n readonly useClearcoat: boolean;\n readonly useSheen: boolean;\n readonly useRefraction: boolean;\n readonly useSubsurface: boolean;\n readonly useAnisotropy: boolean;\n readonly useIridescence: boolean;\n readonly useShAlbedoScaling: boolean;\n readonly useCcBump: boolean;\n readonly useCcTint: boolean;\n readonly useSpecularAA: boolean;\n readonly remapClearcoatF0: boolean;\n}\n\n// ─── WGSL value types ───────────────────────────────────────────────\n\nexport type NodeValueType = \"f32\" | \"vec2f\" | \"vec3f\" | \"vec4f\" | \"mat4f\" | \"texture2d\" | \"textureCube\";\n\n/** Typed WGSL expression produced by an emitter. */\nexport interface NodeExpr {\n readonly expr: string;\n readonly type: NodeValueType;\n}\n\nexport const WGSL: Readonly<Record<NodeValueType, string>> = {\n f32: \"f32\",\n vec2f: \"vec2<f32>\",\n vec3f: \"vec3<f32>\",\n vec4f: \"vec4<f32>\",\n mat4f: \"mat4x4<f32>\",\n texture2d: \"texture_2d<f32>\",\n textureCube: \"texture_cube<f32>\",\n};\n\n// ─── Shader stage ───────────────────────────────────────────────────\n\n/** Which shader stage an emitter writes into. Neutral blocks can run in either;\n * the walker places them in the stage of their consumer (fragment by default). */\nexport type Stage = \"vertex\" | \"fragment\";\n\n// ─── Emitter API ────────────────────────────────────────────────────\n\n/** Accumulators for a single shader stage. */\nexport interface StageState {\n /** Top-level helper declarations (functions, constants) keyed by canonical id. */\n readonly helpers: Map<string, string>;\n /** Statements emitted inside main(). */\n readonly body: string[];\n /** Memoized (blockId, outputName) → expr for already-emitted values in this stage. */\n readonly memo: Map<string, NodeExpr>;\n}\n\nexport interface NodeLoopVariable {\n readonly valueVar: string;\n readonly valueType: NodeValueType;\n readonly indexVar: string;\n}\n\n/** Build state threaded through every emit call. */\nexport interface NodeBuildState {\n readonly vertex: StageState;\n readonly fragment: StageState;\n // Shared across stages:\n readonly vertexAttributes: VertexAttribute[];\n readonly varyings: Varying[];\n readonly nodeUboFields: UboField[];\n readonly bindings: BindingDecl[];\n readonly textures: NodeTextureBinding[];\n /** PBRMetallicRoughnessBlock helper bodies are large, so the block records\n * feature-specific helper requests here and node-material resolves them\n * through dynamic imports after graph emission. */\n readonly pbrMrHelperRequests: NodePbrMrHelperRequest[];\n /** Active LoopBlock storage variables keyed by `${stage}|${blockId}` while\n * the loop body is being emitted. StorageReadBlock/StorageWriteBlock use\n * this to route their loopID object connection to the mutable WGSL var. */\n readonly loopVariables: Map<string, NodeLoopVariable>;\n /** Monotonic counter for SSA temp names, shared across stages. */\n nextTemp: number;\n /** Set by any block that references the scene lights UBO (LightBlock,\n * LightInformationBlock, …). The pipeline builder allocates a binding +\n * struct decls + BGL entry when true. */\n usesLightsUbo: boolean;\n /** Set by ScreenSizeBlock. The pipeline exposes the current canvas size via\n * spare base scene-UBO scalars (no extra bindings / no per-graph UBO size change). */\n usesScreenSize: boolean;\n /** Set by FragDepthBlock. The pipeline switches the fragment return type\n * from a bare color to a `color+@builtin(frag_depth)` output struct. */\n usesFragDepth: boolean;\n usesClipPlanes: boolean;\n usesMeshAttributeExists: boolean;\n /** Set by MorphTargetsBlock. The pipeline allocates two vertex-only\n * bindings (morph texture + morph UBO), declares the struct, and adds\n * a `@builtin(vertex_index)` param to vs_main. */\n usesMorphTargets: boolean;\n /** Set by parseNodeMaterialFromSnippet when shadowGenerators are supplied.\n * The pipeline allocates shadow bindings (texture + sampler + UBO) per\n * shadow-casting light, emits light-space varyings in vs_main, and injects\n * a `nme_computeShadowFactors` helper that LightBlock calls before the\n * lighting loop. Zero entries = no bindings, no WGSL — invisible to scenes\n * without shadows. */\n shadowLights: { lightIndex: number; shadowType: \"esm\" | \"pcf\" }[];\n /** Set by ReflectionBlock or any block that needs scene env textures\n * (specular cube + BRDF LUT + SH irradiance). The pipeline allocates\n * 4 group-1 bindings (env_iblTexture/sampler + env_brdfLUT/sampler) and\n * reads SH coefficients + envRotationY + lodGenerationScale from the\n * canonical frame-graph scene UBO. Materials without env\n * pay zero — empty default. */\n usesEnv: boolean;\n /** Set by ClearCoatBlock; tells PBRMetallicRoughnessBlock to walk into\n * the connected ClearCoatBlock and emit the clear-coat layer code path\n * (extra GGX layer + Fresnel modulation of the base specular). */\n usesClearcoat: boolean;\n /** Set by SheenBlock; tells PBRMetallicRoughnessBlock to add the Charlie\n * NDF + Ashikhmin visibility sheen layer (cloth/velvet look). */\n usesSheen: boolean;\n /** Set by AnisotropyBlock; reserved for future anisotropic GGX path.\n * Currently used only to validate marker plumbing in scene 70 — at\n * intensity=0 the BJS anisotropic path reduces to standard GGX. */\n usesAnisotropy: boolean;\n /** Set by IridescenceBlock; tells PBRMetallicRoughnessBlock to replace the\n * base-layer F0 by the thin-film interference Fresnel color before direct\n * and IBL specular evaluation. */\n usesIridescence: boolean;\n /** Set by SubSurfaceBlock; reserved for future SS path. Marker only. */\n usesSubsurface: boolean;\n /** When false (default), BonesBlock emits a pass-through of its `world`\n * input — no skeleton binding is required. Set to true only when every\n * mesh using this material has a skeleton. */\n hasSkeleton: boolean;\n /** When false (default), InstancesBlock passes through the uniform world\n * matrix. Set to true when thin-instance attributes are bound. */\n hasInstances: boolean;\n /** @internal Populated by {@link GeometryTextureOutputBlock} during a\n * geometry-pass re-emit (see node-geometry-view.ts). Maps each CONNECTED\n * geometry input to its already-resolved WGSL expression so the node\n * pipeline can write the multi-attachment `FragmentOutput`. Absent\n * (undefined) for the normal colour pass, keeping zero footprint on\n * non-geometry node scenes. */\n _geometryInputs?: Map<GeometryTextureType, NodeExpr>;\n}\n\nexport interface NodeTextureBinding {\n readonly name: string;\n readonly kind: \"texture2d\" | \"textureCube\";\n readonly texture: Texture2D | null;\n}\n\n/** A block emitter — pure functions, no per-instance state. */\nexport interface BlockEmitter {\n /** Class name this emitter handles (e.g. \"InputBlock\"). */\n readonly className: string;\n /** Which shader stage this block produces into. Defaults to \"fragment\". */\n readonly stage?: Stage;\n /** Terminal \"side-effect\" block that has no outputs the graph reads (e.g.\n * DiscardBlock). emitGraph force-emits these after the root walk so they\n * participate even without a downstream consumer. */\n readonly sideEffect?: boolean;\n /** Emit the value of `outputName` for `block`, returning a typed WGSL expression. */\n emit(block: NodeBlock, outputName: string, stage: Stage, state: NodeBuildState, ctx: NodeEmitContext): NodeExpr;\n}\n\nexport interface NodeEmitContext {\n /** Resolve an input → WGSL expression (handles memoization + recursive walk). */\n readonly resolve: (block: NodeBlock, inputName: string, stage: Stage, state: NodeBuildState) => NodeExpr;\n /** Resolve a specific (producerBlock, outputName) — used when one block reads another directly. */\n readonly resolveOutput: (producer: NodeBlock, outputName: string, stage: Stage, state: NodeBuildState) => NodeExpr;\n /** Mint a fresh SSA temp name. */\n readonly temp: (state: NodeBuildState, prefix?: string) => string;\n /** Cast a typed expression to a target WGSL type when the shapes differ. */\n readonly cast: (value: NodeExpr, target: NodeValueType) => NodeExpr;\n /** Sanitize a block/input name for use as a WGSL identifier. */\n readonly sanitize: (name: string) => string;\n /** Map Babylon.js connection-point flags to Lite's node value types. */\n readonly bjsTypeToNodeType: (type: number, source?: string) => NodeValueType;\n /** Access the surrounding graph (so emitters can find upstream blocks). */\n readonly graph: NodeGraph;\n /** @internal */\n readonly _loadedEmitters: Map<string, BlockEmitter>;\n}\n"],"names":[],"mappings":"AAkFO,MAAM,IAAA,GAAgD;AAAA,EACzD,GAAA,EAAK,KAAA;AAAA,EACL,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,aAAA;AAAA,EACP,SAAA,EAAW,iBAAA;AAAA,EACX,WAAA,EAAa;AACjB;;;;"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { PBR_HAS_ALPHA_BLEND } from '../pbr-flag-bits.js';
|
|
2
|
+
import { MAX_LIGHTS } from '../../../light/types.js';
|
|
3
|
+
|
|
4
|
+
const PBR2_HAS_SHADOW_ONLY = 1 << 30;
|
|
5
|
+
function createShadowOnlyFragment() {
|
|
6
|
+
const unrolled = [];
|
|
7
|
+
for (let i = 0; i < MAX_LIGHTS; i++) {
|
|
8
|
+
unrolled.push(`so_shadowMin = min(so_shadowMin, shadowFactors[${i}]);`);
|
|
9
|
+
}
|
|
10
|
+
const bc = `
|
|
11
|
+
{
|
|
12
|
+
var so_shadowMin = 1.0;
|
|
13
|
+
${unrolled.join("\n")}
|
|
14
|
+
color = material.shadowOnlyColor;
|
|
15
|
+
alpha = saturate((1.0 - so_shadowMin) * material.shadowOnlyFalloff) * material.shadowOnlyOpacity;
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
18
|
+
return {
|
|
19
|
+
_id: "shadow-only",
|
|
20
|
+
_uboFields: [
|
|
21
|
+
{ _name: "shadowOnlyColor", _type: "vec3<f32>" },
|
|
22
|
+
{ _name: "shadowOnlyOpacity", _type: "f32" },
|
|
23
|
+
{ _name: "shadowOnlyFalloff", _type: "f32" }
|
|
24
|
+
],
|
|
25
|
+
_fragmentSlots: {
|
|
26
|
+
BC: bc,
|
|
27
|
+
// Overwrite finalAlpha after the alpha block's luminanceOverAlpha fold so
|
|
28
|
+
// environment/direct specular can't make the shadow catcher opaque. `alpha`
|
|
29
|
+
// holds the shadow term set in BC.
|
|
30
|
+
FA: `finalAlpha = alpha * material.materialAlpha;`
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function writeShadowOnlyUBO(data, material, offsets) {
|
|
35
|
+
if (!material.shadowOnly) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (offsets.has("shadowOnlyColor")) {
|
|
39
|
+
const off = offsets.get("shadowOnlyColor") / 4;
|
|
40
|
+
const tint = material.shadowOnlyColor ?? [0, 0, 0];
|
|
41
|
+
data[off] = tint[0];
|
|
42
|
+
data[off + 1] = tint[1];
|
|
43
|
+
data[off + 2] = tint[2];
|
|
44
|
+
}
|
|
45
|
+
if (offsets.has("shadowOnlyOpacity")) {
|
|
46
|
+
data[offsets.get("shadowOnlyOpacity") / 4] = material.shadowOnlyOpacity ?? 1;
|
|
47
|
+
}
|
|
48
|
+
if (offsets.has("shadowOnlyFalloff")) {
|
|
49
|
+
data[offsets.get("shadowOnlyFalloff") / 4] = material.shadowOnlyFalloff ?? 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const pbrExt = {
|
|
53
|
+
id: "shadow-only",
|
|
54
|
+
phase: "fragment",
|
|
55
|
+
detect(mat) {
|
|
56
|
+
return mat.shadowOnly ? { f: PBR_HAS_ALPHA_BLEND, f2: PBR2_HAS_SHADOW_ONLY } : { f: 0, f2: 0 };
|
|
57
|
+
},
|
|
58
|
+
frag(ctx) {
|
|
59
|
+
if (!(ctx._features2 & PBR2_HAS_SHADOW_ONLY)) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return createShadowOnlyFragment();
|
|
63
|
+
},
|
|
64
|
+
writeUbo: writeShadowOnlyUBO
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export { createShadowOnlyFragment, pbrExt, writeShadowOnlyUBO };
|
|
68
|
+
//# sourceMappingURL=shadow-only-fragment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadow-only-fragment.js","sources":["../../../../../src/material/pbr/fragments/shadow-only-fragment.ts"],"sourcesContent":["/**\n * Shadow-Only Fragment.\n *\n * Mirrors BJS `BackgroundMaterial.shadowOnly`: the surface is invisible except\n * where shadow falls on it. Unshadowed fragments output alpha=0 (fully\n * transparent); shadowed fragments output alpha proportional to the shadow\n * strength, in a caller-chosen `shadowOnlyColor` (defaults to black).\n *\n * Zero bytes in bundles for scenes that don't use shadow-only materials — the\n * module is dynamically imported by pbr-renderable only when at least one mesh\n * in the scene has `mat.shadowOnly === true`.\n *\n * Implementation notes\n * --------------------\n * A shadow-only mesh sets `receiveShadows = true`, which forces the multi-light\n * PBR path (lightMode = 2). That path declares\n * `var shadowFactors: array<f32, MAX_LIGHTS>` (all entries initialised to 1.0 =\n * no shadow) at fragment-main\n * scope and the shadow fragment writes the real shadow factor into\n * `shadowFactors[lightIndex]` for each shadow-casting light.\n *\n * In the BC slot (just before the alpha-blend block, after the color path) we\n * override the final color with `shadowOnlyColor` and override `alpha` with the\n * shadow term so the surface is opaque where shadow is and transparent where it\n * isn't.\n *\n * The alpha-blend block then folds `luminanceOverAlpha` (direct + IBL specular\n * luminance) into `finalAlpha`, which would make a shadow catcher opaque\n * wherever the environment reflects in it. `finalSpecularScaled` /\n * `finalRadianceScaled` are immutable `let`s at that point, so we cannot zero\n * them from BC. Instead we inject the `FA` slot (emitted just before the alpha\n * return) to overwrite `finalAlpha` with the pure shadow term, bypassing the\n * luminance bleed entirely. The `FA` marker costs nothing in shaders that don't\n * load this fragment.\n */\n\nimport type { ShaderFragment } from \"../../../shader/fragment-types.js\";\nimport type { PbrMaterialProps } from \"../pbr-material.js\";\nimport type { PbrExt } from \"../pbr-flags.js\";\nimport { PBR_HAS_ALPHA_BLEND } from \"../pbr-flags.js\";\nimport { MAX_LIGHTS } from \"../../../light/types.js\";\n\n// Feature2 bit local to this lazy module (see pbr-flag-bits.ts): never retained\n// in the entry/shared chunk for scenes that don't load this fragment.\nconst PBR2_HAS_SHADOW_ONLY = 1 << 30;\n\n/**\n * Create a shadow-only fragment that overrides color/alpha at the BC injection point.\n *\n * Unrolls a `min()` across the local `shadowFactors` array (declared by the\n * multi-light block) to compute the strongest shadow term, then overwrites\n * `color` and `alpha` with the shadow-only outputs.\n */\nexport function createShadowOnlyFragment(): ShaderFragment {\n const unrolled: string[] = [];\n for (let i = 0; i < MAX_LIGHTS; i++) {\n unrolled.push(`so_shadowMin = min(so_shadowMin, shadowFactors[${i}]);`);\n }\n const bc = `\n{\nvar so_shadowMin = 1.0;\n${unrolled.join(\"\\n\")}\ncolor = material.shadowOnlyColor;\nalpha = saturate((1.0 - so_shadowMin) * material.shadowOnlyFalloff) * material.shadowOnlyOpacity;\n}\n`;\n\n return {\n _id: \"shadow-only\",\n _uboFields: [\n { _name: \"shadowOnlyColor\", _type: \"vec3<f32>\" },\n { _name: \"shadowOnlyOpacity\", _type: \"f32\" },\n { _name: \"shadowOnlyFalloff\", _type: \"f32\" },\n ],\n _fragmentSlots: {\n BC: bc,\n // Overwrite finalAlpha after the alpha block's luminanceOverAlpha fold so\n // environment/direct specular can't make the shadow catcher opaque. `alpha`\n // holds the shadow term set in BC.\n FA: `finalAlpha = alpha * material.materialAlpha;`,\n },\n };\n}\n\n/** Write the shadow-only material-UBO slice. */\nexport function writeShadowOnlyUBO(data: Float32Array, material: PbrMaterialProps, offsets: ReadonlyMap<string, number>): void {\n if (!material.shadowOnly) {\n return;\n }\n if (offsets.has(\"shadowOnlyColor\")) {\n const off = offsets.get(\"shadowOnlyColor\")! / 4;\n const tint = material.shadowOnlyColor ?? [0, 0, 0];\n data[off] = tint[0]!;\n data[off + 1] = tint[1]!;\n data[off + 2] = tint[2]!;\n }\n if (offsets.has(\"shadowOnlyOpacity\")) {\n data[offsets.get(\"shadowOnlyOpacity\")! / 4] = material.shadowOnlyOpacity ?? 1.0;\n }\n if (offsets.has(\"shadowOnlyFalloff\")) {\n data[offsets.get(\"shadowOnlyFalloff\")! / 4] = material.shadowOnlyFalloff ?? 1.0;\n }\n}\n\nexport const pbrExt: PbrExt = {\n id: \"shadow-only\",\n phase: \"fragment\",\n detect(mat) {\n // Force PBR_HAS_ALPHA_BLEND so the shadow catcher composites as a transparent\n // surface regardless of whether the caller set `alpha`/`alphaBlend`. This is\n // required for correctness: (1) `isTransparent` in pbr-renderable keys off\n // PBR_HAS_ALPHA_BLEND to admit the mesh into the transparent pass with GPU\n // blending, and (2) the `/*FA*/` slot this fragment injects only exists in the\n // template's alpha-blend branch. The bit lives in the shared chunk already, so\n // forcing it here adds no bytes to scenes that never load this fragment.\n return (mat as PbrMaterialProps).shadowOnly ? { f: PBR_HAS_ALPHA_BLEND, f2: PBR2_HAS_SHADOW_ONLY } : { f: 0, f2: 0 };\n },\n frag(ctx) {\n if (!(ctx._features2 & PBR2_HAS_SHADOW_ONLY)) {\n return null;\n }\n return createShadowOnlyFragment();\n },\n writeUbo: writeShadowOnlyUBO as PbrExt[\"writeUbo\"],\n};\n"],"names":[],"mappings":";;;AA4CA,MAAM,uBAAuB,CAAA,IAAK,EAAA;AAS3B,SAAS,wBAAA,GAA2C;AACvD,EAAA,MAAM,WAAqB,EAAC;AAC5B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,UAAA,EAAY,CAAA,EAAA,EAAK;AACjC,IAAA,QAAA,CAAS,IAAA,CAAK,CAAA,+CAAA,EAAkD,CAAC,CAAA,GAAA,CAAK,CAAA;AAAA,EAC1E;AACA,EAAA,MAAM,EAAA,GAAK;AAAA;AAAA;AAAA,EAGb,QAAA,CAAS,IAAA,CAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA,CAAA;AAMjB,EAAA,OAAO;AAAA,IACH,GAAA,EAAK,aAAA;AAAA,IACL,UAAA,EAAY;AAAA,MACR,EAAE,KAAA,EAAO,iBAAA,EAAmB,KAAA,EAAO,WAAA,EAAY;AAAA,MAC/C,EAAE,KAAA,EAAO,mBAAA,EAAqB,KAAA,EAAO,KAAA,EAAM;AAAA,MAC3C,EAAE,KAAA,EAAO,mBAAA,EAAqB,KAAA,EAAO,KAAA;AAAM,KAC/C;AAAA,IACA,cAAA,EAAgB;AAAA,MACZ,EAAA,EAAI,EAAA;AAAA;AAAA;AAAA;AAAA,MAIJ,EAAA,EAAI,CAAA,4CAAA;AAAA;AACR,GACJ;AACJ;AAGO,SAAS,kBAAA,CAAmB,IAAA,EAAoB,QAAA,EAA4B,OAAA,EAA4C;AAC3H,EAAA,IAAI,CAAC,SAAS,UAAA,EAAY;AACtB,IAAA;AAAA,EACJ;AACA,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,iBAAiB,CAAA,EAAG;AAChC,IAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,GAAA,CAAI,iBAAiB,CAAA,GAAK,CAAA;AAC9C,IAAA,MAAM,OAAO,QAAA,CAAS,eAAA,IAAmB,CAAC,CAAA,EAAG,GAAG,CAAC,CAAA;AACjD,IAAA,IAAA,CAAK,GAAG,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAClB,IAAA,IAAA,CAAK,GAAA,GAAM,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACtB,IAAA,IAAA,CAAK,GAAA,GAAM,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAAA,EAC1B;AACA,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,mBAAmB,CAAA,EAAG;AAClC,IAAA,IAAA,CAAK,QAAQ,GAAA,CAAI,mBAAmB,IAAK,CAAC,CAAA,GAAI,SAAS,iBAAA,IAAqB,CAAA;AAAA,EAChF;AACA,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,mBAAmB,CAAA,EAAG;AAClC,IAAA,IAAA,CAAK,QAAQ,GAAA,CAAI,mBAAmB,IAAK,CAAC,CAAA,GAAI,SAAS,iBAAA,IAAqB,CAAA;AAAA,EAChF;AACJ;AAEO,MAAM,MAAA,GAAiB;AAAA,EAC1B,EAAA,EAAI,aAAA;AAAA,EACJ,KAAA,EAAO,UAAA;AAAA,EACP,OAAO,GAAA,EAAK;AAQR,IAAA,OAAQ,GAAA,CAAyB,UAAA,GAAa,EAAE,CAAA,EAAG,mBAAA,EAAqB,EAAA,EAAI,oBAAA,EAAqB,GAAI,EAAE,CAAA,EAAG,CAAA,EAAG,EAAA,EAAI,CAAA,EAAE;AAAA,EACvH,CAAA;AAAA,EACA,KAAK,GAAA,EAAK;AACN,IAAA,IAAI,EAAE,GAAA,CAAI,UAAA,GAAa,oBAAA,CAAA,EAAuB;AAC1C,MAAA,OAAO,IAAA;AAAA,IACX;AACA,IAAA,OAAO,wBAAA,EAAyB;AAAA,EACpC,CAAA;AAAA,EACA,QAAA,EAAU;AACd;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pbr-flag-bits.js","sources":["../../../../src/material/pbr/pbr-flag-bits.ts"],"sourcesContent":["export const PBR_HAS_NORMAL_MAP = 1 << 0;\nexport const PBR_HAS_EMISSIVE = 1 << 1;\nexport const PBR_HAS_ENV = 1 << 2;\nexport const PBR_HAS_ALPHA_TEST = 1 << 3;\nexport const PBR_HAS_TONEMAP = 1 << 4;\n/** Scene has fog enabled (scene.fog != null). A scene-feature bit (threaded via\n * sceneFeatures), gating the PBR fog blend + calcFogFactor helper into the shader.\n * Compile-time gated so non-fog PBR scenes stay byte-identical. */\nexport const PBR_HAS_FOG = 1 << 5;\nexport const PBR_HAS_ALPHA_BLEND = 1 << 6;\nexport const PBR_HAS_SPEC_GLOSS = 1 << 7;\nexport const PBR_HAS_DOUBLE_SIDED = 1 << 8;\nexport const PBR_HAS_COTANGENT_NORMAL = 1 << 9;\nexport const PBR_HAS_METALLIC_REFLECTANCE_MAP = 1 << 10;\nexport const PBR_HAS_REFLECTANCE_MAP = 1 << 11;\nexport const PBR_HAS_USE_ALPHA_ONLY_MR = 1 << 12;\nexport const PBR_HAS_OCCLUSION = 1 << 15;\nexport const PBR_HAS_SPECULAR_AA = 1 << 17;\nexport const PBR_HAS_CLEARCOAT = 1 << 20;\nexport const PBR_HAS_EMISSIVE_COLOR = 1 << 21;\nexport const PBR_HAS_SHEEN = 1 << 22;\nexport const PBR_HAS_SHEEN_TEXTURE = 1 << 23;\nexport const PBR_HAS_GAMMA_ALBEDO = 1 << 25;\nexport const PBR_HAS_ANISOTROPY = 1 << 26;\nexport const PBR_HAS_SUBSURFACE = 1 << 27;\nexport const PBR_HAS_THICKNESS_MAP = 1 << 28;\nexport const PBR_HAS_SKYBOX = 1 << 29;\nexport const PBR_HAS_SHEEN_ALBEDO_SCALING = 1 << 30;\n\n// ─── features2 (extended feature bits) ──────────────────────────────\n// Used when `features` runs out of bits. Threaded separately through\n// composePbr / getOrCreatePbrPipeline / createPbrMeshBindGroup.\n// 1<<0 .. 1<<3 are clearcoat-local (clearcoat-fragment.ts).\n/** Material has KHR_materials_transmission (refraction through surface). */\nexport const PBR2_HAS_REFRACTION = 1 << 4;\n// 1<<5 .. 1<<7 are refraction/subsurface-local; 1<<8 is unlit-local.\n/** Any bound texture on this material carries a non-identity UV transform\n * (`uScale/vScale/uOffset/vOffset/uAng` on its Texture2D). Enables per-\n * texture UV-transform UBO fields + `txfUV` wrapping in the shader. */\nexport const PBR2_HAS_UV_TRANSFORM = 1 << 9;\n/** Material has non-default metallicF0Factor or metallicReflectanceColor\n * without reflectance textures (factor-only KHR_materials_specular). */\nexport const PBR2_HAS_REFLECTANCE_FACTORS = 1 << 10;\n/** Material samples occlusion from TEXCOORD_1 when the mesh provides UV2. */\nexport const PBR2_HAS_UV2 = 1 << 11;\n/** Material multiplies textured albedo by a non-default glTF baseColorFactor. */\nexport const PBR2_HAS_BASE_COLOR_FACTOR = 1 << 12;\n// 1<<13 is sheen-local; 1<<14 is refraction-local.\n/** Material view runs the fragment shader but declares no color output. */\nexport const PBR2_NO_COLOR_OUTPUT = 1 << 15;\n/** Material view runs discard/clip logic and writes exponential shadow-map color. */\nexport const PBR2_ESM_SHADOW_OUTPUT = 1 << 16;\n// 1<<17 .. 1<<19 are iridescence-local; 1<<20 is refraction-local;\n// 1<<21 is geometry-output-local.\n// ─── Extension-local features2 bits (1<<22 .. 1<<28) ────────────────\n// RESERVED here but DEFINED inside their lazy fragment modules so the constants\n// are never retained in the entry/shared chunk for scenes that don't load those\n// fragments (literally zero bundle movement). Do not reuse these bits.\n// 1<<22 PBR2_HAS_TRANSLUCENCY_COLOR_MAP (subsurface-fragment.ts)\n// 1<<23 PBR2_HAS_TRANSLUCENCY_INTENSITY_MAP (subsurface-fragment.ts)\n// 1<<24 PBR2_HAS_TRANSLUCENCY_UV_TX (subsurface-fragment.ts)\n// 1<<25 PBR2_CC_UV_TX (clearcoat-fragment.ts)\n// 1<<26 PBR2_REFL_UV_TX (reflectance-fragment.ts)\n// 1<<27 PBR2_HAS_ANISO_TEX (anisotropy-fragment.ts)\n// 1<<28 PBR2_OCCL_UV_SPLIT (uv-transform-fragment.ts + pbr-template-ext.ts)\n"],"names":[],"mappings":"AAAO,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,mBAAmB,CAAA,IAAK;AAC9B,MAAM,cAAc,CAAA,IAAK;AACzB,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,kBAAkB,CAAA,IAAK;AAI7B,MAAM,cAAc,CAAA,IAAK;AACzB,MAAM,sBAAsB,CAAA,IAAK;AACjC,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,uBAAuB,CAAA,IAAK;AAClC,MAAM,2BAA2B,CAAA,IAAK;AACtC,MAAM,mCAAmC,CAAA,IAAK;AAC9C,MAAM,0BAA0B,CAAA,IAAK;AACrC,MAAM,4BAA4B,CAAA,IAAK;AACvC,MAAM,oBAAoB,CAAA,IAAK;AAC/B,MAAM,sBAAsB,CAAA,IAAK;AACjC,MAAM,oBAAoB,CAAA,IAAK;AAC/B,MAAM,yBAAyB,CAAA,IAAK;AACpC,MAAM,gBAAgB,CAAA,IAAK;AAC3B,MAAM,wBAAwB,CAAA,IAAK;AACnC,MAAM,uBAAuB,CAAA,IAAK;AAClC,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,wBAAwB,CAAA,IAAK;AACnC,MAAM,iBAAiB,CAAA,IAAK;AAC5B,MAAM,+BAA+B,CAAA,IAAK;AAO1C,MAAM,sBAAsB,CAAA,IAAK;AAKjC,MAAM,wBAAwB,CAAA,IAAK;AAGnC,MAAM,+BAA+B,CAAA,IAAK;AAE1C,MAAM,eAAe,CAAA,IAAK;AAE1B,MAAM,6BAA6B,CAAA,IAAK;AAGxC,MAAM,uBAAuB,CAAA,IAAK;AAElC,MAAM,yBAAyB,CAAA,IAAK;;;;"}
|
|
1
|
+
{"version":3,"file":"pbr-flag-bits.js","sources":["../../../../src/material/pbr/pbr-flag-bits.ts"],"sourcesContent":["export const PBR_HAS_NORMAL_MAP = 1 << 0;\nexport const PBR_HAS_EMISSIVE = 1 << 1;\nexport const PBR_HAS_ENV = 1 << 2;\nexport const PBR_HAS_ALPHA_TEST = 1 << 3;\nexport const PBR_HAS_TONEMAP = 1 << 4;\n/** Scene has fog enabled (scene.fog != null). A scene-feature bit (threaded via\n * sceneFeatures), gating the PBR fog blend + calcFogFactor helper into the shader.\n * Compile-time gated so non-fog PBR scenes stay byte-identical. */\nexport const PBR_HAS_FOG = 1 << 5;\nexport const PBR_HAS_ALPHA_BLEND = 1 << 6;\nexport const PBR_HAS_SPEC_GLOSS = 1 << 7;\nexport const PBR_HAS_DOUBLE_SIDED = 1 << 8;\nexport const PBR_HAS_COTANGENT_NORMAL = 1 << 9;\nexport const PBR_HAS_METALLIC_REFLECTANCE_MAP = 1 << 10;\nexport const PBR_HAS_REFLECTANCE_MAP = 1 << 11;\nexport const PBR_HAS_USE_ALPHA_ONLY_MR = 1 << 12;\nexport const PBR_HAS_OCCLUSION = 1 << 15;\nexport const PBR_HAS_SPECULAR_AA = 1 << 17;\nexport const PBR_HAS_CLEARCOAT = 1 << 20;\nexport const PBR_HAS_EMISSIVE_COLOR = 1 << 21;\nexport const PBR_HAS_SHEEN = 1 << 22;\nexport const PBR_HAS_SHEEN_TEXTURE = 1 << 23;\nexport const PBR_HAS_GAMMA_ALBEDO = 1 << 25;\nexport const PBR_HAS_ANISOTROPY = 1 << 26;\nexport const PBR_HAS_SUBSURFACE = 1 << 27;\nexport const PBR_HAS_THICKNESS_MAP = 1 << 28;\nexport const PBR_HAS_SKYBOX = 1 << 29;\nexport const PBR_HAS_SHEEN_ALBEDO_SCALING = 1 << 30;\n\n// ─── features2 (extended feature bits) ──────────────────────────────\n// Used when `features` runs out of bits. Threaded separately through\n// composePbr / getOrCreatePbrPipeline / createPbrMeshBindGroup.\n// 1<<0 .. 1<<3 are clearcoat-local (clearcoat-fragment.ts).\n/** Material has KHR_materials_transmission (refraction through surface). */\nexport const PBR2_HAS_REFRACTION = 1 << 4;\n// 1<<5 .. 1<<7 are refraction/subsurface-local; 1<<8 is unlit-local.\n/** Any bound texture on this material carries a non-identity UV transform\n * (`uScale/vScale/uOffset/vOffset/uAng` on its Texture2D). Enables per-\n * texture UV-transform UBO fields + `txfUV` wrapping in the shader. */\nexport const PBR2_HAS_UV_TRANSFORM = 1 << 9;\n/** Material has non-default metallicF0Factor or metallicReflectanceColor\n * without reflectance textures (factor-only KHR_materials_specular). */\nexport const PBR2_HAS_REFLECTANCE_FACTORS = 1 << 10;\n/** Material samples occlusion from TEXCOORD_1 when the mesh provides UV2. */\nexport const PBR2_HAS_UV2 = 1 << 11;\n/** Material multiplies textured albedo by a non-default glTF baseColorFactor. */\nexport const PBR2_HAS_BASE_COLOR_FACTOR = 1 << 12;\n// 1<<13 is sheen-local; 1<<14 is refraction-local.\n/** Material view runs the fragment shader but declares no color output. */\nexport const PBR2_NO_COLOR_OUTPUT = 1 << 15;\n/** Material view runs discard/clip logic and writes exponential shadow-map color. */\nexport const PBR2_ESM_SHADOW_OUTPUT = 1 << 16;\n// 1<<17 .. 1<<19 are iridescence-local; 1<<20 is refraction-local;\n// 1<<21 is geometry-output-local.\n// ─── Extension-local features2 bits (1<<22 .. 1<<28) ────────────────\n// RESERVED here but DEFINED inside their lazy fragment modules so the constants\n// are never retained in the entry/shared chunk for scenes that don't load those\n// fragments (literally zero bundle movement). Do not reuse these bits.\n// 1<<22 PBR2_HAS_TRANSLUCENCY_COLOR_MAP (subsurface-fragment.ts)\n// 1<<23 PBR2_HAS_TRANSLUCENCY_INTENSITY_MAP (subsurface-fragment.ts)\n// 1<<24 PBR2_HAS_TRANSLUCENCY_UV_TX (subsurface-fragment.ts)\n// 1<<25 PBR2_CC_UV_TX (clearcoat-fragment.ts)\n// 1<<26 PBR2_REFL_UV_TX (reflectance-fragment.ts)\n// 1<<27 PBR2_HAS_ANISO_TEX (anisotropy-fragment.ts)\n// 1<<28 PBR2_OCCL_UV_SPLIT (uv-transform-fragment.ts + pbr-template-ext.ts)\n// 1<<30 PBR2_HAS_SHADOW_ONLY (shadow-only-fragment.ts)\n"],"names":[],"mappings":"AAAO,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,mBAAmB,CAAA,IAAK;AAC9B,MAAM,cAAc,CAAA,IAAK;AACzB,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,kBAAkB,CAAA,IAAK;AAI7B,MAAM,cAAc,CAAA,IAAK;AACzB,MAAM,sBAAsB,CAAA,IAAK;AACjC,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,uBAAuB,CAAA,IAAK;AAClC,MAAM,2BAA2B,CAAA,IAAK;AACtC,MAAM,mCAAmC,CAAA,IAAK;AAC9C,MAAM,0BAA0B,CAAA,IAAK;AACrC,MAAM,4BAA4B,CAAA,IAAK;AACvC,MAAM,oBAAoB,CAAA,IAAK;AAC/B,MAAM,sBAAsB,CAAA,IAAK;AACjC,MAAM,oBAAoB,CAAA,IAAK;AAC/B,MAAM,yBAAyB,CAAA,IAAK;AACpC,MAAM,gBAAgB,CAAA,IAAK;AAC3B,MAAM,wBAAwB,CAAA,IAAK;AACnC,MAAM,uBAAuB,CAAA,IAAK;AAClC,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,qBAAqB,CAAA,IAAK;AAChC,MAAM,wBAAwB,CAAA,IAAK;AACnC,MAAM,iBAAiB,CAAA,IAAK;AAC5B,MAAM,+BAA+B,CAAA,IAAK;AAO1C,MAAM,sBAAsB,CAAA,IAAK;AAKjC,MAAM,wBAAwB,CAAA,IAAK;AAGnC,MAAM,+BAA+B,CAAA,IAAK;AAE1C,MAAM,eAAe,CAAA,IAAK;AAE1B,MAAM,6BAA6B,CAAA,IAAK;AAGxC,MAAM,uBAAuB,CAAA,IAAK;AAElC,MAAM,yBAAyB,CAAA,IAAK;;;;"}
|