UNPKG

@babylonjs/viewer

Version:

The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.

367 lines (362 loc) 13 kB
import { aU as PATH_WEIGHTS, aV as PATH_SCALE, aW as PATH_ROTATION, aX as PATH_TRANSLATION, aZ as PATH_POINTER } from './index-By0tcgYN.esm.js'; import { s as setSubtreeVisible } from './visibility-BuRfFMHe.esm.js'; import { _installPointerHandlers } from './gltf-animation-CvJhPzAe.esm.js'; function applyEmissive(mat) { if (!mat.emissiveColor) { return; } const f = mat._animEmissiveFactor ?? [0, 0, 0]; const s = mat._animEmissiveStrength ?? 1; mat.emissiveColor[0] = f[0] * s; mat.emissiveColor[1] = f[1] * s; mat.emissiveColor[2] = f[2] * s; mat._uboVersion++; } const TX_SLOT = { "pbrMetallicRoughness/baseColorTexture": "baseColorTexture", emissiveTexture: "emissiveTexture", normalTexture: "normalTexture", occlusionTexture: "ormTexture" }; function resolveExtTexture(mat, ext, field) { const m = mat; switch (`${ext}/${field}`) { case "KHR_materials_iridescence/iridescenceTexture": return privateTexture(m.iridescence, "texture"); case "KHR_materials_iridescence/iridescenceThicknessTexture": return privateTexture(m.iridescence, "thicknessTexture"); case "KHR_materials_anisotropy/anisotropyTexture": return privateTexture(m.anisotropy, "texture"); case "KHR_materials_sheen/sheenColorTexture": return privateTexture(m.sheen, "texture"); case "KHR_materials_sheen/sheenRoughnessTexture": return privateTexture(m.sheen, m.sheen?.roughnessTexture ? "roughnessTexture" : "texture"); case "KHR_materials_clearcoat/clearcoatTexture": return privateTexture(m.clearCoat, "texture"); case "KHR_materials_clearcoat/clearcoatRoughnessTexture": return privateTexture(m.clearCoat, "roughnessTexture"); case "KHR_materials_clearcoat/clearcoatNormalTexture": return privateTexture(m.clearCoat, "bumpTexture"); case "KHR_materials_specular/specularTexture": return privateTexture(m, "metallicReflectanceTexture"); case "KHR_materials_specular/specularColorTexture": return privateTexture(m, "reflectanceTexture"); case "KHR_materials_diffuse_transmission/diffuseTransmissionColorTexture": return privateTexture(m.subsurface?.translucency, "colorTexture"); case "KHR_materials_diffuse_transmission/diffuseTransmissionTexture": return privateTexture(m.subsurface?.translucency, "intensityTexture"); case "KHR_materials_transmission/transmissionTexture": return privateTexture(m.subsurface?.refraction, "texture"); case "KHR_materials_volume/thicknessTexture": return privateTexture(m.subsurface?.thickness, "texture"); default: return void 0; } } function privateTexture(parent, key) { const cur = parent?.[key]; if (!cur) { return void 0; } if (cur._animPriv) { return cur; } const clone = { ...cur, _animPriv: true }; parent[key] = clone; return clone; } function uvTransformWriter(mat, tex, kind) { if (kind === "rotation") { return { arity: 1, writer: (out, off) => { tex.uAng = out[off]; mat._uboVersion++; } }; } const isScale = kind === "scale"; return { arity: 2, writer: (out, off) => { if (isScale) { tex.uScale = out[off]; tex.vScale = out[off + 1]; } else { tex.uOffset = out[off]; tex.vOffset = out[off + 1]; } mat._uboVersion++; } }; } const _registry = [ // /nodes/{n}/extensions/KHR_node_visibility/visible — scalar (0 = hidden). // The setter cascade handles descendants per the KHR_node_visibility spec // and bumps the module-scoped visibility epoch so the engine invalidates // its cached render bundle. [ /^\/nodes\/(\d+)\/extensions\/KHR_node_visibility\/visible$/, (m, ctx) => { const n = ctx.nodes[+m[1]]; if (!n) { return null; } return { arity: 1, writer: (out, off) => { setSubtreeVisible(n, out[off] !== 0); } }; } ], // /materials/{m}/.../KHR_texture_transform/{offset|scale|rotation} — animated UV // transform. offset/scale are vec2; rotation is a scalar (radians). Mutates the // slot texture's uOffset/vOffset, uScale/vScale, or uAng and bumps the material's // UBO version so the renderable re-uploads the UV matrix. [ /^\/materials\/(\d+)\/(pbrMetallicRoughness\/baseColorTexture|emissiveTexture|normalTexture|occlusionTexture)\/extensions\/KHR_texture_transform\/(offset|scale|rotation)$/, (m, ctx) => { const mat = ctx.materials?.[+m[1]]; if (!mat) { return null; } const slot = m[2]; const field = slot === "occlusionTexture" && mat.occlusionTexture ? "occlusionTexture" : TX_SLOT[slot]; const tex = privateTexture(mat, field); if (!tex) { return null; } return uvTransformWriter(mat, tex, m[3]); } ], // /materials/{m}/extensions/{KHR_materials_*}/{slot}Texture/.../KHR_texture_transform/{offset|scale|rotation} // — animated UV transform on a material-extension texture (iridescence, sheen, // diffuse transmission). Resolves the runtime extension texture and drives its // UV transform exactly like the core slots. [ /^\/materials\/(\d+)\/extensions\/(KHR_materials_\w+)\/(\w+Texture)\/extensions\/KHR_texture_transform\/(offset|scale|rotation)$/, (m, ctx) => { const mat = ctx.materials?.[+m[1]]; const tex = mat && resolveExtTexture(mat, m[2], m[3]); if (!mat || !tex) { return null; } return uvTransformWriter(mat, tex, m[4]); } ], // /materials/{m}/emissiveFactor — vec3. Recombined with emissiveStrength into // the runtime emissiveColor. Requires the material to carry an emissive slot // (non-zero load-time emissiveFactor) so the UBO field exists. [ /^\/materials\/(\d+)\/emissiveFactor$/, (m, ctx) => { const mat = ctx.materials?.[+m[1]]; if (!mat?.emissiveColor) { return null; } return { arity: 3, writer: (out, off) => { mat._animEmissiveFactor = [out[off], out[off + 1], out[off + 2]]; applyEmissive(mat); } }; } ], // /materials/{m}/extensions/KHR_materials_emissive_strength/emissiveStrength — // scalar HDR multiplier on emissiveFactor. [ /^\/materials\/(\d+)\/extensions\/KHR_materials_emissive_strength\/emissiveStrength$/, (m, ctx) => { const mat = ctx.materials?.[+m[1]]; if (!mat?.emissiveColor) { return null; } return { arity: 1, writer: (out, off) => { mat._animEmissiveStrength = out[off]; applyEmissive(mat); } }; } ], // /materials/{m}/pbrMetallicRoughness/baseColorFactor — vec4 linear RGBA factor. // Only animatable when the material already carries a baseColorFactor UBO slot. [ /^\/materials\/(\d+)\/pbrMetallicRoughness\/baseColorFactor$/, (m, ctx) => { const mat = ctx.materials?.[+m[1]]; if (!mat?.baseColorFactor) { return null; } return { arity: 4, writer: (out, off) => { mat.baseColorFactor[0] = out[off]; mat.baseColorFactor[1] = out[off + 1]; mat.baseColorFactor[2] = out[off + 2]; mat.baseColorFactor[3] = out[off + 3]; mat._uboVersion++; } }; } ] ]; function _appendPointerHandlers(handlers) { _registry.push(...handlers); } const _warned = /* @__PURE__ */ new Set(); function resolveAnimationPointer(pointer, ctx) { for (const [rx, make] of _registry) { const m = rx.exec(pointer); if (m) { return make(m, ctx); } } if (!_warned.has(pointer)) { _warned.add(pointer); console.warn(`[babylon-lite] KHR_animation_pointer: no handler for "${pointer}"`); } return null; } const NODE_TRS_PATH = { translation: PATH_TRANSLATION, rotation: PATH_ROTATION, scale: PATH_SCALE, weights: PATH_WEIGHTS }; let _matMapKey = null; let _matMap = []; const _LIGHT_POINTER_RE = /^\/extensions\/KHR_lights_punctual\/lights\/\d+\/(?:color|intensity|range|spot\/outerConeAngle)$/; const _MAT_EXT_POINTER_RE = /^\/materials\/\d+\/(?:pbrMetallicRoughness\/metallicFactor|normalTexture\/scale|occlusionTexture\/strength|extensions\/KHR_materials_(?:transmission|ior|volume|iridescence)\/)/; const _BASE_COLOR_POINTER_RE = /^\/materials\/\d+\/pbrMetallicRoughness\/baseColorFactor$/; let _matExtMod = null; let _baseColorMod = null; function materialMap(json, meshes) { if (meshes === _matMapKey) { return _matMap; } _matMapKey = meshes; const map = []; const baseColorAnimated = /* @__PURE__ */ new Set(); const uvTransformAnimated = /* @__PURE__ */ new Set(); for (const anim of json.animations ?? []) { for (const ch of anim.channels ?? []) { const ptr = ch.target?.extensions?.KHR_animation_pointer?.pointer; const m = ptr && /^\/materials\/(\d+)\/pbrMetallicRoughness\/baseColorFactor$/.exec(ptr); if (m) { baseColorAnimated.add(+m[1]); } const tx = ptr && /^\/materials\/(\d+)\/.*\/KHR_texture_transform\/(offset|scale|rotation)$/.exec(ptr); if (tx) { uvTransformAnimated.add(+tx[1]); } } } const nodes = json.nodes ?? []; let gpuIdx = 0; for (let ni = 0; ni < nodes.length; ni++) { const meshRef = nodes[ni]?.mesh; if (meshRef === void 0) { continue; } const prims = json.meshes?.[meshRef]?.primitives ?? []; for (let p = 0; p < prims.length; p++) { const matIdx = prims[p]?.material; const mesh = meshes[gpuIdx++]; if (matIdx !== void 0 && mesh) { const pm = mesh.material; const def = json.materials?.[matIdx]; if (def && pm.emissiveColor) { const ef = def.emissiveFactor ?? [0, 0, 0]; pm._animEmissiveFactor = [ef[0] ?? 0, ef[1] ?? 0, ef[2] ?? 0]; pm._animEmissiveStrength = def.extensions?.KHR_materials_emissive_strength?.emissiveStrength ?? 1; } if (baseColorAnimated.has(matIdx) && !pm.baseColorFactor) { const bcf = def?.pbrMetallicRoughness?.baseColorFactor ?? [1, 1, 1, 1]; pm.baseColorFactor = [bcf[0] ?? 1, bcf[1] ?? 1, bcf[2] ?? 1, bcf[3] ?? 1]; } if (uvTransformAnimated.has(matIdx)) { pm._hasUvTx = true; } map[matIdx] = pm; } } } _matExtMod?.seedExtMaterials(json, map); _matMap = map; return map; } _installPointerHandlers((ptr, c, nodeMap, json, meshes) => { if (!nodeMap) { return null; } const trs = /^\/nodes\/(\d+)\/(translation|rotation|scale|weights)$/.exec(ptr); if (trs) { return { samplerIdx: c.sampler, nodeIdx: +trs[1], path: NODE_TRS_PATH[trs[2]] }; } const resolved = resolveAnimationPointer(ptr, { nodes: nodeMap, materials: materialMap(json, meshes), _json: json }); if (!resolved) { return null; } const ch = { samplerIdx: c.sampler, nodeIdx: -1, path: PATH_POINTER, pointerWriter: resolved.writer, pointerArity: resolved.arity }; return ch; }); const feature = { id: "KHR_animation_pointer", // Raw glTF material defs whose pbrMetallicRoughness/baseColorFactor is animated. // Collected here (where `json` is available) and consumed in applyMaterial (which // only receives the GltfMaterialData). Both hooks live in this lazy feature module, // so non-pointer scenes pay zero bytes for the white-fallback handling. async preParse(json) { let hasLightPointer = false; let hasMatExtPointer = false; let hasBaseColorPointer = false; for (const anim of json.animations ?? []) { for (const ch of anim.channels ?? []) { const ptr = ch.target?.extensions?.KHR_animation_pointer?.pointer; if (!ptr) { continue; } if (_BASE_COLOR_POINTER_RE.test(ptr)) { hasBaseColorPointer = true; } if (_LIGHT_POINTER_RE.test(ptr)) { hasLightPointer = true; } if (_MAT_EXT_POINTER_RE.test(ptr)) { hasMatExtPointer = true; } } } if (hasBaseColorPointer) { _baseColorMod = await import('./animation-pointer-basecolor-LJgJbGqQ.esm.js'); _baseColorMod.collectBaseColorDefs(json); } if (hasLightPointer) { await import('./animation-pointer-lights-f4E4fB55.esm.js'); } if (hasMatExtPointer) { _matExtMod = await import('./animation-pointer-ext-DuDsEpH0.esm.js'); } }, // Animated baseColorFactor on untextured materials needs a white 1×1 fallback so the // factor isn't double-applied; the logic lives in the lazy base-color module loaded above. async applyMaterial(mat) { return _baseColorMod?.whiteFallback(mat) ?? null; } }; var gltfFeatureAnimationPointer = /*#__PURE__*/Object.freeze({ __proto__: null, default: feature }); export { _appendPointerHandlers as _, gltfFeatureAnimationPointer as g }; //# sourceMappingURL=gltf-feature-animation-pointer-DbLO7iMT.esm.js.map