1
0
forked from Rowland/EG
EG/demo/test_selection_bounds.py
2025-07-10 09:19:51 +08:00

359 lines
11 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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❌ 部分测试失败,需要进一步调试。")