@babylonjs/lite 1.6.0 → 1.8.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 +735 -0
- package/README.md +26 -1
- package/THIRD_PARTY_NOTICES.txt +139 -0
- package/dist/index.js +321 -301
- package/dist/index.js.map +1 -1
- package/index.d.ts +294 -13
- package/lib/_chunks/vendor/{manifold-Sh8xE2da.js → manifold-DtI3BJoR.js} +2 -2
- package/lib/_chunks/vendor/{manifold-Sh8xE2da.js.map → manifold-DtI3BJoR.js.map} +1 -1
- package/lib/animation/animation-group-task.js +1 -1
- package/lib/animation/animation-group-task.js.map +1 -1
- package/lib/animation/animation-group.js +20 -15
- package/lib/animation/animation-group.js.map +1 -1
- package/lib/animation/animation-tick.js +10 -0
- package/lib/animation/animation-tick.js.map +1 -0
- package/lib/animation/property-animation.js +2 -1
- package/lib/animation/property-animation.js.map +1 -1
- package/lib/animation/weighted-gltf-mixer.js +1 -1
- package/lib/animation/weighted-gltf-mixer.js.map +1 -1
- package/lib/animation/weighted-pointer-mixer.js +1 -1
- package/lib/animation/weighted-pointer-mixer.js.map +1 -1
- package/lib/engine/device-lost-recovery.js +1 -0
- package/lib/engine/device-lost-recovery.js.map +1 -1
- package/lib/engine/engine.js +1 -1
- package/lib/engine/null-engine.js +29 -0
- package/lib/engine/null-engine.js.map +1 -0
- package/lib/frame-graph/depth-pyramid.js +158 -0
- package/lib/frame-graph/depth-pyramid.js.map +1 -0
- package/lib/frame-graph/depth-resolve-task.js +117 -0
- package/lib/frame-graph/depth-resolve-task.js.map +1 -0
- package/lib/frame-graph/frame-graph-actions.js +10 -1
- package/lib/frame-graph/frame-graph-actions.js.map +1 -1
- package/lib/frame-graph/render-task.js +7 -0
- package/lib/frame-graph/render-task.js.map +1 -1
- package/lib/frame-graph/transmission-depth-grab.js +88 -0
- package/lib/frame-graph/transmission-depth-grab.js.map +1 -0
- package/lib/frame-graph/transmission.js +34 -4
- package/lib/frame-graph/transmission.js.map +1 -1
- package/lib/gizmo/bounding-box-gizmo.js +1 -1
- package/lib/index.js +9 -6
- package/lib/index.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-gpu-instancing.js +1 -1
- package/lib/loader-gltf/gltf-interleave.js +1 -1
- package/lib/loader-gltf/load-gltf.js +1 -1
- package/lib/material/shader/shader-material.js +4 -2
- package/lib/material/shader/shader-material.js.map +1 -1
- package/lib/material/shader/shader-pipeline.js +11 -1
- package/lib/material/shader/shader-pipeline.js.map +1 -1
- package/lib/material/shader/shader-renderable.js +42 -14
- package/lib/material/shader/shader-renderable.js.map +1 -1
- package/lib/material/shader/shader-thin-instance.js +1 -1
- package/lib/material/shader/shader-thin-instance.js.map +1 -1
- package/lib/math/aabb.js +1 -1
- package/lib/math/compute-aabb.js +63 -1
- package/lib/math/compute-aabb.js.map +1 -1
- package/lib/math/index.js +1 -1
- package/lib/mesh/csg2.js +3 -2
- package/lib/mesh/csg2.js.map +1 -1
- package/lib/mesh/mesh-factories.js +1 -1
- package/lib/mesh/thin-instance-gpu-culling.js +4 -2
- package/lib/mesh/thin-instance-gpu-culling.js.map +1 -1
- package/lib/mesh/thin-instance.js +8 -1
- package/lib/mesh/thin-instance.js.map +1 -1
- package/lib/navigation/index.js +1 -1
- package/lib/navigation/navigation.js +9 -1
- package/lib/navigation/navigation.js.map +1 -1
- package/lib/physics/character-controller.js +2 -2
- package/lib/physics/character-controller.js.map +1 -1
- package/lib/physics/havok-floating-origin.js +2 -2
- package/lib/physics/havok-floating-origin.js.map +1 -1
- package/lib/physics/havok.js +40 -13
- package/lib/physics/havok.js.map +1 -1
- package/lib/picking/gpu-picker.js +16 -2
- package/lib/picking/gpu-picker.js.map +1 -1
- package/lib/scene/scene-core.js +14 -5
- package/lib/scene/scene-core.js.map +1 -1
- package/lib/scene/scene-remove.js +8 -0
- package/lib/scene/scene-remove.js.map +1 -1
- package/lib/shadow/csm-shadow-task-hooks.js +14 -6
- package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
- package/lib/shadow/pcf-shadow-task-hooks.js +6 -0
- package/lib/shadow/pcf-shadow-task-hooks.js.map +1 -1
- package/lib/texture/pixels-texture.js +31 -1
- package/lib/texture/pixels-texture.js.map +1 -1
- package/lib/vat/vat-baker.js +41 -2
- package/lib/vat/vat-baker.js.map +1 -1
- package/package.json +15 -3
- package/lib/_chunks/__vite-browser-external-BFTKbDcV.js +0 -68
- package/lib/_chunks/__vite-browser-external-BFTKbDcV.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader-material.js","sources":["../../../../src/material/shader/shader-material.ts"],"sourcesContent":["import { F32 } from \"../../engine/typed-arrays.js\";\nimport type { Material, StencilState } from \"../material.js\";\nimport type { Texture2D } from \"../../texture/texture-2d.js\";\nimport type { Mat4 } from \"../../math/types.js\";\nimport { getShaderGroupBuilder } from \"./shader-group-builder.js\";\n\n/** Vertex attribute names a ShaderMaterial can bind. */\nexport type ShaderAttributeName = \"position\" | \"normal\" | \"uv\" | \"uv2\" | \"tangent\" | \"color\";\n/** WGSL scalar/vector/matrix types supported for ShaderMaterial uniforms. */\nexport type ShaderUniformType = \"f32\" | \"u32\" | \"i32\" | \"vec2<f32>\" | \"vec3<f32>\" | \"vec4<f32>\" | \"mat4x4<f32>\";\n/** Built-in uniform names automatically populated by the renderer each frame\n * (transforms, camera position, screen size, alpha cutoff). */\nexport type ShaderSystemUniformName = \"world\" | \"view\" | \"projection\" | \"viewProjection\" | \"worldView\" | \"worldViewProjection\" | \"cameraPosition\" | \"screenSize\" | \"alphaCutoff\";\n/** A uniform entry: either a system uniform name or an explicit custom declaration. */\nexport type ShaderUniformOption = ShaderSystemUniformName | ShaderUniformDecl;\n/** Accepted value shape when setting a ShaderMaterial uniform. */\nexport type ShaderUniformValue = number | readonly number[] | Float32Array;\n/** A sampler entry: either a bare sampler name or an explicit declaration. */\nexport type ShaderSamplerOption = string | ShaderSamplerDecl;\n/** A storage-buffer entry: a read-only WGSL storage binding declaration. */\nexport type ShaderStorageBufferOption = ShaderStorageBufferDecl;\n/** Value of a WGSL preprocessor define — boolean toggle or numeric constant. */\nexport type ShaderDefineValue = boolean | number;\n/** Map of WGSL preprocessor define names to their values. */\nexport type ShaderDefineMap = Readonly<Record<string, ShaderDefineValue>>;\n\n/** Options describing a ShaderMaterial: WGSL sources, attributes, uniforms,\n * samplers, defines, and blend/depth state. Passed to `createShaderMaterial()`. */\nexport interface ShaderMaterialOptions {\n readonly name?: string;\n readonly vertexSource: string;\n readonly fragmentSource: string;\n readonly attributes: readonly ShaderAttributeName[];\n readonly uniforms?: readonly ShaderUniformOption[];\n readonly samplers?: readonly ShaderSamplerOption[];\n readonly storageBuffers?: readonly ShaderStorageBufferOption[];\n readonly defines?: ShaderDefineMap;\n readonly needAlphaBlending?: boolean;\n /** Blend equation used when `needAlphaBlending` is set. \"alpha\" (default) is\n * standard src-over; \"additive\" adds the fragment's premultiplied-by-alpha\n * color to the framebuffer, which is the right choice for glows/light FX. */\n readonly blendMode?: \"alpha\" | \"additive\";\n /** Mark this surface as transmissive/refractive: the renderer grabs the opaque scene color\n * behind it just before it draws, so the fragment can sample what is *through* it (water,\n * glass). Requires `needAlphaBlending` (the surface composites over the grabbed scene\n * color). Enable the scene-color grab on the surface's render task with\n * `enableRenderTaskTransmission`, then bind the resulting texture via `setShaderTexture`.\n * Default false. */\n readonly transmissive?: boolean;\n readonly needAlphaTesting?: boolean;\n readonly backFaceCulling?: boolean;\n readonly depthWrite?: boolean;\n readonly depthCompare?: GPUCompareFunction;\n /** Compile/run the fragment stage even for depth-only render targets (no colour attachments).\n * Use for depth-only casters that need `discard` (alpha/clip masks). The fragment shader must not\n * declare colour outputs when drawn into a depth-only target. Default false. */\n readonly depthOnlyFragment?: boolean;\n /** Constant depth-bias added in the pipeline's depth-stencil state (units of the depth format's minimum\n * representable value). Lets a surface that hugs another (e.g. tiles overlapping a cone, decals) win the\n * depth test consistently and avoid z-fighting. Default 0 (no bias). */\n readonly depthBias?: number;\n /** Slope-scaled depth bias — extra bias proportional to the depth gradient, so steeply-angled (grazing)\n * surfaces get more bias. Pairs with `depthBias` to kill z-fighting at oblique angles. Default 0. */\n readonly depthBiasSlopeScale?: number;\n}\n\n/** A custom uniform declaration: WGSL identifier, type, and optional default. */\nexport interface ShaderUniformDecl {\n readonly name: string;\n readonly type: ShaderUniformType;\n readonly defaultValue?: number | readonly number[];\n}\n\n/** A sampler declaration: WGSL identifier and the bound texture's sample type. */\nexport interface ShaderSamplerDecl {\n readonly name: string;\n readonly sampleType?: \"float\" | \"unfilterable-float\" | \"depth\";\n /** Texture view dimension. Default \"2d\". Use \"2d-array\" for layered maps such as\n * cascaded-shadow (CSM) depth arrays. */\n readonly viewDimension?: \"2d\" | \"2d-array\";\n /** Bind a hardware comparison sampler (`sampler_comparison`) for depth compare / PCF\n * filtering. Implies a depth texture. Default false. */\n readonly comparison?: boolean;\n}\n\n/** A storage buffer declaration. `type` is the WGSL variable type, e.g. `array<vec4<f32>>`. */\nexport interface ShaderStorageBufferDecl {\n readonly name: string;\n readonly type: string;\n}\n\n/** A resolved WGSL preprocessor define (name + value). */\nexport interface ShaderDefine {\n readonly name: string;\n readonly value: ShaderDefineValue;\n}\n\nexport interface ShaderUniformSlot {\n readonly decl: ShaderUniformDecl;\n readonly value: Float32Array;\n}\n\nexport interface ShaderTextureSlot {\n readonly decl: ShaderSamplerDecl;\n current: Texture2D | null;\n}\n\nexport interface ShaderStorageBufferSlot {\n readonly decl: ShaderStorageBufferDecl;\n current: GPUBuffer | null;\n}\n\n/** A custom WGSL material: compiled from user-supplied vertex/fragment sources\n * with declared attributes, uniforms, samplers, and defines. Update its values\n * via `setShaderUniform()` / `setShaderTexture()` and friends. */\nexport interface ShaderMaterial extends Material {\n readonly name?: string;\n readonly vertexSource: string;\n readonly fragmentSource: string;\n readonly attributes: readonly ShaderAttributeName[];\n readonly uniformDecls: readonly ShaderUniformDecl[];\n readonly samplerDecls: readonly ShaderSamplerDecl[];\n readonly storageBufferDecls: readonly ShaderStorageBufferDecl[];\n readonly defines: readonly ShaderDefine[];\n readonly needAlphaBlending: boolean;\n readonly blendMode: \"alpha\" | \"additive\";\n /** True for transmissive/refractive surfaces (see `ShaderMaterialOptions.transmissive`). */\n readonly transmissive: boolean;\n readonly needAlphaTesting: boolean;\n readonly backFaceCulling: boolean;\n readonly depthWrite: boolean;\n readonly depthCompare: GPUCompareFunction;\n readonly depthOnlyFragment: boolean;\n readonly depthBias: number;\n readonly depthBiasSlopeScale: number;\n /** Optional stencil-test state baked into the main-pass pipeline (mask write / discard). Set after\n * creation (`mat.stencil = { ... }`) and call `enableMaterialStencil()` before `registerScene`. Default\n * none. See `StencilState`. */\n stencil?: StencilState;\n /** @internal */\n _uniformValues: Map<string, ShaderUniformSlot>;\n /** @internal */\n _textureSlots: Map<string, ShaderTextureSlot>;\n /** @internal */\n _storageBufferSlots: Map<string, ShaderStorageBufferSlot>;\n /** @internal */\n _uniformVersion: number;\n /** @internal */\n _resourceVersion: number;\n}\n\nfunction isIdentifier(name: string): boolean {\n return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name);\n}\n\nfunction assertIdentifier(kind: string, name: string): void {\n if (!isIdentifier(name)) {\n throw new Error(`ShaderMaterial: ${kind} name \"${name}\" is not a valid WGSL identifier.`);\n }\n}\n\nfunction isSupportedAttribute(name: string): name is ShaderAttributeName {\n return name === \"position\" || name === \"normal\" || name === \"uv\" || name === \"uv2\" || name === \"tangent\" || name === \"color\";\n}\n\nfunction isSystemUniform(name: string): name is ShaderSystemUniformName {\n return (\n name === \"world\" ||\n name === \"view\" ||\n name === \"projection\" ||\n name === \"viewProjection\" ||\n name === \"worldView\" ||\n name === \"worldViewProjection\" ||\n name === \"cameraPosition\" ||\n name === \"screenSize\" ||\n name === \"alphaCutoff\"\n );\n}\n\nfunction systemUniformType(name: ShaderSystemUniformName): ShaderUniformType {\n if (name === \"cameraPosition\") {\n return \"vec3<f32>\";\n }\n if (name === \"screenSize\") {\n return \"vec2<f32>\";\n }\n if (name === \"alphaCutoff\") {\n return \"f32\";\n }\n return \"mat4x4<f32>\";\n}\n\nexport function _isShaderSystemUniform(name: string): name is ShaderSystemUniformName {\n return isSystemUniform(name);\n}\n\n/** Create a ShaderMaterial from WGSL sources and declarations, validating\n * attributes, uniforms, samplers, and defines.\n * @param options - Sources, attributes, uniforms, samplers, defines, and render state.\n * @returns The constructed `ShaderMaterial`. */\nexport function createShaderMaterial(options: ShaderMaterialOptions): ShaderMaterial {\n if (!options.vertexSource || !options.fragmentSource) {\n throw new Error(\"ShaderMaterial: vertexSource and fragmentSource must be non-empty WGSL strings.\");\n }\n const attributes: ShaderAttributeName[] = [];\n const seenAttributes = new Set<string>();\n for (const attr of options.attributes) {\n if (!isSupportedAttribute(attr)) {\n throw new Error(`ShaderMaterial: unsupported attribute \"${String(attr)}\". Supported attributes: position, normal, uv, uv2, tangent, color.`);\n }\n if (seenAttributes.has(attr)) {\n throw new Error(`ShaderMaterial: duplicate attribute \"${attr}\".`);\n }\n seenAttributes.add(attr);\n attributes.push(attr);\n }\n if (!seenAttributes.has(\"position\")) {\n throw new Error('ShaderMaterial: \"position\" attribute is required for mesh rendering.');\n }\n\n const uniformDecls: ShaderUniformDecl[] = [];\n const uniformValues = new Map<string, ShaderUniformSlot>();\n const usedNames = new Set<string>();\n for (const opt of options.uniforms ?? []) {\n const decl = typeof opt === \"string\" ? normalizeSystemUniform(opt) : normalizeCustomUniform(opt);\n assertUniqueName(usedNames, \"uniform\", decl.name);\n uniformDecls.push(decl);\n uniformValues.set(decl.name, { decl, value: normalizeUniformValue(decl, decl.defaultValue ?? defaultUniformValue(decl)) });\n }\n\n const samplerDecls: ShaderSamplerDecl[] = [];\n const textureSlots = new Map<string, ShaderTextureSlot>();\n for (const opt of options.samplers ?? []) {\n const decl: ShaderSamplerDecl =\n typeof opt === \"string\"\n ? { name: opt, sampleType: \"float\" }\n : {\n name: opt.name,\n sampleType: opt.sampleType ?? (opt.comparison ? \"depth\" : \"float\"),\n viewDimension: opt.viewDimension ?? \"2d\",\n comparison: opt.comparison ?? false,\n };\n assertIdentifier(\"sampler\", decl.name);\n assertUniqueName(usedNames, \"sampler\", decl.name);\n assertUniqueName(usedNames, \"sampler\", `${decl.name}Sampler`);\n samplerDecls.push(decl);\n textureSlots.set(decl.name, { decl, current: null });\n }\n\n const storageBufferDecls: ShaderStorageBufferDecl[] = [];\n const storageBufferSlots = new Map<string, ShaderStorageBufferSlot>();\n for (const opt of options.storageBuffers ?? []) {\n assertIdentifier(\"storage buffer\", opt.name);\n assertUniqueName(usedNames, \"storage buffer\", opt.name);\n storageBufferDecls.push(opt);\n storageBufferSlots.set(opt.name, { decl: opt, current: null });\n }\n\n const defines: ShaderDefine[] = [];\n for (const [name, value] of Object.entries(options.defines ?? {})) {\n assertIdentifier(\"define\", name);\n assertUniqueName(usedNames, \"define\", name);\n if (typeof value !== \"boolean\" && typeof value !== \"number\") {\n throw new Error(`ShaderMaterial: define \"${name}\" must be a boolean or number.`);\n }\n defines.push({ name, value });\n }\n defines.sort((a, b) => a.name.localeCompare(b.name));\n\n if (options.transmissive && !(options.needAlphaBlending ?? false)) {\n throw new Error(\"ShaderMaterial: `transmissive` requires `needAlphaBlending` (the surface composites over the grabbed opaque scene color).\");\n }\n\n return {\n name: options.name,\n vertexSource: options.vertexSource,\n fragmentSource: options.fragmentSource,\n attributes,\n uniformDecls,\n samplerDecls,\n storageBufferDecls,\n defines,\n needAlphaBlending: options.needAlphaBlending ?? false,\n blendMode: options.blendMode ?? \"alpha\",\n transmissive: options.transmissive ?? false,\n needAlphaTesting: options.needAlphaTesting ?? false,\n backFaceCulling: options.backFaceCulling ?? true,\n depthWrite: options.depthWrite ?? true,\n depthCompare: options.depthCompare ?? \"greater-equal\",\n depthOnlyFragment: options.depthOnlyFragment ?? false,\n depthBias: options.depthBias ?? 0,\n depthBiasSlopeScale: options.depthBiasSlopeScale ?? 0,\n _buildGroup: getShaderGroupBuilder(),\n _uboVersion: 0,\n _uniformValues: uniformValues,\n _textureSlots: textureSlots,\n _storageBufferSlots: storageBufferSlots,\n _uniformVersion: 0,\n _resourceVersion: 0,\n };\n}\n\nfunction normalizeSystemUniform(name: string): ShaderUniformDecl {\n if (!isSystemUniform(name)) {\n throw new Error(`ShaderMaterial: custom uniform \"${name}\" must use an explicit typed declaration.`);\n }\n return { name, type: systemUniformType(name) };\n}\n\nfunction normalizeCustomUniform(decl: ShaderUniformDecl): ShaderUniformDecl {\n assertIdentifier(\"uniform\", decl.name);\n if (!isUniformType(decl.type)) {\n throw new Error(`ShaderMaterial: unsupported uniform type \"${String(decl.type)}\" for \"${decl.name}\".`);\n }\n return decl;\n}\n\nfunction isUniformType(type: string): type is ShaderUniformType {\n return type === \"f32\" || type === \"u32\" || type === \"i32\" || type === \"vec2<f32>\" || type === \"vec3<f32>\" || type === \"vec4<f32>\" || type === \"mat4x4<f32>\";\n}\n\nfunction assertUniqueName(usedNames: Set<string>, kind: string, name: string): void {\n if (usedNames.has(name)) {\n throw new Error(`ShaderMaterial: duplicate generated identifier \"${name}\" while adding ${kind}.`);\n }\n usedNames.add(name);\n}\n\nfunction elementCount(type: ShaderUniformType): number {\n switch (type) {\n case \"f32\":\n case \"u32\":\n case \"i32\":\n return 1;\n case \"vec2<f32>\":\n return 2;\n case \"vec3<f32>\":\n return 3;\n case \"vec4<f32>\":\n return 4;\n case \"mat4x4<f32>\":\n return 16;\n }\n}\n\nfunction defaultUniformValue(decl: ShaderUniformDecl): ShaderUniformValue {\n if (decl.name === \"alphaCutoff\") {\n return 0.4;\n }\n const count = elementCount(decl.type);\n return count === 1 ? 0 : new Array(count).fill(0);\n}\n\nfunction normalizeUniformValue(decl: ShaderUniformDecl, value: ShaderUniformValue): Float32Array {\n const count = elementCount(decl.type);\n const arr = typeof value === \"number\" ? new F32([value]) : value instanceof F32 ? new F32(value) : new F32(value);\n if (arr.length !== count) {\n throw new Error(`ShaderMaterial: uniform \"${decl.name}\" of type ${decl.type} expects ${count} value(s), got ${arr.length}.`);\n }\n return arr;\n}\n\n/** Set a declared uniform's value, validating its element count against the\n * declared type and bumping the material's UBO version.\n * @param material - Target material.\n * @param name - Declared uniform name.\n * @param value - New value (scalar, array, or `Float32Array`). */\nexport function setShaderUniform(material: ShaderMaterial, name: string, value: ShaderUniformValue): void {\n const slot = material._uniformValues.get(name);\n if (!slot) {\n throw new Error(`ShaderMaterial: uniform \"${name}\" was not declared.`);\n }\n slot.value.set(normalizeUniformValue(slot.decl, value));\n material._uniformVersion++;\n material._uboVersion = material._uniformVersion;\n}\n\n/** Bind (or clear) the texture for a declared sampler, enforcing that depth and\n * non-depth samplers receive a matching `Texture2D`.\n * @param material - Target material.\n * @param name - Declared sampler name.\n * @param texture - Texture to bind, or `null` to clear. */\nexport function setShaderTexture(material: ShaderMaterial, name: string, texture: Texture2D | null): void {\n const slot = material._textureSlots.get(name);\n if (!slot) {\n throw new Error(`ShaderMaterial: sampler \"${name}\" was not declared.`);\n }\n if (texture) {\n const expectsDepth = slot.decl.comparison || slot.decl.sampleType === \"depth\";\n const isDepthTexture = texture._sampleType === \"depth\";\n if (expectsDepth && !isDepthTexture) {\n throw new Error(`ShaderMaterial: sampler \"${name}\" expects a depth Texture2D.`);\n }\n if (!expectsDepth && isDepthTexture) {\n throw new Error(`ShaderMaterial: sampler \"${name}\" cannot use a depth Texture2D.`);\n }\n }\n // Only invalidate the cached bind groups when the bound texture HANDLE actually changes. The bind group\n // references the texture's view + sampler (see createShaderBindGroup), so re-binding the SAME Texture2D (the\n // common \"keep my shadow map / scene-depth bound every frame\" pattern) leaves those identical. Bumping the\n // resource version unconditionally therefore forced a BRAND-NEW bind group every frame (per material, for every\n // packet using it), churning the D3D12 descriptor heap until it OOMed on content-heavy scenes (e.g. reloading\n // a big save). A texture's CONTENTS can change freely without a new bind group (the bound view is live), so\n // identity comparison is correct.\n if (slot.current !== texture) {\n slot.current = texture;\n material._resourceVersion++;\n }\n}\n\n/** Bind (or clear) a declared read-only storage buffer. */\nexport function setShaderStorageBuffer(material: ShaderMaterial, name: string, buffer: GPUBuffer | null): void {\n const slot = material._storageBufferSlots.get(name);\n if (!slot) {\n throw new Error(`ShaderMaterial: storage buffer \"${name}\" was not declared.`);\n }\n // See setShaderTexture: only invalidate the bind groups when the bound buffer HANDLE changes; re-binding the\n // same GPUBuffer is a no-op (contents update live), so an unconditional bump churned the descriptor heap.\n if (slot.current !== buffer) {\n slot.current = buffer;\n material._resourceVersion++;\n }\n}\n\n/** Set a declared `f32` uniform. Convenience wrapper over `setShaderUniform()`. */\nexport function setShaderFloat(material: ShaderMaterial, name: string, value: number): void {\n setShaderUniform(material, name, value);\n}\n\n/** Set a declared `vec3<f32>` uniform. Convenience wrapper over `setShaderUniform()`. */\nexport function setShaderVector3(material: ShaderMaterial, name: string, value: readonly [number, number, number]): void {\n setShaderUniform(material, name, value);\n}\n\n/** Set a declared `mat4x4<f32>` uniform. Convenience wrapper over `setShaderUniform()`.\n * Accepts a raw `Float32Array` or the engine's branded `Mat4` (e.g. the result of\n * `getViewProjectionMatrix()` / `mat4Invert()`), so camera/math matrices can be fed\n * straight into a matrix uniform without laundering through a typed array. */\nexport function setShaderMatrix(material: ShaderMaterial, name: string, value: Float32Array | Mat4): void {\n setShaderUniform(material, name, value instanceof Float32Array ? value : Array.from(value));\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shader-material.js","sources":["../../../../src/material/shader/shader-material.ts"],"sourcesContent":["import { F32 } from \"../../engine/typed-arrays.js\";\nimport type { Material, StencilState } from \"../material.js\";\nimport type { Texture2D } from \"../../texture/texture-2d.js\";\nimport type { Mat4 } from \"../../math/types.js\";\nimport { getShaderGroupBuilder } from \"./shader-group-builder.js\";\n\n/** Vertex attribute names a ShaderMaterial can bind. `joints`/`weights` (and `joints1`/`weights1`\n * for \\>4 bones/vertex) are the skinning attributes — bound from the mesh's skeleton/VAT buffers,\n * letting a custom material do vertex skinning (e.g. baked vertex-animation). */\nexport type ShaderAttributeName = \"position\" | \"normal\" | \"uv\" | \"uv2\" | \"tangent\" | \"color\" | \"joints\" | \"weights\" | \"joints1\" | \"weights1\";\n/** WGSL scalar/vector/matrix types supported for ShaderMaterial uniforms. */\nexport type ShaderUniformType = \"f32\" | \"u32\" | \"i32\" | \"vec2<f32>\" | \"vec3<f32>\" | \"vec4<f32>\" | \"mat4x4<f32>\";\n/** Built-in uniform names automatically populated by the renderer each frame\n * (transforms, camera position, screen size, alpha cutoff). */\nexport type ShaderSystemUniformName = \"world\" | \"view\" | \"projection\" | \"viewProjection\" | \"worldView\" | \"worldViewProjection\" | \"cameraPosition\" | \"screenSize\" | \"alphaCutoff\";\n/** A uniform entry: either a system uniform name or an explicit custom declaration. */\nexport type ShaderUniformOption = ShaderSystemUniformName | ShaderUniformDecl;\n/** Accepted value shape when setting a ShaderMaterial uniform. */\nexport type ShaderUniformValue = number | readonly number[] | Float32Array;\n/** A sampler entry: either a bare sampler name or an explicit declaration. */\nexport type ShaderSamplerOption = string | ShaderSamplerDecl;\n/** A storage-buffer entry: a read-only WGSL storage binding declaration. */\nexport type ShaderStorageBufferOption = ShaderStorageBufferDecl;\n/** Value of a WGSL preprocessor define — boolean toggle or numeric constant. */\nexport type ShaderDefineValue = boolean | number;\n/** Map of WGSL preprocessor define names to their values. */\nexport type ShaderDefineMap = Readonly<Record<string, ShaderDefineValue>>;\n\n/** Options describing a ShaderMaterial: WGSL sources, attributes, uniforms,\n * samplers, defines, and blend/depth state. Passed to `createShaderMaterial()`. */\nexport interface ShaderMaterialOptions {\n readonly name?: string;\n readonly vertexSource: string;\n readonly fragmentSource: string;\n readonly attributes: readonly ShaderAttributeName[];\n readonly uniforms?: readonly ShaderUniformOption[];\n readonly samplers?: readonly ShaderSamplerOption[];\n readonly storageBuffers?: readonly ShaderStorageBufferOption[];\n readonly defines?: ShaderDefineMap;\n readonly needAlphaBlending?: boolean;\n /** Blend equation used when `needAlphaBlending` is set. \"alpha\" (default) is\n * standard src-over; \"additive\" adds the fragment's premultiplied-by-alpha\n * color to the framebuffer, which is the right choice for glows/light FX. */\n readonly blendMode?: \"alpha\" | \"additive\";\n /** Mark this surface as transmissive/refractive: the renderer grabs the opaque scene color\n * behind it just before it draws, so the fragment can sample what is *through* it (water,\n * glass). Requires `needAlphaBlending` (the surface composites over the grabbed scene\n * color). Enable the scene-color grab on the surface's render task with\n * `enableRenderTaskTransmission`, then bind the resulting texture via `setShaderTexture`.\n * Default false. */\n readonly transmissive?: boolean;\n readonly needAlphaTesting?: boolean;\n readonly backFaceCulling?: boolean;\n readonly depthWrite?: boolean;\n readonly depthCompare?: GPUCompareFunction;\n /** Compile/run the fragment stage even for depth-only render targets (no colour attachments).\n * Use for depth-only casters that need `discard` (alpha/clip masks). The fragment shader must not\n * declare colour outputs when drawn into a depth-only target. Default false. */\n readonly depthOnlyFragment?: boolean;\n /** Constant depth-bias added in the pipeline's depth-stencil state (units of the depth format's minimum\n * representable value). Lets a surface that hugs another (e.g. tiles overlapping a cone, decals) win the\n * depth test consistently and avoid z-fighting. Default 0 (no bias). */\n readonly depthBias?: number;\n /** Slope-scaled depth bias — extra bias proportional to the depth gradient, so steeply-angled (grazing)\n * surfaces get more bias. Pairs with `depthBias` to kill z-fighting at oblique angles. Default 0. */\n readonly depthBiasSlopeScale?: number;\n}\n\n/** A custom uniform declaration: WGSL identifier, type, and optional default. */\nexport interface ShaderUniformDecl {\n readonly name: string;\n readonly type: ShaderUniformType;\n readonly defaultValue?: number | readonly number[];\n}\n\n/** A sampler declaration: WGSL identifier and the bound texture's sample type. */\nexport interface ShaderSamplerDecl {\n readonly name: string;\n readonly sampleType?: \"float\" | \"unfilterable-float\" | \"depth\";\n /** Texture view dimension. Default \"2d\". Use \"2d-array\" for layered maps such as\n * cascaded-shadow (CSM) depth arrays. */\n readonly viewDimension?: \"2d\" | \"2d-array\";\n /** Bind a hardware comparison sampler (`sampler_comparison`) for depth compare / PCF\n * filtering. Implies a depth texture. Default false. */\n readonly comparison?: boolean;\n}\n\n/** A storage buffer declaration. `type` is the WGSL variable type, e.g. `array<vec4<f32>>`. */\nexport interface ShaderStorageBufferDecl {\n readonly name: string;\n readonly type: string;\n}\n\n/** A resolved WGSL preprocessor define (name + value). */\nexport interface ShaderDefine {\n readonly name: string;\n readonly value: ShaderDefineValue;\n}\n\nexport interface ShaderUniformSlot {\n readonly decl: ShaderUniformDecl;\n readonly value: Float32Array;\n}\n\nexport interface ShaderTextureSlot {\n readonly decl: ShaderSamplerDecl;\n current: Texture2D | null;\n}\n\nexport interface ShaderStorageBufferSlot {\n readonly decl: ShaderStorageBufferDecl;\n current: GPUBuffer | null;\n}\n\n/** A custom WGSL material: compiled from user-supplied vertex/fragment sources\n * with declared attributes, uniforms, samplers, and defines. Update its values\n * via `setShaderUniform()` / `setShaderTexture()` and friends. */\nexport interface ShaderMaterial extends Material {\n readonly name?: string;\n readonly vertexSource: string;\n readonly fragmentSource: string;\n readonly attributes: readonly ShaderAttributeName[];\n readonly uniformDecls: readonly ShaderUniformDecl[];\n readonly samplerDecls: readonly ShaderSamplerDecl[];\n readonly storageBufferDecls: readonly ShaderStorageBufferDecl[];\n readonly defines: readonly ShaderDefine[];\n readonly needAlphaBlending: boolean;\n readonly blendMode: \"alpha\" | \"additive\";\n /** True for transmissive/refractive surfaces (see `ShaderMaterialOptions.transmissive`). */\n readonly transmissive: boolean;\n readonly needAlphaTesting: boolean;\n readonly backFaceCulling: boolean;\n readonly depthWrite: boolean;\n readonly depthCompare: GPUCompareFunction;\n readonly depthOnlyFragment: boolean;\n readonly depthBias: number;\n readonly depthBiasSlopeScale: number;\n /** Optional stencil-test state baked into the main-pass pipeline (mask write / discard). Set after\n * creation (`mat.stencil = { ... }`) and call `enableMaterialStencil()` before `registerScene`. Default\n * none. See `StencilState`. */\n stencil?: StencilState;\n /** @internal */\n _uniformValues: Map<string, ShaderUniformSlot>;\n /** @internal */\n _textureSlots: Map<string, ShaderTextureSlot>;\n /** @internal */\n _storageBufferSlots: Map<string, ShaderStorageBufferSlot>;\n /** @internal */\n _uniformVersion: number;\n /** @internal */\n _resourceVersion: number;\n}\n\nfunction isIdentifier(name: string): boolean {\n return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name);\n}\n\nfunction assertIdentifier(kind: string, name: string): void {\n if (!isIdentifier(name)) {\n throw new Error(`ShaderMaterial: ${kind} name \"${name}\" is not a valid WGSL identifier.`);\n }\n}\n\nfunction isSupportedAttribute(name: string): name is ShaderAttributeName {\n return (\n name === \"position\" ||\n name === \"normal\" ||\n name === \"uv\" ||\n name === \"uv2\" ||\n name === \"tangent\" ||\n name === \"color\" ||\n name === \"joints\" ||\n name === \"weights\" ||\n name === \"joints1\" ||\n name === \"weights1\"\n );\n}\n\nfunction isSystemUniform(name: string): name is ShaderSystemUniformName {\n return (\n name === \"world\" ||\n name === \"view\" ||\n name === \"projection\" ||\n name === \"viewProjection\" ||\n name === \"worldView\" ||\n name === \"worldViewProjection\" ||\n name === \"cameraPosition\" ||\n name === \"screenSize\" ||\n name === \"alphaCutoff\"\n );\n}\n\nfunction systemUniformType(name: ShaderSystemUniformName): ShaderUniformType {\n if (name === \"cameraPosition\") {\n return \"vec3<f32>\";\n }\n if (name === \"screenSize\") {\n return \"vec2<f32>\";\n }\n if (name === \"alphaCutoff\") {\n return \"f32\";\n }\n return \"mat4x4<f32>\";\n}\n\nexport function _isShaderSystemUniform(name: string): name is ShaderSystemUniformName {\n return isSystemUniform(name);\n}\n\n/** Create a ShaderMaterial from WGSL sources and declarations, validating\n * attributes, uniforms, samplers, and defines.\n * @param options - Sources, attributes, uniforms, samplers, defines, and render state.\n * @returns The constructed `ShaderMaterial`. */\nexport function createShaderMaterial(options: ShaderMaterialOptions): ShaderMaterial {\n if (!options.vertexSource || !options.fragmentSource) {\n throw new Error(\"ShaderMaterial: vertexSource and fragmentSource must be non-empty WGSL strings.\");\n }\n const attributes: ShaderAttributeName[] = [];\n const seenAttributes = new Set<string>();\n for (const attr of options.attributes) {\n if (!isSupportedAttribute(attr)) {\n throw new Error(\n `ShaderMaterial: unsupported attribute \"${String(attr)}\". Supported attributes: position, normal, uv, uv2, tangent, color, joints, weights, joints1, weights1.`\n );\n }\n if (seenAttributes.has(attr)) {\n throw new Error(`ShaderMaterial: duplicate attribute \"${attr}\".`);\n }\n seenAttributes.add(attr);\n attributes.push(attr);\n }\n if (!seenAttributes.has(\"position\")) {\n throw new Error('ShaderMaterial: \"position\" attribute is required for mesh rendering.');\n }\n\n const uniformDecls: ShaderUniformDecl[] = [];\n const uniformValues = new Map<string, ShaderUniformSlot>();\n const usedNames = new Set<string>();\n for (const opt of options.uniforms ?? []) {\n const decl = typeof opt === \"string\" ? normalizeSystemUniform(opt) : normalizeCustomUniform(opt);\n assertUniqueName(usedNames, \"uniform\", decl.name);\n uniformDecls.push(decl);\n uniformValues.set(decl.name, { decl, value: normalizeUniformValue(decl, decl.defaultValue ?? defaultUniformValue(decl)) });\n }\n\n const samplerDecls: ShaderSamplerDecl[] = [];\n const textureSlots = new Map<string, ShaderTextureSlot>();\n for (const opt of options.samplers ?? []) {\n const decl: ShaderSamplerDecl =\n typeof opt === \"string\"\n ? { name: opt, sampleType: \"float\" }\n : {\n name: opt.name,\n sampleType: opt.sampleType ?? (opt.comparison ? \"depth\" : \"float\"),\n viewDimension: opt.viewDimension ?? \"2d\",\n comparison: opt.comparison ?? false,\n };\n assertIdentifier(\"sampler\", decl.name);\n assertUniqueName(usedNames, \"sampler\", decl.name);\n assertUniqueName(usedNames, \"sampler\", `${decl.name}Sampler`);\n samplerDecls.push(decl);\n textureSlots.set(decl.name, { decl, current: null });\n }\n\n const storageBufferDecls: ShaderStorageBufferDecl[] = [];\n const storageBufferSlots = new Map<string, ShaderStorageBufferSlot>();\n for (const opt of options.storageBuffers ?? []) {\n assertIdentifier(\"storage buffer\", opt.name);\n assertUniqueName(usedNames, \"storage buffer\", opt.name);\n storageBufferDecls.push(opt);\n storageBufferSlots.set(opt.name, { decl: opt, current: null });\n }\n\n const defines: ShaderDefine[] = [];\n for (const [name, value] of Object.entries(options.defines ?? {})) {\n assertIdentifier(\"define\", name);\n assertUniqueName(usedNames, \"define\", name);\n if (typeof value !== \"boolean\" && typeof value !== \"number\") {\n throw new Error(`ShaderMaterial: define \"${name}\" must be a boolean or number.`);\n }\n defines.push({ name, value });\n }\n defines.sort((a, b) => a.name.localeCompare(b.name));\n\n if (options.transmissive && !(options.needAlphaBlending ?? false)) {\n throw new Error(\"ShaderMaterial: `transmissive` requires `needAlphaBlending` (the surface composites over the grabbed opaque scene color).\");\n }\n\n return {\n name: options.name,\n vertexSource: options.vertexSource,\n fragmentSource: options.fragmentSource,\n attributes,\n uniformDecls,\n samplerDecls,\n storageBufferDecls,\n defines,\n needAlphaBlending: options.needAlphaBlending ?? false,\n blendMode: options.blendMode ?? \"alpha\",\n transmissive: options.transmissive ?? false,\n needAlphaTesting: options.needAlphaTesting ?? false,\n backFaceCulling: options.backFaceCulling ?? true,\n depthWrite: options.depthWrite ?? true,\n depthCompare: options.depthCompare ?? \"greater-equal\",\n depthOnlyFragment: options.depthOnlyFragment ?? false,\n depthBias: options.depthBias ?? 0,\n depthBiasSlopeScale: options.depthBiasSlopeScale ?? 0,\n _buildGroup: getShaderGroupBuilder(),\n _uboVersion: 0,\n _uniformValues: uniformValues,\n _textureSlots: textureSlots,\n _storageBufferSlots: storageBufferSlots,\n _uniformVersion: 0,\n _resourceVersion: 0,\n };\n}\n\nfunction normalizeSystemUniform(name: string): ShaderUniformDecl {\n if (!isSystemUniform(name)) {\n throw new Error(`ShaderMaterial: custom uniform \"${name}\" must use an explicit typed declaration.`);\n }\n return { name, type: systemUniformType(name) };\n}\n\nfunction normalizeCustomUniform(decl: ShaderUniformDecl): ShaderUniformDecl {\n assertIdentifier(\"uniform\", decl.name);\n if (!isUniformType(decl.type)) {\n throw new Error(`ShaderMaterial: unsupported uniform type \"${String(decl.type)}\" for \"${decl.name}\".`);\n }\n return decl;\n}\n\nfunction isUniformType(type: string): type is ShaderUniformType {\n return type === \"f32\" || type === \"u32\" || type === \"i32\" || type === \"vec2<f32>\" || type === \"vec3<f32>\" || type === \"vec4<f32>\" || type === \"mat4x4<f32>\";\n}\n\nfunction assertUniqueName(usedNames: Set<string>, kind: string, name: string): void {\n if (usedNames.has(name)) {\n throw new Error(`ShaderMaterial: duplicate generated identifier \"${name}\" while adding ${kind}.`);\n }\n usedNames.add(name);\n}\n\nfunction elementCount(type: ShaderUniformType): number {\n switch (type) {\n case \"f32\":\n case \"u32\":\n case \"i32\":\n return 1;\n case \"vec2<f32>\":\n return 2;\n case \"vec3<f32>\":\n return 3;\n case \"vec4<f32>\":\n return 4;\n case \"mat4x4<f32>\":\n return 16;\n }\n}\n\nfunction defaultUniformValue(decl: ShaderUniformDecl): ShaderUniformValue {\n if (decl.name === \"alphaCutoff\") {\n return 0.4;\n }\n const count = elementCount(decl.type);\n return count === 1 ? 0 : new Array(count).fill(0);\n}\n\nfunction normalizeUniformValue(decl: ShaderUniformDecl, value: ShaderUniformValue): Float32Array {\n const count = elementCount(decl.type);\n const arr = typeof value === \"number\" ? new F32([value]) : value instanceof F32 ? new F32(value) : new F32(value);\n if (arr.length !== count) {\n throw new Error(`ShaderMaterial: uniform \"${decl.name}\" of type ${decl.type} expects ${count} value(s), got ${arr.length}.`);\n }\n return arr;\n}\n\n/** Set a declared uniform's value, validating its element count against the\n * declared type and bumping the material's UBO version.\n * @param material - Target material.\n * @param name - Declared uniform name.\n * @param value - New value (scalar, array, or `Float32Array`). */\nexport function setShaderUniform(material: ShaderMaterial, name: string, value: ShaderUniformValue): void {\n const slot = material._uniformValues.get(name);\n if (!slot) {\n throw new Error(`ShaderMaterial: uniform \"${name}\" was not declared.`);\n }\n slot.value.set(normalizeUniformValue(slot.decl, value));\n material._uniformVersion++;\n material._uboVersion = material._uniformVersion;\n}\n\n/** Bind (or clear) the texture for a declared sampler, enforcing that depth and\n * non-depth samplers receive a matching `Texture2D`.\n * @param material - Target material.\n * @param name - Declared sampler name.\n * @param texture - Texture to bind, or `null` to clear. */\nexport function setShaderTexture(material: ShaderMaterial, name: string, texture: Texture2D | null): void {\n const slot = material._textureSlots.get(name);\n if (!slot) {\n throw new Error(`ShaderMaterial: sampler \"${name}\" was not declared.`);\n }\n if (texture) {\n const expectsDepth = slot.decl.comparison || slot.decl.sampleType === \"depth\";\n const isDepthTexture = texture._sampleType === \"depth\";\n if (expectsDepth && !isDepthTexture) {\n throw new Error(`ShaderMaterial: sampler \"${name}\" expects a depth Texture2D.`);\n }\n if (!expectsDepth && isDepthTexture) {\n throw new Error(`ShaderMaterial: sampler \"${name}\" cannot use a depth Texture2D.`);\n }\n }\n // Only invalidate the cached bind groups when the bound texture HANDLE actually changes. The bind group\n // references the texture's view + sampler (see createShaderBindGroup), so re-binding the SAME Texture2D (the\n // common \"keep my shadow map / scene-depth bound every frame\" pattern) leaves those identical. Bumping the\n // resource version unconditionally therefore forced a BRAND-NEW bind group every frame (per material, for every\n // packet using it), churning the D3D12 descriptor heap until it OOMed on content-heavy scenes (e.g. reloading\n // a big save). A texture's CONTENTS can change freely without a new bind group (the bound view is live), so\n // identity comparison is correct.\n if (slot.current !== texture) {\n slot.current = texture;\n material._resourceVersion++;\n }\n}\n\n/** Bind (or clear) a declared read-only storage buffer. */\nexport function setShaderStorageBuffer(material: ShaderMaterial, name: string, buffer: GPUBuffer | null): void {\n const slot = material._storageBufferSlots.get(name);\n if (!slot) {\n throw new Error(`ShaderMaterial: storage buffer \"${name}\" was not declared.`);\n }\n // See setShaderTexture: only invalidate the bind groups when the bound buffer HANDLE changes; re-binding the\n // same GPUBuffer is a no-op (contents update live), so an unconditional bump churned the descriptor heap.\n if (slot.current !== buffer) {\n slot.current = buffer;\n material._resourceVersion++;\n }\n}\n\n/** Set a declared `f32` uniform. Convenience wrapper over `setShaderUniform()`. */\nexport function setShaderFloat(material: ShaderMaterial, name: string, value: number): void {\n setShaderUniform(material, name, value);\n}\n\n/** Set a declared `vec3<f32>` uniform. Convenience wrapper over `setShaderUniform()`. */\nexport function setShaderVector3(material: ShaderMaterial, name: string, value: readonly [number, number, number]): void {\n setShaderUniform(material, name, value);\n}\n\n/** Set a declared `mat4x4<f32>` uniform. Convenience wrapper over `setShaderUniform()`.\n * Accepts a raw `Float32Array` or the engine's branded `Mat4` (e.g. the result of\n * `getViewProjectionMatrix()` / `mat4Invert()`), so camera/math matrices can be fed\n * straight into a matrix uniform without laundering through a typed array. */\nexport function setShaderMatrix(material: ShaderMaterial, name: string, value: Float32Array | Mat4): void {\n setShaderUniform(material, name, value instanceof Float32Array ? value : Array.from(value));\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -9,7 +9,6 @@ let _stencilResolver = null;
|
|
|
9
9
|
function _installShaderStencilResolver(resolve) {
|
|
10
10
|
_stencilResolver = resolve;
|
|
11
11
|
}
|
|
12
|
-
const SHADER_STAGE_ALL = SS.VERTEX | SS.FRAGMENT;
|
|
13
12
|
function getOrCreateShaderPipelineBindings(engine, material) {
|
|
14
13
|
const state = material;
|
|
15
14
|
if (state._shaderBindings && state._shaderDevice === engine._device) {
|
|
@@ -97,6 +96,7 @@ function toUboField(decl) {
|
|
|
97
96
|
return { _name: decl.name, _type: decl.type };
|
|
98
97
|
}
|
|
99
98
|
function buildBindGroupLayoutEntries(samplers, storageBuffers, hasCustomUbo) {
|
|
99
|
+
const SHADER_STAGE_ALL = SS.VERTEX | SS.FRAGMENT;
|
|
100
100
|
const entries = [{ binding: 0, visibility: SHADER_STAGE_ALL, buffer: { type: "uniform" } }];
|
|
101
101
|
let nextBinding = 1;
|
|
102
102
|
if (hasCustomUbo) {
|
|
@@ -138,7 +138,12 @@ function attributeLayout(name, shaderLocation) {
|
|
|
138
138
|
return { arrayStride: 8, attributes: [{ shaderLocation, offset: 0, format: "float32x2" }] };
|
|
139
139
|
case "tangent":
|
|
140
140
|
case "color":
|
|
141
|
+
case "weights":
|
|
142
|
+
case "weights1":
|
|
141
143
|
return { arrayStride: 16, attributes: [{ shaderLocation, offset: 0, format: "float32x4" }] };
|
|
144
|
+
case "joints":
|
|
145
|
+
case "joints1":
|
|
146
|
+
return { arrayStride: 16, attributes: [{ shaderLocation, offset: 0, format: "uint32x4" }] };
|
|
142
147
|
}
|
|
143
148
|
}
|
|
144
149
|
function buildShaderPrelude(material, systemSpec, customSpec, instanceAttrs = "") {
|
|
@@ -204,7 +209,12 @@ function attributeWgslType(name) {
|
|
|
204
209
|
return "vec2<f32>";
|
|
205
210
|
case "tangent":
|
|
206
211
|
case "color":
|
|
212
|
+
case "weights":
|
|
213
|
+
case "weights1":
|
|
207
214
|
return "vec4<f32>";
|
|
215
|
+
case "joints":
|
|
216
|
+
case "joints1":
|
|
217
|
+
return "vec4<u32>";
|
|
208
218
|
}
|
|
209
219
|
}
|
|
210
220
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shader-pipeline.js","sources":["../../../../src/material/shader/shader-pipeline.ts"],"sourcesContent":["import { SS } from \"../../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport { targetSignatureKey } from \"../../engine/render-target.js\";\nimport { getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\nimport { SCENE_UBO_WGSL } from \"../../shader/scene-uniforms.js\";\nimport { computeUboLayout } from \"../../shader/ubo-layout.js\";\nimport type { UboField, UboSpec } from \"../../shader/fragment-types.js\";\nimport type { ShaderAttributeName, ShaderMaterial, ShaderSamplerDecl, ShaderUniformDecl } from \"./shader-material.js\";\nimport { _isShaderSystemUniform } from \"./shader-material.js\";\nimport type { ResolvedStencil } from \"../stencil-state.js\";\nimport type { StencilState } from \"../material.js\";\n\n/** Stencil resolver, installed only by `enableMaterialStencil`. Module-local with a single exported setter:\n * when `enableMaterialStencil` is absent from the bundle the setter tree-shakes, the bundler proves this is\n * always null, and every stencil branch below folds away — stencil-free Shader scenes stay byte-identical. */\nlet _stencilResolver: ((stencil: StencilState) => ResolvedStencil) | null = null;\n/** @internal Install the stencil resolver into the Shader pipeline (called by `enableMaterialStencil`). */\nexport function _installShaderStencilResolver(resolve: (stencil: StencilState) => ResolvedStencil): void {\n _stencilResolver = resolve;\n}\n\nexport interface ShaderPipelineBindings {\n readonly group1BGL: GPUBindGroupLayout;\n readonly systemSpec: UboSpec;\n readonly customSpec: UboSpec | null;\n readonly vertexBuffers: readonly GPUVertexBufferLayout[];\n readonly pipelines: Map<string, GPURenderPipeline>;\n}\n\ninterface ShaderMaterialPipelineState extends ShaderMaterial {\n _shaderDevice?: GPUDevice;\n _shaderBindings?: ShaderPipelineBindings;\n _shaderCustomUbo?: GPUBuffer | null;\n _shaderCustomSpec?: UboSpec | null;\n _shaderCustomData?: ArrayBuffer | null;\n _shaderCustomVersion?: number;\n}\n\nconst SHADER_STAGE_ALL = SS.VERTEX | SS.FRAGMENT;\n\nexport function getOrCreateShaderPipelineBindings(engine: EngineContext, material: ShaderMaterial): ShaderPipelineBindings {\n const state = material as ShaderMaterialPipelineState;\n if (state._shaderBindings && state._shaderDevice === engine._device) {\n return state._shaderBindings;\n }\n\n state._shaderDevice = engine._device;\n const systemFields = material.uniformDecls.filter((u) => _isShaderSystemUniform(u.name)).map(toUboField);\n const customFields = material.uniformDecls.filter((u) => !_isShaderSystemUniform(u.name)).map(toUboField);\n const systemSpec = computeUboLayout(systemFields.length > 0 ? systemFields : [{ _name: \"_pad\", _type: \"vec4<f32>\" }]);\n const customSpec = customFields.length > 0 ? computeUboLayout(customFields) : null;\n const group1BGL = engine._device.createBindGroupLayout({\n label: \"shader-material-group1\",\n entries: buildBindGroupLayoutEntries(material.samplerDecls, material.storageBufferDecls, customSpec !== null),\n });\n const bindings: ShaderPipelineBindings = {\n group1BGL,\n systemSpec,\n customSpec,\n vertexBuffers: material.attributes.map(attributeLayout),\n pipelines: new Map(),\n };\n state._shaderBindings = bindings;\n state._shaderCustomSpec = customSpec;\n state._shaderCustomUbo = null;\n state._shaderCustomData = null;\n state._shaderCustomVersion = -1;\n return bindings;\n}\n\nexport function getOrCreateShaderPipeline(\n engine: EngineContext,\n sig: RenderTargetSignature,\n material: ShaderMaterial,\n bindings: ShaderPipelineBindings,\n variantKey = \"\",\n vertexBuffers: readonly GPUVertexBufferLayout[] = bindings.vertexBuffers,\n instanceAttrs = \"\"\n): GPURenderPipeline {\n // `variantKey`, `vertexBuffers` and `instanceAttrs` default to the\n // non-instanced pipeline — byte-for-byte identical behaviour to before\n // instancing existed. The dynamically-imported thin-instance module is the\n // only caller that passes non-default values, so no instancing logic runs\n // for non-instanced scenes.\n const key = `${targetSignatureKey(sig)}${variantKey}`;\n const cached = bindings.pipelines.get(key);\n if (cached) {\n return cached;\n }\n const stencil = material.stencil && _stencilResolver ? _stencilResolver(material.stencil) : null;\n const device = engine._device;\n const prelude = buildShaderPrelude(material, bindings.systemSpec, bindings.customSpec, instanceAttrs);\n const vertModule = device.createShaderModule({ label: `${material.name ?? \"shader\"}-vertex`, code: `${prelude}\\n${material.vertexSource}` });\n const wantsFragment = !!sig._colorFormat || material.depthOnlyFragment;\n const fragModule = wantsFragment ? device.createShaderModule({ label: `${material.name ?? \"shader\"}-fragment`, code: `${prelude}\\n${material.fragmentSource}` }) : null;\n const colorTarget: GPUColorTargetState | null = sig._colorFormat\n ? {\n format: sig._colorFormat,\n ...(material.needAlphaBlending\n ? {\n blend:\n material.blendMode === \"additive\"\n ? ({\n color: { srcFactor: \"src-alpha\", dstFactor: \"one\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one\", operation: \"add\" },\n } satisfies GPUBlendState)\n : ({\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n } satisfies GPUBlendState),\n }\n : {}),\n }\n : null;\n\n const pipeline = device.createRenderPipeline({\n label: `${material.name ?? \"shader\"}-pipeline`,\n layout: device.createPipelineLayout({ bindGroupLayouts: [getSceneBindGroupLayout(engine), bindings.group1BGL] }),\n vertex: { module: vertModule, entryPoint: \"mainVertex\", buffers: vertexBuffers as GPUVertexBufferLayout[] },\n ...(fragModule ? { fragment: { module: fragModule, entryPoint: \"mainFragment\", targets: colorTarget ? [colorTarget] : [] } } : {}),\n ...(sig._depthStencilFormat\n ? {\n depthStencil: {\n format: sig._depthStencilFormat,\n // The target's declared depth convention wins over the material default: a depth-only\n // caster authored for the forward-Z shadow map (\"less-equal\") must still depth-test\n // correctly when drawn into a reverse-Z camera depth prepass that declares\n // \"greater-equal\" — otherwise every fragment fails against the 0-cleared buffer.\n depthCompare: sig._depthCompare ?? material.depthCompare,\n depthWriteEnabled: material.needAlphaBlending ? false : material.depthWrite,\n ...(material.depthBias ? { depthBias: material.depthBias } : {}),\n ...(material.depthBiasSlopeScale ? { depthBiasSlopeScale: material.depthBiasSlopeScale } : {}),\n // Pre-baked stencil sub-fields, resolved through the opt-in `_stencilResolver` hook above;\n // applied only on a stencil-capable target — a material reused in the depth32float\n // shadow/depth pass keeps plain depth state (no stencil → no format mismatch). `stencil`\n // is a local const that folds to null in stencil-free bundles, so this branch disappears.\n ...(stencil && sig._depthStencilFormat.includes(\"stencil\") ? stencil._desc : {}),\n },\n }\n : {}),\n multisample: { count: sig._sampleCount },\n primitive: { topology: \"triangle-list\", cullMode: material.backFaceCulling ? \"back\" : \"none\", frontFace: \"ccw\" },\n });\n bindings.pipelines.set(key, pipeline);\n return pipeline;\n}\n\nfunction toUboField(decl: ShaderUniformDecl): UboField {\n return { _name: decl.name, _type: decl.type };\n}\n\nfunction buildBindGroupLayoutEntries(\n samplers: readonly ShaderSamplerDecl[],\n storageBuffers: readonly { name: string; type: string }[],\n hasCustomUbo: boolean\n): GPUBindGroupLayoutEntry[] {\n const entries: GPUBindGroupLayoutEntry[] = [{ binding: 0, visibility: SHADER_STAGE_ALL, buffer: { type: \"uniform\" } }];\n let nextBinding = 1;\n if (hasCustomUbo) {\n entries.push({ binding: nextBinding++, visibility: SHADER_STAGE_ALL, buffer: { type: \"uniform\" } });\n }\n for (const sampler of samplers) {\n const isArray = sampler.viewDimension === \"2d-array\";\n const sampleType = sampler.comparison === true ? \"depth\" : (sampler.sampleType ?? \"float\");\n entries.push({\n binding: nextBinding++,\n visibility: SHADER_STAGE_ALL,\n texture: {\n sampleType,\n viewDimension: isArray ? \"2d-array\" : \"2d\",\n },\n });\n entries.push({\n binding: nextBinding++,\n visibility: SHADER_STAGE_ALL,\n sampler: { type: sampler.comparison === true ? \"comparison\" : sampleType === \"float\" ? \"filtering\" : \"non-filtering\" },\n });\n }\n for (const _storage of storageBuffers) {\n entries.push({\n binding: nextBinding++,\n visibility: SHADER_STAGE_ALL,\n buffer: { type: \"read-only-storage\" },\n });\n }\n return entries;\n}\n\nfunction attributeLayout(name: ShaderAttributeName, shaderLocation: number): GPUVertexBufferLayout {\n switch (name) {\n case \"position\":\n case \"normal\":\n return { arrayStride: 12, attributes: [{ shaderLocation, offset: 0, format: \"float32x3\" }] };\n case \"uv\":\n case \"uv2\":\n return { arrayStride: 8, attributes: [{ shaderLocation, offset: 0, format: \"float32x2\" }] };\n case \"tangent\":\n case \"color\":\n return { arrayStride: 16, attributes: [{ shaderLocation, offset: 0, format: \"float32x4\" }] };\n }\n}\n\nfunction buildShaderPrelude(material: ShaderMaterial, systemSpec: UboSpec, customSpec: UboSpec | null, instanceAttrs = \"\"): string {\n let wgsl = `${SCENE_UBO_WGSL}\nstruct ShaderSystemUniforms {\n${systemSpec._structBody}\n}\n@group(1) @binding(0) var<uniform> shaderSystem: ShaderSystemUniforms;\n`;\n if (customSpec) {\n wgsl += `struct ShaderUniforms {\n${customSpec._structBody}\n}\n@group(1) @binding(1) var<uniform> shaderUniforms: ShaderUniforms;\n`;\n }\n let nextBinding = customSpec ? 2 : 1;\n for (const sampler of material.samplerDecls) {\n const isArray = sampler.viewDimension === \"2d-array\";\n const isDepth = sampler.comparison === true || sampler.sampleType === \"depth\";\n const texType = isDepth ? (isArray ? \"texture_depth_2d_array\" : \"texture_depth_2d\") : isArray ? \"texture_2d_array<f32>\" : \"texture_2d<f32>\";\n const samplerType = sampler.comparison === true ? \"sampler_comparison\" : \"sampler\";\n wgsl += `@group(1) @binding(${nextBinding++}) var ${sampler.name}: ${texType};\n@group(1) @binding(${nextBinding++}) var ${sampler.name}Sampler: ${samplerType};\n`;\n }\n for (const storage of material.storageBufferDecls) {\n wgsl += `@group(1) @binding(${nextBinding++}) var<storage, read> ${storage.name}: ${storage.type};\n`;\n }\n for (const define of material.defines) {\n wgsl += `const ${define.name}: ${typeof define.value === \"boolean\" ? \"bool\" : \"f32\"} = ${formatDefineValue(define.value)};\n`;\n }\n wgsl += `struct VertexInput {\n`;\n for (let i = 0; i < material.attributes.length; i++) {\n const attr = material.attributes[i]!;\n wgsl += `@location(${i}) ${attr}: ${attributeWgslType(attr)},\n`;\n }\n wgsl += instanceAttrs;\n wgsl += `};\n`;\n return wgsl;\n}\n\nfunction formatDefineValue(value: boolean | number): string {\n if (typeof value === \"boolean\") {\n return value ? \"true\" : \"false\";\n }\n if (Number.isInteger(value)) {\n return `${value}.0`;\n }\n return String(value);\n}\n\nfunction attributeWgslType(name: ShaderAttributeName): string {\n switch (name) {\n case \"position\":\n case \"normal\":\n return \"vec3<f32>\";\n case \"uv\":\n case \"uv2\":\n return \"vec2<f32>\";\n case \"tangent\":\n case \"color\":\n return \"vec4<f32>\";\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shader-pipeline.js","sources":["../../../../src/material/shader/shader-pipeline.ts"],"sourcesContent":["import { SS } from \"../../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../../engine/engine.js\";\nimport type { RenderTargetSignature } from \"../../engine/render-target.js\";\nimport { targetSignatureKey } from \"../../engine/render-target.js\";\nimport { getSceneBindGroupLayout } from \"../../render/scene-helpers.js\";\nimport { SCENE_UBO_WGSL } from \"../../shader/scene-uniforms.js\";\nimport { computeUboLayout } from \"../../shader/ubo-layout.js\";\nimport type { UboField, UboSpec } from \"../../shader/fragment-types.js\";\nimport type { ShaderAttributeName, ShaderMaterial, ShaderSamplerDecl, ShaderUniformDecl } from \"./shader-material.js\";\nimport { _isShaderSystemUniform } from \"./shader-material.js\";\nimport type { ResolvedStencil } from \"../stencil-state.js\";\nimport type { StencilState } from \"../material.js\";\n\n/** Stencil resolver, installed only by `enableMaterialStencil`. Module-local with a single exported setter:\n * when `enableMaterialStencil` is absent from the bundle the setter tree-shakes, the bundler proves this is\n * always null, and every stencil branch below folds away — stencil-free Shader scenes stay byte-identical. */\nlet _stencilResolver: ((stencil: StencilState) => ResolvedStencil) | null = null;\n/** @internal Install the stencil resolver into the Shader pipeline (called by `enableMaterialStencil`). */\nexport function _installShaderStencilResolver(resolve: (stencil: StencilState) => ResolvedStencil): void {\n _stencilResolver = resolve;\n}\n\nexport interface ShaderPipelineBindings {\n readonly group1BGL: GPUBindGroupLayout;\n readonly systemSpec: UboSpec;\n readonly customSpec: UboSpec | null;\n readonly vertexBuffers: readonly GPUVertexBufferLayout[];\n readonly pipelines: Map<string, GPURenderPipeline>;\n}\n\ninterface ShaderMaterialPipelineState extends ShaderMaterial {\n _shaderDevice?: GPUDevice;\n _shaderBindings?: ShaderPipelineBindings;\n _shaderCustomUbo?: GPUBuffer | null;\n _shaderCustomSpec?: UboSpec | null;\n _shaderCustomData?: ArrayBuffer | null;\n _shaderCustomVersion?: number;\n}\n\nexport function getOrCreateShaderPipelineBindings(engine: EngineContext, material: ShaderMaterial): ShaderPipelineBindings {\n const state = material as ShaderMaterialPipelineState;\n if (state._shaderBindings && state._shaderDevice === engine._device) {\n return state._shaderBindings;\n }\n\n state._shaderDevice = engine._device;\n const systemFields = material.uniformDecls.filter((u) => _isShaderSystemUniform(u.name)).map(toUboField);\n const customFields = material.uniformDecls.filter((u) => !_isShaderSystemUniform(u.name)).map(toUboField);\n const systemSpec = computeUboLayout(systemFields.length > 0 ? systemFields : [{ _name: \"_pad\", _type: \"vec4<f32>\" }]);\n const customSpec = customFields.length > 0 ? computeUboLayout(customFields) : null;\n const group1BGL = engine._device.createBindGroupLayout({\n label: \"shader-material-group1\",\n entries: buildBindGroupLayoutEntries(material.samplerDecls, material.storageBufferDecls, customSpec !== null),\n });\n const bindings: ShaderPipelineBindings = {\n group1BGL,\n systemSpec,\n customSpec,\n vertexBuffers: material.attributes.map(attributeLayout),\n pipelines: new Map(),\n };\n state._shaderBindings = bindings;\n state._shaderCustomSpec = customSpec;\n state._shaderCustomUbo = null;\n state._shaderCustomData = null;\n state._shaderCustomVersion = -1;\n return bindings;\n}\n\nexport function getOrCreateShaderPipeline(\n engine: EngineContext,\n sig: RenderTargetSignature,\n material: ShaderMaterial,\n bindings: ShaderPipelineBindings,\n variantKey = \"\",\n vertexBuffers: readonly GPUVertexBufferLayout[] = bindings.vertexBuffers,\n instanceAttrs = \"\"\n): GPURenderPipeline {\n // `variantKey`, `vertexBuffers` and `instanceAttrs` default to the\n // non-instanced pipeline — byte-for-byte identical behaviour to before\n // instancing existed. The dynamically-imported thin-instance module is the\n // only caller that passes non-default values, so no instancing logic runs\n // for non-instanced scenes.\n const key = `${targetSignatureKey(sig)}${variantKey}`;\n const cached = bindings.pipelines.get(key);\n if (cached) {\n return cached;\n }\n const stencil = material.stencil && _stencilResolver ? _stencilResolver(material.stencil) : null;\n const device = engine._device;\n const prelude = buildShaderPrelude(material, bindings.systemSpec, bindings.customSpec, instanceAttrs);\n const vertModule = device.createShaderModule({ label: `${material.name ?? \"shader\"}-vertex`, code: `${prelude}\\n${material.vertexSource}` });\n const wantsFragment = !!sig._colorFormat || material.depthOnlyFragment;\n const fragModule = wantsFragment ? device.createShaderModule({ label: `${material.name ?? \"shader\"}-fragment`, code: `${prelude}\\n${material.fragmentSource}` }) : null;\n const colorTarget: GPUColorTargetState | null = sig._colorFormat\n ? {\n format: sig._colorFormat,\n ...(material.needAlphaBlending\n ? {\n blend:\n material.blendMode === \"additive\"\n ? ({\n color: { srcFactor: \"src-alpha\", dstFactor: \"one\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one\", operation: \"add\" },\n } satisfies GPUBlendState)\n : ({\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n } satisfies GPUBlendState),\n }\n : {}),\n }\n : null;\n\n const pipeline = device.createRenderPipeline({\n label: `${material.name ?? \"shader\"}-pipeline`,\n layout: device.createPipelineLayout({ bindGroupLayouts: [getSceneBindGroupLayout(engine), bindings.group1BGL] }),\n vertex: { module: vertModule, entryPoint: \"mainVertex\", buffers: vertexBuffers as GPUVertexBufferLayout[] },\n ...(fragModule ? { fragment: { module: fragModule, entryPoint: \"mainFragment\", targets: colorTarget ? [colorTarget] : [] } } : {}),\n ...(sig._depthStencilFormat\n ? {\n depthStencil: {\n format: sig._depthStencilFormat,\n // The target's declared depth convention wins over the material default: a depth-only\n // caster authored for the forward-Z shadow map (\"less-equal\") must still depth-test\n // correctly when drawn into a reverse-Z camera depth prepass that declares\n // \"greater-equal\" — otherwise every fragment fails against the 0-cleared buffer.\n depthCompare: sig._depthCompare ?? material.depthCompare,\n depthWriteEnabled: material.needAlphaBlending ? false : material.depthWrite,\n ...(material.depthBias ? { depthBias: material.depthBias } : {}),\n ...(material.depthBiasSlopeScale ? { depthBiasSlopeScale: material.depthBiasSlopeScale } : {}),\n // Pre-baked stencil sub-fields, resolved through the opt-in `_stencilResolver` hook above;\n // applied only on a stencil-capable target — a material reused in the depth32float\n // shadow/depth pass keeps plain depth state (no stencil → no format mismatch). `stencil`\n // is a local const that folds to null in stencil-free bundles, so this branch disappears.\n ...(stencil && sig._depthStencilFormat.includes(\"stencil\") ? stencil._desc : {}),\n },\n }\n : {}),\n multisample: { count: sig._sampleCount },\n primitive: { topology: \"triangle-list\", cullMode: material.backFaceCulling ? \"back\" : \"none\", frontFace: \"ccw\" },\n });\n bindings.pipelines.set(key, pipeline);\n return pipeline;\n}\n\nfunction toUboField(decl: ShaderUniformDecl): UboField {\n return { _name: decl.name, _type: decl.type };\n}\n\nfunction buildBindGroupLayoutEntries(\n samplers: readonly ShaderSamplerDecl[],\n storageBuffers: readonly { name: string; type: string }[],\n hasCustomUbo: boolean\n): GPUBindGroupLayoutEntry[] {\n // Local (not module-level): reading the WebGPU flag globals must be deferred until\n // first device/pipeline use so importing the engine never requires them to exist.\n const SHADER_STAGE_ALL = SS.VERTEX | SS.FRAGMENT;\n const entries: GPUBindGroupLayoutEntry[] = [{ binding: 0, visibility: SHADER_STAGE_ALL, buffer: { type: \"uniform\" } }];\n let nextBinding = 1;\n if (hasCustomUbo) {\n entries.push({ binding: nextBinding++, visibility: SHADER_STAGE_ALL, buffer: { type: \"uniform\" } });\n }\n for (const sampler of samplers) {\n const isArray = sampler.viewDimension === \"2d-array\";\n const sampleType = sampler.comparison === true ? \"depth\" : (sampler.sampleType ?? \"float\");\n entries.push({\n binding: nextBinding++,\n visibility: SHADER_STAGE_ALL,\n texture: {\n sampleType,\n viewDimension: isArray ? \"2d-array\" : \"2d\",\n },\n });\n entries.push({\n binding: nextBinding++,\n visibility: SHADER_STAGE_ALL,\n sampler: { type: sampler.comparison === true ? \"comparison\" : sampleType === \"float\" ? \"filtering\" : \"non-filtering\" },\n });\n }\n for (const _storage of storageBuffers) {\n entries.push({\n binding: nextBinding++,\n visibility: SHADER_STAGE_ALL,\n buffer: { type: \"read-only-storage\" },\n });\n }\n return entries;\n}\n\nfunction attributeLayout(name: ShaderAttributeName, shaderLocation: number): GPUVertexBufferLayout {\n switch (name) {\n case \"position\":\n case \"normal\":\n return { arrayStride: 12, attributes: [{ shaderLocation, offset: 0, format: \"float32x3\" }] };\n case \"uv\":\n case \"uv2\":\n return { arrayStride: 8, attributes: [{ shaderLocation, offset: 0, format: \"float32x2\" }] };\n case \"tangent\":\n case \"color\":\n case \"weights\":\n case \"weights1\":\n return { arrayStride: 16, attributes: [{ shaderLocation, offset: 0, format: \"float32x4\" }] };\n case \"joints\":\n case \"joints1\":\n return { arrayStride: 16, attributes: [{ shaderLocation, offset: 0, format: \"uint32x4\" }] };\n }\n}\n\nfunction buildShaderPrelude(material: ShaderMaterial, systemSpec: UboSpec, customSpec: UboSpec | null, instanceAttrs = \"\"): string {\n let wgsl = `${SCENE_UBO_WGSL}\nstruct ShaderSystemUniforms {\n${systemSpec._structBody}\n}\n@group(1) @binding(0) var<uniform> shaderSystem: ShaderSystemUniforms;\n`;\n if (customSpec) {\n wgsl += `struct ShaderUniforms {\n${customSpec._structBody}\n}\n@group(1) @binding(1) var<uniform> shaderUniforms: ShaderUniforms;\n`;\n }\n let nextBinding = customSpec ? 2 : 1;\n for (const sampler of material.samplerDecls) {\n const isArray = sampler.viewDimension === \"2d-array\";\n const isDepth = sampler.comparison === true || sampler.sampleType === \"depth\";\n const texType = isDepth ? (isArray ? \"texture_depth_2d_array\" : \"texture_depth_2d\") : isArray ? \"texture_2d_array<f32>\" : \"texture_2d<f32>\";\n const samplerType = sampler.comparison === true ? \"sampler_comparison\" : \"sampler\";\n wgsl += `@group(1) @binding(${nextBinding++}) var ${sampler.name}: ${texType};\n@group(1) @binding(${nextBinding++}) var ${sampler.name}Sampler: ${samplerType};\n`;\n }\n for (const storage of material.storageBufferDecls) {\n wgsl += `@group(1) @binding(${nextBinding++}) var<storage, read> ${storage.name}: ${storage.type};\n`;\n }\n for (const define of material.defines) {\n wgsl += `const ${define.name}: ${typeof define.value === \"boolean\" ? \"bool\" : \"f32\"} = ${formatDefineValue(define.value)};\n`;\n }\n wgsl += `struct VertexInput {\n`;\n for (let i = 0; i < material.attributes.length; i++) {\n const attr = material.attributes[i]!;\n wgsl += `@location(${i}) ${attr}: ${attributeWgslType(attr)},\n`;\n }\n wgsl += instanceAttrs;\n wgsl += `};\n`;\n return wgsl;\n}\n\nfunction formatDefineValue(value: boolean | number): string {\n if (typeof value === \"boolean\") {\n return value ? \"true\" : \"false\";\n }\n if (Number.isInteger(value)) {\n return `${value}.0`;\n }\n return String(value);\n}\n\nfunction attributeWgslType(name: ShaderAttributeName): string {\n switch (name) {\n case \"position\":\n case \"normal\":\n return \"vec3<f32>\";\n case \"uv\":\n case \"uv2\":\n return \"vec2<f32>\";\n case \"tangent\":\n case \"color\":\n case \"weights\":\n case \"weights1\":\n return \"vec4<f32>\";\n case \"joints\":\n case \"joints1\":\n return \"vec4<u32>\";\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -52,14 +52,14 @@ function buildMaterialRenderables(scene, material, meshes, isOverride = false) {
|
|
|
52
52
|
const engine = scene.surface.engine;
|
|
53
53
|
const bindings = getOrCreateShaderPipelineBindings(engine, material);
|
|
54
54
|
ensureCustomUbo(engine, material, bindings.customSpec);
|
|
55
|
-
const packets = meshes.map((mesh) => createPacket(scene, material, bindings.systemSpec, mesh));
|
|
55
|
+
const packets = meshes.map((mesh) => createPacket(scene, material, bindings.systemSpec, mesh, isOverride));
|
|
56
56
|
const isTransparent = material.needAlphaBlending;
|
|
57
57
|
if (isTransparent) {
|
|
58
58
|
return packets.map((packet) => createTransparentRenderable(scene, material, packet, isOverride));
|
|
59
59
|
}
|
|
60
60
|
return [createOpaqueRenderable(scene, material, packets, isOverride)];
|
|
61
61
|
}
|
|
62
|
-
function createPacket(scene, material, systemSpec, mesh) {
|
|
62
|
+
function createPacket(scene, material, systemSpec, mesh, aux = false) {
|
|
63
63
|
const engine = scene.surface.engine;
|
|
64
64
|
const systemUBO = createEmptyUniformBuffer(engine, systemSpec._totalBytes, "shader-system-ubo");
|
|
65
65
|
const systemData = new F32(systemSpec._totalBytes / 4);
|
|
@@ -77,7 +77,7 @@ function createPacket(scene, material, systemSpec, mesh) {
|
|
|
77
77
|
for (const tex of packet._boundTextures) {
|
|
78
78
|
acquireTexture(tex);
|
|
79
79
|
}
|
|
80
|
-
registerMeshTextureDisposer(scene, mesh, packet);
|
|
80
|
+
registerMeshTextureDisposer(scene, mesh, packet, aux);
|
|
81
81
|
return packet;
|
|
82
82
|
}
|
|
83
83
|
function createOpaqueRenderable(scene, material, packets, isOverride) {
|
|
@@ -166,25 +166,40 @@ function createTransparentRenderable(scene, material, packet, isOverride) {
|
|
|
166
166
|
function updatePacket(scene, material, packet, context) {
|
|
167
167
|
const engine = scene.surface.engine;
|
|
168
168
|
const state = material;
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
const camera = context._camera ?? scene.camera;
|
|
170
|
+
const cameraVersion = camera ? camera.worldMatrixVersion : -1;
|
|
171
|
+
const meshWmVersion = packet.mesh.worldMatrixVersion;
|
|
172
|
+
const alphaCutoff = material._uniformValues.get("alphaCutoff")?.value[0] ?? 0.4;
|
|
173
|
+
const aspect = camera ? getEffectiveAspectRatio(camera, context.targetWidth, context.targetHeight) : 1;
|
|
174
|
+
if (packet._lastCamera !== camera || packet._lastCameraVersion !== cameraVersion || packet._lastMeshWmVersion !== meshWmVersion || packet._lastTargetWidth !== context.targetWidth || packet._lastTargetHeight !== context.targetHeight || packet._lastAspect !== aspect || packet._lastAlphaCutoff !== alphaCutoff) {
|
|
175
|
+
writeSystemUniforms(packet.systemData, state._shaderBindings.systemSpec, material, packet.mesh, camera, context.targetWidth, context.targetHeight);
|
|
176
|
+
engine._device.queue.writeBuffer(packet.systemUBO, 0, packet.systemData);
|
|
177
|
+
packet._lastCamera = camera;
|
|
178
|
+
packet._lastCameraVersion = cameraVersion;
|
|
179
|
+
packet._lastMeshWmVersion = meshWmVersion;
|
|
180
|
+
packet._lastTargetWidth = context.targetWidth;
|
|
181
|
+
packet._lastTargetHeight = context.targetHeight;
|
|
182
|
+
packet._lastAspect = aspect;
|
|
183
|
+
packet._lastAlphaCutoff = alphaCutoff;
|
|
184
|
+
}
|
|
171
185
|
if (packet._lastResourceVersion !== material._resourceVersion) {
|
|
186
|
+
const newTextures = collectShaderTextures(material);
|
|
187
|
+
for (const tex of newTextures) {
|
|
188
|
+
acquireTexture(tex);
|
|
189
|
+
}
|
|
172
190
|
for (const tex of packet._boundTextures) {
|
|
173
191
|
releaseTexture(tex);
|
|
174
192
|
}
|
|
175
193
|
packet._bindGroup = createShaderBindGroup(engine, material, packet.systemUBO);
|
|
176
|
-
packet._boundTextures =
|
|
194
|
+
packet._boundTextures = newTextures;
|
|
177
195
|
packet._boundStorageBuffers = collectShaderStorageBuffers(material);
|
|
178
|
-
for (const tex of packet._boundTextures) {
|
|
179
|
-
acquireTexture(tex);
|
|
180
|
-
}
|
|
181
196
|
packet._lastResourceVersion = material._resourceVersion;
|
|
182
197
|
}
|
|
183
198
|
}
|
|
184
199
|
function drawPacket(pass, engine, material, packet) {
|
|
185
200
|
const gpu = packet.mesh._gpu;
|
|
186
201
|
for (let i = 0; i < material.attributes.length; i++) {
|
|
187
|
-
pass.setVertexBuffer(i, getAttrBuffer(engine,
|
|
202
|
+
pass.setVertexBuffer(i, getAttrBuffer(engine, packet.mesh, material.attributes[i]));
|
|
188
203
|
}
|
|
189
204
|
pass.setIndexBuffer(gpu.indexBuffer, gpu.indexFormat);
|
|
190
205
|
pass.setBindGroup(1, packet._bindGroup);
|
|
@@ -284,8 +299,9 @@ function collectShaderStorageBuffers(material) {
|
|
|
284
299
|
}
|
|
285
300
|
return buffers;
|
|
286
301
|
}
|
|
287
|
-
function registerMeshTextureDisposer(scene, mesh, packet) {
|
|
288
|
-
const
|
|
302
|
+
function registerMeshTextureDisposer(scene, mesh, packet, aux = false) {
|
|
303
|
+
const map = aux ? scene._meshAuxDisposables : scene._meshDisposables;
|
|
304
|
+
const list = map.get(mesh) ?? [];
|
|
289
305
|
list.push(() => {
|
|
290
306
|
packet._disposed = true;
|
|
291
307
|
if (packet._owner) {
|
|
@@ -302,7 +318,7 @@ function registerMeshTextureDisposer(scene, mesh, packet) {
|
|
|
302
318
|
packet._boundTextures = [];
|
|
303
319
|
packet._boundStorageBuffers = [];
|
|
304
320
|
});
|
|
305
|
-
|
|
321
|
+
map.set(mesh, list);
|
|
306
322
|
}
|
|
307
323
|
function writeSystemUniforms(data, spec, material, mesh, camera, targetWidth, targetHeight) {
|
|
308
324
|
data.fill(0);
|
|
@@ -387,7 +403,11 @@ function getZeroAttrBuffer(engine, gpu, name) {
|
|
|
387
403
|
cache.set(name, buffer);
|
|
388
404
|
return buffer;
|
|
389
405
|
}
|
|
390
|
-
function
|
|
406
|
+
function getSkinBuffer(mesh, field) {
|
|
407
|
+
return mesh.vat?.[field] ?? mesh.skeleton?.[field] ?? null;
|
|
408
|
+
}
|
|
409
|
+
function getAttrBuffer(engine, mesh, name) {
|
|
410
|
+
const gpu = mesh._gpu;
|
|
391
411
|
switch (name) {
|
|
392
412
|
case "position":
|
|
393
413
|
return gpu.positionBuffer;
|
|
@@ -401,6 +421,14 @@ function getAttrBuffer(engine, gpu, name) {
|
|
|
401
421
|
return gpu.tangentBuffer ?? getZeroAttrBuffer(engine, gpu, "tangent");
|
|
402
422
|
case "color":
|
|
403
423
|
return gpu.colorBuffer ?? getZeroAttrBuffer(engine, gpu, "color");
|
|
424
|
+
case "joints":
|
|
425
|
+
return getSkinBuffer(mesh, "jointsBuffer") ?? getZeroAttrBuffer(engine, gpu, "joints");
|
|
426
|
+
case "weights":
|
|
427
|
+
return getSkinBuffer(mesh, "weightsBuffer") ?? getZeroAttrBuffer(engine, gpu, "weights");
|
|
428
|
+
case "joints1":
|
|
429
|
+
return getSkinBuffer(mesh, "joints1Buffer") ?? getZeroAttrBuffer(engine, gpu, "joints1");
|
|
430
|
+
case "weights1":
|
|
431
|
+
return getSkinBuffer(mesh, "weights1Buffer") ?? getZeroAttrBuffer(engine, gpu, "weights1");
|
|
404
432
|
}
|
|
405
433
|
}
|
|
406
434
|
|