forked from Rowland/EG
4.7 KiB
4.7 KiB
FBX模型缩放标准化位置修复说明
问题描述
在FBX模型导入时,经常遇到子节点有大缩放值(如100)的问题。我们的缩放标准化功能可以将这些大缩放值调整为1,但最初的实现存在一个重要问题:只调整了缩放,没有相应调整位置,导致子节点之间的距离变得过大。
问题分析
原始FBX结构(示例)
根节点 (缩放: 1.0, 位置: 0,0,0)
├── 子节点A (缩放: 100, 位置: 0,0,0)
├── 子节点B (缩放: 100, 位置: 60,5,320)
└── 子节点C (缩放: 100, 位置: -16,-3,-347)
问题:仅缩放标准化
根节点 (缩放: 1.0, 位置: 0,0,0)
├── 子节点A (缩放: 1.0, 位置: 0,0,0) ✓ 正常
├── 子节点B (缩放: 1.0, 位置: 60,5,320) ✗ 距离过大!
└── 子节点C (缩放: 1.0, 位置: -16,-3,-347) ✗ 距离过大!
问题根源:原来在100倍缩放下,(60,5,320)这样的位置是合理的,因为视觉上的有效距离会被缩放影响。但当缩放变成1时,这个位置就显得过大了。
解决方案
核心思路
当我们将子节点的缩放按比例缩小时,也要将它们的位置按相同比例缩小,以保持视觉上的相对关系。
修复后的标准化
根节点 (缩放: 1.0, 位置: 0,0,0)
├── 子节点A (缩放: 1.0, 位置: 0,0,0) ✓ 正常
├── 子节点B (缩放: 1.0, 位置: 0.6,0.05,3.2) ✓ 距离合理
└── 子节点C (缩放: 1.0, 位置: -0.16,-0.03,-3.47) ✓ 距离合理
技术实现
修复前的代码
def _applyScaleNormalization(self, node, normalize_factor, depth=0):
# 只调整缩放
if max_scale_component > 10:
new_scale = current_scale * normalize_factor
node.setScale(new_scale)
# 位置保持不变 - 这是问题所在!
修复后的代码
def _applyScaleNormalization(self, node, normalize_factor, depth=0):
# 同时调整缩放和位置
if max_scale_component > 10:
# 应用新的缩放
new_scale = current_scale * normalize_factor
node.setScale(new_scale)
# 同时调整位置:保持视觉相对位置一致
new_pos = current_pos * normalize_factor
node.setPos(new_pos)
效果对比
修复前
- ✅ 缩放值正确(100 → 1.0)
- ❌ 子节点距离过大(几百个单位)
- ❌ 视觉布局异常
修复后
- ✅ 缩放值正确(100 → 1.0)
- ✅ 子节点距离合理(几个单位)
- ✅ 视觉布局保持原有比例关系
测试验证
使用测试脚本验证修复效果:
1. 位置测试脚本
cd demo
python scale_position_test.py
按T键运行完整的位置测试,检查:
- 缩放因子是否正确(100 → 1.0)
- 位置缩放是否正确(位置 × 0.01)
- 相对位置关系是否保持
2. FBX导入测试
cd demo
python fbx_import_test.py
导入实际的FBX文件,使用I键查看模型信息,确认:
- 子节点缩放标准化为1.0
- 子节点位置为合理数值
- 整体视觉效果正常
算法详解
标准化因子计算
- 收集缩放信息:递归扫描所有节点的缩放值
- 识别大缩放:找出缩放值 > 10 的节点
- 统计最常见值:使用Counter找到最频繁的大缩放值(如100)
- 计算标准化因子:normalize_factor = 1.0 / common_large_scale
同步调整规则
# 对于每个需要标准化的节点
if max_scale_component > 10:
new_scale = current_scale * normalize_factor # 缩放调整
new_pos = current_pos * normalize_factor # 位置同步调整
配置选项
在importModel方法中提供灵活配置:
# 推荐配置(默认)
world.importModel("model.fbx",
apply_unit_conversion=False, # 不使用传统单位转换
normalize_scales=True) # 使用智能缩放标准化
# 传统配置
world.importModel("model.fbx",
apply_unit_conversion=True, # 使用传统0.01根缩放
normalize_scales=False) # 不使用智能标准化
# 完全保持原始
world.importModel("model.fbx",
apply_unit_conversion=False, # 不转换
normalize_scales=False) # 不标准化
总结
这个修复解决了FBX模型缩放标准化时的关键问题:
- 保持视觉一致性:子节点之间的相对位置关系不变
- 简化层级结构:避免复杂的缩放层级组合
- 提高易用性:导入后的模型结构直观易懂
- 兼容性好:不影响现有功能,提供可选配置
这确保了"一键导入,完美显示"的用户体验,解决了FBX模型导入中的核心痛点。