211 lines
6.7 KiB
Markdown
211 lines
6.7 KiB
Markdown
# FBX模型缩放层级修复说明
|
||
|
||
## 🔍 问题描述
|
||
|
||
用户反馈FBX模型导入时会出现缩放层级混乱的问题:
|
||
- **根节点缩放**: 0.01(强制应用的单位转换)
|
||
- **子节点缩放**: 100(FBX内部的原始缩放)
|
||
- **视觉效果**: 正常显示,但层级结构复杂难处理
|
||
|
||
## ⚡ 问题原因分析
|
||
|
||
### 原始导入逻辑
|
||
```python
|
||
# 旧代码 - 强制FBX单位转换
|
||
if filepath.lower().endswith('.fbx'):
|
||
scale_factor = 0.01 # 厘米到米
|
||
model.setScale(scale_factor) # 根节点 = 0.01
|
||
```
|
||
|
||
### 层级结构混乱
|
||
```
|
||
FBX模型结构:
|
||
├─ 根节点 (setScale 0.01) ← 强制设置
|
||
│ ├─ 子节点A (原始缩放 100) ← FBX内部缩放
|
||
│ ├─ 子节点B (原始缩放 100) ← FBX内部缩放
|
||
│ └─ 子节点C (原始缩放 50) ← FBX内部缩放
|
||
|
||
结果: 0.01 × 100 = 1.0 (正常显示,但层级复杂)
|
||
```
|
||
|
||
## 🛠 解决方案
|
||
|
||
### 1. **新的导入逻辑**
|
||
```python
|
||
def importModel(self, filepath, apply_unit_conversion=False, normalize_scales=True):
|
||
"""新的导入方法 - 智能缩放处理"""
|
||
|
||
# 可选: 单位转换
|
||
if apply_unit_conversion and filepath.lower().endswith('.fbx'):
|
||
self._applyUnitConversion(model, 0.01)
|
||
|
||
# 智能: 缩放标准化(推荐开启)
|
||
if normalize_scales and filepath.lower().endswith('.fbx'):
|
||
self._normalizeModelScales(model)
|
||
|
||
# 只调整位置,不强制缩放
|
||
self._adjustModelToGround(model)
|
||
```
|
||
|
||
### 2. **智能缩放标准化**
|
||
新增核心功能,自动检测和处理FBX子节点的大缩放值:
|
||
- 🔍 **自动检测**: 扫描所有子节点,识别大缩放值(>10)
|
||
- 📊 **统计分析**: 找到最常见的大缩放值(如100)
|
||
- ⚙️ **智能标准化**: 计算合适的标准化因子(如1/100 = 0.01)
|
||
- 🎯 **精确应用**: 只处理有问题的大缩放节点
|
||
|
||
### 2. **保持原有结构的优势**
|
||
- ✅ **简化层级**: 避免0.01 × 100的复杂计算
|
||
- ✅ **保持一致**: 所有文件格式统一处理
|
||
- ✅ **用户选择**: 可选择是否应用单位转换
|
||
- ✅ **易于处理**: 缩放操作更直观
|
||
|
||
## 📊 修复对比
|
||
|
||
### **修复前**
|
||
```python
|
||
# 强制FBX单位转换
|
||
FBX根节点.setScale(0.01)
|
||
|
||
层级结构:
|
||
根节点(0.01) -> 子节点A(100) -> 孙子节点(1)
|
||
实际显示: 0.01 × 100 × 1 = 1.0 ✅视觉正常
|
||
处理复杂度: ❌复杂,需要考虑多层缩放
|
||
```
|
||
|
||
### **修复后**
|
||
```python
|
||
# 智能缩放标准化(推荐)
|
||
model.importModel(filepath, normalize_scales=True)
|
||
|
||
层级结构:
|
||
根节点(1.0) -> 子节点A(1.0) -> 孙子节点(1.0)
|
||
实际显示: 1.0 × 1.0 × 1.0 = 1.0 ✅完美
|
||
处理复杂度: ✅简单,统一缩放层级
|
||
|
||
# 或者保持原始结构
|
||
model.importModel(filepath, normalize_scales=False)
|
||
|
||
层级结构:
|
||
根节点(1.0) -> 子节点A(100) -> 孙子节点(1)
|
||
实际显示: 1.0 × 100 × 1 = 100 ⚠️可能很大
|
||
处理复杂度: ✅简单,但需要手动调整
|
||
```
|
||
|
||
## 🎛 使用方式
|
||
|
||
### **方式1: 智能导入(推荐)**
|
||
```python
|
||
# 默认开启缩放标准化,自动处理子节点大缩放值
|
||
model = world.importModel("model.fbx") # normalize_scales=True
|
||
```
|
||
|
||
### **方式2: 完全保持原始结构**
|
||
```python
|
||
# 关闭所有自动处理,保持FBX原始结构
|
||
model = world.importModel("model.fbx", normalize_scales=False)
|
||
```
|
||
|
||
### **方式3: 传统单位转换**
|
||
```python
|
||
# 应用厘米到米的转换 + 缩放标准化
|
||
model = world.importModel("model.fbx", apply_unit_conversion=True, normalize_scales=True)
|
||
```
|
||
|
||
### **方式4: 交互式测试**
|
||
```python
|
||
# 使用测试脚本
|
||
python demo/fbx_import_test.py
|
||
# 按U键切换单位转换模式
|
||
# 按N键切换缩放标准化模式
|
||
```
|
||
|
||
## 🧪 测试验证
|
||
|
||
### **测试场景**
|
||
1. **大型建筑模型**: 通常FBX使用厘米,模型会很大
|
||
2. **角色模型**: 通常已经合适的比例
|
||
3. **道具模型**: 混合使用情况
|
||
|
||
### **验证方法**
|
||
```bash
|
||
# 启动测试程序
|
||
python demo/fbx_import_test.py
|
||
|
||
# 测试步骤:
|
||
1. 导入FBX模型(默认保持原有缩放)
|
||
2. 按I键查看缩放信息
|
||
3. 按U键切换单位转换模式
|
||
4. 重新导入同一模型对比
|
||
5. 观察层级结构差异
|
||
```
|
||
|
||
## 🎯 智能位置调整
|
||
|
||
### **地面对齐算法**
|
||
```python
|
||
def _adjustModelToGround(self, model):
|
||
"""智能调整到地面,不改变缩放"""
|
||
bounds = model.getBounds()
|
||
min_point = bounds.getMin()
|
||
|
||
# 计算地面偏移(不涉及缩放)
|
||
ground_offset = -min_point.getZ()
|
||
model.setPos(0, 0, ground_offset)
|
||
```
|
||
|
||
### **优势**
|
||
- 🎯 **精确对齐**: 无论模型大小都能准确放在地面
|
||
- 🔄 **缩放无关**: 位置调整独立于缩放操作
|
||
- 🛡 **错误处理**: 边界获取失败时使用默认位置
|
||
|
||
## 📋 最佳实践建议
|
||
|
||
### **推荐工作流程**
|
||
1. **首次导入**: 使用默认设置(不转换单位)
|
||
2. **检查大小**: 如果模型过大,考虑单位转换
|
||
3. **手动调整**: 根据需要手动设置合适的缩放
|
||
4. **保存设置**: 记录适合项目的导入参数
|
||
|
||
### **针对不同模型类型**
|
||
| 模型类型 | 推荐设置 | 说明 |
|
||
|---------|---------|------|
|
||
| 建筑/场景 | 单位转换=True | 通常用厘米,需要转换 |
|
||
| 角色/动物 | 单位转换=False | 通常已合适比例 |
|
||
| 道具/物品 | 按情况选择 | 根据实际大小决定 |
|
||
| 机械设备 | 单位转换=True | CAD导出常用厘米 |
|
||
|
||
### **调试技巧**
|
||
```python
|
||
# 检查模型层级结构
|
||
def print_model_hierarchy(model, depth=0):
|
||
indent = " " * depth
|
||
print(f"{indent}{model.getName()}: scale={model.getScale()}")
|
||
for i in range(model.getNumChildren()):
|
||
print_model_hierarchy(model.getChild(i), depth+1)
|
||
```
|
||
|
||
## 🚀 总结
|
||
|
||
这次修复彻底解决了FBX导入时的缩放层级问题:
|
||
|
||
### 🎯 **核心突破**
|
||
- ✅ **智能标准化**: 自动检测并修复子节点大缩放值(如100 → 1)
|
||
- ✅ **统一层级**: 实现全模型1:1缩放,避免复杂的多层计算
|
||
- ✅ **保持结构**: 维护FBX内部的相对比例关系
|
||
- ✅ **零干扰**: 只处理有问题的节点,不影响正常节点
|
||
|
||
### 🔧 **技术优势**
|
||
- 🔍 **智能检测**: 自动扫描识别大缩放值
|
||
- 📊 **统计分析**: 基于最常见缩放值计算标准化因子
|
||
- ⚙️ **精确处理**: 只标准化明显异常的缩放(>10)
|
||
- 🎛️ **用户控制**: 提供完整的开关选项
|
||
|
||
### 📈 **效果对比**
|
||
| 处理方式 | 根节点缩放 | 子节点缩放 | 最终效果 | 推荐度 |
|
||
|---------|-----------|-----------|---------|--------|
|
||
| 旧方案 | 0.01 | 100 | 复杂层级 | ❌ |
|
||
| 关闭处理 | 1.0 | 100 | 模型过大 | ⚠️ |
|
||
| **智能标准化** | **1.0** | **1.0** | **完美统一** | ✅ |
|
||
|
||
现在用户可以简单地导入FBX模型,系统会自动处理所有缩放问题,实现真正的"一键导入,完美显示"! |