chore:模型调整
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
"""Batch-convert GLB files to FBX through Blender.
|
||||
|
||||
Run this file with Blender's Python, not the system Python. The script keeps
|
||||
the source folder layout and writes an errors.csv next to the output files.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--source", required=True, type=Path)
|
||||
parser.add_argument("--destination", required=True, type=Path)
|
||||
parser.add_argument("--overwrite", action="store_true")
|
||||
return parser.parse_args(sys.argv[sys.argv.index("--") + 1 :] if "--" in sys.argv else [])
|
||||
|
||||
|
||||
def clear_scene() -> None:
|
||||
bpy.ops.object.select_all(action="SELECT")
|
||||
bpy.ops.object.delete(use_global=False)
|
||||
for collection in (bpy.data.meshes, bpy.data.materials, bpy.data.images, bpy.data.armatures):
|
||||
for item in list(collection):
|
||||
collection.remove(item)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
source = args.source.resolve()
|
||||
destination = args.destination.resolve()
|
||||
if not source.is_dir():
|
||||
print(f"ERROR: source folder does not exist: {source}")
|
||||
return 2
|
||||
if source == destination:
|
||||
print("ERROR: destination must be different from source")
|
||||
return 2
|
||||
|
||||
glb_files = sorted(source.rglob("*.glb"))
|
||||
destination.mkdir(parents=True, exist_ok=True)
|
||||
errors: list[tuple[str, str]] = []
|
||||
converted = skipped = 0
|
||||
|
||||
for index, input_file in enumerate(glb_files, start=1):
|
||||
output_file = destination / input_file.relative_to(source).with_suffix(".fbx")
|
||||
if output_file.exists() and not args.overwrite:
|
||||
print(f"[{index}/{len(glb_files)}] SKIP {input_file.name}")
|
||||
skipped += 1
|
||||
continue
|
||||
output_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
clear_scene()
|
||||
bpy.ops.import_scene.gltf(filepath=str(input_file))
|
||||
bpy.ops.export_scene.fbx(
|
||||
filepath=str(output_file),
|
||||
use_selection=False,
|
||||
object_types={"EMPTY", "CAMERA", "LIGHT", "ARMATURE", "MESH", "OTHER"},
|
||||
use_mesh_modifiers=True,
|
||||
add_leaf_bones=False,
|
||||
path_mode="COPY",
|
||||
embed_textures=True,
|
||||
)
|
||||
converted += 1
|
||||
print(f"[{index}/{len(glb_files)}] OK {input_file.name}")
|
||||
except Exception as exc: # continue converting the remaining assets
|
||||
errors.append((str(input_file), repr(exc)))
|
||||
print(f"[{index}/{len(glb_files)}] FAIL {input_file.name}: {exc}")
|
||||
|
||||
if errors:
|
||||
error_log = destination / "errors.csv"
|
||||
with error_log.open("w", newline="", encoding="utf-8-sig") as handle:
|
||||
writer = csv.writer(handle)
|
||||
writer.writerow(("source_file", "error"))
|
||||
writer.writerows(errors)
|
||||
print(f"Error log: {error_log}")
|
||||
print(f"Finished: {converted} converted, {skipped} skipped, {len(errors)} failed.")
|
||||
return 1 if errors else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user