fix(level-builder): 锚点补偿+旋转修复+天空盒+解析器去重

- asset_mapping: 38种BSP资产实测锚点+pivot_offset_xy自动补偿
- scene_builder: Rotator改关键字参数修正旋转轴映射
- scene_builder: spawn前XY锚点补偿(支持Yaw旋转)
- scene_builder: 新增ExponentialHeightFog+大气效果后处理
- build_cmdline: 构建后自动添加雾+GameMode+DirectionalLight大气
- build_guide_parser: 去重+全局地面+旋转列名兼容+边界段范围修正
- BarrierWall实际尺寸修正(60×210非20×100)
- 搭建指南: 全局地面中心坐标+西边界旋转统一+院门改双开门
This commit is contained in:
2026-06-08 19:05:50 +08:00
parent c3c10a9fcb
commit a3c38aa92a
13 changed files with 1284 additions and 1879 deletions
+123
View File
@@ -0,0 +1,123 @@
"""BSP 资产锚点检测脚本。
在 UE5 编辑器 Python 环境中运行,检测每个资产的 Bounds Origin,
判断锚点是中心、角落还是底部中心。
用法:
方式1 — 命令行: python main.py check-pivots
方式2 — 编辑器内: exec(open(r"check_pivots.py").read())
"""
import sys
import os
from pathlib import Path
# 将 level-builder 根目录加入 sys.path
_SCRIPT_DIR = Path(__file__).resolve().parent
_LB_DIR = _SCRIPT_DIR
if str(_LB_DIR) not in sys.path:
sys.path.insert(0, str(_LB_DIR))
from config.asset_mapping import MESH_ASSETS
try:
import unreal
HAS_UNREAL = True
except ImportError:
HAS_UNREAL = False
def check_pivots():
"""检测所有 BSP 资产的锚点类型。"""
if not HAS_UNREAL:
print("[错误] 需要在 UE5 编辑器 Python 环境中运行")
return
results = []
for name, info in MESH_ASSETS.items():
path = info["path"]
default_size = info.get("default_size")
mesh = unreal.load_asset(path)
if not mesh:
results.append(f"{name}: ⚠️ 无法加载")
continue
# 获取 Bounding Box (UE5 Box 对象有 min/max,没有 origin/extent)
bb = mesh.get_bounding_box()
bmin = bb.min
bmax = bb.max
mn_x, mn_y, mn_z = bmin.x, bmin.y, bmin.z
mx_x, mx_y, mx_z = bmax.x, bmax.y, bmax.z
size_x = mx_x - mn_x
size_y = mx_y - mn_y
size_z = mx_z - mn_z
# 判断锚点类型:
# CENTER: min ≈ (-half, -half, -half),对称包围盒
# CORNER: min ≈ (0, 0, 0),锚点在角落
# CENTER_BOTTOM: min ≈ (-half, -half, 0),锚点在底部中心
pivot_type = "UNKNOWN"
offset_desc = ""
if default_size:
dw, dh, dd = default_size
half_w, half_h, half_d = dw / 2, dh / 2, dd / 2
tol = 5 # cm 容差
is_corner = (abs(mn_x) < tol and abs(mn_y) < tol and abs(mn_z) < tol)
is_center = (abs(mn_x + half_w) < tol and abs(mn_y + half_h) < tol
and abs(mn_z + half_d) < tol)
is_center_bot = (abs(mn_x + half_w) < tol and abs(mn_y + half_h) < tol
and abs(mn_z) < tol)
if is_corner:
pivot_type = "CORNER"
elif is_center:
pivot_type = "CENTER"
elif is_center_bot:
pivot_type = "CENTER_BOTTOM"
else:
pivot_type = "OTHER"
offset_desc = f" (min=({mn_x:.0f},{mn_y:.0f},{mn_z:.0f}), expected corner=0/center=-{half_w:.0f})"
else:
# 无 default_size,用 min 值推断
tol = 5
if abs(mn_x) < tol and abs(mn_y) < tol and abs(mn_z) < tol:
pivot_type = "CORNER?"
elif mn_z < -tol:
pivot_type = "CENTER?"
else:
pivot_type = "CENTER_BOTTOM?"
offset_desc = f" (no default_size, inferred)"
results.append(
f"{name}:\n"
f" min=({mn_x:.1f}, {mn_y:.1f}, {mn_z:.1f}) "
f"max=({mx_x:.1f}, {mx_y:.1f}, {mx_z:.1f}) "
f"size=({size_x:.0f}, {size_y:.0f}, {size_z:.0f})\n"
f" default_size={default_size} → pivot={pivot_type}{offset_desc}"
)
print("=" * 60)
print("BSP 资产锚点检测结果")
print("=" * 60)
for r in results:
print(r)
print("=" * 60)
# 保存结果
out_path = Path(__file__).parent / "output" / "pivot_check.txt"
out_path.parent.mkdir(exist_ok=True)
with open(out_path, "w", encoding="utf-8") as f:
f.write("BSP 资产锚点检测结果\n")
f.write("=" * 60 + "\n")
for r in results:
f.write(r + "\n")
print(f"\n结果已保存: {out_path}")
# 供命令行调用
if __name__ == "__main__":
check_pivots()