#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 选择框边界测试脚本 测试保存和加载场景后选择框是否正常显示 """ import sys import os import tempfile import shutil # 添加项目路径 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from main import MyWorld from PyQt5.QtWidgets import QApplication def test_selection_bounds(): """测试选择框边界问题""" print("=== 选择框边界测试 ===\n") # 创建应用程序 app = QApplication.instance() if app is None: app = QApplication(sys.argv) # 创建世界 world = MyWorld() return test_selection_bounds_with_world(world) def test_selection_bounds_with_world(world): """使用提供的world实例测试选择框边界问题""" print("=== 选择框边界测试 ===\n") # 清理之前的测试数据 world.models.clear() for child in world.render.getChildren(): if child.getName() in ["test_cube", "fbx_model", "selectionBox", "gizmo"]: child.removeNode() print("1. 创建测试模型...") # 创建一个简单的测试立方体 from panda3d.core import CardMaker cm = CardMaker("test_cube") cm.setFrame(-1, 1, -1, 1) # 创建立方体的6个面(使用ModelRoot确保保存/加载正常) from panda3d.core import ModelRoot model_root = ModelRoot("test_cube") cube = world.render.attachNewNode(model_root) # 前面 front = cube.attachNewNode(cm.generate()) front.setP(-90) front.setZ(1) front.setColor(1, 0, 0, 1) # 后面 back = cube.attachNewNode(cm.generate()) back.setP(-90) back.setZ(-1) back.setColor(0, 1, 0, 1) # 设置测试缩放(模拟FBX导入后的状态) cube.setScale(0.5, 0.5, 0.5) cube.setPos(2, 0, 1) # 设置碰撞检测 world.scene_manager.setupCollision(cube) # 添加到模型列表 world.models.append(cube) cube.setTag("file", "test_cube.fbx") cube.setTag("is_model_root", "1") print("✓ 测试模型创建完成") print(f" 位置: {cube.getPos()}") print(f" 缩放: {cube.getScale()}") print(f" 边界: {cube.getBounds().getMin()} 到 {cube.getBounds().getMax()}") print("\n2. 测试选择功能...") # 选择模型 world.selection.updateSelection(cube) # 获取原始选择框信息 original_bounds = cube.getBounds() original_pos = cube.getPos() original_scale = cube.getScale() print(f" 原始边界: {original_bounds.getMin()} 到 {original_bounds.getMax()}") print(f" 原始位置: {original_pos}") print(f" 原始缩放: {original_scale}") print("\n3. 保存场景...") # 创建临时文件 temp_dir = tempfile.mkdtemp(prefix="bounds_test_") scene_file = os.path.join(temp_dir, "test_scene.bam") try: # 保存场景 success = world.scene_manager.saveScene(scene_file) if success: print("✓ 场景保存成功") else: print("✗ 场景保存失败") return False print("\n4. 重新加载场景...") # 加载场景 success = world.scene_manager.loadScene(scene_file) if success: print("✓ 场景加载成功") else: print("✗ 场景加载失败") return False print("\n5. 检查加载后的模型状态...") if not world.models: print("✗ 加载后没有找到模型") return False loaded_model = world.models[0] loaded_bounds = loaded_model.getBounds() loaded_pos = loaded_model.getPos() loaded_scale = loaded_model.getScale() print(f" 加载后边界: {loaded_bounds.getMin()} 到 {loaded_bounds.getMax()}") print(f" 加载后位置: {loaded_pos}") print(f" 加载后缩放: {loaded_scale}") print("\n6. 比较结果...") # 检查位置是否一致 pos_diff = (loaded_pos - original_pos).length() scale_diff = (loaded_scale - original_scale).length() print(f" 位置差异: {pos_diff}") print(f" 缩放差异: {scale_diff}") # 检查边界大小 original_size = (original_bounds.getMax() - original_bounds.getMin()).length() loaded_size = (loaded_bounds.getMax() - loaded_bounds.getMin()).length() size_diff = abs(loaded_size - original_size) print(f" 原始边界大小: {original_size:.3f}") print(f" 加载后边界大小: {loaded_size:.3f}") print(f" 边界大小差异: {size_diff:.3f}") print("\n7. 测试选择框...") # 选择加载后的模型 world.selection.updateSelection(loaded_model) # 检查选择框是否创建成功 if world.selection.selectionBox: print("✓ 选择框创建成功") else: print("✗ 选择框创建失败") return False print("\n=== 测试结果 ===") success = True if pos_diff < 0.01: print("✓ 位置信息正确恢复") else: print("✗ 位置信息恢复有误") success = False if scale_diff < 0.01: print("✓ 缩放信息正确恢复") else: print("✗ 缩放信息恢复有误") success = False if size_diff < 0.1: print("✓ 边界大小正常") else: print("✗ 边界大小异常") success = False if success: print("\n🎉 选择框边界测试通过!") print("保存和加载后选择框显示正常。") else: print("\n❌ 选择框边界测试失败。") print("需要进一步检查变换信息的保存和恢复。") return success except Exception as e: print(f"测试过程中出现错误: {str(e)}") import traceback traceback.print_exc() return False finally: # 清理临时文件 try: shutil.rmtree(temp_dir) print(f"\n清理临时文件: {temp_dir}") except Exception as e: print(f"清理临时文件失败: {str(e)}") def test_fbx_simulation(world=None): """模拟FBX模型的缩放标准化情况""" print("\n=== FBX缩放标准化测试 ===\n") # 重用现有的world实例,避免ShowBase冲突 if world is None: # 创建应用程序 app = QApplication.instance() if app is None: app = QApplication(sys.argv) # 创建世界 world = MyWorld() else: # 清理之前的测试数据 world.models.clear() for child in world.render.getChildren(): if child.getName() in ["test_cube", "fbx_model", "selectionBox", "gizmo"]: child.removeNode() print("1. 创建模拟FBX模型(大缩放值)...") # 创建一个模拟FBX导入的模型结构 from panda3d.core import CardMaker, ModelRoot # 创建根节点(使用ModelRoot确保保存/加载正常) model_root_node = ModelRoot("fbx_model") model_root = world.render.attachNewNode(model_root_node) # 创建子节点,模拟FBX的大缩放值 child_node = model_root.attachNewNode("mesh_node") child_node.setScale(100, 100, 100) # 模拟FBX的厘米到米转换问题 # 创建几何体 cm = CardMaker("geometry") cm.setFrame(-0.01, 0.01, -0.01, 0.01) # 很小的几何体,配合大缩放 geom = child_node.attachNewNode(cm.generate()) geom.setColor(0, 0, 1, 1) # 应用标准化(模拟导入时的处理) print("2. 应用缩放标准化...") normalize_factor = 0.01 # 1/100 child_node.setScale(child_node.getScale() * normalize_factor) child_node.setPos(child_node.getPos() * normalize_factor) print(f" 标准化后缩放: {child_node.getScale()}") print(f" 标准化后位置: {child_node.getPos()}") # 设置模型根的标准变换 model_root.setPos(0, 5, 0) model_root.setScale(2, 2, 2) # 设置碰撞检测 world.scene_manager.setupCollision(model_root) # 添加到模型列表 world.models.append(model_root) model_root.setTag("file", "test_fbx.fbx") model_root.setTag("is_model_root", "1") model_root.setTag("scale_normalization_applied", "true") print(f" 模型根位置: {model_root.getPos()}") print(f" 模型根缩放: {model_root.getScale()}") print(f" 模型边界: {model_root.getBounds().getMin()} 到 {model_root.getBounds().getMax()}") # 继续使用与前面测试相同的流程 print("\n3. 保存和加载测试...") # 创建临时文件 temp_dir = tempfile.mkdtemp(prefix="fbx_bounds_test_") scene_file = os.path.join(temp_dir, "fbx_test_scene.bam") try: # 保存场景 world.scene_manager.saveScene(scene_file) # 记录原始状态 original_bounds = model_root.getBounds() original_pos = model_root.getPos() original_scale = model_root.getScale() # 重新加载 world.scene_manager.loadScene(scene_file) # 检查结果 if world.models: loaded_model = world.models[0] loaded_bounds = loaded_model.getBounds() loaded_pos = loaded_model.getPos() loaded_scale = loaded_model.getScale() print(f" 原始边界大小: {(original_bounds.getMax() - original_bounds.getMin()).length():.3f}") print(f" 加载后边界大小: {(loaded_bounds.getMax() - loaded_bounds.getMin()).length():.3f}") pos_diff = (loaded_pos - original_pos).length() scale_diff = (loaded_scale - original_scale).length() print(f" 位置差异: {pos_diff:.6f}") print(f" 缩放差异: {scale_diff:.6f}") if pos_diff < 0.01 and scale_diff < 0.01: print("✓ FBX模拟测试通过") return True else: print("✗ FBX模拟测试失败") return False else: print("✗ 加载后没有找到模型") return False finally: # 清理临时文件 try: shutil.rmtree(temp_dir) except: pass if __name__ == "__main__": print("选择框边界问题测试\n") # 创建应用程序 app = QApplication.instance() if app is None: app = QApplication(sys.argv) # 创建世界(只创建一次) world = MyWorld() # 运行基础测试 test1_result = test_selection_bounds_with_world(world) # 运行FBX模拟测试 test2_result = test_fbx_simulation(world) print(f"\n=== 最终测试结果 ===") print(f"基础边界测试: {'通过' if test1_result else '失败'}") print(f"FBX模拟测试: {'通过' if test2_result else '失败'}") if test1_result and test2_result: print("\n🎉 所有测试通过!选择框边界问题已修复。") else: print("\n❌ 部分测试失败,需要进一步调试。")