@mml-io/3d-web-avatar 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,12 @@
|
|
1
1
|
import { GLTF } from "three/examples/jsm/loaders/GLTFLoader.js";
|
2
2
|
export declare class ModelLoader {
|
3
|
+
private debug;
|
3
4
|
private static instance;
|
4
5
|
private readonly loadingManager;
|
5
6
|
private readonly gltfLoader;
|
6
7
|
private modelCache;
|
7
8
|
private ongoingLoads;
|
8
|
-
constructor(maxCacheSize?: number);
|
9
|
+
constructor(maxCacheSize?: number, debug?: boolean);
|
9
10
|
static getInstance(): ModelLoader;
|
10
11
|
load(fileUrl: string): Promise<GLTF | undefined>;
|
11
12
|
private loadFromUrl;
|
@@ -0,0 +1,9 @@
|
|
1
|
+
export type MMLCharacterDescriptionPart = {
|
2
|
+
url: string;
|
3
|
+
};
|
4
|
+
export type MMLCharacterDescription = {
|
5
|
+
base: MMLCharacterDescriptionPart;
|
6
|
+
parts: MMLCharacterDescriptionPart[];
|
7
|
+
};
|
8
|
+
export type LoadingErrors = string[];
|
9
|
+
export declare const parseMMLDescription: (mmlDescription: string) => [MMLCharacterDescription, LoadingErrors];
|
package/build/index.d.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
1
|
export { Character } from "./character/Character";
|
2
2
|
export { TimeManagerInterface } from "./character/types";
|
3
3
|
export { ModelLoader } from "./character/ModelLoader";
|
4
|
+
export { type LoadingErrors, type MMLCharacterDescriptionPart, type MMLCharacterDescription, parseMMLDescription, } from "./helpers/parseMMLDescription";
|
package/build/index.js
CHANGED
@@ -240,7 +240,8 @@ var LRUCache = class {
|
|
240
240
|
}
|
241
241
|
};
|
242
242
|
var _ModelLoader = class _ModelLoader {
|
243
|
-
constructor(maxCacheSize = 100) {
|
243
|
+
constructor(maxCacheSize = 100, debug = false) {
|
244
|
+
this.debug = debug;
|
244
245
|
this.ongoingLoads = /* @__PURE__ */ new Map();
|
245
246
|
this.loadingManager = new LoadingManager();
|
246
247
|
this.gltfLoader = new CachedGLTFLoader(this.loadingManager);
|
@@ -255,12 +256,16 @@ var _ModelLoader = class _ModelLoader {
|
|
255
256
|
async load(fileUrl) {
|
256
257
|
const cachedModel = this.modelCache.get(fileUrl);
|
257
258
|
if (cachedModel) {
|
258
|
-
|
259
|
+
if (this.debug === true) {
|
260
|
+
console.log(`Loading ${fileUrl.split("/").pop()} from cache`);
|
261
|
+
}
|
259
262
|
const blobURL = URL.createObjectURL(cachedModel.blob);
|
260
263
|
this.gltfLoader.setBlobUrl(fileUrl, blobURL);
|
261
264
|
return this.loadFromUrl(blobURL);
|
262
265
|
} else {
|
263
|
-
|
266
|
+
if (this.debug === true) {
|
267
|
+
console.log(`Loading ${fileUrl} from server`);
|
268
|
+
}
|
264
269
|
const ongoingLoad = this.ongoingLoads.get(fileUrl);
|
265
270
|
if (ongoingLoad)
|
266
271
|
return ongoingLoad;
|
@@ -292,8 +297,78 @@ var _ModelLoader = class _ModelLoader {
|
|
292
297
|
};
|
293
298
|
_ModelLoader.instance = null;
|
294
299
|
var ModelLoader = _ModelLoader;
|
300
|
+
|
301
|
+
// src/helpers/parseMMLDescription.ts
|
302
|
+
var parseMMLDescription = (mmlDescription) => {
|
303
|
+
const parser = new DOMParser();
|
304
|
+
const doc = parser.parseFromString(mmlDescription, "text/html");
|
305
|
+
const tag = (count) => {
|
306
|
+
return count > 1 ? "tags" : "tag";
|
307
|
+
};
|
308
|
+
const errors = [];
|
309
|
+
const warn = (errorMessage) => {
|
310
|
+
errors.push(errorMessage);
|
311
|
+
console.warn(errorMessage);
|
312
|
+
};
|
313
|
+
const characters = Array.from(doc.body.children).filter(
|
314
|
+
(child) => child.tagName.toLowerCase() === "m-character"
|
315
|
+
);
|
316
|
+
const validCharacter = characters.shift();
|
317
|
+
if (characters.length > 0) {
|
318
|
+
const tagStr = tag(characters.length);
|
319
|
+
warn(
|
320
|
+
`ignoring ${characters.length} extra <m-character> ${tagStr} found in the root of the document (only the first one is valid).`
|
321
|
+
);
|
322
|
+
}
|
323
|
+
const nestedCharacters = doc.querySelectorAll("body * m-character");
|
324
|
+
if (nestedCharacters.length > 0) {
|
325
|
+
const tagStr = tag(nestedCharacters.length);
|
326
|
+
warn(
|
327
|
+
`ignoring ${nestedCharacters.length} nested <m-character> ${tagStr} found within other tags. A valid <m-character> tag must be at the root of the document.`
|
328
|
+
);
|
329
|
+
}
|
330
|
+
const rootModels = Array.from(doc.body.children).filter(
|
331
|
+
(child) => child.tagName.toLowerCase() === "m-model"
|
332
|
+
);
|
333
|
+
if (rootModels.length > 0) {
|
334
|
+
const tagStr = tag(rootModels.length);
|
335
|
+
warn(
|
336
|
+
`ignoring ${rootModels.length} <m-model> ${tagStr} were found at the root of the document (<m-model> tags must be children of a valid <m-character> tag).`
|
337
|
+
);
|
338
|
+
}
|
339
|
+
let base = { url: "" };
|
340
|
+
let parts = [];
|
341
|
+
if (validCharacter) {
|
342
|
+
const baseSrc = validCharacter.getAttribute("src") ?? "";
|
343
|
+
base = { url: baseSrc };
|
344
|
+
const directModelChildren = Array.from(validCharacter.children).filter(
|
345
|
+
(child) => child.tagName.toLowerCase() === "m-model"
|
346
|
+
);
|
347
|
+
parts = directModelChildren.map((model) => {
|
348
|
+
const partSrc = model.getAttribute("src") ?? "";
|
349
|
+
return { url: partSrc };
|
350
|
+
});
|
351
|
+
const wrappedModelTags = Array.from(doc.querySelectorAll("m-character m-model")).filter(
|
352
|
+
(model) => !directModelChildren.includes(model)
|
353
|
+
);
|
354
|
+
if (wrappedModelTags.length > 0) {
|
355
|
+
const tagStr = tag(wrappedModelTags.length);
|
356
|
+
warn(
|
357
|
+
`ignoring ${wrappedModelTags.length} <m-model> ${tagStr} that were found wrapped inside tags other than a valid <m-character> tag.`
|
358
|
+
);
|
359
|
+
}
|
360
|
+
} else {
|
361
|
+
warn(`No valid <m-character> tag was found in the provided document.`);
|
362
|
+
}
|
363
|
+
const characterDescription = {
|
364
|
+
base,
|
365
|
+
parts
|
366
|
+
};
|
367
|
+
return [characterDescription, errors];
|
368
|
+
};
|
295
369
|
export {
|
296
370
|
Character,
|
297
|
-
ModelLoader
|
371
|
+
ModelLoader,
|
372
|
+
parseMMLDescription
|
298
373
|
};
|
299
374
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
|
-
"sources": ["../src/helpers/SkeletonHelpers.ts", "../src/character/Character.ts", "../src/character/ModelLoader.ts"],
|
4
|
-
"sourcesContent": ["import { Bone, Matrix4, Object3D, Skeleton, SkinnedMesh } from \"three\";\nimport { GLTF } from \"three/examples/jsm/loaders/GLTFLoader.js\";\n\ntype ClonedGLTFParts = {\n gltf: GLTF;\n sharedSkeleton: Skeleton;\n matrixWorld: Matrix4;\n};\n\ntype BoneHierarchyMap = Map<string, BoneHierarchyMap>;\ntype DiffResult = {\n identical: boolean;\n differences: string[];\n};\n\nexport class SkeletonHelpers {\n private debug: boolean = false;\n private hierarchies: BoneHierarchyMap[] = [];\n private modelNames: string[] = [];\n\n private extractBoneHierarchy(node: Object3D): BoneHierarchyMap | null {\n if (node.type !== \"Bone\") return null;\n const boneMap: BoneHierarchyMap = new Map();\n node.children.forEach((child) => {\n const childHierarchy = this.extractBoneHierarchy(child);\n if (childHierarchy) boneMap.set(child.name, childHierarchy);\n });\n return boneMap;\n }\n\n private areBoneHierarchiesEqual(\n a: BoneHierarchyMap,\n b: BoneHierarchyMap,\n modelNameA: string,\n modelNameB: string,\n path: string[] = [],\n ): DiffResult {\n let identical = true;\n const differences: string[] = [];\n\n if (a.size !== b.size) {\n differences.push(\n `Different number of children at path: ${path.join(\n \" -> \",\n )} in models ${modelNameA} and ${modelNameB}.`,\n );\n identical = false;\n }\n\n for (const [key, value] of a) {\n if (!b.has(key)) {\n differences.push(\n `Bone \"${key}\" was found in model ${modelNameA} but not in model ${modelNameB} at path: ${path.join(\n \" -> \",\n )}.`,\n );\n identical = false;\n continue;\n }\n\n const newPath = [...path, key];\n const result = this.areBoneHierarchiesEqual(\n value,\n b.get(key)!,\n modelNameA,\n modelNameB,\n newPath,\n );\n\n if (!result.identical) {\n identical = false;\n differences.push(...result.differences);\n }\n }\n\n for (const key of b.keys()) {\n if (!a.has(key)) {\n differences.push(\n `Bone \"${key}\" was found in model ${modelNameB} but not in model ${modelNameA} at path: ${path.join(\n \" -> \",\n )}.`,\n );\n identical = false;\n }\n }\n\n return {\n identical,\n differences,\n };\n }\n\n public extractAndStoreBoneHierarchy(node: Object3D, modelName: string) {\n const newHierarchy = this.extractBoneHierarchy(node);\n\n if (!newHierarchy) {\n console.log(`No bone hierarchy found in the model: ${modelName}.`);\n return;\n }\n\n this.hierarchies.push(newHierarchy);\n this.modelNames.push(modelName);\n }\n\n public compareLatestHierarchies() {\n if (this.hierarchies.length < 2) return;\n\n const latestHierarchy = this.hierarchies[this.hierarchies.length - 1];\n const previousHierarchy = this.hierarchies[this.hierarchies.length - 2];\n\n const diff = this.areBoneHierarchiesEqual(\n previousHierarchy,\n latestHierarchy,\n this.modelNames[this.modelNames.length - 2],\n this.modelNames[this.modelNames.length - 1],\n [],\n );\n\n if (diff.identical) {\n if (this.debug) console.log(\"The skeletons are identical.\");\n } else {\n diff.differences.forEach((difference) => console.log(difference));\n }\n }\n\n public cloneGLTF(gltf: GLTF, modelName: string): ClonedGLTFParts {\n const clone: Partial<GLTF> = {\n animations: gltf.animations,\n scene: gltf.scene.clone(true),\n };\n\n let sharedSkeleton: Skeleton | null = null;\n let matrixWorld: Matrix4 | null = null;\n\n const skinnedMeshes: Record<string, SkinnedMesh> = {};\n\n gltf.scene.traverse((node) => {\n if (node.type === \"SkinnedMesh\") {\n skinnedMeshes[node.name] = node as SkinnedMesh;\n }\n });\n\n const cloneBones: Record<string, Bone> = {};\n const cloneSkinnedMeshes: Record<string, SkinnedMesh> = {};\n\n let hierarchyCheck = false;\n clone.scene!.traverse((node) => {\n if (node.type === \"Bone\") {\n if (hierarchyCheck === false) {\n hierarchyCheck = true;\n this.extractAndStoreBoneHierarchy(node, modelName);\n this.compareLatestHierarchies();\n }\n cloneBones[node.name] = node as Bone;\n }\n\n if (node.type === \"SkinnedMesh\") {\n cloneSkinnedMeshes[node.name] = node as SkinnedMesh;\n }\n });\n\n for (const name in skinnedMeshes) {\n const skinnedMesh = skinnedMeshes[name];\n const skeleton = skinnedMesh.skeleton;\n const cloneSkinnedMesh = cloneSkinnedMeshes[name];\n\n const orderedCloneBones = [];\n\n for (let i = 0; i < skeleton.bones.length; ++i) {\n const cloneBone = cloneBones[skeleton.bones[i].name];\n orderedCloneBones.push(cloneBone);\n }\n\n if (sharedSkeleton === null) {\n sharedSkeleton = new Skeleton(orderedCloneBones, skeleton.boneInverses);\n }\n\n if (matrixWorld === null) {\n matrixWorld = cloneSkinnedMesh.matrixWorld;\n }\n\n cloneSkinnedMesh.bind(sharedSkeleton, matrixWorld);\n }\n\n return {\n gltf: clone as GLTF,\n sharedSkeleton: sharedSkeleton as Skeleton,\n matrixWorld: matrixWorld as Matrix4,\n };\n }\n}\n", "import { Group, Matrix4, Object3D, Skeleton, SkinnedMesh } from \"three\";\nimport { GLTF } from \"three/examples/jsm/loaders/GLTFLoader\";\n\nimport { SkeletonHelpers } from \"../helpers/SkeletonHelpers\";\n\nimport { ModelLoader } from \"./ModelLoader\";\n\nexport class Character {\n private skeletonHelpers: SkeletonHelpers = new SkeletonHelpers();\n private skinnedMeshesParent: Group | null = null;\n private sharedSkeleton: Skeleton | null = null;\n private sharedMatrixWorld: Matrix4 | null = null;\n\n constructor(private modelLoader: ModelLoader) {}\n\n public async mergeBodyParts(fullBodyURL: string, bodyParts: Array<string>): Promise<Object3D> {\n const fullBodyAsset = await this.modelLoader.load(fullBodyURL);\n const fullBodyGLTF = this.skeletonHelpers.cloneGLTF(fullBodyAsset as GLTF, \"fullBody\");\n\n const assetPromises: Array<Promise<{ asset: GLTF; partUrl: string }>> = bodyParts.map(\n (partUrl) => {\n return new Promise((resolve) => {\n this.modelLoader.load(partUrl).then((asset) => {\n resolve({ asset: asset!, partUrl });\n });\n });\n },\n );\n const assets = await Promise.all(assetPromises);\n\n const fullBodyModelGroup = fullBodyGLTF.gltf.scene;\n\n this.skinnedMeshesParent = null;\n\n fullBodyModelGroup.traverse((child) => {\n if (child.type === \"SkinnedMesh\") {\n (child as SkinnedMesh).castShadow = true;\n if (this.skinnedMeshesParent === null) {\n this.skinnedMeshesParent = child.parent as Group;\n }\n }\n });\n this.sharedSkeleton = fullBodyGLTF.sharedSkeleton;\n this.sharedMatrixWorld = fullBodyGLTF.matrixWorld;\n\n for (const loadingAsset of assets) {\n const gltf = this.skeletonHelpers.cloneGLTF(loadingAsset.asset, loadingAsset.partUrl);\n const modelGroup = gltf.gltf.scene;\n modelGroup.traverse((child) => {\n if (child.type === \"SkinnedMesh\") {\n (child as SkinnedMesh).castShadow = true;\n (child as SkinnedMesh).bind(this.sharedSkeleton!, this.sharedMatrixWorld!);\n this.skinnedMeshesParent?.children.splice(3, 0, child as SkinnedMesh);\n }\n });\n }\n\n return fullBodyGLTF!.gltf.scene as Object3D;\n }\n}\n", "import { LoadingManager } from \"three\";\nimport { GLTF, GLTFLoader as ThreeGLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\n\nclass CachedGLTFLoader extends ThreeGLTFLoader {\n private blobCache: Map<string, string>;\n\n constructor(manager?: LoadingManager) {\n super(manager);\n this.blobCache = new Map();\n }\n\n setBlobUrl(originalUrl: string, blobUrl: string) {\n this.blobCache.set(originalUrl, blobUrl);\n }\n\n getBlobUrl(originalUrl: string): string | undefined {\n return this.blobCache.get(originalUrl);\n }\n\n load(\n url: string,\n onLoad: (gltf: GLTF) => void,\n onProgress?: ((event: ProgressEvent<EventTarget>) => void) | undefined,\n onError?: ((event: ErrorEvent) => void) | undefined,\n ): void {\n const blobUrl = this.getBlobUrl(url);\n const effectiveUrl = blobUrl || url;\n super.load(effectiveUrl, onLoad, onProgress, onError);\n }\n}\n\nclass LRUCache<K, V> {\n private maxSize: number;\n private cache: Map<K, V>;\n\n constructor(maxSize: number = 100) {\n this.maxSize = maxSize;\n this.cache = new Map();\n }\n\n get(key: K): V | undefined {\n const item = this.cache.get(key);\n if (item) {\n this.cache.delete(key);\n this.cache.set(key, item);\n }\n return item;\n }\n\n set(key: K, value: V): void {\n if (this.cache.size >= this.maxSize) {\n const oldestKey = this.cache.keys().next().value;\n this.cache.delete(oldestKey);\n }\n this.cache.set(key, value);\n }\n}\n\ninterface CachedModel {\n blob: Blob;\n}\n\nexport class ModelLoader {\n private static instance: ModelLoader | null = null;\n\n private readonly loadingManager: LoadingManager;\n private readonly gltfLoader: CachedGLTFLoader;\n private modelCache: LRUCache<string, CachedModel>;\n private ongoingLoads: Map<string, Promise<GLTF | undefined>> = new Map();\n\n constructor(maxCacheSize: number = 100) {\n this.loadingManager = new LoadingManager();\n this.gltfLoader = new CachedGLTFLoader(this.loadingManager);\n this.modelCache = new LRUCache(maxCacheSize);\n }\n\n static getInstance(): ModelLoader {\n if (!ModelLoader.instance) {\n ModelLoader.instance = new ModelLoader();\n }\n return ModelLoader.instance;\n }\n\n async load(fileUrl: string): Promise<GLTF | undefined> {\n const cachedModel = this.modelCache.get(fileUrl);\n\n if (cachedModel) {\n console.log(`Loading ${fileUrl.split(\"/\").pop()} from cache`);\n const blobURL = URL.createObjectURL(cachedModel.blob);\n this.gltfLoader.setBlobUrl(fileUrl, blobURL);\n return this.loadFromUrl(blobURL);\n } else {\n console.log(`Loading ${fileUrl} from server`);\n const ongoingLoad = this.ongoingLoads.get(fileUrl);\n if (ongoingLoad) return ongoingLoad;\n\n const loadPromise = fetch(fileUrl)\n .then((response) => response.blob())\n .then((blob) => {\n this.modelCache.set(fileUrl, { blob });\n const blobURL = URL.createObjectURL(blob);\n this.ongoingLoads.delete(fileUrl);\n return this.loadFromUrl(blobURL);\n });\n\n this.ongoingLoads.set(fileUrl, loadPromise);\n return loadPromise;\n }\n }\n\n private async loadFromUrl(url: string): Promise<GLTF | undefined> {\n return new Promise((resolve, reject) => {\n this.gltfLoader.load(\n url,\n (object: GLTF) => {\n resolve(object);\n },\n undefined,\n (error) => {\n console.error(`Error loading model from ${url}: ${error}`);\n reject(error);\n },\n );\n });\n }\n}\n"],
|
5
|
-
"mappings": "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
|
3
|
+
"sources": ["../src/helpers/SkeletonHelpers.ts", "../src/character/Character.ts", "../src/character/ModelLoader.ts", "../src/helpers/parseMMLDescription.ts"],
|
4
|
+
"sourcesContent": ["import { Bone, Matrix4, Object3D, Skeleton, SkinnedMesh } from \"three\";\nimport { GLTF } from \"three/examples/jsm/loaders/GLTFLoader.js\";\n\ntype ClonedGLTFParts = {\n gltf: GLTF;\n sharedSkeleton: Skeleton;\n matrixWorld: Matrix4;\n};\n\ntype BoneHierarchyMap = Map<string, BoneHierarchyMap>;\ntype DiffResult = {\n identical: boolean;\n differences: string[];\n};\n\nexport class SkeletonHelpers {\n private debug: boolean = false;\n private hierarchies: BoneHierarchyMap[] = [];\n private modelNames: string[] = [];\n\n private extractBoneHierarchy(node: Object3D): BoneHierarchyMap | null {\n if (node.type !== \"Bone\") return null;\n const boneMap: BoneHierarchyMap = new Map();\n node.children.forEach((child) => {\n const childHierarchy = this.extractBoneHierarchy(child);\n if (childHierarchy) boneMap.set(child.name, childHierarchy);\n });\n return boneMap;\n }\n\n private areBoneHierarchiesEqual(\n a: BoneHierarchyMap,\n b: BoneHierarchyMap,\n modelNameA: string,\n modelNameB: string,\n path: string[] = [],\n ): DiffResult {\n let identical = true;\n const differences: string[] = [];\n\n if (a.size !== b.size) {\n differences.push(\n `Different number of children at path: ${path.join(\n \" -> \",\n )} in models ${modelNameA} and ${modelNameB}.`,\n );\n identical = false;\n }\n\n for (const [key, value] of a) {\n if (!b.has(key)) {\n differences.push(\n `Bone \"${key}\" was found in model ${modelNameA} but not in model ${modelNameB} at path: ${path.join(\n \" -> \",\n )}.`,\n );\n identical = false;\n continue;\n }\n\n const newPath = [...path, key];\n const result = this.areBoneHierarchiesEqual(\n value,\n b.get(key)!,\n modelNameA,\n modelNameB,\n newPath,\n );\n\n if (!result.identical) {\n identical = false;\n differences.push(...result.differences);\n }\n }\n\n for (const key of b.keys()) {\n if (!a.has(key)) {\n differences.push(\n `Bone \"${key}\" was found in model ${modelNameB} but not in model ${modelNameA} at path: ${path.join(\n \" -> \",\n )}.`,\n );\n identical = false;\n }\n }\n\n return {\n identical,\n differences,\n };\n }\n\n public extractAndStoreBoneHierarchy(node: Object3D, modelName: string) {\n const newHierarchy = this.extractBoneHierarchy(node);\n\n if (!newHierarchy) {\n console.log(`No bone hierarchy found in the model: ${modelName}.`);\n return;\n }\n\n this.hierarchies.push(newHierarchy);\n this.modelNames.push(modelName);\n }\n\n public compareLatestHierarchies() {\n if (this.hierarchies.length < 2) return;\n\n const latestHierarchy = this.hierarchies[this.hierarchies.length - 1];\n const previousHierarchy = this.hierarchies[this.hierarchies.length - 2];\n\n const diff = this.areBoneHierarchiesEqual(\n previousHierarchy,\n latestHierarchy,\n this.modelNames[this.modelNames.length - 2],\n this.modelNames[this.modelNames.length - 1],\n [],\n );\n\n if (diff.identical) {\n if (this.debug) console.log(\"The skeletons are identical.\");\n } else {\n diff.differences.forEach((difference) => console.log(difference));\n }\n }\n\n public cloneGLTF(gltf: GLTF, modelName: string): ClonedGLTFParts {\n const clone: Partial<GLTF> = {\n animations: gltf.animations,\n scene: gltf.scene.clone(true),\n };\n\n let sharedSkeleton: Skeleton | null = null;\n let matrixWorld: Matrix4 | null = null;\n\n const skinnedMeshes: Record<string, SkinnedMesh> = {};\n\n gltf.scene.traverse((node) => {\n if (node.type === \"SkinnedMesh\") {\n skinnedMeshes[node.name] = node as SkinnedMesh;\n }\n });\n\n const cloneBones: Record<string, Bone> = {};\n const cloneSkinnedMeshes: Record<string, SkinnedMesh> = {};\n\n let hierarchyCheck = false;\n clone.scene!.traverse((node) => {\n if (node.type === \"Bone\") {\n if (hierarchyCheck === false) {\n hierarchyCheck = true;\n this.extractAndStoreBoneHierarchy(node, modelName);\n this.compareLatestHierarchies();\n }\n cloneBones[node.name] = node as Bone;\n }\n\n if (node.type === \"SkinnedMesh\") {\n cloneSkinnedMeshes[node.name] = node as SkinnedMesh;\n }\n });\n\n for (const name in skinnedMeshes) {\n const skinnedMesh = skinnedMeshes[name];\n const skeleton = skinnedMesh.skeleton;\n const cloneSkinnedMesh = cloneSkinnedMeshes[name];\n\n const orderedCloneBones = [];\n\n for (let i = 0; i < skeleton.bones.length; ++i) {\n const cloneBone = cloneBones[skeleton.bones[i].name];\n orderedCloneBones.push(cloneBone);\n }\n\n if (sharedSkeleton === null) {\n sharedSkeleton = new Skeleton(orderedCloneBones, skeleton.boneInverses);\n }\n\n if (matrixWorld === null) {\n matrixWorld = cloneSkinnedMesh.matrixWorld;\n }\n\n cloneSkinnedMesh.bind(sharedSkeleton, matrixWorld);\n }\n\n return {\n gltf: clone as GLTF,\n sharedSkeleton: sharedSkeleton as Skeleton,\n matrixWorld: matrixWorld as Matrix4,\n };\n }\n}\n", "import { Group, Matrix4, Object3D, Skeleton, SkinnedMesh } from \"three\";\nimport { GLTF } from \"three/examples/jsm/loaders/GLTFLoader\";\n\nimport { SkeletonHelpers } from \"../helpers/SkeletonHelpers\";\n\nimport { ModelLoader } from \"./ModelLoader\";\n\nexport class Character {\n private skeletonHelpers: SkeletonHelpers = new SkeletonHelpers();\n private skinnedMeshesParent: Group | null = null;\n private sharedSkeleton: Skeleton | null = null;\n private sharedMatrixWorld: Matrix4 | null = null;\n\n constructor(private modelLoader: ModelLoader) {}\n\n public async mergeBodyParts(fullBodyURL: string, bodyParts: Array<string>): Promise<Object3D> {\n const fullBodyAsset = await this.modelLoader.load(fullBodyURL);\n const fullBodyGLTF = this.skeletonHelpers.cloneGLTF(fullBodyAsset as GLTF, \"fullBody\");\n\n const assetPromises: Array<Promise<{ asset: GLTF; partUrl: string }>> = bodyParts.map(\n (partUrl) => {\n return new Promise((resolve) => {\n this.modelLoader.load(partUrl).then((asset) => {\n resolve({ asset: asset!, partUrl });\n });\n });\n },\n );\n const assets = await Promise.all(assetPromises);\n\n const fullBodyModelGroup = fullBodyGLTF.gltf.scene;\n\n this.skinnedMeshesParent = null;\n\n fullBodyModelGroup.traverse((child) => {\n if (child.type === \"SkinnedMesh\") {\n (child as SkinnedMesh).castShadow = true;\n if (this.skinnedMeshesParent === null) {\n this.skinnedMeshesParent = child.parent as Group;\n }\n }\n });\n this.sharedSkeleton = fullBodyGLTF.sharedSkeleton;\n this.sharedMatrixWorld = fullBodyGLTF.matrixWorld;\n\n for (const loadingAsset of assets) {\n const gltf = this.skeletonHelpers.cloneGLTF(loadingAsset.asset, loadingAsset.partUrl);\n const modelGroup = gltf.gltf.scene;\n modelGroup.traverse((child) => {\n if (child.type === \"SkinnedMesh\") {\n (child as SkinnedMesh).castShadow = true;\n (child as SkinnedMesh).bind(this.sharedSkeleton!, this.sharedMatrixWorld!);\n this.skinnedMeshesParent?.children.splice(3, 0, child as SkinnedMesh);\n }\n });\n }\n\n return fullBodyGLTF!.gltf.scene as Object3D;\n }\n}\n", "import { LoadingManager } from \"three\";\nimport { GLTF, GLTFLoader as ThreeGLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\n\nclass CachedGLTFLoader extends ThreeGLTFLoader {\n private blobCache: Map<string, string>;\n\n constructor(manager?: LoadingManager) {\n super(manager);\n this.blobCache = new Map();\n }\n\n setBlobUrl(originalUrl: string, blobUrl: string) {\n this.blobCache.set(originalUrl, blobUrl);\n }\n\n getBlobUrl(originalUrl: string): string | undefined {\n return this.blobCache.get(originalUrl);\n }\n\n load(\n url: string,\n onLoad: (gltf: GLTF) => void,\n onProgress?: ((event: ProgressEvent<EventTarget>) => void) | undefined,\n onError?: ((event: ErrorEvent) => void) | undefined,\n ): void {\n const blobUrl = this.getBlobUrl(url);\n const effectiveUrl = blobUrl || url;\n super.load(effectiveUrl, onLoad, onProgress, onError);\n }\n}\n\nclass LRUCache<K, V> {\n private maxSize: number;\n private cache: Map<K, V>;\n\n constructor(maxSize: number = 100) {\n this.maxSize = maxSize;\n this.cache = new Map();\n }\n\n get(key: K): V | undefined {\n const item = this.cache.get(key);\n if (item) {\n this.cache.delete(key);\n this.cache.set(key, item);\n }\n return item;\n }\n\n set(key: K, value: V): void {\n if (this.cache.size >= this.maxSize) {\n const oldestKey = this.cache.keys().next().value;\n this.cache.delete(oldestKey);\n }\n this.cache.set(key, value);\n }\n}\n\ninterface CachedModel {\n blob: Blob;\n}\n\nexport class ModelLoader {\n private static instance: ModelLoader | null = null;\n\n private readonly loadingManager: LoadingManager;\n private readonly gltfLoader: CachedGLTFLoader;\n private modelCache: LRUCache<string, CachedModel>;\n private ongoingLoads: Map<string, Promise<GLTF | undefined>> = new Map();\n\n constructor(\n maxCacheSize: number = 100,\n private debug: boolean = false,\n ) {\n this.loadingManager = new LoadingManager();\n this.gltfLoader = new CachedGLTFLoader(this.loadingManager);\n this.modelCache = new LRUCache(maxCacheSize);\n }\n\n static getInstance(): ModelLoader {\n if (!ModelLoader.instance) {\n ModelLoader.instance = new ModelLoader();\n }\n return ModelLoader.instance;\n }\n\n async load(fileUrl: string): Promise<GLTF | undefined> {\n const cachedModel = this.modelCache.get(fileUrl);\n\n if (cachedModel) {\n if (this.debug === true) {\n console.log(`Loading ${fileUrl.split(\"/\").pop()} from cache`);\n }\n const blobURL = URL.createObjectURL(cachedModel.blob);\n this.gltfLoader.setBlobUrl(fileUrl, blobURL);\n return this.loadFromUrl(blobURL);\n } else {\n if (this.debug === true) {\n console.log(`Loading ${fileUrl} from server`);\n }\n const ongoingLoad = this.ongoingLoads.get(fileUrl);\n if (ongoingLoad) return ongoingLoad;\n\n const loadPromise = fetch(fileUrl)\n .then((response) => response.blob())\n .then((blob) => {\n this.modelCache.set(fileUrl, { blob });\n const blobURL = URL.createObjectURL(blob);\n this.ongoingLoads.delete(fileUrl);\n return this.loadFromUrl(blobURL);\n });\n\n this.ongoingLoads.set(fileUrl, loadPromise);\n return loadPromise;\n }\n }\n\n private async loadFromUrl(url: string): Promise<GLTF | undefined> {\n return new Promise((resolve, reject) => {\n this.gltfLoader.load(\n url,\n (object: GLTF) => {\n resolve(object);\n },\n undefined,\n (error) => {\n console.error(`Error loading model from ${url}: ${error}`);\n reject(error);\n },\n );\n });\n }\n}\n", "export type MMLCharacterDescriptionPart = {\n url: string;\n};\n\nexport type MMLCharacterDescription = {\n base: MMLCharacterDescriptionPart;\n parts: MMLCharacterDescriptionPart[];\n};\n\nexport type LoadingErrors = string[];\n\nexport const parseMMLDescription = (\n mmlDescription: string,\n): [MMLCharacterDescription, LoadingErrors] => {\n const parser: DOMParser = new DOMParser();\n const doc = parser.parseFromString(mmlDescription, \"text/html\");\n\n const tag = (count: number) => {\n return count > 1 ? \"tags\" : \"tag\";\n };\n\n const errors: string[] = [];\n\n const warn = (errorMessage: string) => {\n errors.push(errorMessage);\n console.warn(errorMessage);\n };\n\n const characters = Array.from(doc.body.children).filter(\n (child) => child.tagName.toLowerCase() === \"m-character\",\n );\n const validCharacter = characters.shift();\n\n if (characters.length > 0) {\n const tagStr = tag(characters.length);\n warn(\n `ignoring ${characters.length} extra <m-character> ${tagStr} found in the root of the document (only the first one is valid).`,\n );\n }\n\n const nestedCharacters = doc.querySelectorAll(\"body * m-character\");\n if (nestedCharacters.length > 0) {\n const tagStr = tag(nestedCharacters.length);\n warn(\n `ignoring ${nestedCharacters.length} nested <m-character> ${tagStr} found within other tags. A valid <m-character> tag must be at the root of the document.`,\n );\n }\n\n const rootModels = Array.from(doc.body.children).filter(\n (child) => child.tagName.toLowerCase() === \"m-model\",\n );\n if (rootModels.length > 0) {\n const tagStr = tag(rootModels.length);\n warn(\n `ignoring ${rootModels.length} <m-model> ${tagStr} were found at the root of the document (<m-model> tags must be children of a valid <m-character> tag).`,\n );\n }\n\n let base: MMLCharacterDescriptionPart = { url: \"\" };\n let parts: MMLCharacterDescriptionPart[] = [];\n\n if (validCharacter) {\n const baseSrc = validCharacter.getAttribute(\"src\") ?? \"\";\n base = { url: baseSrc };\n\n const directModelChildren = Array.from(validCharacter.children).filter(\n (child) => child.tagName.toLowerCase() === \"m-model\",\n );\n parts = directModelChildren.map((model) => {\n const partSrc = model.getAttribute(\"src\") ?? \"\";\n return { url: partSrc };\n });\n\n const wrappedModelTags = Array.from(doc.querySelectorAll(\"m-character m-model\")).filter(\n (model) => !directModelChildren.includes(model),\n );\n if (wrappedModelTags.length > 0) {\n const tagStr = tag(wrappedModelTags.length);\n warn(\n `ignoring ${wrappedModelTags.length} <m-model> ${tagStr} that were found wrapped inside tags other than a valid <m-character> tag.`,\n );\n }\n } else {\n warn(`No valid <m-character> tag was found in the provided document.`);\n }\n\n const characterDescription: MMLCharacterDescription = {\n base: base,\n parts: parts,\n };\n\n return [characterDescription, errors];\n};\n"],
|
5
|
+
"mappings": "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",
|
6
6
|
"names": []
|
7
7
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@mml-io/3d-web-avatar",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.11.0",
|
4
4
|
"publishConfig": {
|
5
5
|
"access": "public"
|
6
6
|
},
|
@@ -30,5 +30,5 @@
|
|
30
30
|
"@types/three": "0.153.0",
|
31
31
|
"esbuild-css-modules-plugin": "3.0.1"
|
32
32
|
},
|
33
|
-
"gitHead": "
|
33
|
+
"gitHead": "6af5c28adc1db01972634248ae05dedba01fba80"
|
34
34
|
}
|