40 lines
2.7 KiB
Python
40 lines
2.7 KiB
Python
"""Read-only comparison of static and Mixamo FBX UVs/materials/textures."""
|
|
import json,hashlib
|
|
from pathlib import Path
|
|
import bpy
|
|
import numpy as np
|
|
from io_scene_fbx import parse_fbx
|
|
|
|
ROOT=Path(__file__).resolve().parents[2]
|
|
OUT=ROOT/'Tools/output/lmgirl_tpose_studio/material_audit'
|
|
OUT.mkdir(parents=True,exist_ok=True)
|
|
def inspect(path):
|
|
tree,_=parse_fbx.parse(str(path))
|
|
objects=next(e for e in tree.elems if e.id==b'Objects')
|
|
raw=[]
|
|
for e in objects.elems:
|
|
if e.id not in (b'Material',b'Texture',b'Video',b'Geometry'):continue
|
|
item=dict(type=e.id.decode(),name=str(e.props[1]))
|
|
if e.id==b'Geometry':item['uv_layers']=[dict(name=str(x.id),children=[str(v.id) for v in x.elems]) for x in e.elems if x.id==b'LayerElementUV']
|
|
if e.id in (b'Texture',b'Video'):item['files']=[str(x.props) for x in e.elems if x.id in (b'FileName',b'RelativeFilename',b'Filename')];item['embedded_bytes']=sum(len(x.props[0]) for x in e.elems if x.id==b'Content' and x.props and isinstance(x.props[0],bytes))
|
|
raw.append(item)
|
|
bpy.ops.wm.read_factory_settings(use_empty=True)
|
|
bpy.ops.import_scene.fbx(filepath=str(path),use_anim=False)
|
|
meshes=[];uv_values=[]
|
|
for obj in bpy.context.scene.objects:
|
|
if obj.type!='MESH':continue
|
|
layers=[]
|
|
for layer in obj.data.uv_layers:
|
|
values=np.array([tuple(v.uv) for v in layer.data],dtype='<f4')
|
|
if layer==obj.data.uv_layers.active:uv_values.extend(values.tolist())
|
|
layers.append(dict(name=layer.name,corners=len(values),min=values.min(0).tolist(),max=values.max(0).tolist(),unique=len(np.unique(values,axis=0)),sha256=hashlib.sha256(values.tobytes()).hexdigest()))
|
|
meshes.append(dict(name=obj.name,vertices=len(obj.data.vertices),triangles=sum(len(p.vertices)-2 for p in obj.data.polygons),uv=layers,
|
|
material_slots=[dict(name=s.material.name if s.material else None,images=[dict(name=n.image.name,path=n.image.filepath) for n in s.material.node_tree.nodes if n.type=='TEX_IMAGE' and n.image] if s.material and s.material.use_nodes else []) for s in obj.material_slots]))
|
|
return dict(path=str(path.relative_to(ROOT)),sha256=hashlib.sha256(path.read_bytes()).hexdigest(),raw=raw,meshes=meshes),np.array(sorted(tuple(np.round(v,6)) for v in uv_values))
|
|
|
|
source,source_uv=inspect(ROOT/'Tools/output/lmgirl_tpose_studio/static/LmGirlTpose.fbx')
|
|
mixamo,mixamo_uv=inspect(ROOT/'AIClient/Assets/Bundles/Characters/Human/test/girl/LmGirlTpose.fbx')
|
|
report=dict(source=source,mixamo=mixamo,uv_corner_multiset_equal=source_uv.shape==mixamo_uv.shape and bool(np.array_equal(source_uv,mixamo_uv)))
|
|
(OUT/'fbx_materials.json').write_text(json.dumps(report,indent=2),encoding='utf-8')
|
|
print(json.dumps(report,indent=2))
|