Refactor GLTF model import and project asset storage
This commit is contained in:
@@ -1,9 +1,6 @@
|
|||||||
import { Box3, BoxGeometry, Group, Mesh, MeshStandardMaterial, Object3D, type BufferGeometry, type Material } from "three";
|
import { Box3, Group, Mesh, Object3D } from "three";
|
||||||
import { GLTFLoader, type GLTF } from "three/examples/jsm/loaders/GLTFLoader.js";
|
import { GLTFLoader, type GLTF } from "three/examples/jsm/loaders/GLTFLoader.js";
|
||||||
|
|
||||||
import { createOpaqueId } from "../core/ids";
|
|
||||||
import type { Vec3 } from "../core/vector";
|
|
||||||
|
|
||||||
import { createModelInstance, type ModelInstance } from "./model-instances";
|
import { createModelInstance, type ModelInstance } from "./model-instances";
|
||||||
import {
|
import {
|
||||||
createProjectAssetStorageKey,
|
createProjectAssetStorageKey,
|
||||||
@@ -11,6 +8,7 @@ import {
|
|||||||
type ModelAssetRecord,
|
type ModelAssetRecord,
|
||||||
type ProjectAssetStorage
|
type ProjectAssetStorage
|
||||||
} from "./project-assets";
|
} from "./project-assets";
|
||||||
|
import { createOpaqueId } from "../core/ids";
|
||||||
import type { ProjectAssetStorageRecord } from "./project-asset-storage";
|
import type { ProjectAssetStorageRecord } from "./project-asset-storage";
|
||||||
|
|
||||||
export interface LoadedModelAsset {
|
export interface LoadedModelAsset {
|
||||||
@@ -26,14 +24,6 @@ export interface ImportedModelAssetResult {
|
|||||||
loadedAsset: LoadedModelAsset;
|
loadedAsset: LoadedModelAsset;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cloneVec3(vector: Vec3): Vec3 {
|
|
||||||
return {
|
|
||||||
x: vector.x,
|
|
||||||
y: vector.y,
|
|
||||||
z: vector.z
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getErrorDetail(error: unknown): string {
|
function getErrorDetail(error: unknown): string {
|
||||||
if (error instanceof Error && error.message.trim().length > 0) {
|
if (error instanceof Error && error.message.trim().length > 0) {
|
||||||
return error.message.trim();
|
return error.message.trim();
|
||||||
@@ -98,7 +88,7 @@ function collectMaterialNames(scene: Group): string[] {
|
|||||||
const names = new Set<string>();
|
const names = new Set<string>();
|
||||||
|
|
||||||
scene.traverse((object) => {
|
scene.traverse((object) => {
|
||||||
const maybeMesh = object as Mesh | null;
|
const maybeMesh = object as Mesh & { isMesh?: boolean };
|
||||||
|
|
||||||
if (maybeMesh.isMesh !== true) {
|
if (maybeMesh.isMesh !== true) {
|
||||||
return;
|
return;
|
||||||
@@ -131,7 +121,7 @@ function collectTextureNames(parserJson: { textures?: Array<{ name?: string }> }
|
|||||||
|
|
||||||
function collectAnimationNames(gltf: GLTF): string[] {
|
function collectAnimationNames(gltf: GLTF): string[] {
|
||||||
return gltf.animations
|
return gltf.animations
|
||||||
.map((animation, index) => animation.name.trim().length > 0 ? animation.name : `Animation ${index + 1}`)
|
.map((animation, index) => (animation.name.trim().length > 0 ? animation.name : `Animation ${index + 1}`))
|
||||||
.sort((left, right) => left.localeCompare(right));
|
.sort((left, right) => left.localeCompare(right));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +138,6 @@ function countNodes(scene: Group): number {
|
|||||||
export function extractModelAssetMetadata(gltf: GLTF, format: "glb" | "gltf"): ModelAssetMetadata {
|
export function extractModelAssetMetadata(gltf: GLTF, format: "glb" | "gltf"): ModelAssetMetadata {
|
||||||
gltf.scene.updateMatrixWorld(true);
|
gltf.scene.updateMatrixWorld(true);
|
||||||
const boundingBox = createBoundingBoxFromObject(gltf.scene);
|
const boundingBox = createBoundingBoxFromObject(gltf.scene);
|
||||||
const meshCount = gltf.scene.children.length === 0 ? 0 : gltf.scene.getObjectByProperty("isMesh", true) !== undefined ? 1 : 0;
|
|
||||||
|
|
||||||
let actualMeshCount = 0;
|
let actualMeshCount = 0;
|
||||||
|
|
||||||
@@ -185,7 +174,7 @@ export function extractModelAssetMetadata(gltf: GLTF, format: "glb" | "gltf"): M
|
|||||||
format,
|
format,
|
||||||
sceneName: gltf.scene.name.trim().length > 0 ? gltf.scene.name : null,
|
sceneName: gltf.scene.name.trim().length > 0 ? gltf.scene.name : null,
|
||||||
nodeCount: countNodes(gltf.scene),
|
nodeCount: countNodes(gltf.scene),
|
||||||
meshCount: actualMeshCount ?? meshCount,
|
meshCount: actualMeshCount,
|
||||||
materialNames: [...new Set(materialNames)].sort((left, right) => left.localeCompare(right)),
|
materialNames: [...new Set(materialNames)].sort((left, right) => left.localeCompare(right)),
|
||||||
textureNames,
|
textureNames,
|
||||||
animationNames,
|
animationNames,
|
||||||
@@ -286,4 +275,3 @@ export async function loadModelAssetFromStorage(
|
|||||||
|
|
||||||
return createLoadedModelAsset(asset, cloneTemplateScene(gltf.scene));
|
return createLoadedModelAsset(asset, cloneTemplateScene(gltf.scene));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ function openIndexedDb(): Promise<IDBDatabase> {
|
|||||||
class IndexedDbProjectAssetStorage implements ProjectAssetStorage {
|
class IndexedDbProjectAssetStorage implements ProjectAssetStorage {
|
||||||
private readonly databasePromise: Promise<IDBDatabase>;
|
private readonly databasePromise: Promise<IDBDatabase>;
|
||||||
|
|
||||||
constructor() {
|
constructor(databasePromise: Promise<IDBDatabase>) {
|
||||||
this.databasePromise = openIndexedDb();
|
this.databasePromise = databasePromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async withStore<T>(mode: IDBTransactionMode, callback: (store: IDBObjectStore) => IDBRequest<T>): Promise<T> {
|
private async withStore<T>(mode: IDBTransactionMode, callback: (store: IDBObjectStore) => IDBRequest<T>): Promise<T> {
|
||||||
@@ -172,8 +172,10 @@ export async function getBrowserProjectAssetStorageAccess(): Promise<ProjectAsse
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const databasePromise = openIndexedDb();
|
||||||
|
await databasePromise;
|
||||||
return {
|
return {
|
||||||
storage: new IndexedDbProjectAssetStorage(),
|
storage: new IndexedDbProjectAssetStorage(databasePromise),
|
||||||
diagnostic: null
|
diagnostic: null
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -183,4 +185,3 @@ export async function getBrowserProjectAssetStorageAccess(): Promise<ProjectAsse
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user