@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.
363 lines (357 loc) • 11.9 kB
JavaScript
import { T as ThrowLiteError, c as computeAabb, F as F32 } from './index-By0tcgYN.esm.js';
let states = null;
function getPreviousDeformableShadowBounds(generator, mesh, kind) {
const providers = states?.get(generator)?.providers;
let bounds = null;
for (let i = providers?.length ?? 0, kindIndex = 0; --i > kindIndex; ) {
const provider = providers[i];
if (provider?.applies(mesh)) {
bounds = provider.getLocalBounds(mesh, bounds);
}
}
return bounds;
}
function updateShadowMesh(entry) {
const bounds = entry.provider.getLocalBounds(entry.source);
const min = bounds?.[0] ?? entry.source.boundMin;
const max = bounds?.[1] ?? entry.source.boundMax;
const previous = entry._bounds;
let changed = false;
for (let i = 0; i < 3; i++) {
changed = !Object.is(previous[i], min?.[i]) || !Object.is(previous[i + 3], max?.[i]) || changed;
previous[i] = min?.[i];
previous[i + 3] = max?.[i];
}
entry.shadow.boundMin = min;
entry.shadow.boundMax = max;
return changed;
}
function createShadowMesh(source, provider) {
const shadow = Object.create(source);
const entry = { source, shadow, provider, _bounds: [], _version: 0 };
Object.defineProperty(shadow, "worldMatrixVersion", {
configurable: true,
get: () => source.worldMatrixVersion + entry._version
});
updateShadowMesh(entry);
return entry;
}
function mapCasterMeshes(state, casterMeshes) {
if (state.sourceMeshes === casterMeshes) {
return state.shadowMeshes;
}
const entries = [];
const shadowMeshes = casterMeshes.map((mesh) => {
const provider = state.providers.find((candidate) => candidate?.applies(mesh));
if (!provider) {
return mesh;
}
const entry = createShadowMesh(mesh, provider);
entries.push(entry);
return entry.shadow;
});
state.sourceMeshes = casterMeshes;
state.shadowMeshes = shadowMeshes;
state.entries = entries;
return shadowMeshes;
}
function prepareExistingState(generator, state) {
const existing = generator._shadowTaskState;
if (existing && existing._casterMeshes === state.sourceMeshes && state.shadowMeshes) {
existing._casterMeshes = state.shadowMeshes;
}
}
function restoreSourceCasters(taskState, casterMeshes) {
taskState._casterMeshes = casterMeshes;
}
function enableDeformableShadowBounds(generator, provider) {
const kindIndex = provider.kind === "morph" ? 1 : 0;
let state = states?.get(generator);
if (state) {
if (!state.providers[kindIndex]) {
state.providers[kindIndex] = provider;
state.sourceMeshes = void 0;
}
return;
}
const preload = generator._preloadShadowTask;
const ensure = generator._ensureShadowTaskState;
const render = generator._renderShadowMap;
if (!preload || !ensure || !render) {
ThrowLiteError(328);
}
state = {
providers: [],
preload,
ensure,
render
};
state.providers[kindIndex] = provider;
(states ??= /* @__PURE__ */ new WeakMap()).set(generator, state);
generator._preloadShadowTask = (casterMeshes) => preload(mapCasterMeshes(state, casterMeshes));
generator._ensureShadowTaskState = (engine, scene, casterMeshes) => {
prepareExistingState(generator, state);
const shadowMeshes = mapCasterMeshes(state, casterMeshes);
const taskState = ensure(engine, scene, shadowMeshes);
restoreSourceCasters(taskState, casterMeshes);
return taskState;
};
generator._renderShadowMap = (engine, taskState) => {
const shadowMeshes = state.shadowMeshes;
const sourceMeshes = state.sourceMeshes;
if (!shadowMeshes || !sourceMeshes) {
return render(engine, taskState);
}
for (const entry of state.entries ?? []) {
if (updateShadowMesh(entry)) {
entry._version++;
}
}
taskState._casterMeshes = shadowMeshes;
try {
return render(engine, taskState);
} finally {
restoreSourceCasters(taskState, sourceMeshes);
}
};
}
let caches$1 = null;
function createCache(mesh, morphTargets) {
const positions = mesh._cpuPositions;
const base = positions?.length ? computeAabb(positions) : mesh.boundMin && mesh.boundMax ? [mesh.boundMin, mesh.boundMax] : null;
return {
positions,
base,
morphTargets,
targets: morphTargets.targets,
targetRanges: morphTargets.targets.map((target) => computeAabb(target.positions)),
result: [
[0, 0, 0],
[0, 0, 0]
]
};
}
function getCache$1(mesh, morphTargets) {
const cache = (caches$1 ??= /* @__PURE__ */ new WeakMap()).get(mesh);
if (cache && cache.positions === mesh._cpuPositions && cache.morphTargets === morphTargets && cache.targets === morphTargets.targets) {
return cache;
}
const next = createCache(mesh, morphTargets);
caches$1.set(mesh, next);
return next;
}
const morphBoundsProvider = {
kind: "morph",
applies: (mesh) => !!mesh.morphTargets,
getLocalBounds(mesh) {
const morphTargets = mesh.morphTargets;
if (!morphTargets) {
return null;
}
const cache = getCache$1(mesh, morphTargets);
if (!cache.base) {
return null;
}
const min = cache.result[0];
const max = cache.result[1];
for (let axis = 0; axis < 3; axis++) {
min[axis] = cache.base[0][axis];
max[axis] = cache.base[1][axis];
}
for (let target = 0; target < morphTargets.count; target++) {
const range = cache.targetRanges[target];
const weight = morphTargets.weights[target] ?? 0;
if (!range || !weight) {
continue;
}
const targetMin = weight < 0 ? range[1] : range[0];
const targetMax = weight < 0 ? range[0] : range[1];
for (let axis = 0; axis < 3; axis++) {
min[axis] = min[axis] + targetMin[axis] * weight;
max[axis] = max[axis] + targetMax[axis] * weight;
}
}
return cache.result;
}
};
function enableMorphTargetShadows(generator) {
enableDeformableShadowBounds(generator, morphBoundsProvider);
}
function setExtentCorners(corners, min, max) {
for (let i = 0; i < 8; i++) {
corners[i * 3] = i & 1 ? max[0] : min[0];
corners[i * 3 + 1] = i & 2 ? max[1] : min[1];
corners[i * 3 + 2] = i & 4 ? max[2] : min[2];
}
}
function extentCorners(min, max) {
const c = new F32(24);
setExtentCorners(c, min, max);
return c;
}
function buildSkinnedBoneCorners(mesh) {
const positions = mesh._cpuPositions;
const skeleton = mesh.skeleton;
if (!positions || positions.length === 0 || !skeleton || !skeleton.weights) {
return null;
}
const vertexCount = positions.length / 3 | 0;
const boneCount = skeleton.boneCount;
const boneMin = new F32(boneCount * 3).fill(Number.POSITIVE_INFINITY);
const boneMax = new F32(boneCount * 3).fill(Number.NEGATIVE_INFINITY);
const boneUsed = new Uint8Array(boneCount);
const accumulate = (joints, weights, vertex) => {
const base = vertex * 4;
for (let k = 0; k < 4; k++) {
if (weights[base + k] > 0) {
const bone = joints[base + k];
if (bone < boneCount) {
const bo = bone * 3;
const vo = vertex * 3;
if (positions[vo] < boneMin[bo]) {
boneMin[bo] = positions[vo];
}
if (positions[vo + 1] < boneMin[bo + 1]) {
boneMin[bo + 1] = positions[vo + 1];
}
if (positions[vo + 2] < boneMin[bo + 2]) {
boneMin[bo + 2] = positions[vo + 2];
}
if (positions[vo] > boneMax[bo]) {
boneMax[bo] = positions[vo];
}
if (positions[vo + 1] > boneMax[bo + 1]) {
boneMax[bo + 1] = positions[vo + 1];
}
if (positions[vo + 2] > boneMax[bo + 2]) {
boneMax[bo + 2] = positions[vo + 2];
}
boneUsed[bone] = 1;
}
}
}
};
const joints0 = skeleton.joints;
const weights0 = skeleton.weights;
const joints1 = skeleton.joints1;
const weights1 = skeleton.weights1;
for (let v = 0; v < vertexCount; v++) {
accumulate(joints0, weights0, v);
if (joints1 && weights1) {
accumulate(joints1, weights1, v);
}
}
const bones = [];
for (let b = 0; b < boneCount; b++) {
if (boneUsed[b]) {
const o = b * 3;
bones.push({
boneIndex: b,
corners: extentCorners([boneMin[o], boneMin[o + 1], boneMin[o + 2]], [boneMax[o], boneMax[o + 1], boneMax[o + 2]])
});
}
}
return bones;
}
function growCornersByMatrix(corners, matrix, min, max, offset = 0) {
const m0 = matrix[offset], m1 = matrix[offset + 1], m2 = matrix[offset + 2], m4 = matrix[offset + 4], m5 = matrix[offset + 5], m6 = matrix[offset + 6], m8 = matrix[offset + 8], m9 = matrix[offset + 9], m10 = matrix[offset + 10], m12 = matrix[offset + 12], m13 = matrix[offset + 13], m14 = matrix[offset + 14];
for (let i = 0; i < 8; i++) {
const lx = corners[i * 3];
const ly = corners[i * 3 + 1];
const lz = corners[i * 3 + 2];
const x = m0 * lx + m4 * ly + m8 * lz + m12;
const y = m1 * lx + m5 * ly + m9 * lz + m13;
const z = m2 * lx + m6 * ly + m10 * lz + m14;
if (x < min[0]) {
min[0] = x;
}
if (y < min[1]) {
min[1] = y;
}
if (z < min[2]) {
min[2] = z;
}
if (x > max[0]) {
max[0] = x;
}
if (y > max[1]) {
max[1] = y;
}
if (z > max[2]) {
max[2] = z;
}
}
}
let caches = null;
function getCache(mesh) {
const skeleton = mesh.skeleton;
if (!skeleton?.weights || !skeleton.boneMatrices) {
return null;
}
const cache = (caches ??= /* @__PURE__ */ new WeakMap()).get(mesh);
if (cache && cache.positions === mesh._cpuPositions && cache.skeleton === skeleton && cache.joints === skeleton.joints && cache.weights === skeleton.weights && cache.joints1 === skeleton.joints1 && cache.weights1 === skeleton.weights1) {
return cache;
}
const boxes = buildSkinnedBoneCorners(mesh);
const base = boxes ? [
[Infinity, Infinity, Infinity],
[-Infinity, -Infinity, -Infinity]
] : null;
for (const box of boxes ?? []) {
for (let axis = 0; axis < 3; axis++) {
base[0][axis] = Math.min(base[0][axis], box.corners[axis]);
base[1][axis] = Math.max(base[1][axis], box.corners[21 + axis]);
}
}
const next = {
positions: mesh._cpuPositions,
skeleton,
joints: skeleton.joints,
weights: skeleton.weights,
joints1: skeleton.joints1,
weights1: skeleton.weights1,
boxes,
base,
composedCorners: new Float32Array(24),
result: [
[0, 0, 0],
[0, 0, 0]
]
};
caches.set(mesh, next);
return next;
}
function createSkeletonBoundsProvider(generator) {
return {
kind: "skeleton",
applies: (mesh) => !!mesh.skeleton?.weights && !!mesh.skeleton.boneMatrices,
getLocalBounds(mesh) {
const bounds = getPreviousDeformableShadowBounds(generator, mesh);
const cache = getCache(mesh);
const boneMatrices = mesh.skeleton?.boneMatrices;
if (!cache?.boxes || !boneMatrices) {
return bounds;
}
const min = cache.result[0];
const max = cache.result[1];
if (bounds && cache.base) {
for (let axis = 0; axis < 3; axis++) {
min[axis] = Math.min(bounds[0][axis], cache.base[0][axis]);
max[axis] = Math.max(bounds[1][axis], cache.base[1][axis]);
}
setExtentCorners(cache.composedCorners, min, max);
}
min[0] = min[1] = min[2] = Infinity;
max[0] = max[1] = max[2] = -Infinity;
for (const box of cache.boxes) {
growCornersByMatrix(bounds ? cache.composedCorners : box.corners, boneMatrices, min, max, box.boneIndex * 16);
}
return Number.isFinite(min[0]) ? cache.result : bounds;
}
};
}
function enableSkeletonShadows(generator) {
enableDeformableShadowBounds(generator, createSkeletonBoundsProvider(generator));
}
export { enableMorphTargetShadows, enableSkeletonShadows };
//# sourceMappingURL=viewerShadows-DxWYaMlb.esm.js.map