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.

174 lines (171 loc) 6.34 kB
import { n as SS } from './index-DMbDahsc.esm.js'; import { S as SKELETON_HELPERS, m as makeSkinningCode } from './skeleton-fragment-Dc_gcLMX.esm.js'; let _device = null; let _projections = null; let _emptyBGL = null; let _emptyBG = null; const POSITION = { arrayStride: 12, attributes: [{ shaderLocation: 0, offset: 0, format: "float32x3" }] }; function emptyBGL(engine) { return _emptyBGL ??= engine._device.createBindGroupLayout({ label: "picking-deform-empty-bgl", entries: [] }); } function emptyBG(engine) { return _emptyBG ??= engine._device.createBindGroup({ label: "picking-deform-empty-bg", layout: emptyBGL(engine), entries: [] }); } const MORPH_STRUCTS = `struct morphUniforms { count: u32, vertexCount: u32, _p0: u32, _p1: u32, weights: array<f32>, } struct morphDeltasUniforms { d: array<f32>, }`; const MORPH_POSITION = `var morphedPos = position; for (var i = 0u; i < morph.count; i = i + 1u) { let b = (i * morph.vertexCount + vertexIndex) * 6u; morphedPos = morphedPos + morph.weights[i] * vec3<f32>(morphDeltas.d[b], morphDeltas.d[b + 1u], morphDeltas.d[b + 2u]); }`; function declarations(skeleton, morph) { const parts = []; let binding = 0; if (skeleton) { parts.push(SKELETON_HELPERS, `@group(3) @binding(${binding++}) var boneSampler: texture_2d<f32>;`); } if (morph) { parts.push( MORPH_STRUCTS, `@group(3) @binding(${binding++}) var<storage, read> morphDeltas: morphDeltasUniforms;`, `@group(3) @binding(${binding}) var<storage, read> morph: morphUniforms;` ); } return parts.join("\n"); } function inputs(skeleton, has8Bones, morph) { let source = ""; if (skeleton) { source += ", @location(1) joints: vec4<u32>, @location(2) weights: vec4<f32>"; if (has8Bones) { source += ", @location(3) joints1: vec4<u32>, @location(4) weights1: vec4<f32>"; } } if (morph) { source += ", @builtin(vertex_index) vertexIndex: u32"; } return source; } function body(skeleton, has8Bones, morph, worldExpr) { const parts = []; if (morph) { parts.push(MORPH_POSITION); } if (skeleton) { parts.push(`var finalWorld = ${worldExpr};`, makeSkinningCode(has8Bones, worldExpr)); } const transform = skeleton ? "finalWorld" : worldExpr; parts.push(`let projectedTransform = ${transform};`, `let projectedWorld = (${transform} * vec4f(${morph ? "morphedPos" : "position"}, 1.0)).xyz;`); return parts.join("\n"); } function skinLayouts(skeleton, has8Bones) { if (!skeleton) { return []; } const layouts = [ { arrayStride: 16, attributes: [{ shaderLocation: 1, offset: 0, format: "uint32x4" }] }, { arrayStride: 16, attributes: [{ shaderLocation: 2, offset: 0, format: "float32x4" }] } ]; if (has8Bones) { layouts.push( { arrayStride: 16, attributes: [{ shaderLocation: 3, offset: 0, format: "uint32x4" }] }, { arrayStride: 16, attributes: [{ shaderLocation: 4, offset: 0, format: "float32x4" }] } ); } return layouts; } function createProjection(engine, skeleton, has8Bones, morph) { const entries = []; let binding = 0; if (skeleton) { entries.push({ binding: binding++, visibility: SS.VERTEX, texture: { sampleType: "unfilterable-float" } }); } if (morph) { entries.push( { binding: binding++, visibility: SS.VERTEX, buffer: { type: "read-only-storage" } }, { binding, visibility: SS.VERTEX, buffer: { type: "read-only-storage" } } ); } const key = `deform-${skeleton ? has8Bones ? "skin8" : "skin4" : "noskin"}-${morph ? "morph" : "nomorph"}`; const bgl = engine._device.createBindGroupLayout({ label: `picking-${key}-bgl`, entries }); const shared = declarations(skeleton, morph); const sharedInputs = inputs(skeleton, has8Bones, morph); return { key, shader: { regularDeclarations: shared, thinDeclarations: shared, regularInputs: sharedInputs, thinInputs: sharedInputs, regularBody: body(skeleton, has8Bones, morph, "mesh.world"), thinBody: body(skeleton, has8Bones, morph, "world") }, vertexBuffers: skinLayouts(skeleton, has8Bones), regularBGL: bgl, thinBGL: bgl, _layouts: (e, base) => [...base.slice(0, 2), base[2] ?? emptyBGL(e), bgl], _buffers: [POSITION, ...skinLayouts(skeleton, has8Bones)] }; } function projectionFor(engine, skeleton, has8Bones, morph) { if (_device !== engine._device) { _device = engine._device; _projections = null; _emptyBGL = null; _emptyBG = null; } const key = `${skeleton ? has8Bones ? 8 : 4 : 0}-${morph ? 1 : 0}`; const projections = _projections ??= /* @__PURE__ */ new Map(); let projection = projections.get(key); if (!projection) { projection = createProjection(engine, skeleton, has8Bones, morph); projections.set(key, projection); } return projection; } function getDeformPickingProjection(engine, mesh) { if (mesh.vat) { return null; } const skeleton = mesh.skeleton ?? null; const morph = mesh.morphTargets ?? null; if (!skeleton && !morph) { return null; } return projectionFor(engine, !!skeleton, !!(skeleton?.joints1Buffer && skeleton.weights1Buffer), !!morph); } function bindDeformPickingProjection(engine, pass, pipeline, mesh, firstVertexSlot, discardGroupBound) { const skeleton = mesh.skeleton; const morph = mesh.morphTargets; const entries = []; let binding = 0; if (skeleton) { entries.push({ binding: binding++, resource: skeleton.boneTexture.createView() }); } if (morph) { entries.push({ binding: binding++, resource: { buffer: morph.deltasBuffer } }, { binding, resource: { buffer: morph.weightsBuffer } }); } if (!discardGroupBound) { pass.setBindGroup(2, emptyBG(engine)); } pass.setBindGroup(3, engine._device.createBindGroup({ label: "picking-deform-bg", layout: pipeline.getBindGroupLayout(3), entries })); if (skeleton) { let slot = firstVertexSlot; pass.setVertexBuffer(slot++, skeleton.jointsBuffer); pass.setVertexBuffer(slot++, skeleton.weightsBuffer); if (skeleton.joints1Buffer && skeleton.weights1Buffer) { pass.setVertexBuffer(slot++, skeleton.joints1Buffer); pass.setVertexBuffer(slot, skeleton.weights1Buffer); } } } export { bindDeformPickingProjection, getDeformPickingProjection }; //# sourceMappingURL=deform-picking-projection-G3fO67vb.esm.js.map