fix:3的模型动态修改模型文件
This commit is contained in:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user