"""실제 10/11 원본을 각각 다시 열어 모델·재질·기준 컬렉션 재사용을 대조한다.""" import hashlib import json from pathlib import Path import bpy ROOT=Path(__file__).resolve().parents[3] PROJECT=ROOT/'projects/water-hydrogen-bond-surface-tension' def signature(source): bpy.ops.wm.open_mainfile(filepath=str(source)) assert not bpy.data.libraries and not bpy.data.images and not bpy.data.fonts and not bpy.data.sounds meshes={} for obj in bpy.data.objects: if obj.type=='MESH': meshes[obj.name]=dict(vertices=[tuple(v.co) for v in obj.data.vertices],polygons=[tuple(p.vertices) for p in obj.data.polygons],materials=[m.name for m in obj.data.materials]) materials={} for material in bpy.data.materials: nodes=[] for node in material.node_tree.nodes if material.use_nodes else []: values=[] for socket in node.inputs: if hasattr(socket,'default_value'): value=socket.default_value if not isinstance(value,(str,int,float,bool)): value=list(value) if hasattr(value,'__iter__') else str(value) values.append((socket.name,value)) nodes.append((node.type,values)) materials[material.name]=dict(diffuse=list(material.diffuse_color),nodes=nodes) return dict(meshes=meshes,materials=materials,collections={c.name:sorted(o.name for o in c.objects) for c in bpy.data.collections},scenes={s.name:dict(objects=sorted(o.name for o in s.objects),camera=s.camera.name,ortho_scale=s.camera.data.ortho_scale) for s in bpy.data.scenes}) reference=PROJECT/'stages/10-references/r2/generated-source/references.blend' animation=PROJECT/'stages/11-images/r2/generated-source/animation.blend' baseline=signature(reference) actual=signature(animation) assert baseline==actual, '실제 기준 모델·재질·컬렉션·카메라 재사용 불일치' reference_hash=hashlib.sha256(reference.read_bytes()).hexdigest() assert all(s['reference_source_sha256']==reference_hash for s in bpy.data.scenes), '10 원본 해시 연결 불일치' value=dict(result='GREEN',reference_source_sha256=reference_hash,animation_source_sha256=hashlib.sha256(animation.read_bytes()).hexdigest(),actual_reopened_sources=2,mesh_objects=len(actual['meshes']),materials=len(actual['materials']),scenes=len(actual['scenes']),matching_fields=['local_mesh_vertices','polygons','material_slots','material_nodes','collection_members','scene_members','actual_camera_name','orthographic_scale']) (PROJECT/'stages/11-images/r2/reuse-check.json').write_text(json.dumps(value,ensure_ascii=False,indent=2)+'\n',encoding='utf-8') print('실제 10→11 기준 재사용 GREEN',value['mesh_objects'])