@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.
245 lines (242 loc) • 8.38 kB
JavaScript
import { aO as mat4Invert, aP as mat4Identity, aQ as getLoaderTmpAnim, av as mat4MultiplyInto, F as F32, aL as computeNodeWorldMatrix, aj as resolveAccessor, aR as INTERP_CUBICSPLINE, aS as INTERP_STEP, aT as INTERP_LINEAR, aU as PATH_WEIGHTS, aV as PATH_SCALE, aW as PATH_ROTATION, aX as PATH_TRANSLATION, aY as findParent } from './index-By0tcgYN.esm.js';
let _parsePointerChannel = null;
function _installPointerHandlers(parser) {
_parsePointerChannel = parser;
}
let _convertSampler = null;
function _installSamplerConverter(converter) {
_convertSampler = converter;
}
function toSamplerFloat32(src, length, normalized) {
if (_convertSampler) {
return _convertSampler(src, length, normalized);
}
return new F32(src.buffer, src.byteOffset, length);
}
function resolveIBMs(json, binChunk, skin) {
const jointCount = skin.joints.length;
if (skin.inverseBindMatrices !== void 0) {
const ibmData = resolveAccessor(json, binChunk, skin.inverseBindMatrices);
return new F32(ibmData._data.buffer, ibmData._data.byteOffset, jointCount * 16);
}
const out = new F32(jointCount * 16);
for (let i = 0; i < jointCount; i++) {
const o = i * 16;
out[o] = out[o + 5] = out[o + 10] = out[o + 15] = 1;
}
return out;
}
function extractSkin(json, binChunk, skinIdx, meshWorldMatrix, parentMap, worldMatrixCache) {
const skin = json.skins[skinIdx];
const jointNodes = skin.joints;
const inverseBindMatrices = resolveIBMs(json, binChunk, skin);
const jointWorldMatrices = jointNodes.map((nodeIdx) => computeNodeWorldMatrix(json, nodeIdx, parentMap, worldMatrixCache));
return { jointNodes, inverseBindMatrices, jointWorldMatrices, meshWorldMatrix };
}
function computeBoneTextureData(skin) {
const numBones = skin.jointNodes.length;
const data = new F32(numBones * 16);
const invMeshWorld = mat4Invert(skin.meshWorldMatrix) ?? mat4Identity();
const tmp = getLoaderTmpAnim();
for (let i = 0; i < numBones; i++) {
mat4MultiplyInto(tmp, 0, invMeshWorld, 0, skin.jointWorldMatrices[i], 0);
mat4MultiplyInto(data, i * 16, tmp, 0, skin.inverseBindMatrices, i * 16);
}
return data;
}
const INTERP_MAP = {
LINEAR: INTERP_LINEAR,
STEP: INTERP_STEP,
CUBICSPLINE: INTERP_CUBICSPLINE
};
const PATH_MAP = {
translation: PATH_TRANSLATION,
rotation: PATH_ROTATION,
scale: PATH_SCALE,
weights: PATH_WEIGHTS
};
function parseAnimationData(json, binChunk, meshes, parentMap, worldMatrixCache, nodeMap, boneOverrides) {
if (!json.animations || json.animations.length === 0) {
return null;
}
let pointerChannelCount = 0;
const clips = [];
for (const anim of json.animations) {
const samplers = [];
for (const s of anim.samplers) {
const inputAcc = resolveAccessor(json, binChunk, s.input);
const outputAcc = resolveAccessor(json, binChunk, s.output);
const inNorm = json.accessors[s.input]?.normalized === true;
const outNorm = json.accessors[s.output]?.normalized === true;
samplers.push({
input: toSamplerFloat32(inputAcc._data, inputAcc._count, inNorm),
output: toSamplerFloat32(outputAcc._data, outputAcc._count * outputAcc._componentCount, outNorm),
interpolation: INTERP_MAP[s.interpolation ?? "LINEAR"] ?? INTERP_LINEAR
});
}
const channels = [];
for (const c of anim.channels) {
const ptr = c.target?.extensions?.KHR_animation_pointer?.pointer;
if (ptr) {
if (!_parsePointerChannel) {
continue;
}
const ch = _parsePointerChannel(ptr, c, nodeMap, json, meshes);
if (ch) {
channels.push(ch);
pointerChannelCount++;
}
continue;
}
if (c.target.node === void 0) {
continue;
}
const path = PATH_MAP[c.target.path];
if (path === void 0) {
continue;
}
channels.push({ samplerIdx: c.sampler, nodeIdx: c.target.node, path });
}
let duration = 0;
for (const s of samplers) {
if (s.input.length > 0) {
const last = s.input[s.input.length - 1];
if (last > duration) {
duration = last;
}
}
}
clips.push({ name: anim.name ?? "", channels, samplers, duration });
}
const nodeCount = json.nodes?.length ?? 0;
const nodes = [];
for (let i = 0; i < nodeCount; i++) {
const n = json.nodes[i];
const t = n.translation ?? [0, 0, 0];
const r = n.rotation ?? [0, 0, 0, 1];
const s = n.scale ?? [1, 1, 1];
nodes.push({
parentIdx: findParent(parentMap, i),
_matrix: n.matrix,
tx: t[0],
ty: t[1],
tz: t[2],
rx: r[0],
ry: r[1],
rz: r[2],
rw: r[3],
sx: s[0],
sy: s[1],
sz: s[2]
});
}
const nodeToMeshIndices = /* @__PURE__ */ new Map();
let gpuIdx = 0;
for (let ni = 0; ni < nodeCount; ni++) {
const node = json.nodes[ni];
if (node.mesh === void 0) {
continue;
}
const mesh = json.meshes[node.mesh];
const indices = [];
for (let p = 0; p < mesh.primitives.length; p++) {
indices.push(gpuIdx++);
}
nodeToMeshIndices.set(ni, indices);
}
const skeletons = [];
for (let nodeIdx = 0; nodeIdx < nodeCount; nodeIdx++) {
const node = json.nodes[nodeIdx];
if (node.skin === void 0 || !json.skins) {
continue;
}
const meshIndices = nodeToMeshIndices.get(nodeIdx);
if (!meshIndices) {
continue;
}
const skin = json.skins[node.skin];
const jointNodes = skin.joints;
const inverseBindMatrices = resolveIBMs(json, binChunk, skin);
const meshWorldMatrix = computeNodeWorldMatrix(json, nodeIdx, parentMap, worldMatrixCache);
const invMeshWorld = mat4Invert(meshWorldMatrix) ?? mat4Identity();
for (const mi of meshIndices) {
const mesh = meshes[mi];
const skeleton = mesh?.skeleton;
if (!skeleton) {
continue;
}
skeletons.push({
jointNodes,
inverseBindMatrices,
invMeshWorld,
boneTexture: skeleton.boneTexture,
boneCount: jointNodes.length,
boneMatrices: skeleton.boneMatrices,
runtimeSkeleton: skeleton
});
}
}
const morphBindings = [];
for (let nodeIdx = 0; nodeIdx < nodeCount; nodeIdx++) {
const node = json.nodes[nodeIdx];
if (node.mesh === void 0) {
continue;
}
const gltfMesh = json.meshes[node.mesh];
if (!gltfMesh.primitives?.[0]?.targets?.length) {
continue;
}
const meshIndices = nodeToMeshIndices.get(nodeIdx);
if (!meshIndices) {
continue;
}
for (const mi of meshIndices) {
const mesh = meshes[mi];
const morphTargets = mesh?.morphTargets;
if (!morphTargets) {
continue;
}
morphBindings.push({
nodeIdx,
weightsBuffer: morphTargets.weightsBuffer,
weights: morphTargets.weights,
targetCount: morphTargets.count,
runtimeMorphTargets: morphTargets
});
}
}
const nodeTargets = nodeMap ?? [];
const excludedNodeIndices = /* @__PURE__ */ new Set();
for (const skin of json.skins ?? []) {
for (const ji of skin.joints ?? []) {
excludedNodeIndices.add(ji);
}
}
for (let ni = 0; ni < nodeCount; ni++) {
if (json.nodes[ni]?.skin === void 0) {
continue;
}
let p = ni;
while (p >= 0 && !excludedNodeIndices.has(p)) {
excludedNodeIndices.add(p);
p = findParent(parentMap, p);
}
}
if (clips.length === 0 || skeletons.length === 0 && morphBindings.length === 0 && pointerChannelCount === 0 && !hasWritableNodeChannel(clips, nodeTargets, excludedNodeIndices)) {
return null;
}
const nodeNames = (json.nodes ?? []).map((n) => n?.name);
return { clips, nodes, skeletons, morphBindings, nodeTargets, excludedNodeIndices, nodeNames, boneOverrides };
}
function hasWritableNodeChannel(clips, nodeTargets, excludedNodeIndices) {
for (const clip of clips) {
for (const ch of clip.channels) {
if ((ch.path === PATH_TRANSLATION || ch.path === PATH_ROTATION || ch.path === PATH_SCALE) && ch.nodeIdx >= 0 && !excludedNodeIndices.has(ch.nodeIdx) && nodeTargets[ch.nodeIdx]) {
return true;
}
}
}
return false;
}
export { _installPointerHandlers, _installSamplerConverter, computeBoneTextureData, extractSkin, parseAnimationData };
//# sourceMappingURL=gltf-animation-CvJhPzAe.esm.js.map