Replace TownSquare with HomeCamp art and land humanoid bots, LittleBear, and LmGirl review assets.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
"""Verify a final static FBX against its Studio GLB, using full scene transforms."""
|
||||
import sys,json,math,hashlib
|
||||
from pathlib import Path
|
||||
import bpy
|
||||
import numpy as np
|
||||
from mathutils import Matrix
|
||||
|
||||
sys.path.insert(0,str(Path(__file__).resolve().parent))
|
||||
from bl_decimate import prepare_game_export,validate_fbx_yup_scene
|
||||
|
||||
folder=Path(sys.argv[sys.argv.index('--')+1]).resolve()
|
||||
name=sys.argv[sys.argv.index('--')+2]
|
||||
source=folder/'model_ex.glb';target=folder/'static'/(name+'.fbx')
|
||||
out=folder/'axis_pipeline_audit';out.mkdir(parents=True,exist_ok=True)
|
||||
|
||||
def load(path):
|
||||
bpy.ops.wm.read_factory_settings(use_empty=True)
|
||||
if path.suffix=='.fbx':bpy.ops.import_scene.fbx(filepath=str(path),use_anim=False)
|
||||
else:bpy.ops.import_scene.gltf(filepath=str(path),merge_vertices=False)
|
||||
meshes=[o for o in bpy.context.scene.objects if o.type=='MESH']
|
||||
assert len(meshes)==1
|
||||
return meshes[0]
|
||||
|
||||
def uv(obj):return np.array([tuple(v.uv) for v in obj.data.uv_layers.active.data],dtype='<f4')
|
||||
def triangles(obj):return sum(len(p.vertices)-2 for p in obj.data.polygons)
|
||||
|
||||
obj=load(source);prepare_game_export(obj,restore_axis=True)
|
||||
expected=np.array([Matrix.Rotation(math.pi/2,4,'X')@obj.matrix_world@v.co for v in obj.data.vertices])
|
||||
source_uv=uv(obj);source_triangles=triangles(obj)
|
||||
axes=validate_fbx_yup_scene(str(target))
|
||||
obj=load(target);actual=np.array([obj.matrix_world@v.co for v in obj.data.vertices]);target_uv=uv(obj)
|
||||
assert actual.shape==expected.shape and triangles(obj)==source_triangles
|
||||
error=float(np.max(np.abs(actual-expected)));assert error<2e-6
|
||||
assert np.array_equal(target_uv,source_uv)
|
||||
lo=actual.min(0);hi=actual.max(0)
|
||||
assert np.argmax(hi-lo)==2,'The complete scene is horizontal in Blender Z-up'
|
||||
origin_error=max(abs(lo[2]),abs((lo[0]+hi[0])/2),abs((lo[1]+hi[1])/2));assert origin_error<2e-6
|
||||
legacy=out/'legacy'/(name+'.fbx')
|
||||
legacy_rejected=None
|
||||
if legacy.is_file():
|
||||
try:validate_fbx_yup_scene(str(legacy));legacy_rejected=False
|
||||
except ValueError:legacy_rejected=True
|
||||
report=dict(source=str(source),fbx=str(target),sha256=hashlib.sha256(target.read_bytes()).hexdigest(),
|
||||
axes=axes,vertices=len(actual),triangles=source_triangles,uv_preserved=True,
|
||||
uv_sha256=hashlib.sha256(target_uv.tobytes()).hexdigest(),upright=True,
|
||||
height_m=float(hi[2]-lo[2]),bottom_center_error_m=float(origin_error),
|
||||
max_position_error_m=error,legacy_rejected_by_axis_guard=legacy_rejected,
|
||||
blender_world_bounds_min=lo.tolist(),blender_world_bounds_max=hi.tolist())
|
||||
convention=json.loads((Path(__file__).resolve().parents[2]/'Config/Art/ModelConvention.json').read_text(encoding='utf-8'))
|
||||
receipt_path=folder/'mesh_receipt.json'
|
||||
receipt=json.loads(receipt_path.read_text(encoding='utf-8')) if receipt_path.is_file() else {}
|
||||
front=receipt.get('fbxAxes',{}).get('anatomicalFront') if receipt.get('fbxSha256')==report['sha256'] else None
|
||||
report.update(project_forward=convention['forwardAxis'],anatomical_front=front,
|
||||
project_front_conforms=(front==convention['forwardAxis']) if front else None,
|
||||
front_visual_check_required=front is None)
|
||||
(out/'verification.json').write_text(json.dumps(report,indent=2),encoding='utf-8')
|
||||
print('STATIC_VERIFICATION '+json.dumps(report))
|
||||
Reference in New Issue
Block a user