Files
ChildHood/tools/asset-catalog/build_database.py
T
starmen1265 7a2436a612 feat(asset-catalog): 简化分析工具+新增汇总和AI推理脚本
- analyze_meshes: 移除失败的 LineTrace 和六面分析,只保留基础属性
  (包围盒、锚点、复杂度、Socket、材质槽位、自动Tag)
- build_database: 新增离线汇总脚本,将 meshes/*.json 扁平化为
  统一的 asset_database.json
- ai_inference: 新增 GLM API 批量推理脚本,按类别分批推断语义信息
  (朝向、表面高度、功能描述、交互属性、降级方案)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 00:50:56 +08:00

148 lines
4.5 KiB
Python

"""资产数据库汇总脚本。
读取 asset-catalog 的扫描结果(meshes/*.json),汇总为统一的单文件
asset_database.json,以资产名为 key 扁平化存储。
此脚本不依赖 UE5,可离线运行。
用法:
python build_database.py [--input DIR] [--output FILE]
--input 扫描输出目录,默认 output/asset-catalog
--output 输出文件路径,默认 <input>/asset_database.json
"""
import sys
import argparse
from pathlib import Path
_SCRIPT_DIR = Path(__file__).resolve().parent
if str(_SCRIPT_DIR) not in sys.path:
sys.path.insert(0, str(_SCRIPT_DIR))
from _common import read_json, write_json, iso_now
TAG = "[BuildDB]"
def build_database(input_dir: Path, output_file: Path) -> dict:
"""汇总 meshes/*.json 为统一数据库。
Args:
input_dir: 包含 meshes/ 子目录的扫描输出根目录
output_file: 输出的 asset_database.json 路径
Returns:
统计信息 dict
"""
meshes_dir = input_dir / "meshes"
if not meshes_dir.exists():
print(f"{TAG} 错误: {meshes_dir} 不存在,请先运行 analyze_meshes")
return {"status": "error", "reason": "no meshes dir"}
# 收集所有子目录的扫描文件
mesh_files = sorted(meshes_dir.glob("*.json"))
if not mesh_files:
print(f"{TAG} 错误: {meshes_dir} 下无 JSON 文件")
return {"status": "error", "reason": "no mesh files"}
print(f"{TAG} 发现 {len(mesh_files)} 个扫描文件")
# 扁平化合并
assets = {}
total = 0
skipped = 0
for mf in mesh_files:
try:
data = read_json(mf)
except Exception as e:
print(f"{TAG} 警告: 读取 {mf.name} 失败: {e}")
continue
subfolder = data.get("subfolder", mf.stem)
meshes = data.get("meshes", {})
if not meshes:
continue
for name, mesh_data in meshes.items():
total += 1
# 跳过无包围盒的(加载失败的)
if mesh_data.get("bounding_box") is None:
skipped += 1
continue
# 构建统一条目
entry = {
"ue_path": mesh_data.get("ue_path", ""),
"subfolder": subfolder,
"bounding_box": mesh_data.get("bounding_box"),
"pivot": mesh_data.get("pivot"),
"mesh_complexity": mesh_data.get("mesh_complexity", {}),
"material_slots": mesh_data.get("material_slots", []),
"sockets": mesh_data.get("sockets", []),
"tags": {
"style": mesh_data.get("style_tags", []),
"scene": mesh_data.get("scene_tags", []),
},
"ai_inference": None,
}
# 如果资产名重复(不同子目录下同名),加后缀
key = name
if key in assets:
safe_sub = subfolder.replace("/", "_").replace("\\", "_")
key = f"{name}_{safe_sub}"
print(f"{TAG} 注意: 资产名重复 {name},使用 {key}")
assets[key] = entry
# 写入数据库
db = {
"metadata": {
"generated_at": iso_now(),
"source": "asset_catalog_v1",
"total_assets": len(assets),
"skipped_no_bbox": skipped,
"input_files": [mf.name for mf in mesh_files],
},
"assets": assets,
}
write_json(db, output_file)
print(f"{TAG} ✅ 汇总完成: {len(assets)} 个资产 → {output_file}")
print(f"{TAG} 跳过 {skipped} 个无包围盒资产 / 总计 {total}")
return {
"status": "ok",
"total": total,
"assets": len(assets),
"skipped": skipped,
}
def main():
parser = argparse.ArgumentParser(description="汇总资产扫描数据为统一 JSON 数据库")
parser.add_argument(
"--input", type=str,
default=str(_SCRIPT_DIR.parent.parent / "output" / "asset-catalog"),
help="扫描输出目录 (默认: output/asset-catalog)",
)
parser.add_argument(
"--output", type=str, default=None,
help="输出文件路径 (默认: <input>/asset_database.json)",
)
args = parser.parse_args()
input_dir = Path(args.input)
output_file = Path(args.output) if args.output else input_dir / "asset_database.json"
result = build_database(input_dir, output_file)
if result.get("status") != "ok":
sys.exit(1)
if __name__ == "__main__":
main()