fix:3的模型动态修改模型文件

This commit is contained in:
jingyun
2025-08-25 15:09:07 +08:00
parent 1c07d576d3
commit d16474784d
8 changed files with 346 additions and 121 deletions

View File

@@ -1,6 +1,6 @@
import 'dart:convert';
import 'dart:io';
import 'package:animations/utils/binary_manager.dart';
import 'package:flutter/material.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
@@ -21,66 +21,84 @@ class _LocalModelViewerState extends State<LocalModelViewer> {
@override
void initState() {
super.initState();
_initializeViewerAndLoadModel();
ThermionFlutterPlugin.createViewer().then((viewer) async {
_viewer = viewer;
_loadLocalModel(); // 在 viewer 初始化之后再加载模型
});
}
Future<void> _initializeViewerAndLoadModel() async {
Future<void> _loadLocalModel() async {
try {
// 获取应用支持目录并构建模型文件路径
setState(() {
_isLoading = true;
_statusMessage = "获取本地模型路径...";
});
final supportDir = await getApplicationSupportDirectory();
final modelFile = File(p.join(supportDir.path, 'cup', 'model.gltf'));
final modelDir = p.join(supportDir.path, 'cup');
final modelPath = p.join(modelDir, 'model.gltf');
final modelFile = File(modelPath);
// 检查文件是否存在
if (!await modelFile.exists()) {
await BinaryManager.migrate3DModels();
await Future.delayed(const Duration(milliseconds: 3000));
if (await modelFile.exists()) {
// 检查二进制文件
final binPath = p.join(modelDir, 'model.bin');
final binFile = File(binPath);
if (!await binFile.exists()) {
throw Exception("二进制文件不存在: $binPath");
}
// throw Exception("模型文件不存在于路径: ${modelFile.path}");
// 检查文件大小
final binSize = await binFile.length();
if (binSize == 0) {
throw Exception("二进制文件为空");
}
// 检查纹理文件
final texturePath = p.join(modelDir, 'texture.jpg');
final textureFile = File(texturePath);
if (!await textureFile.exists()) {
throw Exception("纹理文件不存在: $texturePath");
}
setState(() {
_statusMessage = "读取和修改模型数据...";
});
// 读取GLTF文件内容
String gltfContent = await modelFile.readAsString();
// 修改纹理路径(去掉"./"前缀)
gltfContent = gltfContent.replaceAll('"./texture.jpg"', '"new.jpg"');
// 转换为字节数组
Uint8List gltfBytes = Uint8List.fromList(utf8.encode(gltfContent));
// 使用绝对路径作为资源URI
final resourceUri = "file://${Directory(modelDir).absolute.path}";
setState(() {
_statusMessage = "加载模型中...";
});
final asset = await _viewer?.loadGltfFromBuffer(
gltfBytes,
resourceUri: resourceUri,
addToScene: true,
);
setState(() {
_asset = asset;
_isLoading = false;
_statusMessage = "模型加载完成";
});
} else {
setState(() {
_isLoading = false;
_statusMessage = "本地模型文件不存在";
});
}
setState(() {
_statusMessage = "创建3D查看器...";
});
// 创建ThermionViewer实例
_viewer = await ThermionFlutterPlugin.createViewer();
setState(() {
_statusMessage = "获取模型路径...";
});
setState(() {
_statusMessage = "加载环境光和天空盒...";
});
// 加载环境光和天空盒确保在pubspec.yaml中注册
await _viewer!.loadSkybox("assets/default_env_skybox.ktx");
await _viewer!.loadIbl("assets/default_env_ibl.ktx");
setState(() {
_statusMessage = "加载3D模型...";
});
// 加载glTF模型 - 使用文件URI格式
_asset = await _viewer!.loadGltf("file://${modelFile.path}");
// 可选:将模型缩放到单位立方体
await _asset!.transformToUnitCube();
// 配置场景
final camera = await _viewer!.getActiveCamera();
await camera.lookAt(Vector3(0, 0, 6));
// 开始渲染
await _viewer!.setRendering(true);
setState(() {
_isLoading = false;
_hasError = false;
_statusMessage = "加载完成";
});
} catch (e) {
print("加载模型失败: $e");
print('加载本地模型失败: $e');
setState(() {
_isLoading = false;
_hasError = true;
@@ -115,7 +133,7 @@ class _LocalModelViewerState extends State<LocalModelViewer> {
Text(_statusMessage, style: TextStyle(color: Colors.red)),
SizedBox(height: 16),
ElevatedButton(
onPressed: _initializeViewerAndLoadModel,
onPressed: _loadLocalModel,
child: Text("重试"),
),
],
@@ -164,7 +182,7 @@ class _LocalModelViewerState extends State<LocalModelViewer> {
@override
void dispose() {
deleteModelFile();
// deleteModelFile();
// 清理资源
_viewer?.dispose();
super.dispose();