修复项目加载
This commit is contained in:
parent
8b6b8daf9b
commit
3b1b547ed8
86
Start_Run.py
86
Start_Run.py
@ -1,37 +1,49 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 添加项目根目录到 Python 路径
|
||||
project_root = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, project_root)
|
||||
|
||||
# 设置工作目录为项目根目录
|
||||
os.chdir(project_root)
|
||||
|
||||
# 添加 RenderPipeline 到路径(注意路径名称应与实际目录一致)
|
||||
render_pipeline_path = os.path.join(project_root, "RenderPipeline")
|
||||
sys.path.insert(0, render_pipeline_path)
|
||||
|
||||
# 添加 RenderPipelineFile 路径
|
||||
render_pipeline_file_path = os.path.join(project_root, "RenderPipelineFile")
|
||||
sys.path.insert(0, render_pipeline_file_path)
|
||||
|
||||
# 添加 icons 目录到路径
|
||||
icons_path = os.path.join(project_root, "icons")
|
||||
sys.path.insert(0, icons_path)
|
||||
|
||||
# 现在可以导入并运行主程序
|
||||
if __name__ == "__main__":
|
||||
args = sys.argv[1:]
|
||||
# args = "/home/tiger/桌面/Test1"
|
||||
# args = "C:/Users/29381/Desktop/1"
|
||||
print(f'Path is {args}')
|
||||
# 将整个列表转换为字符串(包括方括号)
|
||||
args_str = ''.join(args)
|
||||
|
||||
from main import run
|
||||
if args:
|
||||
run(args_str)
|
||||
# run(args)
|
||||
else:
|
||||
run()
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 添加项目根目录到 Python 路径
|
||||
project_root = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, project_root)
|
||||
|
||||
# 设置工作目录为项目根目录
|
||||
os.chdir(project_root)
|
||||
|
||||
# 添加 RenderPipeline 到路径(注意路径名称应与实际目录一致)
|
||||
render_pipeline_path = os.path.join(project_root, "RenderPipeline")
|
||||
sys.path.insert(0, render_pipeline_path)
|
||||
|
||||
# 添加 RenderPipelineFile 路径
|
||||
render_pipeline_file_path = os.path.join(project_root, "RenderPipelineFile")
|
||||
sys.path.insert(0, render_pipeline_file_path)
|
||||
|
||||
# 添加 icons 目录到路径
|
||||
icons_path = os.path.join(project_root, "icons")
|
||||
sys.path.insert(0, icons_path)
|
||||
|
||||
# 现在可以导入并运行主程序
|
||||
if __name__ == "__main__":
|
||||
args = sys.argv[1:]
|
||||
# args = "/home/tiger/桌面/Test1"
|
||||
# args = "C:/Users/29381/Desktop/1"
|
||||
print(f'Path is {args}')
|
||||
# 将整个列表转换为字符串(包括方括号)
|
||||
args_str = ''.join(args)
|
||||
|
||||
from main import MyWorld
|
||||
if args:
|
||||
# print(f"[DEBUG] 启动时传入项目路径: {args_str}")
|
||||
# 创建应用实例
|
||||
app = MyWorld()
|
||||
# 如果传入了项目路径,尝试打开项目
|
||||
if hasattr(app, 'project_manager'):
|
||||
# print(f"[DEBUG] 尝试打开项目: {args_str}")
|
||||
success = app.project_manager.openProject(args_str)
|
||||
# print(f"[DEBUG] 项目打开结果: {success}")
|
||||
else:
|
||||
# print(f"[DEBUG] 项目管理器未初始化")
|
||||
pass
|
||||
app.run()
|
||||
else:
|
||||
# print(f"[DEBUG] 无项目路径,正常启动")
|
||||
app = MyWorld()
|
||||
app.run()
|
||||
9
main.py
9
main.py
@ -148,10 +148,14 @@ class MyWorld(CoreWorld):
|
||||
self.video_manager = None
|
||||
|
||||
# 初始化场景管理系统
|
||||
# print(f"[DEBUG] 初始化场景管理系统...")
|
||||
self.scene_manager = SceneManager(self)
|
||||
# print(f"[DEBUG] 场景管理系统初始化完成")
|
||||
|
||||
# 初始化项目管理系统
|
||||
# print(f"[DEBUG] 初始化项目管理系统...")
|
||||
self.project_manager = ProjectManager(self)
|
||||
# print(f"[DEBUG] 项目管理系统初始化完成")
|
||||
|
||||
self.info_panel_manager = InfoPanelManager(self)
|
||||
|
||||
@ -424,6 +428,11 @@ class MyWorld(CoreWorld):
|
||||
self.add_info_message("拖拽导入功能已启用 - 可将3D文件拖拽到窗口中导入")
|
||||
|
||||
print("✓ MyWorld 初始化完成")
|
||||
# print(f"[DEBUG] MyWorld 初始化完成,所有管理器已就绪")
|
||||
# print(f"[DEBUG] 场景管理器: {hasattr(self, 'scene_manager')}")
|
||||
# print(f"[DEBUG] 项目管理器: {hasattr(self, 'project_manager')}")
|
||||
# print(f"[DEBUG] GUI管理器: {hasattr(self, 'gui_manager')}")
|
||||
# print(f"[DEBUG] 脚本管理器: {hasattr(self, 'script_manager')}")
|
||||
|
||||
# ==================== 兼容性属性 ====================
|
||||
|
||||
|
||||
@ -92,6 +92,7 @@ class ProjectManager:
|
||||
Returns:
|
||||
bool: 打开是否成功
|
||||
"""
|
||||
# print(f"\n[DEBUG] ===== 开始打开项目: {project_path} =====")
|
||||
try:
|
||||
if not project_path:
|
||||
print("错误: 项目路径不能为空")
|
||||
@ -99,21 +100,83 @@ class ProjectManager:
|
||||
|
||||
# 检查是否是有效的项目文件夹
|
||||
config_file = os.path.join(project_path, "project.json")
|
||||
# print(f"[DEBUG] 项目配置文件路径: {config_file}")
|
||||
# print(f"[DEBUG] 配置文件是否存在: {os.path.exists(config_file)}")
|
||||
|
||||
if not os.path.exists(config_file):
|
||||
print("错误: 选择的不是有效的项目文件夹!")
|
||||
return False
|
||||
|
||||
# 读取项目配置
|
||||
# print(f"[DEBUG] 开始读取项目配置文件...")
|
||||
with open(config_file, "r", encoding="utf-8") as f:
|
||||
project_config = json.load(f)
|
||||
# print(f"[DEBUG] 项目配置读取成功: {project_config.get('name', 'Unknown')}")
|
||||
|
||||
# 检查场景文件
|
||||
scene_file = os.path.join(project_path, "scenes", "scene.bam")
|
||||
# print(f"[DEBUG] 场景文件路径: {scene_file}")
|
||||
# print(f"[DEBUG] 场景文件是否存在: {os.path.exists(scene_file)}")
|
||||
|
||||
if os.path.exists(scene_file):
|
||||
# 加载场景
|
||||
# 加载场景前的安全检查
|
||||
# print(f"[DEBUG] 开始加载场景文件...")
|
||||
# print(f"[DEBUG] 当前world状态检查:")
|
||||
# print(f"[DEBUG] - render节点存在: {hasattr(self.world, 'render') and self.world.render is not None}")
|
||||
# print(f"[DEBUG] - loader存在: {hasattr(self.world, 'loader') and self.world.loader is not None}")
|
||||
# print(f"[DEBUG] - scene_manager存在: {hasattr(self.world, 'scene_manager') and self.world.scene_manager is not None}")
|
||||
|
||||
# 检查world的基本状态
|
||||
if not hasattr(self.world, 'render') or self.world.render is None:
|
||||
# print(f"[DEBUG] 错误: world.render不存在或为None")
|
||||
return False
|
||||
|
||||
if not hasattr(self.world, 'loader') or self.world.loader is None:
|
||||
# print(f"[DEBUG] 错误: world.loader不存在或为None")
|
||||
return False
|
||||
|
||||
# 清理可能的残留状态
|
||||
try:
|
||||
# 清理选择状态
|
||||
if hasattr(self.world, 'selection') and self.world.selection:
|
||||
self.world.selection.clearSelection()
|
||||
# print(f"[DEBUG] 选择状态已清理")
|
||||
|
||||
# 清理GUI状态
|
||||
if hasattr(self.world, 'gui_elements'):
|
||||
for gui_elem in self.world.gui_elements:
|
||||
if gui_elem and not gui_elem.isEmpty():
|
||||
gui_elem.detachNode()
|
||||
self.world.gui_elements.clear()
|
||||
# print(f"[DEBUG] GUI元素已清理")
|
||||
|
||||
# 验证BAM文件
|
||||
# print(f"[DEBUG] 验证BAM文件完整性...")
|
||||
if os.path.getsize(scene_file) == 0:
|
||||
# print(f"[DEBUG] 错误: BAM文件为空")
|
||||
return False
|
||||
|
||||
# 检查文件权限
|
||||
if not os.access(scene_file, os.R_OK):
|
||||
# print(f"[DEBUG] 错误: BAM文件不可读")
|
||||
return False
|
||||
|
||||
# print(f"[DEBUG] BAM文件验证通过")
|
||||
|
||||
except Exception as e:
|
||||
# print(f"[DEBUG] 清理状态时发生异常: {e}")
|
||||
return False
|
||||
|
||||
if self.world.scene_manager.loadScene(scene_file):
|
||||
# print(f"[DEBUG] 场景加载成功")
|
||||
# 更新项目配置
|
||||
project_config["scene_file"] = os.path.relpath(scene_file, project_path)
|
||||
else:
|
||||
# print(f"[DEBUG] 场景加载失败")
|
||||
return False
|
||||
else:
|
||||
# print(f"[DEBUG] 场景文件不存在,跳过场景加载")
|
||||
pass
|
||||
|
||||
project_config["last_modified"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
with open(config_file, "w", encoding="utf-8") as f:
|
||||
@ -123,11 +186,15 @@ class ProjectManager:
|
||||
self.current_project_path = project_path
|
||||
self.project_config = project_config
|
||||
|
||||
# print(f"[DEBUG] ===== 项目打开成功: {project_path} =====")
|
||||
print("项目加载成功!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
# print(f"[DEBUG] ===== 项目打开失败 =====")
|
||||
print(f"加载项目时发生错误:{str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def openProjectForPath(self, project_path):
|
||||
|
||||
@ -1433,29 +1433,83 @@ class SceneManager:
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def loadScene(self, filename):
|
||||
def loadScene(self, filename, retry_count=0):
|
||||
"""从BAM文件加载场景"""
|
||||
max_retries = 3
|
||||
try:
|
||||
print(f"\n=== 开始加载场景: {filename} ===")
|
||||
print(f"\n=== 开始加载场景: {filename} (尝试 {retry_count + 1}/{max_retries + 1}) ===")
|
||||
# print(f"[DEBUG] loadScene 被调用,参数: {filename}")
|
||||
# print(f"[DEBUG] 当前场景中的模型数量: {len(self.models)}")
|
||||
# print(f"[DEBUG] 当前场景中的灯光数量: {len(self.Spotlight) + len(self.Pointlight)}")
|
||||
# print(f"[DEBUG] 当前GUI元素数量: {len(self.world.gui_elements) if hasattr(self.world, 'gui_elements') else 0}")
|
||||
|
||||
# 确保文件路径是规范化的
|
||||
filename = os.path.normpath(filename)
|
||||
# print(f"[DEBUG] 规范化后的文件路径: {filename}")
|
||||
|
||||
# 检查文件是否存在
|
||||
if not os.path.exists(filename):
|
||||
print(f"场景文件不存在: {filename}")
|
||||
return False
|
||||
|
||||
# print(f"[DEBUG] 文件大小: {os.path.getsize(filename)} bytes")
|
||||
|
||||
# 检查文件是否损坏
|
||||
if os.path.getsize(filename) == 0:
|
||||
# print(f"[DEBUG] 错误: 场景文件为空")
|
||||
return False
|
||||
|
||||
# 预防性清理:确保Panda3D处于稳定状态
|
||||
if retry_count > 0:
|
||||
# print(f"[DEBUG] 执行预防性清理...")
|
||||
try:
|
||||
# 清理所有可能的残留状态
|
||||
from panda3d.core import ModelPool
|
||||
ModelPool.releaseAllModels()
|
||||
|
||||
# 强制垃圾回收
|
||||
import gc
|
||||
gc.collect()
|
||||
|
||||
# 清理渲染状态
|
||||
if hasattr(self.world, 'render') and self.world.render:
|
||||
# 清理渲染节点的子节点(保留基本节点)
|
||||
children_to_remove = []
|
||||
for i in range(self.world.render.getNumChildren()):
|
||||
child = self.world.render.getChild(i)
|
||||
if child.getName() not in ['camera', 'alight', 'dlight', 'ambient', 'render']:
|
||||
children_to_remove.append(child)
|
||||
|
||||
for child in children_to_remove:
|
||||
if not child.isEmpty():
|
||||
child.removeNode()
|
||||
|
||||
# print(f"[DEBUG] 清理了 {len(children_to_remove)} 个渲染子节点")
|
||||
|
||||
except Exception as cleanup_error:
|
||||
# print(f"[DEBUG] 预防性清理时发生异常: {cleanup_error}")
|
||||
pass
|
||||
|
||||
# print(f"[DEBUG] 预加载检查完成,开始正式加载...")
|
||||
|
||||
tree_widget = self._get_tree_widget()
|
||||
# print(f"[DEBUG] 获取树形控件: {tree_widget is not None}")
|
||||
|
||||
# 清除当前场景
|
||||
print("\n清除当前场景...")
|
||||
for model in self.models:
|
||||
# print(f"[DEBUG] 需要清理的模型数量: {len(self.models)}")
|
||||
|
||||
for i, model in enumerate(self.models):
|
||||
# print(f"[DEBUG] 清理模型 {i+1}/{len(self.models)}: {model.getName() if model else 'None'}")
|
||||
if tree_widget:
|
||||
tree_widget.delete_item(model)
|
||||
else:
|
||||
# 直接移除节点
|
||||
if not model.isEmpty():
|
||||
model.removeNode()
|
||||
|
||||
self.models.clear()
|
||||
# print(f"[DEBUG] 模型清理完成")
|
||||
|
||||
# 清除灯光
|
||||
for light_node in self.Spotlight:
|
||||
@ -1524,13 +1578,73 @@ class SceneManager:
|
||||
self._cleanupAuxiliaryNodes()
|
||||
|
||||
# 加载场景
|
||||
scene = self.world.loader.loadModel(Filename.fromOsSpecific(filename))
|
||||
if not scene:
|
||||
print("场景加载失败")
|
||||
# print(f"[DEBUG] 开始加载BAM文件...")
|
||||
|
||||
# 安全清理措施
|
||||
try:
|
||||
# 1. 清理Panda3D模型缓存
|
||||
from panda3d.core import ModelPool
|
||||
ModelPool.releaseAllModels()
|
||||
# print(f"[DEBUG] 模型缓存已清理")
|
||||
|
||||
# 2. 强制垃圾回收
|
||||
import gc
|
||||
gc.collect()
|
||||
# print(f"[DEBUG] 垃圾回收完成")
|
||||
|
||||
# 3. 检查文件状态
|
||||
if not os.access(filename, os.R_OK):
|
||||
# print(f"[DEBUG] 文件不可读: {filename}")
|
||||
return False
|
||||
|
||||
# 4. 使用更安全的加载方式
|
||||
# print(f"[DEBUG] 尝试加载BAM文件...")
|
||||
panda_filename = Filename.fromOsSpecific(filename)
|
||||
# print(f"[DEBUG] Panda3D文件名: {panda_filename}")
|
||||
|
||||
# 设置加载选项
|
||||
from panda3d.core import LoaderOptions
|
||||
loader_options = LoaderOptions()
|
||||
loader_options.setFlags(loader_options.LFNoCache) # 禁用缓存
|
||||
|
||||
scene = self.world.loader.loadModel(panda_filename, loader_options)
|
||||
|
||||
if not scene:
|
||||
print("场景加载失败")
|
||||
return False
|
||||
|
||||
# print(f"[DEBUG] BAM文件加载成功")
|
||||
|
||||
except Exception as e:
|
||||
# print(f"[DEBUG] BAM加载过程中发生异常: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
# print(f"[DEBUG] BAM文件加载成功,场景根节点: {scene.getName()}")
|
||||
# print(f"[DEBUG] 场景子节点数量: {scene.getNumChildren()}")
|
||||
|
||||
# 验证场景节点的有效性
|
||||
if scene.isEmpty():
|
||||
# print(f"[DEBUG] 警告: 加载的场景节点为空")
|
||||
return False
|
||||
|
||||
if not scene.hasParent():
|
||||
# print(f"[DEBUG] 将场景节点临时挂载到render")
|
||||
scene.reparentTo(self.world.render)
|
||||
|
||||
if tree_widget:
|
||||
tree_widget.create_model_items(scene)
|
||||
# print(f"[DEBUG] 创建模型项...")
|
||||
try:
|
||||
tree_widget.create_model_items(scene)
|
||||
# print(f"[DEBUG] 模型项创建完成")
|
||||
except Exception as e:
|
||||
# print(f"[DEBUG] 创建模型项失败: {e}")
|
||||
# 继续执行,不影响场景加载
|
||||
pass
|
||||
else:
|
||||
# print(f"[DEBUG] 树形控件为空,跳过创建模型项")
|
||||
pass
|
||||
# 遍历场景中的所有模型节点
|
||||
# 用于存储处理后的灯光节点,避免重复处理
|
||||
processed_lights = []
|
||||
@ -1542,7 +1656,12 @@ class SceneManager:
|
||||
# 遍历场景中的所有节点
|
||||
def processNode(nodePath, depth=0):
|
||||
indent = " " * depth
|
||||
print(f"{indent}处理节点: {nodePath.getName()} (类型: {type(nodePath.node()).__name__})")
|
||||
# print(f"{indent}处理节点: {nodePath.getName()} (类型: {type(nodePath.node()).__name__})")
|
||||
|
||||
# 检查节点是否有效
|
||||
if nodePath.isEmpty():
|
||||
# print(f"{indent}[DEBUG] 节点为空,跳过处理")
|
||||
return
|
||||
|
||||
#存储节点以便后续处理父子关系
|
||||
loaded_nodes[nodePath.getName()] = nodePath
|
||||
@ -1870,9 +1989,29 @@ class SceneManager:
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"=== 场景加载失败 ===")
|
||||
print(f"加载场景时发生错误: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
# 重试机制
|
||||
if retry_count < 3:
|
||||
print(f"[DEBUG] 准备重试... ({retry_count + 1}/{3})")
|
||||
try:
|
||||
# 清理状态
|
||||
import gc
|
||||
gc.collect()
|
||||
from panda3d.core import ModelPool
|
||||
ModelPool.releaseAllModels()
|
||||
|
||||
# 等待一小段时间后重试
|
||||
import time
|
||||
time.sleep(0.5)
|
||||
|
||||
return self.loadScene(filename, retry_count + 1)
|
||||
except Exception as retry_error:
|
||||
print(f"[DEBUG] 重试失败: {retry_error}")
|
||||
|
||||
return False
|
||||
|
||||
def _rebuildParentChildRelationships(self, loaded_nodes):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user