@babylonjs/lite 1.4.0 → 1.5.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/dist/index.js +381 -375
- package/dist/index.js.map +1 -1
- package/index.d.ts +757 -0
- package/lib/audio/analyzer.js +65 -0
- package/lib/audio/analyzer.js.map +1 -0
- package/lib/audio/audio-bus.js +38 -0
- package/lib/audio/audio-bus.js.map +1 -0
- package/lib/audio/audio-engine.js +188 -0
- package/lib/audio/audio-engine.js.map +1 -0
- package/lib/audio/audio-fetch.js +18 -0
- package/lib/audio/audio-fetch.js.map +1 -0
- package/lib/audio/audio-param.js +96 -0
- package/lib/audio/audio-param.js.map +1 -0
- package/lib/audio/audio-signal.js +46 -0
- package/lib/audio/audio-signal.js.map +1 -0
- package/lib/audio/bus.js +33 -0
- package/lib/audio/bus.js.map +1 -0
- package/lib/audio/host-types.js +2 -0
- package/lib/audio/host-types.js.map +1 -0
- package/lib/audio/index.js +12 -0
- package/lib/audio/index.js.map +1 -0
- package/lib/audio/sound-buffer.js +59 -0
- package/lib/audio/sound-buffer.js.map +1 -0
- package/lib/audio/sound-source.js +57 -0
- package/lib/audio/sound-source.js.map +1 -0
- package/lib/audio/sound-sub-graph.js +72 -0
- package/lib/audio/sound-sub-graph.js.map +1 -0
- package/lib/audio/spatial.js +466 -0
- package/lib/audio/spatial.js.map +1 -0
- package/lib/audio/static-sound.js +313 -0
- package/lib/audio/static-sound.js.map +1 -0
- package/lib/audio/stereo.js +40 -0
- package/lib/audio/stereo.js.map +1 -0
- package/lib/audio/streaming-sound.js +377 -0
- package/lib/audio/streaming-sound.js.map +1 -0
- package/lib/audio/unmute-ui.js +72 -0
- package/lib/audio/unmute-ui.js.map +1 -0
- package/lib/audio/visualizer.js +101 -0
- package/lib/audio/visualizer.js.map +1 -0
- package/lib/engine/engine.js +1 -1
- package/lib/index.js +11 -0
- package/lib/index.js.map +1 -1
- package/lib/light/types.js.map +1 -1
- package/lib/loader-gltf/animation-pointer-basecolor.js +25 -0
- package/lib/loader-gltf/animation-pointer-basecolor.js.map +1 -0
- package/lib/loader-gltf/animation-pointer-ext.js +244 -0
- package/lib/loader-gltf/animation-pointer-ext.js.map +1 -0
- package/lib/loader-gltf/animation-pointer-lights.js +46 -0
- package/lib/loader-gltf/animation-pointer-lights.js.map +1 -0
- package/lib/loader-gltf/animation-pointer.js +4 -1
- package/lib/loader-gltf/animation-pointer.js.map +1 -1
- package/lib/loader-gltf/gltf-animation.js +5 -3
- package/lib/loader-gltf/gltf-animation.js.map +1 -1
- package/lib/loader-gltf/gltf-color-normalize.js +10 -1
- package/lib/loader-gltf/gltf-color-normalize.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-animation-pointer.js +67 -47
- package/lib/loader-gltf/gltf-feature-animation-pointer.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-lights-punctual.js +51 -9
- package/lib/loader-gltf/gltf-feature-lights-punctual.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-primitive.js +20 -0
- package/lib/loader-gltf/gltf-feature-primitive.js.map +1 -0
- package/lib/loader-gltf/gltf-feature-registry.js +25 -0
- package/lib/loader-gltf/gltf-feature-registry.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-skeleton.js +18 -3
- package/lib/loader-gltf/gltf-feature-skeleton.js.map +1 -1
- package/lib/loader-gltf/gltf-interleave.js +3 -2
- package/lib/loader-gltf/gltf-interleave.js.map +1 -1
- package/lib/loader-gltf/gltf-light-pointer-state.js +18 -0
- package/lib/loader-gltf/gltf-light-pointer-state.js.map +1 -0
- package/lib/loader-gltf/gltf-parser.js +7 -1
- package/lib/loader-gltf/gltf-parser.js.map +1 -1
- package/lib/loader-gltf/gltf-pbr-builder-ext.js +1 -1
- package/lib/loader-gltf/gltf-pbr-builder-ext.js.map +1 -1
- package/lib/loader-gltf/gltf-pbr-builder.js +1 -1
- package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
- package/lib/loader-gltf/gltf-sampler-denorm.js +20 -0
- package/lib/loader-gltf/gltf-sampler-denorm.js.map +1 -0
- package/lib/loader-gltf/gltf-sampler-desc.js +11 -2
- package/lib/loader-gltf/gltf-sampler-desc.js.map +1 -1
- package/lib/loader-gltf/gltf-uv-denorm.js +28 -0
- package/lib/loader-gltf/gltf-uv-denorm.js.map +1 -0
- package/lib/loader-gltf/load-gltf.js +15 -6
- package/lib/loader-gltf/load-gltf.js.map +1 -1
- package/lib/material/material-rebuild.js +4 -0
- package/lib/material/material-rebuild.js.map +1 -1
- package/lib/material/mesh-features.js +8 -1
- package/lib/material/mesh-features.js.map +1 -1
- package/lib/material/pbr/fragments/reflectance-fragment.js +1 -1
- package/lib/material/pbr/fragments/reflectance-fragment.js.map +1 -1
- package/lib/material/pbr/fragments/refraction-rtt-fragment.js +1 -1
- package/lib/material/pbr/fragments/refraction-rtt-fragment.js.map +1 -1
- package/lib/material/pbr/pbr-pipeline.js +7 -3
- package/lib/material/pbr/pbr-pipeline.js.map +1 -1
- package/lib/material/pbr/pbr-primitive-resolver.js +34 -0
- package/lib/material/pbr/pbr-primitive-resolver.js.map +1 -0
- package/lib/material/pbr/pbr-renderable.js +1 -1
- package/lib/material/pbr/pbr-renderable.js.map +1 -1
- package/lib/material/shader/shader-material.js +9 -5
- package/lib/material/shader/shader-material.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/material/standard/standard-renderable.js +1 -1
- package/lib/material/standard/standard-renderable.js.map +1 -1
- package/lib/mesh/mesh-dispose.js +1 -0
- package/lib/mesh/mesh-dispose.js.map +1 -1
- package/lib/mesh/thin-instance-cull-binding.js +15 -6
- package/lib/mesh/thin-instance-cull-binding.js.map +1 -1
- package/lib/scene/scene-core.js +1 -0
- package/lib/scene/scene-core.js.map +1 -1
- package/lib/scene/scene-material-swap.js +2 -0
- package/lib/scene/scene-material-swap.js.map +1 -1
- package/lib/shadow/csm-shadow-task-hooks.js +67 -9
- package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
- package/lib/sprite/sprite-2d.js +4 -0
- package/lib/sprite/sprite-2d.js.map +1 -1
- package/lib/sprite/sprite-pipeline.js +25 -22
- package/lib/sprite/sprite-pipeline.js.map +1 -1
- package/lib/text/_gpu/text-pipeline.js +1 -1
- package/lib/text/_gpu/text-pipeline.js.map +1 -1
- package/lib/text/text-renderer.js +3 -1
- package/lib/text/text-renderer.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gltf-pbr-builder.js","sources":["../../../src/loader-gltf/gltf-pbr-builder.ts"],"sourcesContent":["/** Shared PBR-material assembly + texture upload + ext-layer merging.\n * Used by both the core loader (`load-gltf.ts`) and the variants loader\n * (`gltf-variants.ts`) so they can't drift. */\n\nimport { U8 } from \"../engine/typed-arrays.js\";\nimport { TU } from \"../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Texture2D } from \"../texture/texture-2d.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport { getPbrGroupBuilder } from \"../material/pbr/pbr-material.js\";\nimport type { GltfMaterialData, GltfMatExtCtx } from \"./gltf-material.js\";\nimport type { GltfFeature } from \"./gltf-feature.js\";\nimport { mipLevelCount } from \"../texture/mip-count.js\";\nimport { linearToSrgbByte } from \"../math/color.js\";\n\n/** Texture post-processor composed from every active feature's `wrapTexture`\n * hook. Identity when no feature contributes one (common case). Kept simple\n * so the core loader stays feature-agnostic and tree-shakes cleanly. */\nexport type TextureWrapFn = (tex: Texture2D, texInfo: unknown) => Texture2D;\nexport const identityTexWrap: TextureWrapFn = (tex) => tex;\n\nexport type GenerateMipmapsFn = (engine: EngineContext, texture: GPUTexture, face?: number) => void;\n\nexport function uploadTex(\n engine: EngineContext,\n bitmap: ImageBitmap | null,\n srgb: boolean,\n sampler: GPUSampler,\n generateMipmaps: GenerateMipmapsFn,\n fallback?: Uint8Array\n): Texture2D {\n const device = engine._device;\n const w = bitmap?.width ?? 1;\n const h = bitmap?.height ?? 1;\n const fmt: GPUTextureFormat = srgb ? \"rgba8unorm-srgb\" : \"rgba8unorm\";\n const mips = bitmap ? mipLevelCount(w, h) : 1;\n const tex = device.createTexture({\n size: { width: w, height: h },\n format: fmt,\n usage: TU.TEXTURE_BINDING | TU.COPY_DST | TU.COPY_SRC | TU.RENDER_ATTACHMENT,\n mipLevelCount: mips,\n });\n if (bitmap) {\n device.queue.copyExternalImageToTexture({ source: bitmap }, { texture: tex, premultipliedAlpha: false }, { width: w, height: h });\n generateMipmaps(engine, tex);\n } else {\n device.queue.writeTexture({ texture: tex }, (fallback ?? new U8([255, 255, 255, 255])) as Uint8Array<ArrayBuffer>, { bytesPerRow: 4 }, { width: 1, height: 1 });\n }\n const result: Texture2D = {\n texture: tex,\n view: tex.createView(),\n sampler,\n width: w,\n height: h,\n };\n engine._dlr?.b(result, bitmap, srgb, !!bitmap, fallback);\n return result;\n}\n\n/** Assemble a PbrMaterialProps from parsed glTF material data + already-uploaded\n * textures + per-ext fragment overrides. Fast-path: no wrapTex, no occlusionOnUv2,\n * no occlusionTexture. Slow-path additions live in gltf-pbr-builder-ext.ts. */\nexport function assemblePbrProps(\n mat: GltfMaterialData,\n baseColorTexture: Texture2D,\n ormTexture: Texture2D,\n normalTexture: Texture2D | undefined,\n emissiveTexture: Texture2D | undefined,\n extLayers: Partial<PbrMaterialProps> | undefined\n): PbrMaterialProps {\n const ef = mat._emissiveFactor;\n const defaultFactor = (ef[0] === 1 && ef[1] === 1 && ef[2] === 1) || (ef[0] === 0 && ef[1] === 0 && ef[2] === 0);\n return {\n baseColorTexture,\n normalTexture,\n ormTexture,\n emissiveTexture,\n ...(mat._baseColorImage && !isDefaultBaseColorFactor(mat._baseColorFactor) ? { baseColorFactor: mat._baseColorFactor } : undefined),\n doubleSided: mat._doubleSided,\n occlusionStrength: mat._occlusionImage ? 1.0 : 0,\n ...(mat._normalScale !== 1 ? { normalTextureScale: mat._normalScale } : undefined),\n ...(mat._metallicRoughnessImage ? { metallicFactor: mat._metallicFactor, roughnessFactor: mat._roughnessFactor } : undefined),\n ...(!defaultFactor ? { emissiveColor: [ef[0], ef[1], ef[2]] as [number, number, number] } : undefined),\n enableSpecularAA: true,\n ...(mat._alphaMode === \"BLEND\" ? { alphaBlend: true, alpha: mat._baseColorFactor[3] } : undefined),\n ...(mat._alphaMode === \"MASK\" ? { alpha: mat._baseColorFactor[3], alphaCutOff: mat._alphaCutoff } : undefined),\n ...(mat._rawMatDef?.name ? { name: mat._rawMatDef.name as string } : undefined),\n ...extLayers,\n _buildGroup: getPbrGroupBuilder(),\n _uboVersion: 0,\n } as PbrMaterialProps;\n}\n\nfunction isDefaultBaseColorFactor(f: readonly number[]): boolean {\n return f[0] === 1 && f[1] === 1 && f[2] === 1 && f[3] === 1;\n}\n\n/** Build the always-present default textures (base color + ORM) from a parsed glTF material.\n * Fast-path version: no wrapTex, no occlusion-on-uv2 handling. The slow path lives\n * in gltf-pbr-builder-ext.ts and is lazy-loaded only when needed. */\nexport function buildDefaultPbrTextures(\n engine: EngineContext,\n mat: GltfMaterialData,\n sampler: GPUSampler,\n generateMipmaps: GenerateMipmapsFn,\n getCachedTex: (bitmap: ImageBitmap, srgb: boolean) => Texture2D\n): { baseColorTexture: Texture2D; ormTexture: Texture2D; normalTexture: Texture2D | undefined; emissiveTexture: Texture2D | undefined } {\n const baseColorTexture = mat._baseColorImage\n ? getCachedTex(mat._baseColorImage, true)\n : (() => {\n const f = mat._baseColorFactor;\n return uploadTex(\n engine,\n null,\n true,\n sampler,\n generateMipmaps,\n new U8([linearToSrgbByte(f[0]), linearToSrgbByte(f[1]), linearToSrgbByte(f[2]), Math.round(Math.max(0, Math.min(1, f[3])) * 255)])\n );\n })();\n const normalTexture = mat._normalImage ? getCachedTex(mat._normalImage, false) : undefined;\n const emissiveTexture = mat._emissiveImage ? getCachedTex(mat._emissiveImage, true) : undefined;\n\n const single = mat._metallicRoughnessImage ?? mat._occlusionImage;\n let ormTexture: Texture2D;\n if (single && (!mat._metallicRoughnessImage || !mat._occlusionImage || mat._metallicRoughnessImage === mat._occlusionImage)) {\n ormTexture = getCachedTex(single, false);\n } else if (!single) {\n const clamp = (v: number) => Math.round(Math.max(0, Math.min(1, v)) * 255);\n ormTexture = uploadTex(engine, null, false, sampler, generateMipmaps, new U8([255, clamp(mat._roughnessFactor), clamp(mat._metallicFactor), 255]));\n } else {\n ormTexture = getCachedTex(mat._metallicRoughnessImage!, false);\n }\n return { baseColorTexture, ormTexture, normalTexture, emissiveTexture };\n}\n\n/** Run all material-layer features and merge their fragments. */\nexport async function runMatExts(mat: GltfMaterialData, exts: GltfFeature[], ctx: GltfMatExtCtx): Promise<Partial<PbrMaterialProps> | undefined> {\n if (!exts.length) {\n return undefined;\n }\n const fragments = await Promise.all(exts.map((ext) => ext.applyMaterial!(mat, ctx)));\n let layers: Partial<PbrMaterialProps> | undefined;\n for (const f of fragments) {\n if (f) {\n layers ??= {};\n Object.assign(layers, f);\n }\n }\n return layers;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gltf-pbr-builder.js","sources":["../../../src/loader-gltf/gltf-pbr-builder.ts"],"sourcesContent":["/** Shared PBR-material assembly + texture upload + ext-layer merging.\n * Used by both the core loader (`load-gltf.ts`) and the variants loader\n * (`gltf-variants.ts`) so they can't drift. */\n\nimport { U8 } from \"../engine/typed-arrays.js\";\nimport { TU } from \"../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Texture2D } from \"../texture/texture-2d.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport { getPbrGroupBuilder } from \"../material/pbr/pbr-material.js\";\nimport type { GltfMaterialData, GltfMatExtCtx } from \"./gltf-material.js\";\nimport type { GltfFeature } from \"./gltf-feature.js\";\nimport { mipLevelCount } from \"../texture/mip-count.js\";\nimport { linearToSrgbByte } from \"../math/color.js\";\n\n/** Texture post-processor composed from every active feature's `wrapTexture`\n * hook. Identity when no feature contributes one (common case). Kept simple\n * so the core loader stays feature-agnostic and tree-shakes cleanly. */\nexport type TextureWrapFn = (tex: Texture2D, texInfo: unknown) => Texture2D;\nexport const identityTexWrap: TextureWrapFn = (tex) => tex;\n\nexport type GenerateMipmapsFn = (engine: EngineContext, texture: GPUTexture, face?: number) => void;\n\nexport function uploadTex(\n engine: EngineContext,\n bitmap: ImageBitmap | null,\n srgb: boolean,\n sampler: GPUSampler,\n generateMipmaps: GenerateMipmapsFn,\n fallback?: Uint8Array\n): Texture2D {\n const device = engine._device;\n const w = bitmap?.width ?? 1;\n const h = bitmap?.height ?? 1;\n const fmt: GPUTextureFormat = srgb ? \"rgba8unorm-srgb\" : \"rgba8unorm\";\n const mips = bitmap ? mipLevelCount(w, h) : 1;\n const tex = device.createTexture({\n size: { width: w, height: h },\n format: fmt,\n usage: TU.TEXTURE_BINDING | TU.COPY_DST | TU.COPY_SRC | TU.RENDER_ATTACHMENT,\n mipLevelCount: mips,\n });\n if (bitmap) {\n device.queue.copyExternalImageToTexture({ source: bitmap }, { texture: tex, premultipliedAlpha: false }, { width: w, height: h });\n generateMipmaps(engine, tex);\n } else {\n device.queue.writeTexture({ texture: tex }, (fallback ?? new U8([255, 255, 255, 255])) as Uint8Array<ArrayBuffer>, { bytesPerRow: 4 }, { width: 1, height: 1 });\n }\n const result: Texture2D = {\n texture: tex,\n view: tex.createView(),\n sampler,\n width: w,\n height: h,\n };\n engine._dlr?.b(result, bitmap, srgb, !!bitmap, fallback);\n return result;\n}\n\n/** Assemble a PbrMaterialProps from parsed glTF material data + already-uploaded\n * textures + per-ext fragment overrides. Fast-path: no wrapTex, no occlusionOnUv2,\n * no occlusionTexture. Slow-path additions live in gltf-pbr-builder-ext.ts. */\nexport function assemblePbrProps(\n mat: GltfMaterialData,\n baseColorTexture: Texture2D,\n ormTexture: Texture2D,\n normalTexture: Texture2D | undefined,\n emissiveTexture: Texture2D | undefined,\n extLayers: Partial<PbrMaterialProps> | undefined\n): PbrMaterialProps {\n const ef = mat._emissiveFactor;\n // emissiveFactor multiplies the emissive texture, so [1,1,1] is a no-op WHEN a texture is\n // present. With no emissive texture, [1,1,1] is a real full-white emissive that must be applied\n // (the glTF default is [0,0,0]) — otherwise the surface renders unlit/dark (Material_03).\n const defaultFactor = (ef[0] === 0 && ef[1] === 0 && ef[2] === 0) || (!!emissiveTexture && ef[0] === 1 && ef[1] === 1 && ef[2] === 1);\n return {\n baseColorTexture,\n normalTexture,\n ormTexture,\n emissiveTexture,\n ...(mat._baseColorImage && !isDefaultBaseColorFactor(mat._baseColorFactor) ? { baseColorFactor: mat._baseColorFactor } : undefined),\n doubleSided: mat._doubleSided,\n occlusionStrength: mat._occlusionImage ? 1.0 : 0,\n ...(mat._normalScale !== 1 ? { normalTextureScale: mat._normalScale } : undefined),\n ...(mat._metallicRoughnessImage ? { metallicFactor: mat._metallicFactor, roughnessFactor: mat._roughnessFactor } : undefined),\n ...(!defaultFactor ? { emissiveColor: [ef[0], ef[1], ef[2]] as [number, number, number] } : undefined),\n enableSpecularAA: true,\n ...(mat._alphaMode === \"BLEND\" ? { alphaBlend: true, alpha: mat._baseColorFactor[3] } : undefined),\n ...(mat._alphaMode === \"MASK\" ? { alpha: mat._baseColorFactor[3], alphaCutOff: mat._alphaCutoff } : undefined),\n ...(mat._rawMatDef?.name ? { name: mat._rawMatDef.name as string } : undefined),\n ...extLayers,\n _buildGroup: getPbrGroupBuilder(),\n _uboVersion: 0,\n } as PbrMaterialProps;\n}\n\nfunction isDefaultBaseColorFactor(f: readonly number[]): boolean {\n return f[0] === 1 && f[1] === 1 && f[2] === 1 && f[3] === 1;\n}\n\n/** Build the always-present default textures (base color + ORM) from a parsed glTF material.\n * Fast-path version: no wrapTex, no occlusion-on-uv2 handling. The slow path lives\n * in gltf-pbr-builder-ext.ts and is lazy-loaded only when needed. */\nexport function buildDefaultPbrTextures(\n engine: EngineContext,\n mat: GltfMaterialData,\n sampler: GPUSampler,\n generateMipmaps: GenerateMipmapsFn,\n getCachedTex: (bitmap: ImageBitmap, srgb: boolean) => Texture2D\n): { baseColorTexture: Texture2D; ormTexture: Texture2D; normalTexture: Texture2D | undefined; emissiveTexture: Texture2D | undefined } {\n const baseColorTexture = mat._baseColorImage\n ? getCachedTex(mat._baseColorImage, true)\n : (() => {\n const f = mat._baseColorFactor;\n return uploadTex(\n engine,\n null,\n true,\n sampler,\n generateMipmaps,\n new U8([linearToSrgbByte(f[0]), linearToSrgbByte(f[1]), linearToSrgbByte(f[2]), Math.round(Math.max(0, Math.min(1, f[3])) * 255)])\n );\n })();\n const normalTexture = mat._normalImage ? getCachedTex(mat._normalImage, false) : undefined;\n const emissiveTexture = mat._emissiveImage ? getCachedTex(mat._emissiveImage, true) : undefined;\n\n const single = mat._metallicRoughnessImage ?? mat._occlusionImage;\n let ormTexture: Texture2D;\n if (single && (!mat._metallicRoughnessImage || !mat._occlusionImage || mat._metallicRoughnessImage === mat._occlusionImage)) {\n ormTexture = getCachedTex(single, false);\n } else if (!single) {\n const clamp = (v: number) => Math.round(Math.max(0, Math.min(1, v)) * 255);\n ormTexture = uploadTex(engine, null, false, sampler, generateMipmaps, new U8([255, clamp(mat._roughnessFactor), clamp(mat._metallicFactor), 255]));\n } else {\n ormTexture = getCachedTex(mat._metallicRoughnessImage!, false);\n }\n return { baseColorTexture, ormTexture, normalTexture, emissiveTexture };\n}\n\n/** Run all material-layer features and merge their fragments. */\nexport async function runMatExts(mat: GltfMaterialData, exts: GltfFeature[], ctx: GltfMatExtCtx): Promise<Partial<PbrMaterialProps> | undefined> {\n if (!exts.length) {\n return undefined;\n }\n const fragments = await Promise.all(exts.map((ext) => ext.applyMaterial!(mat, ctx)));\n let layers: Partial<PbrMaterialProps> | undefined;\n for (const f of fragments) {\n if (f) {\n layers ??= {};\n Object.assign(layers, f);\n }\n }\n return layers;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { F32, I8, I16, U8 } from '../engine/typed-arrays.js';
|
|
2
|
+
import { _installSamplerConverter } from './gltf-animation.js';
|
|
3
|
+
|
|
4
|
+
_installSamplerConverter((src, length, normalized) => {
|
|
5
|
+
if (src instanceof F32) {
|
|
6
|
+
return new F32(src.buffer, src.byteOffset, length);
|
|
7
|
+
}
|
|
8
|
+
const out = new F32(length);
|
|
9
|
+
const div = src instanceof I8 ? 127 : src instanceof I16 ? 32767 : src instanceof U8 ? 255 : 65535;
|
|
10
|
+
const signed = src instanceof I8 || src instanceof I16;
|
|
11
|
+
const s = src;
|
|
12
|
+
for (let i = 0; i < length; i++) {
|
|
13
|
+
out[i] = normalized ? signed ? Math.max(s[i] / div, -1) : s[i] / div : s[i];
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
});
|
|
17
|
+
const feature = { id: "_sampler_denorm" };
|
|
18
|
+
|
|
19
|
+
export { feature as default };
|
|
20
|
+
//# sourceMappingURL=gltf-sampler-denorm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gltf-sampler-denorm.js","sources":["../../../src/loader-gltf/gltf-sampler-denorm.ts"],"sourcesContent":["/** Lazily-installed animation-sampler converter for non-Float32 / normalized accessor payloads:\n * normalized signed BYTE/SHORT rotation output (glTF-Asset-Generator Animation_SamplerType),\n * normalized UNSIGNED_BYTE flags, misaligned Float32, etc. Imported for side effect only when an\n * animation sampler is non-float (registry trigger) or by KHR_animation_pointer, so plain\n * float-sampler animations never bundle this denormalization code and stay byte-identical. */\nimport { F32, U8, I8, I16 } from \"../engine/typed-arrays.js\";\nimport type { GltfFeature } from \"./gltf-feature.js\";\nimport { _installSamplerConverter } from \"./gltf-animation.js\";\n\n_installSamplerConverter((src, length, normalized) => {\n // Aligned Float32 fast path (also covers the misaligned-reinterpret case the default handled).\n if (src instanceof F32) {\n return new F32(src.buffer, src.byteOffset, length);\n }\n const out = new F32(length);\n const div = src instanceof I8 ? 127 : src instanceof I16 ? 32767 : src instanceof U8 ? 255 : 65535;\n const signed = src instanceof I8 || src instanceof I16;\n const s = src as unknown as { [i: number]: number };\n for (let i = 0; i < length; i++) {\n out[i] = normalized ? (signed ? Math.max(s[i]! / div, -1) : s[i]! / div) : s[i]!;\n }\n return out;\n});\n\n// Hookless feature: registered in the registry so loadGltfFeatures imports this module (installing\n// the converter above as a side effect). The empty default keeps `mods.map(m => m.default)` valid.\nconst feature: GltfFeature = { id: \"_sampler_denorm\" };\nexport default feature;\n"],"names":[],"mappings":";;;AASA,wBAAA,CAAyB,CAAC,GAAA,EAAK,MAAA,EAAQ,UAAA,KAAe;AAElD,EAAA,IAAI,eAAe,GAAA,EAAK;AACpB,IAAA,OAAO,IAAI,GAAA,CAAI,GAAA,CAAI,MAAA,EAAQ,GAAA,CAAI,YAAY,MAAM,CAAA;AAAA,EACrD;AACA,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,MAAM,CAAA;AAC1B,EAAA,MAAM,GAAA,GAAM,eAAe,EAAA,GAAK,GAAA,GAAM,eAAe,GAAA,GAAM,KAAA,GAAQ,GAAA,YAAe,EAAA,GAAK,GAAA,GAAM,KAAA;AAC7F,EAAA,MAAM,MAAA,GAAS,GAAA,YAAe,EAAA,IAAM,GAAA,YAAe,GAAA;AACnD,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC7B,IAAA,GAAA,CAAI,CAAC,CAAA,GAAI,UAAA,GAAc,MAAA,GAAS,IAAA,CAAK,IAAI,CAAA,CAAE,CAAC,CAAA,GAAK,GAAA,EAAK,EAAE,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAK,GAAA,GAAO,EAAE,CAAC,CAAA;AAAA,EAClF;AACA,EAAA,OAAO,GAAA;AACX,CAAC,CAAA;AAID,MAAM,OAAA,GAAuB,EAAE,EAAA,EAAI,iBAAA;;;;"}
|
|
@@ -9,6 +9,7 @@ function gltfTexSamplerDesc(json, texInfo) {
|
|
|
9
9
|
const minF = s?.minFilter;
|
|
10
10
|
const minNearest = minF === 9728 || minF === 9984 || minF === 9986;
|
|
11
11
|
const mipNearest = minF === 9984 || minF === 9985;
|
|
12
|
+
const noMip = minF === 9728 || minF === 9729;
|
|
12
13
|
const magLinear = s?.magFilter !== 9728;
|
|
13
14
|
return {
|
|
14
15
|
magFilter: magLinear ? "linear" : "nearest",
|
|
@@ -16,13 +17,21 @@ function gltfTexSamplerDesc(json, texInfo) {
|
|
|
16
17
|
mipmapFilter: mipNearest ? "nearest" : "linear",
|
|
17
18
|
addressModeU: wrap(s?.wrapS),
|
|
18
19
|
addressModeV: wrap(s?.wrapT),
|
|
20
|
+
...noMip ? { lodMaxClamp: 0 } : void 0,
|
|
19
21
|
// WebGPU forbids anisotropy unless mag/min/mip filters are ALL linear; gate on
|
|
20
22
|
// every filter (incl. mipNearest, e.g. glTF LINEAR_MIPMAP_NEAREST) or createSampler throws.
|
|
21
|
-
|
|
23
|
+
// Also disable it for the clamped-mip path (single LOD → anisotropy is meaningless).
|
|
24
|
+
maxAnisotropy: magLinear && !minNearest && !mipNearest && !noMip ? 4 : 1
|
|
22
25
|
};
|
|
23
26
|
}
|
|
24
27
|
function makeSamplerFor(engine, json, defaultSampler) {
|
|
25
|
-
return (texInfo) =>
|
|
28
|
+
return (texInfo) => {
|
|
29
|
+
if (texInfo == null) {
|
|
30
|
+
return defaultSampler;
|
|
31
|
+
}
|
|
32
|
+
const desc = gltfTexSamplerDesc(json, texInfo);
|
|
33
|
+
return desc.lodMaxClamp === 0 ? engine._device.createSampler(desc) : getOrCreateSampler(engine, desc);
|
|
34
|
+
};
|
|
26
35
|
}
|
|
27
36
|
function buildSampledPbrTextures(engine, mat, defaultSampler, generateMipmaps, samplerFor, getCachedTex) {
|
|
28
37
|
const def = mat._rawMatDef ?? {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gltf-sampler-desc.js","sources":["../../../src/loader-gltf/gltf-sampler-desc.ts"],"sourcesContent":["import { getOrCreateSampler } from \"../resource/gpu-pool.js\";\nimport { U8 } from \"../engine/typed-arrays.js\";\nimport { linearToSrgbByte } from \"../math/color.js\";\nimport { uploadTex } from \"./gltf-pbr-builder.js\";\nimport type { GenerateMipmapsFn } from \"./gltf-pbr-builder.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Texture2D } from \"../texture/texture-2d.js\";\nimport type { GltfMaterialData } from \"./gltf-material.js\";\n\n/** Map a glTF textureInfo's sampler (wrapS/wrapT/magFilter/minFilter) to a WebGPU sampler\n * descriptor. glTF wrap: 33071 CLAMP_TO_EDGE, 33648 MIRRORED_REPEAT, else REPEAT.\n * glTF filter: 9728 NEAREST else LINEAR; min/mip from the combined min filter enum. */\nfunction gltfTexSamplerDesc(json: any, texInfo: any): GPUSamplerDescriptor {\n const s = json.textures?.[texInfo.index]?.sampler != null ? json.samplers?.[json.textures[texInfo.index].sampler] : undefined;\n const wrap = (m: number | undefined): GPUAddressMode => (m === 33071 ? \"clamp-to-edge\" : m === 33648 ? \"mirror-repeat\" : \"repeat\");\n const minF: number | undefined = s?.minFilter;\n const minNearest = minF === 9728 || minF === 9984 || minF === 9986;\n const mipNearest = minF === 9984 || minF === 9985;\n const magLinear = s?.magFilter !== 9728;\n return {\n magFilter: magLinear ? \"linear\" : \"nearest\",\n minFilter: minNearest ? \"nearest\" : \"linear\",\n mipmapFilter: mipNearest ? \"nearest\" : \"linear\",\n addressModeU: wrap(s?.wrapS),\n addressModeV: wrap(s?.wrapT),\n // WebGPU forbids anisotropy unless mag/min/mip filters are ALL linear; gate on\n // every filter (incl. mipNearest, e.g. glTF LINEAR_MIPMAP_NEAREST) or createSampler throws.\n maxAnisotropy: magLinear && !minNearest && !mipNearest ? 4 : 1,\n };\n}\n\n/** Build a per-texture sampler resolver honoring each texture's glTF sampler\n * (wrap/filter). Loaded lazily only when an asset declares a non-default sampler;\n * the common case (default repeat/linear) uses one shared sampler and never loads this.\n * `texInfo == null` (factor textures) falls back to `defaultSampler`.\n * @internal */\nexport function makeSamplerFor(engine: EngineContext, json: any, defaultSampler: GPUSampler): (texInfo: any) => GPUSampler {\n return (texInfo: any): GPUSampler => (texInfo == null ? defaultSampler : getOrCreateSampler(engine, gltfTexSamplerDesc(json, texInfo)));\n}\n\n/** Sampler-aware variant of buildDefaultPbrTextures. Mirrors the core fast path but wraps\n * each shared GPU texture with the sampler resolved from its glTF textureInfo (wrap/filter),\n * so clamp/mirror/nearest assets render correctly without re-uploading identical images.\n * Lazy-loaded only for non-default-sampler assets — the common path stays byte-identical.\n * @internal */\nexport function buildSampledPbrTextures(\n engine: EngineContext,\n mat: GltfMaterialData,\n defaultSampler: GPUSampler,\n generateMipmaps: GenerateMipmapsFn,\n samplerFor: (texInfo: any) => GPUSampler,\n getCachedTex: (bitmap: ImageBitmap, srgb: boolean) => Texture2D\n): { baseColorTexture: Texture2D; ormTexture: Texture2D; normalTexture: Texture2D | undefined; emissiveTexture: Texture2D | undefined } {\n const def = mat._rawMatDef ?? {};\n const pbr = def.pbrMetallicRoughness ?? {};\n const cached = (bitmap: ImageBitmap, srgb: boolean, texInfo: any): Texture2D => {\n const s = samplerFor(texInfo);\n const tex = getCachedTex(bitmap, srgb);\n return s === defaultSampler ? tex : { ...tex, sampler: s };\n };\n\n const baseColorTexture = mat._baseColorImage\n ? cached(mat._baseColorImage, true, pbr.baseColorTexture)\n : (() => {\n const f = mat._baseColorFactor;\n return uploadTex(\n engine,\n null,\n true,\n defaultSampler,\n generateMipmaps,\n new U8([linearToSrgbByte(f[0]), linearToSrgbByte(f[1]), linearToSrgbByte(f[2]), Math.round(Math.max(0, Math.min(1, f[3])) * 255)])\n );\n })();\n const normalTexture = mat._normalImage ? cached(mat._normalImage, false, def.normalTexture) : undefined;\n const emissiveTexture = mat._emissiveImage ? cached(mat._emissiveImage, true, def.emissiveTexture) : undefined;\n\n const single = mat._metallicRoughnessImage ?? mat._occlusionImage;\n const ormTexInfo = mat._metallicRoughnessImage ? pbr.metallicRoughnessTexture : def.occlusionTexture;\n let ormTexture: Texture2D;\n if (single && (!mat._metallicRoughnessImage || !mat._occlusionImage || mat._metallicRoughnessImage === mat._occlusionImage)) {\n ormTexture = cached(single, false, ormTexInfo);\n } else if (!single) {\n const clamp = (v: number) => Math.round(Math.max(0, Math.min(1, v)) * 255);\n ormTexture = uploadTex(engine, null, false, defaultSampler, generateMipmaps, new U8([255, clamp(mat._roughnessFactor), clamp(mat._metallicFactor), 255]));\n } else {\n ormTexture = cached(mat._metallicRoughnessImage!, false, pbr.metallicRoughnessTexture);\n }\n return { baseColorTexture, ormTexture, normalTexture, emissiveTexture };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gltf-sampler-desc.js","sources":["../../../src/loader-gltf/gltf-sampler-desc.ts"],"sourcesContent":["import { getOrCreateSampler } from \"../resource/gpu-pool.js\";\nimport { U8 } from \"../engine/typed-arrays.js\";\nimport { linearToSrgbByte } from \"../math/color.js\";\nimport { uploadTex } from \"./gltf-pbr-builder.js\";\nimport type { GenerateMipmapsFn } from \"./gltf-pbr-builder.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Texture2D } from \"../texture/texture-2d.js\";\nimport type { GltfMaterialData } from \"./gltf-material.js\";\n\n/** Map a glTF textureInfo's sampler (wrapS/wrapT/magFilter/minFilter) to a WebGPU sampler\n * descriptor. glTF wrap: 33071 CLAMP_TO_EDGE, 33648 MIRRORED_REPEAT, else REPEAT.\n * glTF filter: 9728 NEAREST else LINEAR; min/mip from the combined min filter enum. */\nfunction gltfTexSamplerDesc(json: any, texInfo: any): GPUSamplerDescriptor {\n const s = json.textures?.[texInfo.index]?.sampler != null ? json.samplers?.[json.textures[texInfo.index].sampler] : undefined;\n const wrap = (m: number | undefined): GPUAddressMode => (m === 33071 ? \"clamp-to-edge\" : m === 33648 ? \"mirror-repeat\" : \"repeat\");\n const minF: number | undefined = s?.minFilter;\n const minNearest = minF === 9728 || minF === 9984 || minF === 9986;\n const mipNearest = minF === 9984 || minF === 9985;\n // glTF non-mipmap min filters (9728 NEAREST, 9729 LINEAR) mean \"sample mip 0 only\".\n // The shared uploaded GPU texture always carries a full mip chain, so clamp the LOD\n // to 0 for these filters (matching BJS `noMipmap`); otherwise a minified texture\n // (e.g. small SDF text in a top-down view) would sample blurred mips and render\n // softer/darker than BJS. Mipmapped filters (9984–9987) leave LOD unclamped.\n const noMip = minF === 9728 || minF === 9729;\n const magLinear = s?.magFilter !== 9728;\n return {\n magFilter: magLinear ? \"linear\" : \"nearest\",\n minFilter: minNearest ? \"nearest\" : \"linear\",\n mipmapFilter: mipNearest ? \"nearest\" : \"linear\",\n addressModeU: wrap(s?.wrapS),\n addressModeV: wrap(s?.wrapT),\n ...(noMip ? { lodMaxClamp: 0 } : undefined),\n // WebGPU forbids anisotropy unless mag/min/mip filters are ALL linear; gate on\n // every filter (incl. mipNearest, e.g. glTF LINEAR_MIPMAP_NEAREST) or createSampler throws.\n // Also disable it for the clamped-mip path (single LOD → anisotropy is meaningless).\n maxAnisotropy: magLinear && !minNearest && !mipNearest && !noMip ? 4 : 1,\n };\n}\n\n/** Build a per-texture sampler resolver honoring each texture's glTF sampler\n * (wrap/filter). Loaded lazily only when an asset declares a non-default sampler;\n * the common case (default repeat/linear) uses one shared sampler and never loads this.\n * `texInfo == null` (factor textures) falls back to `defaultSampler`.\n * @internal */\nexport function makeSamplerFor(engine: EngineContext, json: any, defaultSampler: GPUSampler): (texInfo: any) => GPUSampler {\n return (texInfo: any): GPUSampler => {\n if (texInfo == null) {\n return defaultSampler;\n }\n const desc = gltfTexSamplerDesc(json, texInfo);\n // A non-mipmap sampler (lodMaxClamp 0) is created directly: the shared cache key omits\n // the LOD clamp, so caching it there could alias a full-mip sampler with identical\n // filter/wrap. These are rare (SDF/UI textures), so per-call creation is cheaper than\n // growing the universal sampler key — which would move every non-glTF scene's bundle.\n return desc.lodMaxClamp === 0 ? engine._device.createSampler(desc) : getOrCreateSampler(engine, desc);\n };\n}\n\n/** Sampler-aware variant of buildDefaultPbrTextures. Mirrors the core fast path but wraps\n * each shared GPU texture with the sampler resolved from its glTF textureInfo (wrap/filter),\n * so clamp/mirror/nearest assets render correctly without re-uploading identical images.\n * Lazy-loaded only for non-default-sampler assets — the common path stays byte-identical.\n * @internal */\nexport function buildSampledPbrTextures(\n engine: EngineContext,\n mat: GltfMaterialData,\n defaultSampler: GPUSampler,\n generateMipmaps: GenerateMipmapsFn,\n samplerFor: (texInfo: any) => GPUSampler,\n getCachedTex: (bitmap: ImageBitmap, srgb: boolean) => Texture2D\n): { baseColorTexture: Texture2D; ormTexture: Texture2D; normalTexture: Texture2D | undefined; emissiveTexture: Texture2D | undefined } {\n const def = mat._rawMatDef ?? {};\n const pbr = def.pbrMetallicRoughness ?? {};\n const cached = (bitmap: ImageBitmap, srgb: boolean, texInfo: any): Texture2D => {\n const s = samplerFor(texInfo);\n const tex = getCachedTex(bitmap, srgb);\n return s === defaultSampler ? tex : { ...tex, sampler: s };\n };\n\n const baseColorTexture = mat._baseColorImage\n ? cached(mat._baseColorImage, true, pbr.baseColorTexture)\n : (() => {\n const f = mat._baseColorFactor;\n return uploadTex(\n engine,\n null,\n true,\n defaultSampler,\n generateMipmaps,\n new U8([linearToSrgbByte(f[0]), linearToSrgbByte(f[1]), linearToSrgbByte(f[2]), Math.round(Math.max(0, Math.min(1, f[3])) * 255)])\n );\n })();\n const normalTexture = mat._normalImage ? cached(mat._normalImage, false, def.normalTexture) : undefined;\n const emissiveTexture = mat._emissiveImage ? cached(mat._emissiveImage, true, def.emissiveTexture) : undefined;\n\n const single = mat._metallicRoughnessImage ?? mat._occlusionImage;\n const ormTexInfo = mat._metallicRoughnessImage ? pbr.metallicRoughnessTexture : def.occlusionTexture;\n let ormTexture: Texture2D;\n if (single && (!mat._metallicRoughnessImage || !mat._occlusionImage || mat._metallicRoughnessImage === mat._occlusionImage)) {\n ormTexture = cached(single, false, ormTexInfo);\n } else if (!single) {\n const clamp = (v: number) => Math.round(Math.max(0, Math.min(1, v)) * 255);\n ormTexture = uploadTex(engine, null, false, defaultSampler, generateMipmaps, new U8([255, clamp(mat._roughnessFactor), clamp(mat._metallicFactor), 255]));\n } else {\n ormTexture = cached(mat._metallicRoughnessImage!, false, pbr.metallicRoughnessTexture);\n }\n return { baseColorTexture, ormTexture, normalTexture, emissiveTexture };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { F32 } from '../engine/typed-arrays.js';
|
|
2
|
+
|
|
3
|
+
const FLOAT = 5126;
|
|
4
|
+
const UNSIGNED_SHORT = 5123;
|
|
5
|
+
const UNSIGNED_BYTE = 5121;
|
|
6
|
+
const COMP_BYTES = { [UNSIGNED_BYTE]: 1, [UNSIGNED_SHORT]: 2, [FLOAT]: 4 };
|
|
7
|
+
function resolveUvVec2(json, binChunk, idx) {
|
|
8
|
+
const accessor = json.accessors[idx];
|
|
9
|
+
const ct = accessor.componentType;
|
|
10
|
+
const cb = COMP_BYTES[ct] ?? 4;
|
|
11
|
+
const bv = json.bufferViews[accessor.bufferView];
|
|
12
|
+
const stride = bv.byteStride ?? 2 * cb;
|
|
13
|
+
const inv = ct === UNSIGNED_BYTE ? 1 / 255 : ct === UNSIGNED_SHORT ? 1 / 65535 : 1;
|
|
14
|
+
const base = (bv.byteOffset ?? 0) + (accessor.byteOffset ?? 0);
|
|
15
|
+
const out = new F32(accessor.count * 2);
|
|
16
|
+
for (let v = 0; v < accessor.count; v++) {
|
|
17
|
+
const row = base + v * stride;
|
|
18
|
+
for (let c = 0; c < 2; c++) {
|
|
19
|
+
const off = row + c * cb;
|
|
20
|
+
const raw = ct === FLOAT ? binChunk.getFloat32(off, true) : ct === UNSIGNED_SHORT ? binChunk.getUint16(off, true) : binChunk.getUint8(off);
|
|
21
|
+
out[v * 2 + c] = raw * inv;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { resolveUvVec2 };
|
|
28
|
+
//# sourceMappingURL=gltf-uv-denorm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gltf-uv-denorm.js","sources":["../../../src/loader-gltf/gltf-uv-denorm.ts"],"sourcesContent":["/** Denormalize / de-stride a non-Float32 interleaved TEXCOORD_0/_1 accessor to a tight float32 VEC2\n * [0,1] buffer. glTF UVs may be normalized UNSIGNED_BYTE/SHORT and interleaved with a byteStride;\n * bound raw they misalign every vertex (garbage UVs → wrong texturing). Dynamically imported only\n * when an interleaved primitive actually has a non-float UV, so float-UV interleaved meshes (the\n * common case) never bundle this code. Mirrors the tight path's normalizeUvToVec2. */\nimport { F32 } from \"../engine/typed-arrays.js\";\n\nconst FLOAT = 5126;\nconst UNSIGNED_SHORT = 5123;\nconst UNSIGNED_BYTE = 5121;\nconst COMP_BYTES: Record<number, number> = { [UNSIGNED_BYTE]: 1, [UNSIGNED_SHORT]: 2, [FLOAT]: 4 };\n\nexport function resolveUvVec2(json: any, binChunk: DataView, idx: number): Float32Array {\n const accessor = json.accessors[idx];\n const ct = accessor.componentType;\n const cb = COMP_BYTES[ct] ?? 4;\n const bv = json.bufferViews[accessor.bufferView];\n const stride = bv.byteStride ?? 2 * cb;\n const inv = ct === UNSIGNED_BYTE ? 1 / 255 : ct === UNSIGNED_SHORT ? 1 / 65535 : 1;\n const base = (bv.byteOffset ?? 0) + (accessor.byteOffset ?? 0);\n const out = new F32(accessor.count * 2);\n for (let v = 0; v < accessor.count; v++) {\n const row = base + v * stride;\n for (let c = 0; c < 2; c++) {\n const off = row + c * cb;\n const raw = ct === FLOAT ? binChunk.getFloat32(off, true) : ct === UNSIGNED_SHORT ? binChunk.getUint16(off, true) : binChunk.getUint8(off);\n out[v * 2 + c] = raw * inv;\n }\n }\n return out;\n}\n"],"names":[],"mappings":";;AAOA,MAAM,KAAA,GAAQ,IAAA;AACd,MAAM,cAAA,GAAiB,IAAA;AACvB,MAAM,aAAA,GAAgB,IAAA;AACtB,MAAM,UAAA,GAAqC,EAAE,CAAC,aAAa,GAAG,CAAA,EAAG,CAAC,cAAc,GAAG,CAAA,EAAG,CAAC,KAAK,GAAG,CAAA,EAAE;AAE1F,SAAS,aAAA,CAAc,IAAA,EAAW,QAAA,EAAoB,GAAA,EAA2B;AACpF,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,GAAG,CAAA;AACnC,EAAA,MAAM,KAAK,QAAA,CAAS,aAAA;AACpB,EAAA,MAAM,EAAA,GAAK,UAAA,CAAW,EAAE,CAAA,IAAK,CAAA;AAC7B,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,WAAA,CAAY,QAAA,CAAS,UAAU,CAAA;AAC/C,EAAA,MAAM,MAAA,GAAS,EAAA,CAAG,UAAA,IAAc,CAAA,GAAI,EAAA;AACpC,EAAA,MAAM,GAAA,GAAM,OAAO,aAAA,GAAgB,CAAA,GAAI,MAAM,EAAA,KAAO,cAAA,GAAiB,IAAI,KAAA,GAAQ,CAAA;AACjF,EAAA,MAAM,IAAA,GAAA,CAAQ,EAAA,CAAG,UAAA,IAAc,CAAA,KAAM,SAAS,UAAA,IAAc,CAAA,CAAA;AAC5D,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAC,CAAA;AACtC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,OAAO,CAAA,EAAA,EAAK;AACrC,IAAA,MAAM,GAAA,GAAM,OAAO,CAAA,GAAI,MAAA;AACvB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AACxB,MAAA,MAAM,GAAA,GAAM,MAAM,CAAA,GAAI,EAAA;AACtB,MAAA,MAAM,MAAM,EAAA,KAAO,KAAA,GAAQ,QAAA,CAAS,UAAA,CAAW,KAAK,IAAI,CAAA,GAAI,EAAA,KAAO,cAAA,GAAiB,SAAS,SAAA,CAAU,GAAA,EAAK,IAAI,CAAA,GAAI,QAAA,CAAS,SAAS,GAAG,CAAA;AACzI,MAAA,GAAA,CAAI,CAAA,GAAI,CAAA,GAAI,CAAC,CAAA,GAAI,GAAA,GAAM,GAAA;AAAA,IAC3B;AAAA,EACJ;AACA,EAAA,OAAO,GAAA;AACX;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DV, U32, U8, U16
|
|
1
|
+
import { DV, F32, U32, U8, U16 } from '../engine/typed-arrays.js';
|
|
2
2
|
import { BU } from '../engine/gpu-flags.js';
|
|
3
3
|
import { c as computeAabb } from '../_chunks/__vite-browser-external-BFTKbDcV.js';
|
|
4
4
|
import { createTransformNode } from '../scene/transform-node.js';
|
|
@@ -72,7 +72,7 @@ async function loadGltf(engine, source) {
|
|
|
72
72
|
}
|
|
73
73
|
async function fetchGltfAsset(source) {
|
|
74
74
|
const isUrl = typeof source === "string";
|
|
75
|
-
const baseUrl = isUrl ? source.
|
|
75
|
+
const baseUrl = !isUrl ? "" : typeof location !== "undefined" ? new URL(".", new URL(source, location.href)).href : source.slice(0, source.lastIndexOf("/") + 1);
|
|
76
76
|
const buffer = isUrl ? await fetch(source).then((r) => r.arrayBuffer()) : source instanceof Blob ? await source.arrayBuffer() : source;
|
|
77
77
|
if (buffer.byteLength >= 4 && new DV(buffer).getUint32(0, true) === 1179937895) {
|
|
78
78
|
const glb = await import('./gltf-glb-parser.js');
|
|
@@ -82,7 +82,14 @@ async function fetchGltfAsset(source) {
|
|
|
82
82
|
return jsonAsset.parseGltfJsonAsset(buffer, baseUrl);
|
|
83
83
|
}
|
|
84
84
|
function assetUsesGltfFeatures(json) {
|
|
85
|
-
return json.extensionsUsed?.length || json.animations?.length || JSON.stringify(json).includes("extras") || json.skins?.length && anyPrimitive(json, (p) => p.attributes?.JOINTS_0 !== void 0) || anyPrimitive(json, (p) => !!p.targets?.length) ||
|
|
85
|
+
return json.extensionsUsed?.length || json.animations?.length || JSON.stringify(json).includes("extras") || json.skins?.length && anyPrimitive(json, (p) => p.attributes?.JOINTS_0 !== void 0) || anyPrimitive(json, (p) => !!p.targets?.length) || // A node with a negative-determinant local transform (odd negative scale, or a `matrix`
|
|
86
|
+
// with negative 3x3 determinant) may need the negative-winding feature. This mirrors the
|
|
87
|
+
// registry's `hasNegDetNode` predicate so a positive-determinant `matrix` node — extremely
|
|
88
|
+
// common, e.g. TextureSettingsTest — does NOT needlessly pull the feature registry.
|
|
89
|
+
json.nodes?.some(
|
|
90
|
+
(n) => n.scale ? n.scale[0] * n.scale[1] * n.scale[2] < 0 : n.matrix ? n.matrix[0] * (n.matrix[5] * n.matrix[10] - n.matrix[6] * n.matrix[9]) + n.matrix[1] * (n.matrix[6] * n.matrix[8] - n.matrix[4] * n.matrix[10]) + n.matrix[2] * (n.matrix[4] * n.matrix[9] - n.matrix[5] * n.matrix[8]) < 0 : false
|
|
91
|
+
) || // Non-triangle primitive topology (POINTS/LINES/LINE_STRIP/TRIANGLE_STRIP).
|
|
92
|
+
anyPrimitive(json, (p) => p.mode !== void 0 && p.mode !== 4) || needsOrmComposite(json);
|
|
86
93
|
}
|
|
87
94
|
function buildNodeHierarchy(json, meshes, meshDatas) {
|
|
88
95
|
const nodeToMeshes = /* @__PURE__ */ new Map();
|
|
@@ -163,7 +170,7 @@ async function extractAllMeshes(json, binChunk, baseUrl, parentMap, worldMatrixC
|
|
|
163
170
|
const attrs = primitive.attributes;
|
|
164
171
|
const decoded = decodedPrimitives.get(primitive);
|
|
165
172
|
if (!decoded && _strided(primitive)) {
|
|
166
|
-
const ip = (await loadInterleave()).buildInterleavedPartial(json, binChunk, primitive, worldMatrix, nodeIdx);
|
|
173
|
+
const ip = await (await loadInterleave()).buildInterleavedPartial(json, binChunk, primitive, worldMatrix, nodeIdx);
|
|
167
174
|
if (ip) {
|
|
168
175
|
matPromises.push(getMat(primitive.material));
|
|
169
176
|
partials.push(ip);
|
|
@@ -188,6 +195,8 @@ async function extractAllMeshes(json, binChunk, baseUrl, parentMap, worldMatrixC
|
|
|
188
195
|
const idxData = decoded ? decoded._indexCount > 0 ? { _data: decoded._indices, _count: decoded._indexCount} : null : primitive.indices !== void 0 ? resolveAccessor(json, binChunk, primitive.indices) : null;
|
|
189
196
|
const normalsHelper = !idxData || !normData ? await import('./gltf-normals.js') : null;
|
|
190
197
|
const colors = colorData ? (await importColorNormalize()).normalizeColorToVec4(colorData._data, colorData._count, colorData._componentCount) : null;
|
|
198
|
+
const uvs = uvData ? uvData._data instanceof F32 ? uvData._data : (await importColorNormalize()).normalizeUvToVec2(uvData._data, uvData._count) : new F32(posData._count * 2);
|
|
199
|
+
const uv2s = uv2Data ? uv2Data._data instanceof F32 ? uv2Data._data : (await importColorNormalize()).normalizeUvToVec2(uv2Data._data, uv2Data._count) : null;
|
|
191
200
|
const indices = idxData ? idxData._data instanceof U32 ? new U32(idxData._data) : idxData._data instanceof U8 ? Uint16Array.from(idxData._data) : new U16(idxData._data.buffer, idxData._data.byteOffset, idxData._count) : normalsHelper.createSequentialIndices(posData._count);
|
|
192
201
|
matPromises.push(getMat(primitive.material));
|
|
193
202
|
const normals = normData ? normData._data : normalsHelper.computeSmoothNormals(posData._data, indices, posData._count);
|
|
@@ -195,8 +204,8 @@ async function extractAllMeshes(json, binChunk, baseUrl, parentMap, worldMatrixC
|
|
|
195
204
|
_positions: posData._data,
|
|
196
205
|
_normals: normals,
|
|
197
206
|
_tangents: tanData ? tanData._data : null,
|
|
198
|
-
_uvs:
|
|
199
|
-
_uv2s:
|
|
207
|
+
_uvs: uvs,
|
|
208
|
+
_uv2s: uv2s,
|
|
200
209
|
_colors: colors,
|
|
201
210
|
_flatNormal: !normData,
|
|
202
211
|
_indices: indices,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-gltf.js","sources":["../../../src/loader-gltf/load-gltf.ts"],"sourcesContent":["import { F32, U32, U16, U8, DV } from \"../engine/typed-arrays.js\";\nimport { BU } from \"../engine/gpu-flags.js\";\nimport type { Mat4 } from \"../math/types.js\";\nimport { computeAabb } from \"../math/compute-aabb.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { TransformNode } from \"../scene/transform-node.js\";\nimport type { AssetContainer } from \"../asset-container.js\";\nimport { createTransformNode } from \"../scene/transform-node.js\";\nimport { createSceneNodeFromMatrix } from \"../scene/scene-node.js\";\nimport type { Texture2D } from \"../texture/texture-2d.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport type { Mesh, MeshGPU } from \"../mesh/mesh.js\";\nimport { initMeshTransform } from \"../mesh/mesh.js\";\nimport { getOrCreateSampler } from \"../resource/gpu-pool.js\";\nimport { createMappedBuffer } from \"../resource/gpu-buffers.js\";\nimport { resolveAccessor, buildParentMap, computeNodeWorldMatrix, anyPrimitive, needsOrmComposite, TYPE_SIZES } from \"./gltf-parser.js\";\nimport type { AccessorView } from \"./gltf-parser.js\";\nimport type { GltfVb } from \"./gltf-interleave.js\";\nimport type { GltfMaterialData, GltfMatExtCtx } from \"./gltf-material.js\";\nimport { assembleMaterial, makeImageFetcher } from \"./gltf-material.js\";\nimport type { DecodedPrimitive, GltfFeature, GltfLoadCtx } from \"./gltf-feature.js\";\nimport type { TextureWrapFn } from \"./gltf-pbr-builder.js\";\nimport { assemblePbrProps, buildDefaultPbrTextures, identityTexWrap, runMatExts, uploadTex } from \"./gltf-pbr-builder.js\";\nimport type * as GltfColorNormalize from \"./gltf-color-normalize.js\";\nimport type * as GltfFeatureRegistry from \"./gltf-feature-registry.js\";\nimport type * as GltfPbrBuilderExt from \"./gltf-pbr-builder-ext.js\";\n\n/** Dynamically-imported interleave module — loaded only when an asset actually\n * contains a strided bufferView, so non-interleaved scenes pay zero cost. */\ntype InterleaveModule = typeof import(\"./gltf-interleave.js\");\nlet _interleavePromise: Promise<InterleaveModule> | undefined;\nfunction loadInterleave(): Promise<InterleaveModule> {\n return (_interleavePromise ??= import(\"./gltf-interleave.js\"));\n}\n\nlet _gltfFeatureRegistryPromise: Promise<typeof GltfFeatureRegistry> | undefined;\nfunction importGltfFeatureRegistry(): Promise<typeof GltfFeatureRegistry> {\n return (_gltfFeatureRegistryPromise ??= import(\"./gltf-feature-registry.js\"));\n}\n\nlet _colorNormalizePromise: Promise<typeof GltfColorNormalize> | undefined;\nfunction importColorNormalize(): Promise<typeof GltfColorNormalize> {\n return (_colorNormalizePromise ??= import(\"./gltf-color-normalize.js\"));\n}\n\n/** Parsed mesh data ready for GPU upload. */\nexport interface GltfMeshData {\n /** @internal Tight CPU positions, or null when sourced from an interleaved\n * bufferView (in which case `_vb._p` holds the strided source for lazy de-striding). */\n _positions: Float32Array | null;\n /** @internal */\n _normals: Float32Array | null;\n /** @internal */\n _tangents: Float32Array | null;\n /** @internal */\n _uvs: Float32Array | null;\n /** @internal */\n _uv2s: Float32Array | null;\n /** @internal */\n _colors: Float32Array | null;\n /** @internal Primitive had no NORMAL attribute → flat-shade (glTF spec). */\n _flatNormal?: boolean;\n /** @internal */\n _indices: Uint16Array | Uint32Array;\n /** @internal */\n _vertexCount: number;\n /** @internal */\n _indexCount: number;\n /** @internal */\n _worldMatrix: Mat4;\n /** @internal */\n _material: GltfMaterialData;\n /** @internal Interleaved vertex sources (genuine GPU interleaving + lazy CPU de-stride).\n * Absent → all tight. */\n _vb?: GltfVb;\n /** @internal glTF node index this mesh came from (for hierarchy reconstruction\n * and for features that need to resolve skin/morph data lazily). */\n _nodeIndex: number;\n /** @internal Raw primitive definition — features (skeleton, morph, …) read their\n * own attributes/targets from here without bloating core extraction. */\n _primitive: any;\n /** @internal Pre-decoded primitive (Draco et al.) if a preMesh feature produced one. */\n _decoded?: DecodedPrimitive;\n}\n\n/**\n * Load a glTF/GLB asset, parse it, and upload mesh + material data to GPU.\n * Supports both binary GLB and separate .gltf + .bin + image files.\n * Registers a deferred PBR renderable builder.\n * Automatically parses glTF animations if present.\n *\n * Returns a AssetContainer. Pass it to addToScene() which adds the hierarchy,\n * registers animation ticks, and applies any scene-level settings.\n *\n * @param engine - The engine to upload GPU resources to.\n * @param url - URL of the .glb/.gltf asset to fetch.\n */\nexport function loadGltf(engine: EngineContext, url: string): Promise<AssetContainer>;\n/**\n * Load a glTF/GLB asset directly from already-loaded local data (drag-and-drop, OPFS, a `fetch` body, etc.).\n *\n * GLB-vs-glTF is determined from the data's magic bytes, not a file extension. `ArrayBuffer`/`Blob` inputs\n * have no base URL, so they must be self-contained: a GLB, or a glTF whose buffers/images use `data:` URIs.\n * A glTF that references external `.bin`/image files by relative path can only be loaded from a URL.\n *\n * @param engine - The engine to upload GPU resources to.\n * @param data - The raw `ArrayBuffer` or `Blob` of a self-contained glTF/GLB asset.\n */\nexport function loadGltf(engine: EngineContext, data: ArrayBuffer | Blob): Promise<AssetContainer>;\nexport async function loadGltf(engine: EngineContext, source: string | ArrayBuffer | Blob): Promise<AssetContainer> {\n const { json, binChunk, baseUrl } = await fetchGltfAsset(source);\n\n // Build parent map + world-matrix cache once for O(n) hierarchy traversal\n const parentMap = buildParentMap(json);\n const worldMatrixCache = new Map<number, Mat4>();\n\n // Discover every triggered feature (material exts, skeleton, morph,\n // animations, variants, …). The feature registry + its ~24 dynamic-import\n // thunks live in a separate module that is itself dynamic-imported only when\n // the asset can possibly trigger a feature — so plain metallic-roughness\n // GLBs (no extensions/animations/skins/morphs/ORM-composite) never fetch the\n // registry. Core loader knows zero feature names.\n const features = assetUsesGltfFeatures(json) ? await (await importGltfFeatureRegistry()).loadGltfFeatures(json) : [];\n\n // Pre-parse hooks (EXT_meshopt_compression decompression, KHR_mesh_quantization\n // dequantization) may rewrite bufferViews/accessors and hand back a replacement\n // binary chunk. Run sequentially in registry order so later features see earlier\n // rewrites. No-op (and zero cost) when no triggered feature defines preParse.\n let activeBin = binChunk;\n for (const f of features) {\n if (f.preParse) {\n const replacement = await f.preParse(json, activeBin);\n if (replacement) {\n activeBin = replacement;\n }\n }\n }\n\n const matExts: GltfFeature[] = features.filter((f) => f.applyMaterial);\n // Compose every feature's wrapTexture hook into a single function. Identity\n // when no feature contributes one (common case) — keeps the hot path free\n // of per-texture work and lets bundlers tree-shake the helpers.\n const texWraps = features.filter((f) => f.wrapTexture).map((f) => f.wrapTexture!);\n const wrapTex: TextureWrapFn = !texWraps.length ? identityTexWrap : (tex, ti) => texWraps.reduce((acc, w) => w(acc, ti), tex);\n\n // Run every feature's pre-mesh hook (e.g. Draco decompression) and merge\n // their primitive-keyed decode caches. Features without `preMesh` contribute\n // nothing; the map stays empty when no primitive-level feature triggered.\n const decodedPrimitives = new Map<unknown, DecodedPrimitive>();\n for (const frag of await Promise.all(features.flatMap((f) => (f.preMesh ? [f.preMesh(json, activeBin, baseUrl)] : [])))) {\n for (const [k, v] of frag) {\n decodedPrimitives.set(k, v);\n }\n }\n\n const meshDatas = await extractAllMeshes(json, activeBin, baseUrl, parentMap, worldMatrixCache, decodedPrimitives);\n\n const ctx: GltfLoadCtx = {\n _engine: engine,\n _json: json,\n _binChunk: activeBin,\n _baseUrl: baseUrl,\n _parentMap: parentMap,\n _worldMatrixCache: worldMatrixCache,\n _matExts: matExts,\n _wrapTex: wrapTex,\n };\n\n const meshes = await uploadMeshes(meshDatas, features, ctx);\n\n // Build TransformNode hierarchy from glTF nodes. Returns both the synthetic root\n // and a glTF-node-index → SceneNode map (used by node-visibility + animation-pointer).\n const { root, nodeMap } = buildNodeHierarchy(json, meshes, meshDatas);\n ctx._nodeMap = nodeMap;\n\n // Run every feature's per-asset hook (animations, variants, metadata, …) and\n // merge the returned AssetContainer fragments. `entities` is appended (never\n // overwritten) so features like KHR_lights_punctual can contribute lights\n // without trampling the root TransformNode.\n const assetFragments = await Promise.all(features.flatMap((f) => (f.applyAsset ? [f.applyAsset(meshes, root, ctx)] : [])));\n const container: AssetContainer = { entities: [root] };\n for (const frag of assetFragments) {\n if (frag.entities?.length) {\n container.entities.push(...frag.entities);\n }\n const { entities: _ignored, ...rest } = frag;\n void _ignored;\n Object.assign(container, rest);\n }\n return container;\n}\n\n/** Fetch/resolve + parse a glTF or GLB asset from a URL string, ArrayBuffer, or Blob.\n * Returns the JSON, binary chunk, and base URL (empty for non-URL sources). */\nasync function fetchGltfAsset(source: string | ArrayBuffer | Blob): Promise<{ json: any; binChunk: DataView; baseUrl: string }> {\n // Resolve the source to bytes. Only a URL string yields a base URL for resolving external .bin/image\n // references; ArrayBuffer/Blob inputs are self-contained (GLB, or glTF with data: URIs).\n const isUrl = typeof source === \"string\";\n const baseUrl = isUrl ? source.substring(0, source.lastIndexOf(\"/\") + 1) : \"\";\n const buffer = isUrl ? await fetch(source).then((r) => r.arrayBuffer()) : source instanceof Blob ? await source.arrayBuffer() : source;\n\n // Classify by the GLB magic (\"glTF\" = 0x46546c67, little-endian) rather than the URL extension, so\n // object URLs (blob:…), OPFS handles, and extensionless sources are detected correctly. The length guard\n // keeps an empty/too-short input failing with the JSON/GLB parse error below, not a DataView RangeError.\n if (buffer.byteLength >= 4 && new DV(buffer).getUint32(0, true) === 0x46546c67) {\n const glb = await import(\"./gltf-glb-parser.js\");\n return { ...glb.parseGlbContainer(buffer), baseUrl };\n }\n\n const jsonAsset = await import(\"./gltf-json-asset.js\");\n return jsonAsset.parseGltfJsonAsset(buffer, baseUrl);\n}\n\n/** Cheap superset gate: returns true iff the asset can possibly trigger at least\n * one optional glTF feature. Every `_features` predicate in gltf-feature-registry\n * is implied by one of these buckets (all hasExt/hasMatExt features require a\n * non-empty `extensionsUsed`), so when this returns false the registry's\n * `loadGltfFeatures` would return `[]` anyway — letting the core loader skip the\n * registry import entirely and keep its ~24 feature import-thunks out of the\n * bundle for plain metallic-roughness assets. */\nfunction assetUsesGltfFeatures(json: any) {\n return (\n json.extensionsUsed?.length ||\n json.animations?.length ||\n JSON.stringify(json).includes(\"extras\") ||\n (json.skins?.length && anyPrimitive(json, (p) => p.attributes?.JOINTS_0 !== undefined)) ||\n anyPrimitive(json, (p) => !!p.targets?.length) ||\n needsOrmComposite(json)\n );\n}\n\n// --- Hierarchy Reconstruction ---\n\n/** Build a TransformNode tree mirroring the glTF node hierarchy.\n * Meshes are attached as children. Non-mesh nodes become\n * pure TransformNodes preserving TRS for cloning/repositioning.\n * Parent links are set by addToScene() when the tree is added to the scene.\n * Also returns a glTF-node-index → SceneNode map used by per-asset features\n * (KHR_node_visibility, KHR_animation_pointer) to address specific nodes. */\nfunction buildNodeHierarchy(json: any, meshes: Mesh[], meshDatas: GltfMeshData[]): { root: TransformNode; nodeMap: (TransformNode | undefined)[] } {\n // Map nodeIndex → uploaded Mesh[]\n const nodeToMeshes = new Map<number, Mesh[]>();\n for (let i = 0; i < meshDatas.length; i++) {\n const ni = meshDatas[i]!._nodeIndex;\n let arr = nodeToMeshes.get(ni);\n if (!arr) {\n arr = [];\n nodeToMeshes.set(ni, arr);\n }\n arr.push(meshes[i]!);\n }\n\n const nodeMap: (TransformNode | undefined)[] = new Array(json.nodes?.length ?? 0);\n\n // Recursive builder\n function buildNode(nodeIdx: number): TransformNode {\n const node = json.nodes[nodeIdx];\n const name = node.name ?? `node_${nodeIdx}`;\n let tn: TransformNode;\n if (node.matrix) {\n tn = createSceneNodeFromMatrix(name, node.matrix as Mat4);\n } else {\n const t = node.translation ?? [0, 0, 0];\n const r = node.rotation ?? [0, 0, 0, 1];\n const s = node.scale ?? [1, 1, 1];\n tn = createTransformNode(name, t[0], t[1], t[2], r[0], r[1], r[2], r[3], s[0], s[1], s[2]);\n }\n nodeMap[nodeIdx] = tn;\n if (node.children) {\n for (const childIdx of node.children) {\n tn.children.push(buildNode(childIdx));\n }\n }\n const nodeMeshes = nodeToMeshes.get(nodeIdx) ?? [];\n tn.children.push(...nodeMeshes);\n return tn;\n }\n\n // Synthetic root (like BJS __root__) — applies RH→LH conversion via scale\n // BJS: rotation [0,1,0,0] + scale [1,1,-1] = diag(-1, 1, 1, 1)\n const sceneRoots: number[] = json.scenes?.[json.scene ?? 0]?.nodes ?? [];\n const rootChildren = sceneRoots.map((ni: number) => buildNode(ni));\n const root = createTransformNode(\"__root__\", 0, 0, 0, 0, 0, 0, 1, -1, 1, 1);\n root.children.push(...rootChildren);\n return { root, nodeMap };\n}\n\n// --- Mesh Extraction ---\n\nasync function extractAllMeshes(\n json: any,\n binChunk: DataView,\n baseUrl: string,\n parentMap: Map<number, number>,\n worldMatrixCache: Map<number, Mat4>,\n decodedPrimitives: Map<unknown, DecodedPrimitive>\n): Promise<GltfMeshData[]> {\n // Per-load image cache — avoids decoding the same glTF image index multiple times\n const imageCache = new Map<number, Promise<ImageBitmap>>();\n\n // Cache material assembly by glTF material index — avoids duplicate image fetches\n const matCache = new Map<number, Promise<GltfMaterialData>>();\n const getMat = (matIdx: number): Promise<GltfMaterialData> => {\n const key = matIdx ?? -1;\n let p = matCache.get(key);\n if (!p) {\n p = assembleMaterial(json, binChunk, matIdx, baseUrl, imageCache);\n matCache.set(key, p);\n }\n return p;\n };\n\n // First pass: do all sync work, fire all material fetches concurrently\n const partials: Array<Omit<GltfMeshData, \"_material\">> = [];\n const matPromises: Promise<GltfMaterialData>[] = [];\n\n // Genuine GPU interleaving is the ONLY reason to touch the interleave module.\n // Many exporters declare `byteStride` even on tightly-packed bufferViews, and a\n // preMesh feature (e.g. the basisu extension's readStridedFloat path) may already\n // de-stride a primitive — so we load the module only for a primitive that is\n // genuinely over-strided AND not already decoded. Other scenes pay zero cost: the\n // module is fetched lazily on the first such primitive (memoized), never before.\n const _accs = json.accessors as any[];\n const _bvs = json.bufferViews as any[] | undefined;\n const _strided = (p: any): boolean => {\n for (const k in p.attributes) {\n const a = _accs[p.attributes[k]];\n const s = _bvs?.[a?.bufferView]?.byteStride;\n if (\n s !== undefined &&\n s !== (TYPE_SIZES[a.type] ?? 1) * (a.componentType === 5126 || a.componentType === 5125 ? 4 : a.componentType === 5123 || a.componentType === 5122 ? 2 : 1)\n ) {\n return true;\n }\n }\n return false;\n };\n\n for (let nodeIdx = 0; nodeIdx < json.nodes.length; nodeIdx++) {\n const node = json.nodes[nodeIdx];\n if (node.mesh === undefined) {\n continue;\n }\n\n const meshIndex = node.mesh as number;\n const mesh = json.meshes[meshIndex];\n const worldMatrix = computeNodeWorldMatrix(json, nodeIdx, parentMap, worldMatrixCache);\n\n for (let primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {\n const primitive = mesh.primitives[primitiveIndex];\n const attrs = primitive.attributes;\n const decoded = decodedPrimitives.get(primitive);\n\n // Genuine GPU interleaving: only a primitive that genuinely sources ≥1\n // attribute from an over-strided bufferView (and was not already decoded\n // by a preMesh feature) takes this path. The module is imported lazily on\n // first need — non-interleaved assets never fetch it. Tight primitives\n // fall through to the path below (byte-identical to non-interleaved).\n if (!decoded && _strided(primitive)) {\n const ip = (await loadInterleave()).buildInterleavedPartial(json, binChunk, primitive, worldMatrix, nodeIdx);\n if (ip) {\n matPromises.push(getMat(primitive.material));\n partials.push(ip);\n continue;\n }\n }\n\n const resolveAttr = (name: string): AccessorView | null => {\n if (decoded && decoded._attributes.has(name)) {\n const data = decoded._attributes.get(name)!;\n const componentCount = data.length / decoded._vertexCount;\n return { _data: data, _count: decoded._vertexCount, _componentCount: componentCount };\n }\n const idx = attrs[name];\n return idx !== undefined ? resolveAccessor(json, binChunk, idx) : null;\n };\n const posData = resolveAttr(\"POSITION\")!;\n const normData = resolveAttr(\"NORMAL\");\n const uvData = resolveAttr(\"TEXCOORD_0\");\n const uv2Data = resolveAttr(\"TEXCOORD_1\");\n const tanData = resolveAttr(\"TANGENT\");\n const colorData = resolveAttr(\"COLOR_0\");\n const idxData = decoded\n ? decoded._indexCount > 0\n ? { _data: decoded._indices, _count: decoded._indexCount, _componentCount: 1 }\n : null\n : primitive.indices !== undefined\n ? resolveAccessor(json, binChunk, primitive.indices)\n : null;\n const normalsHelper = !idxData || !normData ? await import(\"./gltf-normals.js\") : null;\n // glTF COLOR_0 may be VEC3 or VEC4 with float, normalized ubyte, or normalized\n // ushort components, but the PBR pipeline binds vertex color as a single\n // float32x4 layout (rgb modulates base color, a modulates alpha). Normalize any\n // source to a tight float32 RGBA buffer so the GPU stride matches the layout\n // (otherwise every vertex misaligns -> garbage/black); a VEC3 source gets a=1.\n // The normalizer is imported lazily on first need — colorless assets never fetch it\n // (the runtime caches the module, so the per-primitive import() resolves instantly).\n const colors = colorData ? (await importColorNormalize()).normalizeColorToVec4(colorData._data, colorData._count, colorData._componentCount) : null;\n\n // Keep vertex data as-is from glTF — RH→LH conversion handled by root world matrix\n const indices = idxData\n ? idxData._data instanceof U32\n ? new U32(idxData._data as Uint32Array)\n : idxData._data instanceof U8\n ? Uint16Array.from(idxData._data as Uint8Array)\n : new U16(idxData._data!.buffer, idxData._data!.byteOffset, idxData._count)\n : normalsHelper!.createSequentialIndices(posData._count);\n\n // Fire material fetch without awaiting — all materials load in parallel\n matPromises.push(getMat(primitive.material));\n\n // Smooth-normal generation is lazily imported on first need — assets that\n // always provide NORMAL (the common case) never bundle or fetch this code.\n const normals = normData ? (normData._data as Float32Array) : normalsHelper!.computeSmoothNormals(posData._data as Float32Array, indices, posData._count);\n\n partials.push({\n _positions: posData._data as Float32Array,\n _normals: normals,\n _tangents: tanData ? (tanData._data as Float32Array) : null,\n _uvs: uvData ? (uvData._data as Float32Array) : new F32(posData._count * 2),\n _uv2s: uv2Data ? (uv2Data._data as Float32Array) : null,\n _colors: colors,\n _flatNormal: !normData,\n _indices: indices,\n _vertexCount: posData._count,\n _indexCount: indices.length,\n _worldMatrix: worldMatrix,\n _nodeIndex: nodeIdx,\n _primitive: primitive,\n _decoded: decoded,\n });\n }\n }\n\n // Resolve all material fetches in parallel\n const materials = await Promise.all(matPromises);\n return partials.map((p, i) => ({ ...p, _material: materials[i]! }));\n}\n\n// --- GPU Upload ---\n\n// Pre-resolved generateMipmaps function— loaded once before texture uploads\nlet _generateMipmaps: ((engine: EngineContext, texture: GPUTexture, face?: number) => void) | null = null;\n\nasync function ensureMipmapModule(): Promise<void> {\n if (!_generateMipmaps) {\n _generateMipmaps = (await import(\"../texture/generate-mipmaps.js\")).generateMipmaps;\n }\n}\n\nasync function uploadMeshes(meshDatas: GltfMeshData[], features: GltfFeature[], ctx: GltfLoadCtx): Promise<Mesh[]> {\n const { _engine: engine, _json: json, _binChunk: binChunk, _baseUrl: baseUrl, _matExts: matExts, _wrapTex: wrapTex } = ctx;\n // Default sampler (repeat/linear) used for factor textures and when a texture has no glTF sampler.\n const sampler = getOrCreateSampler(engine, {\n magFilter: \"linear\",\n minFilter: \"linear\",\n mipmapFilter: \"linear\",\n addressModeU: \"repeat\",\n addressModeV: \"repeat\",\n maxAnisotropy: 4,\n });\n // Per-texture glTF samplers (wrap/filter) are honored only when the asset declares a\n // NON-default sampler (clamp/mirror wrap, or nearest filtering); the common case\n // (default repeat/linear) uses the single shared sampler above and the master-identical\n // buildDefaultPbrTextures path. Both the descriptor logic AND the sampler-aware texture\n // builder are lazy so default-sampler assets pay zero bundle bytes for the feature.\n let samplerFor: ((texInfo: any) => GPUSampler) | undefined;\n let buildSampledPbrTextures: typeof import(\"./gltf-sampler-desc.js\").buildSampledPbrTextures | undefined;\n if (json.samplers?.some((s: any) => s.wrapS > 10497 || s.wrapT > 10497 || s.magFilter === 9728 || (s.minFilter != null && s.minFilter !== 9729 && s.minFilter !== 9987))) {\n const mod = await import(\"./gltf-sampler-desc.js\");\n samplerFor = mod.makeSamplerFor(engine, json, sampler);\n buildSampledPbrTextures = mod.buildSampledPbrTextures;\n }\n\n await ensureMipmapModule();\n const meshFeatures = features.filter((f) => f.applyMesh);\n\n // Texture cache: shared textures uploaded once, keyed by (bitmap, srgb).\n const texCache = new Map<number, Texture2D>();\n let texId = 0;\n const bitmapIds = new Map<ImageBitmap, number>();\n\n function getCachedTexture(bitmap: ImageBitmap, srgb: boolean): Texture2D {\n let id = bitmapIds.get(bitmap);\n if (id === undefined) {\n bitmapIds.set(bitmap, (id = texId++));\n }\n const key = id * 2 + +srgb;\n let tex = texCache.get(key);\n if (!tex) {\n tex = uploadTex(engine, bitmap, srgb, sampler, _generateMipmaps!);\n texCache.set(key, tex);\n }\n return tex;\n }\n\n // Per-load image fetcher for ext modules (uses same image cache as core).\n const extImageCache = matExts.length ? new Map<number, Promise<ImageBitmap>>() : null;\n const extFetchImg = extImageCache ? makeImageFetcher(json, binChunk, baseUrl, extImageCache) : null;\n const extCtx: GltfMatExtCtx = {\n _engine: engine,\n async _texture(texInfo, sRGB) {\n if (!texInfo || !extFetchImg) {\n return undefined;\n }\n const img = await extFetchImg(texInfo);\n return img ? wrapTex(getCachedTexture(img, sRGB), texInfo) : undefined;\n },\n _uploadImage(bitmap, sRGB) {\n return uploadTex(engine, bitmap, sRGB, sampler, _generateMipmaps!);\n },\n };\n\n // Slow-path trigger: per-texture UV wrapping (KHR_texture_transform)\n // or any core texture declaring texCoord=1. Scene1 stays identity→fast path.\n let _needsPbrExt = wrapTex !== identityTexWrap;\n if (!_needsPbrExt) {\n const mats = (json as { materials?: unknown[] }).materials;\n if (mats && JSON.stringify(mats).includes('\"texCoord\":1')) {\n _needsPbrExt = true;\n }\n }\n let _pbrExtPromise: Promise<typeof GltfPbrBuilderExt> | null = null;\n const _ensurePbrExt = () => (_pbrExtPromise ??= import(\"./gltf-pbr-builder-ext.js\"));\n\n /** Default ORM upload: single MR-or-occlusion image, or 1×1 fallback baked from\n * metallicFactor/roughnessFactor. The composite case (MR+occlusion separate) is\n * handled by the gltf-ext-orm extension which overrides this via `extLayers`. */\n\n // Build a PbrMaterialProps from parsed glTF material data.\n // Uses shared texture caches so identical bitmaps are uploaded once.\n const builtMaterialCache = new Map<GltfMaterialData, Promise<PbrMaterialProps>>();\n async function buildPbrFromGltfMat(mat: GltfMaterialData): Promise<PbrMaterialProps> {\n let cached = builtMaterialCache.get(mat);\n if (cached) {\n return cached;\n }\n cached = (async () => {\n const extLayers = await runMatExts(mat, matExts, extCtx);\n if (_needsPbrExt) {\n const extMod = await _ensurePbrExt();\n const tex = extMod.buildDefaultPbrTexturesExt(engine, mat, sampler, _generateMipmaps!, getCachedTexture, wrapTex, samplerFor);\n return extMod.assemblePbrPropsExt(mat, tex, extLayers);\n }\n const tex = buildSampledPbrTextures\n ? buildSampledPbrTextures(engine, mat, sampler, _generateMipmaps!, samplerFor!, getCachedTexture)\n : buildDefaultPbrTextures(engine, mat, sampler, _generateMipmaps!, getCachedTexture);\n return assemblePbrProps(mat, tex.baseColorTexture, tex.ormTexture, tex.normalTexture, tex.emissiveTexture, extLayers);\n })();\n builtMaterialCache.set(mat, cached);\n return cached;\n }\n\n const meshes = await Promise.all(\n meshDatas.map(async (m, i): Promise<Mesh> => {\n const material = await buildPbrFromGltfMat(m._material);\n const meshName = json.meshes[json.nodes[m._nodeIndex].mesh].name;\n\n // Interleaved meshes are fully built by the dynamic module (kept out of\n // this bundle for non-interleaved scenes). The tight path below is\n // byte-identical to the non-interleaved engine.\n let mesh: Mesh;\n if (m._vb) {\n mesh = (await loadInterleave()).buildInterleavedMesh(engine, m, i, material, meshName) as Mesh;\n } else {\n const [boundMin, boundMax] = computeAabb(m._positions!, m._worldMatrix);\n const gpu: MeshGPU = {\n positionBuffer: createMappedBuffer(engine, m._positions!, BU.VERTEX),\n normalBuffer: createMappedBuffer(engine, m._normals!, BU.VERTEX),\n tangentBuffer: m._tangents ? createMappedBuffer(engine, m._tangents, BU.VERTEX) : null,\n uvBuffer: createMappedBuffer(engine, m._uvs!, BU.VERTEX),\n uv2Buffer: m._uv2s ? createMappedBuffer(engine, m._uv2s, BU.VERTEX) : null,\n colorBuffer: m._colors ? createMappedBuffer(engine, m._colors, BU.VERTEX) : null,\n indexBuffer: createMappedBuffer(engine, m._indices, BU.INDEX),\n indexCount: m._indexCount,\n indexFormat: (m._indices instanceof U32 ? \"uint32\" : \"uint16\") as GPUIndexFormat,\n };\n\n mesh = {\n name: meshName || `gltf_mesh_${i}`,\n material,\n receiveShadows: false,\n boundMin,\n boundMax,\n skeleton: null,\n morphTargets: null,\n _gpu: gpu,\n _flatNormal: m._flatNormal,\n } as unknown as Mesh;\n initMeshTransform(mesh);\n\n // Retain CPU geometry for detailed picking.\n mesh._cpuPositions = m._positions!;\n mesh._cpuNormals = m._normals!;\n mesh._cpuUvs = m._uvs!;\n mesh._cpuIndices = m._indices instanceof U32 ? m._indices : new U32(m._indices);\n engine._dlr?.m(mesh, m._uv2s, m._tangents, m._colors, m._indices, gpu.indexFormat);\n }\n\n // Run all per-mesh feature hooks (skeleton, morph, …) in parallel.\n // Each hook mutates `mesh` directly (e.g. attaches mesh.skeleton).\n if (meshFeatures.length > 0) {\n await Promise.all(meshFeatures.map((f) => f.applyMesh!(m, mesh, ctx)));\n }\n\n return mesh;\n })\n );\n\n return meshes;\n}\n"],"names":["tex"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"load-gltf.js","sources":["../../../src/loader-gltf/load-gltf.ts"],"sourcesContent":["import { F32, U32, U16, U8, DV } from \"../engine/typed-arrays.js\";\nimport { BU } from \"../engine/gpu-flags.js\";\nimport type { Mat4 } from \"../math/types.js\";\nimport { computeAabb } from \"../math/compute-aabb.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { TransformNode } from \"../scene/transform-node.js\";\nimport type { AssetContainer } from \"../asset-container.js\";\nimport { createTransformNode } from \"../scene/transform-node.js\";\nimport { createSceneNodeFromMatrix } from \"../scene/scene-node.js\";\nimport type { Texture2D } from \"../texture/texture-2d.js\";\nimport type { PbrMaterialProps } from \"../material/pbr/pbr-material.js\";\nimport type { Mesh, MeshGPU } from \"../mesh/mesh.js\";\nimport { initMeshTransform } from \"../mesh/mesh.js\";\nimport { getOrCreateSampler } from \"../resource/gpu-pool.js\";\nimport { createMappedBuffer } from \"../resource/gpu-buffers.js\";\nimport { resolveAccessor, buildParentMap, computeNodeWorldMatrix, anyPrimitive, needsOrmComposite, TYPE_SIZES } from \"./gltf-parser.js\";\nimport type { AccessorView } from \"./gltf-parser.js\";\nimport type { GltfVb } from \"./gltf-interleave.js\";\nimport type { GltfMaterialData, GltfMatExtCtx } from \"./gltf-material.js\";\nimport { assembleMaterial, makeImageFetcher } from \"./gltf-material.js\";\nimport type { DecodedPrimitive, GltfFeature, GltfLoadCtx } from \"./gltf-feature.js\";\nimport type { TextureWrapFn } from \"./gltf-pbr-builder.js\";\nimport { assemblePbrProps, buildDefaultPbrTextures, identityTexWrap, runMatExts, uploadTex } from \"./gltf-pbr-builder.js\";\nimport type * as GltfColorNormalize from \"./gltf-color-normalize.js\";\nimport type * as GltfFeatureRegistry from \"./gltf-feature-registry.js\";\nimport type * as GltfPbrBuilderExt from \"./gltf-pbr-builder-ext.js\";\n\n/** Dynamically-imported interleave module — loaded only when an asset actually\n * contains a strided bufferView, so non-interleaved scenes pay zero cost. */\ntype InterleaveModule = typeof import(\"./gltf-interleave.js\");\nlet _interleavePromise: Promise<InterleaveModule> | undefined;\nfunction loadInterleave(): Promise<InterleaveModule> {\n return (_interleavePromise ??= import(\"./gltf-interleave.js\"));\n}\n\nlet _gltfFeatureRegistryPromise: Promise<typeof GltfFeatureRegistry> | undefined;\nfunction importGltfFeatureRegistry(): Promise<typeof GltfFeatureRegistry> {\n return (_gltfFeatureRegistryPromise ??= import(\"./gltf-feature-registry.js\"));\n}\n\nlet _colorNormalizePromise: Promise<typeof GltfColorNormalize> | undefined;\nfunction importColorNormalize(): Promise<typeof GltfColorNormalize> {\n return (_colorNormalizePromise ??= import(\"./gltf-color-normalize.js\"));\n}\n\n/** Parsed mesh data ready for GPU upload. */\nexport interface GltfMeshData {\n /** @internal Tight CPU positions, or null when sourced from an interleaved\n * bufferView (in which case `_vb._p` holds the strided source for lazy de-striding). */\n _positions: Float32Array | null;\n /** @internal */\n _normals: Float32Array | null;\n /** @internal */\n _tangents: Float32Array | null;\n /** @internal */\n _uvs: Float32Array | null;\n /** @internal */\n _uv2s: Float32Array | null;\n /** @internal */\n _colors: Float32Array | null;\n /** @internal Primitive had no NORMAL attribute → flat-shade (glTF spec). */\n _flatNormal?: boolean;\n /** @internal Non-triangle-list primitive topology index (1=points, 2=lines,\n * 3=line-strip, 4=triangle-strip) from the glTF primitive `mode`. Undefined =\n * triangle-list (the default). LINE_LOOP/TRIANGLE_FAN are unsupported (so is BJS). */\n _topology?: number;\n /** @internal */\n _indices: Uint16Array | Uint32Array;\n /** @internal */\n _vertexCount: number;\n /** @internal */\n _indexCount: number;\n /** @internal */\n _worldMatrix: Mat4;\n /** @internal */\n _material: GltfMaterialData;\n /** @internal Interleaved vertex sources (genuine GPU interleaving + lazy CPU de-stride).\n * Absent → all tight. */\n _vb?: GltfVb;\n /** @internal glTF node index this mesh came from (for hierarchy reconstruction\n * and for features that need to resolve skin/morph data lazily). */\n _nodeIndex: number;\n /** @internal Raw primitive definition — features (skeleton, morph, …) read their\n * own attributes/targets from here without bloating core extraction. */\n _primitive: any;\n /** @internal Pre-decoded primitive (Draco et al.) if a preMesh feature produced one. */\n _decoded?: DecodedPrimitive;\n}\n\n/**\n * Load a glTF/GLB asset, parse it, and upload mesh + material data to GPU.\n * Supports both binary GLB and separate .gltf + .bin + image files.\n * Registers a deferred PBR renderable builder.\n * Automatically parses glTF animations if present.\n *\n * Returns a AssetContainer. Pass it to addToScene() which adds the hierarchy,\n * registers animation ticks, and applies any scene-level settings.\n *\n * @param engine - The engine to upload GPU resources to.\n * @param url - URL of the .glb/.gltf asset to fetch.\n */\nexport function loadGltf(engine: EngineContext, url: string): Promise<AssetContainer>;\n/**\n * Load a glTF/GLB asset directly from already-loaded local data (drag-and-drop, OPFS, a `fetch` body, etc.).\n *\n * GLB-vs-glTF is determined from the data's magic bytes, not a file extension. `ArrayBuffer`/`Blob` inputs\n * have no base URL, so they must be self-contained: a GLB, or a glTF whose buffers/images use `data:` URIs.\n * A glTF that references external `.bin`/image files by relative path can only be loaded from a URL.\n *\n * @param engine - The engine to upload GPU resources to.\n * @param data - The raw `ArrayBuffer` or `Blob` of a self-contained glTF/GLB asset.\n */\nexport function loadGltf(engine: EngineContext, data: ArrayBuffer | Blob): Promise<AssetContainer>;\nexport async function loadGltf(engine: EngineContext, source: string | ArrayBuffer | Blob): Promise<AssetContainer> {\n const { json, binChunk, baseUrl } = await fetchGltfAsset(source);\n\n // Build parent map + world-matrix cache once for O(n) hierarchy traversal\n const parentMap = buildParentMap(json);\n const worldMatrixCache = new Map<number, Mat4>();\n\n // Discover every triggered feature (material exts, skeleton, morph,\n // animations, variants, …). The feature registry + its ~24 dynamic-import\n // thunks live in a separate module that is itself dynamic-imported only when\n // the asset can possibly trigger a feature — so plain metallic-roughness\n // GLBs (no extensions/animations/skins/morphs/ORM-composite) never fetch the\n // registry. Core loader knows zero feature names.\n const features = assetUsesGltfFeatures(json) ? await (await importGltfFeatureRegistry()).loadGltfFeatures(json) : [];\n\n // Pre-parse hooks (EXT_meshopt_compression decompression, KHR_mesh_quantization\n // dequantization) may rewrite bufferViews/accessors and hand back a replacement\n // binary chunk. Run sequentially in registry order so later features see earlier\n // rewrites. No-op (and zero cost) when no triggered feature defines preParse.\n let activeBin = binChunk;\n for (const f of features) {\n if (f.preParse) {\n const replacement = await f.preParse(json, activeBin);\n if (replacement) {\n activeBin = replacement;\n }\n }\n }\n\n const matExts: GltfFeature[] = features.filter((f) => f.applyMaterial);\n // Compose every feature's wrapTexture hook into a single function. Identity\n // when no feature contributes one (common case) — keeps the hot path free\n // of per-texture work and lets bundlers tree-shake the helpers.\n const texWraps = features.filter((f) => f.wrapTexture).map((f) => f.wrapTexture!);\n const wrapTex: TextureWrapFn = !texWraps.length ? identityTexWrap : (tex, ti) => texWraps.reduce((acc, w) => w(acc, ti), tex);\n\n // Run every feature's pre-mesh hook (e.g. Draco decompression) and merge\n // their primitive-keyed decode caches. Features without `preMesh` contribute\n // nothing; the map stays empty when no primitive-level feature triggered.\n const decodedPrimitives = new Map<unknown, DecodedPrimitive>();\n for (const frag of await Promise.all(features.flatMap((f) => (f.preMesh ? [f.preMesh(json, activeBin, baseUrl)] : [])))) {\n for (const [k, v] of frag) {\n decodedPrimitives.set(k, v);\n }\n }\n\n const meshDatas = await extractAllMeshes(json, activeBin, baseUrl, parentMap, worldMatrixCache, decodedPrimitives);\n\n const ctx: GltfLoadCtx = {\n _engine: engine,\n _json: json,\n _binChunk: activeBin,\n _baseUrl: baseUrl,\n _parentMap: parentMap,\n _worldMatrixCache: worldMatrixCache,\n _matExts: matExts,\n _wrapTex: wrapTex,\n };\n\n const meshes = await uploadMeshes(meshDatas, features, ctx);\n\n // Build TransformNode hierarchy from glTF nodes. Returns both the synthetic root\n // and a glTF-node-index → SceneNode map (used by node-visibility + animation-pointer).\n const { root, nodeMap } = buildNodeHierarchy(json, meshes, meshDatas);\n ctx._nodeMap = nodeMap;\n\n // Run every feature's per-asset hook (animations, variants, metadata, …) and\n // merge the returned AssetContainer fragments. `entities` is appended (never\n // overwritten) so features like KHR_lights_punctual can contribute lights\n // without trampling the root TransformNode.\n const assetFragments = await Promise.all(features.flatMap((f) => (f.applyAsset ? [f.applyAsset(meshes, root, ctx)] : [])));\n const container: AssetContainer = { entities: [root] };\n for (const frag of assetFragments) {\n if (frag.entities?.length) {\n container.entities.push(...frag.entities);\n }\n const { entities: _ignored, ...rest } = frag;\n void _ignored;\n Object.assign(container, rest);\n }\n return container;\n}\n\n/** Fetch/resolve + parse a glTF or GLB asset from a URL string, ArrayBuffer, or Blob.\n * Returns the JSON, binary chunk, and base URL (empty for non-URL sources). */\nasync function fetchGltfAsset(source: string | ArrayBuffer | Blob): Promise<{ json: any; binChunk: DataView; baseUrl: string }> {\n // Resolve the source to bytes. Only a URL string yields a base URL for resolving external .bin/image\n // references; ArrayBuffer/Blob inputs are self-contained (GLB, or glTF with data: URIs).\n const isUrl = typeof source === \"string\";\n // Resolve the source to an absolute URL so external .bin / image URIs resolve correctly even when the\n // caller passes a root-relative (\"/models/foo.gltf\") or document-relative path — `new URL(uri, base)`\n // downstream requires an absolute base. Absolute inputs (https://…) are returned unchanged. In a\n // non-DOM context (Node / a worker without `location`) fall back to a plain directory-prefix base.\n const baseUrl = !isUrl ? \"\" : typeof location !== \"undefined\" ? new URL(\".\", new URL(source, location.href)).href : source.slice(0, source.lastIndexOf(\"/\") + 1);\n const buffer = isUrl ? await fetch(source).then((r) => r.arrayBuffer()) : source instanceof Blob ? await source.arrayBuffer() : source;\n\n // Classify by the GLB magic (\"glTF\" = 0x46546c67, little-endian) rather than the URL extension, so\n // object URLs (blob:…), OPFS handles, and extensionless sources are detected correctly. The length guard\n // keeps an empty/too-short input failing with the JSON/GLB parse error below, not a DataView RangeError.\n if (buffer.byteLength >= 4 && new DV(buffer).getUint32(0, true) === 0x46546c67) {\n const glb = await import(\"./gltf-glb-parser.js\");\n return { ...glb.parseGlbContainer(buffer), baseUrl };\n }\n\n const jsonAsset = await import(\"./gltf-json-asset.js\");\n return jsonAsset.parseGltfJsonAsset(buffer, baseUrl);\n}\n\n/** Cheap superset gate: returns true iff the asset can possibly trigger at least\n * one optional glTF feature. Every `_features` predicate in gltf-feature-registry\n * is implied by one of these buckets (all hasExt/hasMatExt features require a\n * non-empty `extensionsUsed`), so when this returns false the registry's\n * `loadGltfFeatures` would return `[]` anyway — letting the core loader skip the\n * registry import entirely and keep its ~24 feature import-thunks out of the\n * bundle for plain metallic-roughness assets. */\nfunction assetUsesGltfFeatures(json: any) {\n return (\n json.extensionsUsed?.length ||\n json.animations?.length ||\n JSON.stringify(json).includes(\"extras\") ||\n (json.skins?.length && anyPrimitive(json, (p) => p.attributes?.JOINTS_0 !== undefined)) ||\n anyPrimitive(json, (p) => !!p.targets?.length) ||\n // A node with a negative-determinant local transform (odd negative scale, or a `matrix`\n // with negative 3x3 determinant) may need the negative-winding feature. This mirrors the\n // registry's `hasNegDetNode` predicate so a positive-determinant `matrix` node — extremely\n // common, e.g. TextureSettingsTest — does NOT needlessly pull the feature registry.\n (json.nodes as any[] | undefined)?.some((n: any) =>\n n.scale\n ? n.scale[0] * n.scale[1] * n.scale[2] < 0\n : n.matrix\n ? n.matrix[0] * (n.matrix[5] * n.matrix[10] - n.matrix[6] * n.matrix[9]) +\n n.matrix[1] * (n.matrix[6] * n.matrix[8] - n.matrix[4] * n.matrix[10]) +\n n.matrix[2] * (n.matrix[4] * n.matrix[9] - n.matrix[5] * n.matrix[8]) <\n 0\n : false\n ) ||\n // Non-triangle primitive topology (POINTS/LINES/LINE_STRIP/TRIANGLE_STRIP).\n anyPrimitive(json, (p) => p.mode !== undefined && p.mode !== 4) ||\n needsOrmComposite(json)\n );\n}\n\n// --- Hierarchy Reconstruction ---\n\n/** Build a TransformNode tree mirroring the glTF node hierarchy.\n * Meshes are attached as children. Non-mesh nodes become\n * pure TransformNodes preserving TRS for cloning/repositioning.\n * Parent links are set by addToScene() when the tree is added to the scene.\n * Also returns a glTF-node-index → SceneNode map used by per-asset features\n * (KHR_node_visibility, KHR_animation_pointer) to address specific nodes. */\nfunction buildNodeHierarchy(json: any, meshes: Mesh[], meshDatas: GltfMeshData[]): { root: TransformNode; nodeMap: (TransformNode | undefined)[] } {\n // Map nodeIndex → uploaded Mesh[]\n const nodeToMeshes = new Map<number, Mesh[]>();\n for (let i = 0; i < meshDatas.length; i++) {\n const ni = meshDatas[i]!._nodeIndex;\n let arr = nodeToMeshes.get(ni);\n if (!arr) {\n arr = [];\n nodeToMeshes.set(ni, arr);\n }\n arr.push(meshes[i]!);\n }\n\n const nodeMap: (TransformNode | undefined)[] = new Array(json.nodes?.length ?? 0);\n\n // Recursive builder\n function buildNode(nodeIdx: number): TransformNode {\n const node = json.nodes[nodeIdx];\n const name = node.name ?? `node_${nodeIdx}`;\n let tn: TransformNode;\n if (node.matrix) {\n tn = createSceneNodeFromMatrix(name, node.matrix as Mat4);\n } else {\n const t = node.translation ?? [0, 0, 0];\n const r = node.rotation ?? [0, 0, 0, 1];\n const s = node.scale ?? [1, 1, 1];\n tn = createTransformNode(name, t[0], t[1], t[2], r[0], r[1], r[2], r[3], s[0], s[1], s[2]);\n }\n nodeMap[nodeIdx] = tn;\n if (node.children) {\n for (const childIdx of node.children) {\n tn.children.push(buildNode(childIdx));\n }\n }\n const nodeMeshes = nodeToMeshes.get(nodeIdx) ?? [];\n tn.children.push(...nodeMeshes);\n return tn;\n }\n\n // Synthetic root (like BJS __root__) — applies RH→LH conversion via scale\n // BJS: rotation [0,1,0,0] + scale [1,1,-1] = diag(-1, 1, 1, 1)\n const sceneRoots: number[] = json.scenes?.[json.scene ?? 0]?.nodes ?? [];\n const rootChildren = sceneRoots.map((ni: number) => buildNode(ni));\n const root = createTransformNode(\"__root__\", 0, 0, 0, 0, 0, 0, 1, -1, 1, 1);\n root.children.push(...rootChildren);\n return { root, nodeMap };\n}\n\n// --- Mesh Extraction ---\n\nasync function extractAllMeshes(\n json: any,\n binChunk: DataView,\n baseUrl: string,\n parentMap: Map<number, number>,\n worldMatrixCache: Map<number, Mat4>,\n decodedPrimitives: Map<unknown, DecodedPrimitive>\n): Promise<GltfMeshData[]> {\n // Per-load image cache — avoids decoding the same glTF image index multiple times\n const imageCache = new Map<number, Promise<ImageBitmap>>();\n\n // Cache material assembly by glTF material index — avoids duplicate image fetches\n const matCache = new Map<number, Promise<GltfMaterialData>>();\n const getMat = (matIdx: number): Promise<GltfMaterialData> => {\n const key = matIdx ?? -1;\n let p = matCache.get(key);\n if (!p) {\n p = assembleMaterial(json, binChunk, matIdx, baseUrl, imageCache);\n matCache.set(key, p);\n }\n return p;\n };\n\n // First pass: do all sync work, fire all material fetches concurrently\n const partials: Array<Omit<GltfMeshData, \"_material\">> = [];\n const matPromises: Promise<GltfMaterialData>[] = [];\n\n // Genuine GPU interleaving is the ONLY reason to touch the interleave module.\n // Many exporters declare `byteStride` even on tightly-packed bufferViews, and a\n // preMesh feature (e.g. the basisu extension's readStridedFloat path) may already\n // de-stride a primitive — so we load the module only for a primitive that is\n // genuinely over-strided AND not already decoded. Other scenes pay zero cost: the\n // module is fetched lazily on the first such primitive (memoized), never before.\n const _accs = json.accessors as any[];\n const _bvs = json.bufferViews as any[] | undefined;\n const _strided = (p: any): boolean => {\n for (const k in p.attributes) {\n const a = _accs[p.attributes[k]];\n const s = _bvs?.[a?.bufferView]?.byteStride;\n if (\n s !== undefined &&\n s !== (TYPE_SIZES[a.type] ?? 1) * (a.componentType === 5126 || a.componentType === 5125 ? 4 : a.componentType === 5123 || a.componentType === 5122 ? 2 : 1)\n ) {\n return true;\n }\n }\n return false;\n };\n\n for (let nodeIdx = 0; nodeIdx < json.nodes.length; nodeIdx++) {\n const node = json.nodes[nodeIdx];\n if (node.mesh === undefined) {\n continue;\n }\n\n const meshIndex = node.mesh as number;\n const mesh = json.meshes[meshIndex];\n const worldMatrix = computeNodeWorldMatrix(json, nodeIdx, parentMap, worldMatrixCache);\n\n for (let primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {\n const primitive = mesh.primitives[primitiveIndex];\n const attrs = primitive.attributes;\n const decoded = decodedPrimitives.get(primitive);\n\n // Genuine GPU interleaving: only a primitive that genuinely sources ≥1\n // attribute from an over-strided bufferView (and was not already decoded\n // by a preMesh feature) takes this path. The module is imported lazily on\n // first need — non-interleaved assets never fetch it. Tight primitives\n // fall through to the path below (byte-identical to non-interleaved).\n if (!decoded && _strided(primitive)) {\n const ip = await (await loadInterleave()).buildInterleavedPartial(json, binChunk, primitive, worldMatrix, nodeIdx);\n if (ip) {\n matPromises.push(getMat(primitive.material));\n partials.push(ip);\n continue;\n }\n }\n\n const resolveAttr = (name: string): AccessorView | null => {\n if (decoded && decoded._attributes.has(name)) {\n const data = decoded._attributes.get(name)!;\n const componentCount = data.length / decoded._vertexCount;\n return { _data: data, _count: decoded._vertexCount, _componentCount: componentCount };\n }\n const idx = attrs[name];\n return idx !== undefined ? resolveAccessor(json, binChunk, idx) : null;\n };\n const posData = resolveAttr(\"POSITION\")!;\n const normData = resolveAttr(\"NORMAL\");\n const uvData = resolveAttr(\"TEXCOORD_0\");\n const uv2Data = resolveAttr(\"TEXCOORD_1\");\n const tanData = resolveAttr(\"TANGENT\");\n const colorData = resolveAttr(\"COLOR_0\");\n const idxData = decoded\n ? decoded._indexCount > 0\n ? { _data: decoded._indices, _count: decoded._indexCount, _componentCount: 1 }\n : null\n : primitive.indices !== undefined\n ? resolveAccessor(json, binChunk, primitive.indices)\n : null;\n const normalsHelper = !idxData || !normData ? await import(\"./gltf-normals.js\") : null;\n // glTF COLOR_0 may be VEC3 or VEC4 with float, normalized ubyte, or normalized\n // ushort components, but the PBR pipeline binds vertex color as a single\n // float32x4 layout (rgb modulates base color, a modulates alpha). Normalize any\n // source to a tight float32 RGBA buffer so the GPU stride matches the layout\n // (otherwise every vertex misaligns -> garbage/black); a VEC3 source gets a=1.\n // The normalizer is imported lazily on first need — colorless assets never fetch it\n // (the runtime caches the module, so the per-primitive import() resolves instantly).\n const colors = colorData ? (await importColorNormalize()).normalizeColorToVec4(colorData._data, colorData._count, colorData._componentCount) : null;\n\n // TEXCOORD_0/_1 may be FLOAT or a normalized UNSIGNED_BYTE/SHORT accessor; the vertex\n // pipeline binds UVs as float32x2, so integer UVs are denormalized to [0,1] (reusing the\n // lazily-imported color/UV normalizer). Float UVs (the common case) pass through untouched.\n const uvs = uvData\n ? uvData._data instanceof F32\n ? (uvData._data as Float32Array)\n : (await importColorNormalize()).normalizeUvToVec2(uvData._data, uvData._count)\n : new F32(posData._count * 2);\n const uv2s = uv2Data\n ? uv2Data._data instanceof F32\n ? (uv2Data._data as Float32Array)\n : (await importColorNormalize()).normalizeUvToVec2(uv2Data._data, uv2Data._count)\n : null;\n\n // Keep vertex data as-is from glTF — RH→LH conversion handled by root world matrix\n const indices = idxData\n ? idxData._data instanceof U32\n ? new U32(idxData._data as Uint32Array)\n : idxData._data instanceof U8\n ? Uint16Array.from(idxData._data as Uint8Array)\n : new U16(idxData._data!.buffer, idxData._data!.byteOffset, idxData._count)\n : normalsHelper!.createSequentialIndices(posData._count);\n\n // Fire material fetch without awaiting — all materials load in parallel\n matPromises.push(getMat(primitive.material));\n\n // Smooth-normal generation is lazily imported on first need — assets that\n // always provide NORMAL (the common case) never bundle or fetch this code.\n const normals = normData ? (normData._data as Float32Array) : normalsHelper!.computeSmoothNormals(posData._data as Float32Array, indices, posData._count);\n\n partials.push({\n _positions: posData._data as Float32Array,\n _normals: normals,\n _tangents: tanData ? (tanData._data as Float32Array) : null,\n _uvs: uvs,\n _uv2s: uv2s,\n _colors: colors,\n _flatNormal: !normData,\n _indices: indices,\n _vertexCount: posData._count,\n _indexCount: indices.length,\n _worldMatrix: worldMatrix,\n _nodeIndex: nodeIdx,\n _primitive: primitive,\n _decoded: decoded,\n });\n }\n }\n\n // Resolve all material fetches in parallel\n const materials = await Promise.all(matPromises);\n return partials.map((p, i) => ({ ...p, _material: materials[i]! }));\n}\n\n// --- GPU Upload ---\n\n// Pre-resolved generateMipmaps function— loaded once before texture uploads\nlet _generateMipmaps: ((engine: EngineContext, texture: GPUTexture, face?: number) => void) | null = null;\n\nasync function ensureMipmapModule(): Promise<void> {\n if (!_generateMipmaps) {\n _generateMipmaps = (await import(\"../texture/generate-mipmaps.js\")).generateMipmaps;\n }\n}\n\nasync function uploadMeshes(meshDatas: GltfMeshData[], features: GltfFeature[], ctx: GltfLoadCtx): Promise<Mesh[]> {\n const { _engine: engine, _json: json, _binChunk: binChunk, _baseUrl: baseUrl, _matExts: matExts, _wrapTex: wrapTex } = ctx;\n // Default sampler (repeat/linear) used for factor textures and when a texture has no glTF sampler.\n const sampler = getOrCreateSampler(engine, {\n magFilter: \"linear\",\n minFilter: \"linear\",\n mipmapFilter: \"linear\",\n addressModeU: \"repeat\",\n addressModeV: \"repeat\",\n maxAnisotropy: 4,\n });\n // Per-texture glTF samplers (wrap/filter) are honored only when the asset declares a\n // NON-default sampler (clamp/mirror wrap, or nearest filtering); the common case\n // (default repeat/linear) uses the single shared sampler above and the master-identical\n // buildDefaultPbrTextures path. Both the descriptor logic AND the sampler-aware texture\n // builder are lazy so default-sampler assets pay zero bundle bytes for the feature.\n let samplerFor: ((texInfo: any) => GPUSampler) | undefined;\n let buildSampledPbrTextures: typeof import(\"./gltf-sampler-desc.js\").buildSampledPbrTextures | undefined;\n if (json.samplers?.some((s: any) => s.wrapS > 10497 || s.wrapT > 10497 || s.magFilter === 9728 || (s.minFilter != null && s.minFilter !== 9729 && s.minFilter !== 9987))) {\n const mod = await import(\"./gltf-sampler-desc.js\");\n samplerFor = mod.makeSamplerFor(engine, json, sampler);\n buildSampledPbrTextures = mod.buildSampledPbrTextures;\n }\n\n await ensureMipmapModule();\n const meshFeatures = features.filter((f) => f.applyMesh);\n\n // Texture cache: shared textures uploaded once, keyed by (bitmap, srgb).\n const texCache = new Map<number, Texture2D>();\n let texId = 0;\n const bitmapIds = new Map<ImageBitmap, number>();\n\n function getCachedTexture(bitmap: ImageBitmap, srgb: boolean): Texture2D {\n let id = bitmapIds.get(bitmap);\n if (id === undefined) {\n bitmapIds.set(bitmap, (id = texId++));\n }\n const key = id * 2 + +srgb;\n let tex = texCache.get(key);\n if (!tex) {\n tex = uploadTex(engine, bitmap, srgb, sampler, _generateMipmaps!);\n texCache.set(key, tex);\n }\n return tex;\n }\n\n // Per-load image fetcher for ext modules (uses same image cache as core).\n const extImageCache = matExts.length ? new Map<number, Promise<ImageBitmap>>() : null;\n const extFetchImg = extImageCache ? makeImageFetcher(json, binChunk, baseUrl, extImageCache) : null;\n const extCtx: GltfMatExtCtx = {\n _engine: engine,\n async _texture(texInfo, sRGB) {\n if (!texInfo || !extFetchImg) {\n return undefined;\n }\n const img = await extFetchImg(texInfo);\n return img ? wrapTex(getCachedTexture(img, sRGB), texInfo) : undefined;\n },\n _uploadImage(bitmap, sRGB) {\n return uploadTex(engine, bitmap, sRGB, sampler, _generateMipmaps!);\n },\n };\n\n // Slow-path trigger: per-texture UV wrapping (KHR_texture_transform)\n // or any core texture declaring texCoord=1. Scene1 stays identity→fast path.\n let _needsPbrExt = wrapTex !== identityTexWrap;\n if (!_needsPbrExt) {\n const mats = (json as { materials?: unknown[] }).materials;\n if (mats && JSON.stringify(mats).includes('\"texCoord\":1')) {\n _needsPbrExt = true;\n }\n }\n let _pbrExtPromise: Promise<typeof GltfPbrBuilderExt> | null = null;\n const _ensurePbrExt = () => (_pbrExtPromise ??= import(\"./gltf-pbr-builder-ext.js\"));\n\n /** Default ORM upload: single MR-or-occlusion image, or 1×1 fallback baked from\n * metallicFactor/roughnessFactor. The composite case (MR+occlusion separate) is\n * handled by the gltf-ext-orm extension which overrides this via `extLayers`. */\n\n // Build a PbrMaterialProps from parsed glTF material data.\n // Uses shared texture caches so identical bitmaps are uploaded once.\n const builtMaterialCache = new Map<GltfMaterialData, Promise<PbrMaterialProps>>();\n async function buildPbrFromGltfMat(mat: GltfMaterialData): Promise<PbrMaterialProps> {\n let cached = builtMaterialCache.get(mat);\n if (cached) {\n return cached;\n }\n cached = (async () => {\n const extLayers = await runMatExts(mat, matExts, extCtx);\n if (_needsPbrExt) {\n const extMod = await _ensurePbrExt();\n const tex = extMod.buildDefaultPbrTexturesExt(engine, mat, sampler, _generateMipmaps!, getCachedTexture, wrapTex, samplerFor);\n return extMod.assemblePbrPropsExt(mat, tex, extLayers);\n }\n const tex = buildSampledPbrTextures\n ? buildSampledPbrTextures(engine, mat, sampler, _generateMipmaps!, samplerFor!, getCachedTexture)\n : buildDefaultPbrTextures(engine, mat, sampler, _generateMipmaps!, getCachedTexture);\n return assemblePbrProps(mat, tex.baseColorTexture, tex.ormTexture, tex.normalTexture, tex.emissiveTexture, extLayers);\n })();\n builtMaterialCache.set(mat, cached);\n return cached;\n }\n\n const meshes = await Promise.all(\n meshDatas.map(async (m, i): Promise<Mesh> => {\n const material = await buildPbrFromGltfMat(m._material);\n const meshName = json.meshes[json.nodes[m._nodeIndex].mesh].name;\n\n // Interleaved meshes are fully built by the dynamic module (kept out of\n // this bundle for non-interleaved scenes). The tight path below is\n // byte-identical to the non-interleaved engine.\n let mesh: Mesh;\n if (m._vb) {\n mesh = (await loadInterleave()).buildInterleavedMesh(engine, m, i, material, meshName) as Mesh;\n } else {\n const [boundMin, boundMax] = computeAabb(m._positions!, m._worldMatrix);\n const gpu: MeshGPU = {\n positionBuffer: createMappedBuffer(engine, m._positions!, BU.VERTEX),\n normalBuffer: createMappedBuffer(engine, m._normals!, BU.VERTEX),\n tangentBuffer: m._tangents ? createMappedBuffer(engine, m._tangents, BU.VERTEX) : null,\n uvBuffer: createMappedBuffer(engine, m._uvs!, BU.VERTEX),\n uv2Buffer: m._uv2s ? createMappedBuffer(engine, m._uv2s, BU.VERTEX) : null,\n colorBuffer: m._colors ? createMappedBuffer(engine, m._colors, BU.VERTEX) : null,\n indexBuffer: createMappedBuffer(engine, m._indices, BU.INDEX),\n indexCount: m._indexCount,\n indexFormat: (m._indices instanceof U32 ? \"uint32\" : \"uint16\") as GPUIndexFormat,\n };\n\n mesh = {\n name: meshName || `gltf_mesh_${i}`,\n material,\n receiveShadows: false,\n boundMin,\n boundMax,\n skeleton: null,\n morphTargets: null,\n _gpu: gpu,\n _flatNormal: m._flatNormal,\n } as unknown as Mesh;\n initMeshTransform(mesh);\n\n // Retain CPU geometry for detailed picking.\n mesh._cpuPositions = m._positions!;\n mesh._cpuNormals = m._normals!;\n mesh._cpuUvs = m._uvs!;\n mesh._cpuIndices = m._indices instanceof U32 ? m._indices : new U32(m._indices);\n engine._dlr?.m(mesh, m._uv2s, m._tangents, m._colors, m._indices, gpu.indexFormat);\n }\n\n // Run all per-mesh feature hooks (skeleton, morph, …) in parallel.\n // Each hook mutates `mesh` directly (e.g. attaches mesh.skeleton).\n if (meshFeatures.length > 0) {\n await Promise.all(meshFeatures.map((f) => f.applyMesh!(m, mesh, ctx)));\n }\n\n return mesh;\n })\n );\n\n return meshes;\n}\n"],"names":["tex"],"mappings":"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"}
|
|
@@ -7,11 +7,15 @@ function rebuildMaterial(scene, materialOrView, options) {
|
|
|
7
7
|
for (const mesh of scene.meshes) {
|
|
8
8
|
if (matchesMaterial(mesh.material, source, materialOrView, rebuildViews)) {
|
|
9
9
|
rebuildSceneMesh(scene, mesh);
|
|
10
|
+
if (mesh.material) {
|
|
11
|
+
mesh.material._csmGen = (mesh.material._csmGen ?? 0) + 1;
|
|
12
|
+
}
|
|
10
13
|
changed = true;
|
|
11
14
|
}
|
|
12
15
|
}
|
|
13
16
|
if (changed) {
|
|
14
17
|
scene._renderableVersion++;
|
|
18
|
+
scene._materialEpoch++;
|
|
15
19
|
}
|
|
16
20
|
if (options?.rebuildFrameGraph) {
|
|
17
21
|
scene._frameGraph.build();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"material-rebuild.js","sources":["../../../src/material/material-rebuild.ts"],"sourcesContent":["import type { SceneContext } from \"../scene/scene.js\";\nimport type { Mesh } from \"../mesh/mesh.js\";\nimport type { Material } from \"./material.js\";\nimport { getMaterialSource, isMaterialView } from \"./material-view.js\";\n\nexport interface RebuildMaterialOptions {\n /** Rebuild views created from the same source material. Defaults to true. */\n rebuildViews?: boolean;\n /** Rebuild the frame graph after material renderables are refreshed. Defaults to false so callers can batch updates. */\n rebuildFrameGraph?: boolean;\n}\n\n/** Rebuild renderables whose pipeline/bind-group feature state depends on a material.\n * Use after texture, sampler, bind-group layout, culling, or feature changes.\n * UBO-only scalar/vector changes should use markMaterialUboDirty instead. */\nexport function rebuildMaterial(scene: SceneContext, materialOrView: Material, options?: RebuildMaterialOptions): void {\n const source = getMaterialSource(materialOrView);\n const rebuildViews = options?.rebuildViews !== false;\n let changed = false;\n\n for (const mesh of scene.meshes) {\n if (matchesMaterial(mesh.material, source, materialOrView, rebuildViews)) {\n rebuildSceneMesh(scene, mesh);\n changed = true;\n }\n }\n\n if (changed) {\n scene._renderableVersion++;\n }\n if (options?.rebuildFrameGraph) {\n scene._frameGraph.build();\n }\n}\n\nfunction matchesMaterial(meshMaterial: Material | null, source: Material, materialOrView: Material, rebuildViews: boolean): boolean {\n if (!meshMaterial) {\n return false;\n }\n if (!rebuildViews) {\n return meshMaterial === materialOrView;\n }\n return meshMaterial === source || (isMaterialView(meshMaterial) && meshMaterial.source === source);\n}\n\nfunction rebuildSceneMesh(ctx: SceneContext, mesh: Mesh): void {\n const material = mesh.material;\n if (!material) {\n return;\n }\n const rebuild = material._buildGroup._rebuildSingle;\n if (!rebuild) {\n return;\n }\n const old = ctx._meshDisposables.get(mesh);\n if (old) {\n for (const fn of old) {\n fn();\n }\n ctx._meshDisposables.delete(mesh);\n }\n for (let i = ctx._renderables.length - 1; i >= 0; i--) {\n if (ctx._renderables[i]!.mesh === mesh) {\n ctx._renderables.splice(i, 1);\n }\n }\n const renderable = rebuild(ctx, mesh);\n let i = ctx._renderables.length;\n while (i > 0 && ctx._renderables[i - 1]!.order > renderable.order) {\n i--;\n }\n ctx._renderables.splice(i, 0, renderable);\n}\n"],"names":["i"],"mappings":";;AAeO,SAAS,eAAA,CAAgB,KAAA,EAAqB,cAAA,EAA0B,OAAA,EAAwC;AACnH,EAAA,MAAM,MAAA,GAAS,kBAAkB,cAAc,CAAA;AAC/C,EAAA,MAAM,YAAA,GAAe,SAAS,YAAA,KAAiB,KAAA;AAC/C,EAAA,IAAI,OAAA,GAAU,KAAA;AAEd,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,MAAA,EAAQ;AAC7B,IAAA,IAAI,gBAAgB,IAAA,CAAK,QAAA,EAAU,MAAA,EAAQ,cAAA,EAAgB,YAAY,CAAA,EAAG;AACtE,MAAA,gBAAA,CAAiB,OAAO,IAAI,CAAA;AAC5B,MAAA,OAAA,GAAU,IAAA;AAAA,IACd;AAAA,EACJ;AAEA,EAAA,IAAI,OAAA,EAAS;AACT,IAAA,KAAA,CAAM,kBAAA,EAAA;AAAA,EACV;AACA,EAAA,IAAI,SAAS,iBAAA,EAAmB;AAC5B,IAAA,KAAA,CAAM,YAAY,KAAA,EAAM;AAAA,EAC5B;AACJ;AAEA,SAAS,eAAA,CAAgB,YAAA,EAA+B,MAAA,EAAkB,cAAA,EAA0B,YAAA,EAAgC;AAChI,EAAA,IAAI,CAAC,YAAA,EAAc;AACf,IAAA,OAAO,KAAA;AAAA,EACX;AACA,EAAA,IAAI,CAAC,YAAA,EAAc;AACf,IAAA,OAAO,YAAA,KAAiB,cAAA;AAAA,EAC5B;AACA,EAAA,OAAO,iBAAiB,MAAA,IAAW,cAAA,CAAe,YAAY,CAAA,IAAK,aAAa,MAAA,KAAW,MAAA;AAC/F;AAEA,SAAS,gBAAA,CAAiB,KAAmB,IAAA,EAAkB;AAC3D,EAAA,MAAM,WAAW,IAAA,CAAK,QAAA;AACtB,EAAA,IAAI,CAAC,QAAA,EAAU;AACX,IAAA;AAAA,EACJ;AACA,EAAA,MAAM,OAAA,GAAU,SAAS,WAAA,CAAY,cAAA;AACrC,EAAA,IAAI,CAAC,OAAA,EAAS;AACV,IAAA;AAAA,EACJ;AACA,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,gBAAA,CAAiB,GAAA,CAAI,IAAI,CAAA;AACzC,EAAA,IAAI,GAAA,EAAK;AACL,IAAA,KAAA,MAAW,MAAM,GAAA,EAAK;AAClB,MAAA,EAAA,EAAG;AAAA,IACP;AACA,IAAA,GAAA,CAAI,gBAAA,CAAiB,OAAO,IAAI,CAAA;AAAA,EACpC;AACA,EAAA,KAAA,IAASA,KAAI,GAAA,CAAI,YAAA,CAAa,SAAS,CAAA,EAAGA,EAAAA,IAAK,GAAGA,EAAAA,EAAAA,EAAK;AACnD,IAAA,IAAI,GAAA,CAAI,YAAA,CAAaA,EAAC,CAAA,CAAG,SAAS,IAAA,EAAM;AACpC,MAAA,GAAA,CAAI,YAAA,CAAa,MAAA,CAAOA,EAAAA,EAAG,CAAC,CAAA;AAAA,IAChC;AAAA,EACJ;AACA,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,GAAA,EAAK,IAAI,CAAA;AACpC,EAAA,IAAI,CAAA,GAAI,IAAI,YAAA,CAAa,MAAA;AACzB,EAAA,OAAO,CAAA,GAAI,KAAK,GAAA,CAAI,YAAA,CAAa,IAAI,CAAC,CAAA,CAAG,KAAA,GAAQ,UAAA,CAAW,KAAA,EAAO;AAC/D,IAAA,CAAA,EAAA;AAAA,EACJ;AACA,EAAA,GAAA,CAAI,YAAA,CAAa,MAAA,CAAO,CAAA,EAAG,CAAA,EAAG,UAAU,CAAA;AAC5C;;;;"}
|
|
1
|
+
{"version":3,"file":"material-rebuild.js","sources":["../../../src/material/material-rebuild.ts"],"sourcesContent":["import type { SceneContext } from \"../scene/scene.js\";\nimport type { Mesh } from \"../mesh/mesh.js\";\nimport type { Material } from \"./material.js\";\nimport { getMaterialSource, isMaterialView } from \"./material-view.js\";\n\nexport interface RebuildMaterialOptions {\n /** Rebuild views created from the same source material. Defaults to true. */\n rebuildViews?: boolean;\n /** Rebuild the frame graph after material renderables are refreshed. Defaults to false so callers can batch updates. */\n rebuildFrameGraph?: boolean;\n}\n\n/** Rebuild renderables whose pipeline/bind-group feature state depends on a material.\n * Use after texture, sampler, bind-group layout, culling, or feature changes.\n * UBO-only scalar/vector changes should use markMaterialUboDirty instead. */\nexport function rebuildMaterial(scene: SceneContext, materialOrView: Material, options?: RebuildMaterialOptions): void {\n const source = getMaterialSource(materialOrView);\n const rebuildViews = options?.rebuildViews !== false;\n let changed = false;\n\n for (const mesh of scene.meshes) {\n if (matchesMaterial(mesh.material, source, materialOrView, rebuildViews)) {\n rebuildSceneMesh(scene, mesh);\n if (mesh.material) {\n // Per-material generation (twin of scene-material-swap): lets the CSM detect when a CASTER's own\n // material was rebuilt — and ONLY then rebuild its shadow views — instead of on the global epoch.\n (mesh.material as { _csmGen?: number })._csmGen = ((mesh.material as { _csmGen?: number })._csmGen ?? 0) + 1;\n }\n changed = true;\n }\n }\n\n if (changed) {\n scene._renderableVersion++;\n scene._materialEpoch++; // material renderables (and their UBOs) were rebuilt → bump the material epoch\n }\n if (options?.rebuildFrameGraph) {\n scene._frameGraph.build();\n }\n}\n\nfunction matchesMaterial(meshMaterial: Material | null, source: Material, materialOrView: Material, rebuildViews: boolean): boolean {\n if (!meshMaterial) {\n return false;\n }\n if (!rebuildViews) {\n return meshMaterial === materialOrView;\n }\n return meshMaterial === source || (isMaterialView(meshMaterial) && meshMaterial.source === source);\n}\n\nfunction rebuildSceneMesh(ctx: SceneContext, mesh: Mesh): void {\n const material = mesh.material;\n if (!material) {\n return;\n }\n const rebuild = material._buildGroup._rebuildSingle;\n if (!rebuild) {\n return;\n }\n const old = ctx._meshDisposables.get(mesh);\n if (old) {\n for (const fn of old) {\n fn();\n }\n ctx._meshDisposables.delete(mesh);\n }\n for (let i = ctx._renderables.length - 1; i >= 0; i--) {\n if (ctx._renderables[i]!.mesh === mesh) {\n ctx._renderables.splice(i, 1);\n }\n }\n const renderable = rebuild(ctx, mesh);\n let i = ctx._renderables.length;\n while (i > 0 && ctx._renderables[i - 1]!.order > renderable.order) {\n i--;\n }\n ctx._renderables.splice(i, 0, renderable);\n}\n"],"names":["i"],"mappings":";;AAeO,SAAS,eAAA,CAAgB,KAAA,EAAqB,cAAA,EAA0B,OAAA,EAAwC;AACnH,EAAA,MAAM,MAAA,GAAS,kBAAkB,cAAc,CAAA;AAC/C,EAAA,MAAM,YAAA,GAAe,SAAS,YAAA,KAAiB,KAAA;AAC/C,EAAA,IAAI,OAAA,GAAU,KAAA;AAEd,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,MAAA,EAAQ;AAC7B,IAAA,IAAI,gBAAgB,IAAA,CAAK,QAAA,EAAU,MAAA,EAAQ,cAAA,EAAgB,YAAY,CAAA,EAAG;AACtE,MAAA,gBAAA,CAAiB,OAAO,IAAI,CAAA;AAC5B,MAAA,IAAI,KAAK,QAAA,EAAU;AAGf,QAAC,KAAK,QAAA,CAAkC,OAAA,GAAA,CAAY,IAAA,CAAK,QAAA,CAAkC,WAAW,CAAA,IAAK,CAAA;AAAA,MAC/G;AACA,MAAA,OAAA,GAAU,IAAA;AAAA,IACd;AAAA,EACJ;AAEA,EAAA,IAAI,OAAA,EAAS;AACT,IAAA,KAAA,CAAM,kBAAA,EAAA;AACN,IAAA,KAAA,CAAM,cAAA,EAAA;AAAA,EACV;AACA,EAAA,IAAI,SAAS,iBAAA,EAAmB;AAC5B,IAAA,KAAA,CAAM,YAAY,KAAA,EAAM;AAAA,EAC5B;AACJ;AAEA,SAAS,eAAA,CAAgB,YAAA,EAA+B,MAAA,EAAkB,cAAA,EAA0B,YAAA,EAAgC;AAChI,EAAA,IAAI,CAAC,YAAA,EAAc;AACf,IAAA,OAAO,KAAA;AAAA,EACX;AACA,EAAA,IAAI,CAAC,YAAA,EAAc;AACf,IAAA,OAAO,YAAA,KAAiB,cAAA;AAAA,EAC5B;AACA,EAAA,OAAO,iBAAiB,MAAA,IAAW,cAAA,CAAe,YAAY,CAAA,IAAK,aAAa,MAAA,KAAW,MAAA;AAC/F;AAEA,SAAS,gBAAA,CAAiB,KAAmB,IAAA,EAAkB;AAC3D,EAAA,MAAM,WAAW,IAAA,CAAK,QAAA;AACtB,EAAA,IAAI,CAAC,QAAA,EAAU;AACX,IAAA;AAAA,EACJ;AACA,EAAA,MAAM,OAAA,GAAU,SAAS,WAAA,CAAY,cAAA;AACrC,EAAA,IAAI,CAAC,OAAA,EAAS;AACV,IAAA;AAAA,EACJ;AACA,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,gBAAA,CAAiB,GAAA,CAAI,IAAI,CAAA;AACzC,EAAA,IAAI,GAAA,EAAK;AACL,IAAA,KAAA,MAAW,MAAM,GAAA,EAAK;AAClB,MAAA,EAAA,EAAG;AAAA,IACP;AACA,IAAA,GAAA,CAAI,gBAAA,CAAiB,OAAO,IAAI,CAAA;AAAA,EACpC;AACA,EAAA,KAAA,IAASA,KAAI,GAAA,CAAI,YAAA,CAAa,SAAS,CAAA,EAAGA,EAAAA,IAAK,GAAGA,EAAAA,EAAAA,EAAK;AACnD,IAAA,IAAI,GAAA,CAAI,YAAA,CAAaA,EAAC,CAAA,CAAG,SAAS,IAAA,EAAM;AACpC,MAAA,GAAA,CAAI,YAAA,CAAa,MAAA,CAAOA,EAAAA,EAAG,CAAC,CAAA;AAAA,IAChC;AAAA,EACJ;AACA,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,GAAA,EAAK,IAAI,CAAA;AACpC,EAAA,IAAI,CAAA,GAAI,IAAI,YAAA,CAAa,MAAA;AACzB,EAAA,OAAO,CAAA,GAAI,KAAK,GAAA,CAAI,YAAA,CAAa,IAAI,CAAC,CAAA,CAAG,KAAA,GAAQ,UAAA,CAAW,KAAA,EAAO;AAC/D,IAAA,CAAA,EAAA;AAAA,EACJ;AACA,EAAA,GAAA,CAAI,YAAA,CAAa,MAAA,CAAO,CAAA,EAAG,CAAA,EAAG,UAAU,CAAA;AAC5C;;;;"}
|
|
@@ -9,6 +9,10 @@ const MSH_HAS_UV2 = 1 << 7;
|
|
|
9
9
|
const MSH_RECEIVE_SHADOWS = 1 << 8;
|
|
10
10
|
const MSH_VAT = 1 << 9;
|
|
11
11
|
const MSH_FLAT_NORMAL = 1 << 10;
|
|
12
|
+
let _meshFeatureExtra = null;
|
|
13
|
+
function _installMeshFeatureExtra(encode) {
|
|
14
|
+
_meshFeatureExtra = encode;
|
|
15
|
+
}
|
|
12
16
|
function _computeMeshFeatures(mesh, receiveShadows = false) {
|
|
13
17
|
const gpu = mesh._gpu;
|
|
14
18
|
let features = 0;
|
|
@@ -47,8 +51,11 @@ function _computeMeshFeatures(mesh, receiveShadows = false) {
|
|
|
47
51
|
if (receiveShadows) {
|
|
48
52
|
features |= MSH_RECEIVE_SHADOWS;
|
|
49
53
|
}
|
|
54
|
+
if (_meshFeatureExtra) {
|
|
55
|
+
features |= _meshFeatureExtra(mesh);
|
|
56
|
+
}
|
|
50
57
|
return features;
|
|
51
58
|
}
|
|
52
59
|
|
|
53
|
-
export { MSH_FLAT_NORMAL, MSH_HAS_INSTANCE_COLOR, MSH_HAS_MORPH_TARGETS, MSH_HAS_SKELETON, MSH_HAS_SKELETON_8, MSH_HAS_TANGENTS, MSH_HAS_THIN_INSTANCES, MSH_HAS_UV2, MSH_HAS_VERTEX_COLOR, MSH_RECEIVE_SHADOWS, MSH_VAT, _computeMeshFeatures };
|
|
60
|
+
export { MSH_FLAT_NORMAL, MSH_HAS_INSTANCE_COLOR, MSH_HAS_MORPH_TARGETS, MSH_HAS_SKELETON, MSH_HAS_SKELETON_8, MSH_HAS_TANGENTS, MSH_HAS_THIN_INSTANCES, MSH_HAS_UV2, MSH_HAS_VERTEX_COLOR, MSH_RECEIVE_SHADOWS, MSH_VAT, _computeMeshFeatures, _installMeshFeatureExtra };
|
|
54
61
|
//# sourceMappingURL=mesh-features.js.map
|