import { ImportMeshAsync, ISceneLoaderProgressEvent } from '@babylonjs/core/Loading/sceneLoader'; import '@babylonjs/loaders/glTF'; import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh'; import { Scene } from '@babylonjs/core/scene'; import { ActionManager, ExecuteCodeAction } from '@babylonjs/core/Actions'; import { Monobehiver } from '../base/Monobehiver'; import { Dictionary } from '../utils/Dictionary'; import { AppConfig } from './AppConfig'; import { EventBridge } from '../event/bridge'; type LoadResult = { success: boolean; meshes?: AbstractMesh[]; skeletons?: unknown[]; error?: string; }; /** * 模型管理类- 负责加载、缓存和管理3D模型 */ export class AppModel extends Monobehiver { private modelDic: Dictionary; private loadedMeshes: AbstractMesh[]; private skeletonManager: any; private outfitManager: any; private isLoading: boolean; private skeletonMerged: boolean; constructor(mainApp: any) { super(mainApp); this.modelDic = new Dictionary(); this.loadedMeshes = []; this.skeletonManager = null; this.outfitManager = null; this.isLoading = false; this.skeletonMerged = false; } /** 初始化子管理器(占位:实际实现已移除) */ initManagers(): void { // 这里原本会初始化 SkeletonManager 和 OutfitManager,已留空以避免恢复已删除的实现 } /** 加载配置中的所有模型 */ async loadModel(): Promise { if (!AppConfig.modelUrlList?.length || this.isLoading) return; this.isLoading = true; try { const total = AppConfig.modelUrlList.length; EventBridge.modelLoadProgress({ loaded: 0, total, urls: AppConfig.modelUrlList, progress: 0, percentage: 0 }); for (let i = 0; i < AppConfig.modelUrlList.length; i++) { const url = AppConfig.modelUrlList[i]; const handleProgress = (event: ISceneLoaderProgressEvent): void => { const currentProgress = event.lengthComputable && event.total > 0 ? Math.min(1, event.loaded / event.total) : 0; const overallProgress = Math.min(1, (i + currentProgress) / total); EventBridge.modelLoadProgress({ loaded: i + currentProgress, total, url, progress: overallProgress, percentage: Number((overallProgress * 100).toFixed(2)), detail: { url, lengthComputable: event.lengthComputable, loadedBytes: event.loaded, totalBytes: event.total } }); }; const result = await this.loadSingleModel(url, handleProgress); const overallProgress = Math.min(1, (i + 1) / total); EventBridge.modelLoadProgress({ loaded: i + 1, total, url, success: result.success, progress: overallProgress, percentage: Number((overallProgress * 100).toFixed(2)) }); if (!result.success) { EventBridge.modelLoadError({ url, error: result.error }); } } EventBridge.modelLoaded({ urls: AppConfig.modelUrlList }); } finally { this.isLoading = false; } } /** * 加载单个模型 * @param modelUrl 模型URL */ async loadSingleModel(modelUrl: string, onProgress?: (event: ISceneLoaderProgressEvent) => void): Promise { try { const cached = this.getCachedMeshes(modelUrl); if (cached) return { success: true, meshes: cached }; const scene: Scene | null = this.mainApp.appScene.object; if (!scene) return { success: false, error: '场景未初始化' }; const result = await ImportMeshAsync(modelUrl, scene, { onProgress }); if (!result?.meshes?.length) return { success: false, error: '未找到网格' }; this.modelDic.Set(modelUrl, result.meshes); this.loadedMeshes.push(...result.meshes); return { success: true, meshes: result.meshes, skeletons: result.skeletons }; } catch (e: any) { console.error(`模型加载失败: ${modelUrl}`, e); return { success: false, error: e?.message }; } } /** 为网格设置阴影(投射和接收) */ setupShadows(meshes: AbstractMesh[]): void { const appLight = this.mainApp.appLight; if (!appLight) return; meshes.forEach(mesh => { if (mesh.getTotalVertices() > 0) { appLight.addShadowCaster(mesh); mesh.receiveShadows = true; } }); } /** 获取缓存的网格 */ getCachedMeshes(url: string): AbstractMesh[] | undefined { return this.modelDic.Get(url); } /** 清理所有资源 */ clean(): void { this.modelDic.Clear(); this.loadedMeshes.forEach(m => m?.dispose()); this.loadedMeshes = []; this.skeletonManager?.clean(); this.outfitManager?.clean(); this.isLoading = false; this.skeletonMerged = false; } /** * 销毁指定模型 * @param modelName 模型名称 */ destroyModel(modelName: string): void { // 遍历模型字典,查找匹配的模型 const keys = this.modelDic.Keys(); for (const key of keys) { if (key.includes(modelName)) { const meshes = this.modelDic.Get(key); if (meshes) { // 销毁所有网格 meshes.forEach(mesh => mesh?.dispose()); // 从字典中移除 this.modelDic.Remove(key); // 从加载的网格列表中移除 this.loadedMeshes = this.loadedMeshes.filter(mesh => !meshes.includes(mesh)); console.log(`Model destroyed: ${modelName}`); return; } } } console.warn(`Model not found: ${modelName}`); } }