a3c38aa92a
- 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) - 搭建指南: 全局地面中心坐标+西边界旋转统一+院门改双开门
124 lines
3.9 KiB
Python
124 lines
3.9 KiB
Python
"""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()
|