"""Reads every exported FBX back into an empty scene and checks what is in it. Run: blender -b --python verify_fbx.py""" import bpy, os, glob, json from mathutils import Vector HERE = os.path.dirname(os.path.abspath(__file__)); ROOT = os.path.dirname(HERE) rep = json.load(open(os.path.join(HERE, 'build_report.json'))); out = {}; bad = [] for folder, want in (('fbx', rep['game_triangles_per_module']), ('fbx_low', {k: a['tri_count'] for k, a in rep['audit'].items()})): fdir = os.path.join(ROOT, folder) for path in sorted(glob.glob(os.path.join(fdir, '*.fbx')) + glob.glob(os.path.join(fdir, 'modules', '*.fbx'))): bpy.ops.wm.read_factory_settings(use_empty=True) bpy.ops.import_scene.fbx(filepath=path) arms = [o for o in bpy.data.objects if o.type == 'ARMATURE']; meshes = [o for o in bpy.data.objects if o.type == 'MESH'] name = folder + '/' + os.path.relpath(path, fdir).replace(os.sep, '/') if len(arms) != 1: bad.append((name, 'armatures', len(arms))); continue a = arms[0]; roots = [b.name for b in a.data.bones if b.parent is None] lo = Vector((1e9,) * 3); hi = Vector((-1e9,) * 3); unw = 0; tris = 0 for m in meshes: for v in m.data.vertices: p = m.matrix_world @ v.co for k in range(3): lo[k] = min(lo[k], p[k]); hi[k] = max(hi[k], p[k]) if not v.groups: unw += 1 m.data.calc_loop_triangles(); n = len(m.data.loop_triangles); tris += n if m.name in want and want[m.name] != n: bad.append((name, m.name, 'triangles', want[m.name], n)) if not any(md.type == 'ARMATURE' for md in m.modifiers): bad.append((name, m.name, 'no armature modifier')) if not m.data.uv_layers: bad.append((name, m.name, 'no uv')) if roots != ['root']: bad.append((name, 'roots', roots)) if len(a.data.bones) != rep['bones']: bad.append((name, 'bones', len(a.data.bones))) if unw: bad.append((name, 'unweighted verts', unw)) out[name] = dict(bones=len(a.data.bones), meshes=len(meshes), tris=tris, size_m=[round(hi[k] - lo[k], 3) for k in range(3)], lowest_z=round(lo.z, 4), materials=sorted({s.material.name for m in meshes for s in m.material_slots if s.material})) json.dump(dict(files=out, problems=bad), open(os.path.join(HERE, 'fbx_report.json'), 'w'), indent=1) for k, v in out.items(): if '/modules/' not in k: print('FBX', k, v['bones'], 'bones', v['meshes'], 'meshes', v['tris'], 'tris', 'size', v['size_m'], 'minz', v['lowest_z']) print('FBX FILES', len(out), 'PROBLEMS', len(bad), bad[:10])