feat(编辑器): 支持导入 GLB/GLTF 模型并驱动角色动画
- 新增 GLB/GLTF 模型加载与渲染,支持内嵌动画播放 - 通过 IndexedDB 持久化大体积模型二进制,规避 localStorage 限制 - 新增动作片段序列,时间轴可添加、编辑与编排多段动作 - 优化机位视角相机同步,修复角度修改不生效问题 - 扩展骨骼识别,兼容 Mixamo 前缀及 UE4 骨架
This commit is contained in:
1 parent
9d3a5b9bea
commit
38dc27501a
36 files changed
+1899
-427
No files matched your search
@@ -1,4 +1,15 @@
|
||||
const LOCAL_MODEL_EXTENSION_RE = /\.(fbx|obj)$/i;
|
||||
import { saveModelBinary } from "./modelBinaryStore";
|
||||
|
||||
const LOCAL_MODEL_EXTENSION_RE = /\.(fbx|obj|glb|gltf)$/i;
|
||||
|
||||
export interface LocalModelFileResult {
|
||||
id: string;
|
||||
fileName: string;
|
||||
name: string;
|
||||
url: string;
|
||||
/** GLB/GLTF 二进制在 IndexedDB 中的存储 id;存在时运行时从 IndexedDB 还原 objectURL。 */
|
||||
binaryId?: string;
|
||||
}
|
||||
|
||||
function readFileAsDataUrl(file: File) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
@@ -17,15 +28,46 @@ function readFileAsDataUrl(file: File) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function readLocalModelFile(file: File) {
|
||||
/**
|
||||
* 读取本地模型文件,返回可在 <primitive url> / useLoader 中直接使用的 url。
|
||||
*
|
||||
* - FBX / OBJ:沿用既有逻辑,读成 data URL(与旧工程兼容,只改了扩展名正则)。
|
||||
* - GLB / GLTF:读成二进制 Blob 存入 IndexedDB(避免 base64 撑爆 localStorage),
|
||||
* 同时返回当前会话可用的 objectURL 与 binaryId;若 IndexedDB 不可用则安静退回 data URL。
|
||||
*/
|
||||
export async function readLocalModelFile(file: File): Promise<LocalModelFileResult> {
|
||||
if (!LOCAL_MODEL_EXTENSION_RE.test(file.name)) {
|
||||
throw new Error("当前仅支持 FBX / OBJ 模型文件");
|
||||
throw new Error("当前仅支持 FBX / OBJ / GLB / GLTF 模型文件");
|
||||
}
|
||||
|
||||
const isGltfFamily = /\.glb$/i.test(file.name) || /\.gltf$/i.test(file.name);
|
||||
|
||||
if (isGltfFamily) {
|
||||
const buffer = await file.arrayBuffer();
|
||||
const blob = new Blob([buffer], { type: file.type || "model/gltf-binary" });
|
||||
const id = crypto.randomUUID();
|
||||
|
||||
try {
|
||||
await saveModelBinary(id, blob);
|
||||
} catch {
|
||||
// IndexedDB 不可用时退回 data URL:当前会话仍可用,只是跨刷新持久化会失效。
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
fileName: file.name,
|
||||
name: file.name.replace(LOCAL_MODEL_EXTENSION_RE, ""),
|
||||
url: URL.createObjectURL(blob),
|
||||
binaryId: id,
|
||||
};
|
||||
}
|
||||
|
||||
const dataUrl = await readFileAsDataUrl(file);
|
||||
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
fileName: file.name,
|
||||
name: file.name.replace(LOCAL_MODEL_EXTENSION_RE, ""),
|
||||
url: await readFileAsDataUrl(file),
|
||||
url: dataUrl,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user