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.

196 lines (193 loc) 7.67 kB
import { b as clearSceneBGLCache, i as isRenderingContextRegistered, d as createEmptyUniformBuffer, e as ensureSceneLightState, g as getSceneBindGroupLayout, S as SCENE_UBO_BYTES, f as createMappedBuffer, B as BU } from './index-DMbDahsc.esm.js'; async function rebuildRegisteredScenes(engine) { clearSceneBGLCache(); engine._pbrFallbackTex = void 0; for (const surface of engine.surfaces) { for (const ctx of surface._renderingContexts) { if (ctx._kind !== "scene") { continue; } const scene = ctx; if (!isRenderingContextRegistered(surface, scene) || scene._z) { continue; } await rebuildSceneGpu(engine, scene); } } } async function rebuildSceneGpu(engine, scene) { if (scene._envTextures) { const { rebuildSceneEnvironment } = await import('./environment-recovery-tYD5QxX7.esm.js'); await runRecoveryStep("rebuilding environment textures", () => rebuildSceneEnvironment(engine, scene)); } await runRecoveryStep("rebuilding material textures", () => rebuildSceneTextures(engine, scene)); await runRecoveryStep("rebuilding meshes", () => _rebuildMeshes(engine, scene)); if (scene._z) { return; } if (scene.shadowGenerators.length > 0 || scene.lights.some((light) => light.shadowGenerator)) { const { rebuildSceneShadowGenerators } = await import('./shadow-recovery-wZDR5ghJ.esm.js'); await runRecoveryStep("rebuilding shadows", () => rebuildSceneShadowGenerators(engine, scene)); } if (scene._z) { return; } const rebuilds = scene._renderables.filter((r) => !!r._rebuild).map((r) => r._rebuild); scene._renderables.length = scene._uniformUpdaters.length = 0; scene._meshDisposables.clear(); scene._meshAuxDisposables.clear(); if (scene._lightGpuState) { scene._lightGpuState = void 0; } for (const [build, meshes] of scene._groups) { const result = await runRecoveryStep("rebuilding material groups", () => build(scene, meshes)); if (scene._z) { return; } meshes.r = scene._runtimeBuilds?.base(build, result.rebuildSingle) ?? result.rebuildSingle; meshes.o = result.renderables; scene._renderables.push(...result.renderables); if (result.updater) { scene._uniformUpdaters.push(result.updater); } } if (rebuilds.length > 0) { scene._renderables.push(...await runRecoveryStep("rebuilding renderables", () => rebuildRenderables(rebuilds))); } scene._renderables.sort((a, b) => a.order - b.order); scene._renderableVersion++; resetFrameGraphTasks(engine, scene); scene._frameGraph.build(); } async function rebuildRenderables(rebuilds) { const rebuilt = []; for (const rebuild of rebuilds) { rebuilt.push(await rebuild()); } return rebuilt; } async function runRecoveryStep(description, action) { try { return await action(); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Device-lost Scene recovery failed while ${description}: ${message}`, { cause: error }); } } function resetFrameGraphTasks(engine, scene) { for (const task of scene._frameGraph._tasks) { if (!("_sceneUBO" in task && "_sceneBG" in task && "_opaqueBindings" in task)) { continue; } const rt = task; rt._sceneUBO = createEmptyUniformBuffer(engine, SCENE_UBO_BYTES); rt._lightsUBO = ensureSceneLightState(engine, scene)._buffer; rt._sceneBG = engine._device.createBindGroup({ layout: getSceneBindGroupLayout(engine), entries: [ { binding: 0, resource: { buffer: rt._sceneUBO } }, { binding: 1, resource: { buffer: rt._lightsUBO } } ] }); rt._opaqueBindings.length = 0; rt._directBindings.length = 0; rt._transparentBindings.length = 0; rt._ob.length = 0; rt._lastVersion = -1; rt._sceneUboCacheKey.length = 0; } } async function _rebuildMeshes(engine, scene) { let skeletonFactory = null; let morphFactory = null; for (const mesh of scene.meshes) { if (mesh._cpuPositions && mesh._cpuNormals && mesh._cpuIndices) { const recoverShared = mesh._gpu._recoverShared; mesh._gpu = recoverShared ? recoverShared(engine, mesh, uploadRetainedMesh) : uploadRetainedMesh(engine, mesh); } if (mesh.skeleton) { skeletonFactory ??= (await import('./create-skeleton-BKApXCJ-.esm.js')).createSkeleton; const old = mesh.skeleton; const rebuilt = skeletonFactory(engine, old.joints, old.weights, old.boneCount, old.boneMatrices, old.joints1, old.weights1); Object.assign(old, rebuilt); } if (mesh.morphTargets) { morphFactory ??= (await import('./create-morph-targets-BfcHXAXK.esm.js')).createMorphTargets; const old = mesh.morphTargets; const rebuilt = morphFactory( engine, old.targets.map((t) => ({ positions: t.positions, normals: t.normals })), mesh._cpuPositions ? mesh._cpuPositions.length / 3 : 0, Array.from(old.weights) ); Object.assign(old, rebuilt); } } } function uploadRetainedMesh(engine, mesh) { const positions = mesh._cpuPositions; const normals = mesh._cpuNormals; const uvs = mesh._cpuUvs; const indices = mesh._cpuGpuIndices ?? mesh._cpuIndices; const device = engine._device; let uvBuffer; if (uvs && uvs.length > 0) { uvBuffer = createMappedBuffer(engine, uvs, BU.VERTEX); } else { uvBuffer = device.createBuffer({ size: positions.length / 3 * 8, usage: BU.VERTEX, mappedAtCreation: true }); uvBuffer.unmap(); } return { positionBuffer: createMappedBuffer(engine, positions, BU.VERTEX), normalBuffer: createMappedBuffer(engine, normals, BU.VERTEX), tangentBuffer: mesh._cpuTangents ? createMappedBuffer(engine, mesh._cpuTangents, BU.VERTEX) : null, uvBuffer, uv2Buffer: mesh._cpuUv2s ? createMappedBuffer(engine, mesh._cpuUv2s, BU.VERTEX) : null, colorBuffer: mesh._cpuColors ? createMappedBuffer(engine, mesh._cpuColors, BU.VERTEX) : null, hasUv: !!uvs && uvs.length > 0, hasUv2: !!mesh._cpuUv2s && mesh._cpuUv2s.length > 0, hasTangent: !!mesh._cpuTangents && mesh._cpuTangents.length > 0, hasColor: !!mesh._cpuColors && mesh._cpuColors.length > 0, indexBuffer: createMappedBuffer(engine, indices, BU.INDEX), // Capacity-reserved meshes retain exact active CPU geometry. Recovery intentionally collapses the // reservation; the next capacity update may grow it again without exposing padded arrays publicly. indexCount: indices.length, indexFormat: mesh._cpuIndexFormat ?? mesh._gpu.indexFormat }; } async function rebuildSceneTextures(engine, scene) { const seen = /* @__PURE__ */ new Set(); const visited = /* @__PURE__ */ new WeakSet(); const textures = []; const visit = (value) => { if (!value || typeof value !== "object") { return; } const obj = value; if (obj.texture && obj.view && obj.sampler && typeof obj.width === "number" && typeof obj.height === "number") { const tex = obj; if (!seen.has(tex)) { seen.add(tex); textures.push(tex); } return; } if (visited.has(value)) { return; } visited.add(value); for (const child of Object.values(obj)) { visit(child); } }; for (const mesh of scene.meshes) { visit(mesh.material); } if (textures.length === 0) { return; } const { rebuildTexture2D } = await import('./texture-recovery-DOZbz_TC.esm.js'); await Promise.all(textures.map((texture) => rebuildTexture2D(engine, texture))); } export { _rebuildMeshes, rebuildRegisteredScenes, rebuildRenderables }; //# sourceMappingURL=recovery-rebuild-OAOymy7J.esm.js.map