"""Read native imported data; fmtf matches upstream tests/python/modules/io_report.py.""" import bpy, hashlib, json def fmtf(f): return '0.000' if abs(f) < 0.0005 else f'{f:.3f}' def value(item): if isinstance(item, float): return fmtf(item) if item is None or isinstance(item, (str, int, bool)): return item return [value(component) for component in item] objects = [] for obj in sorted(bpy.context.scene.objects, key=lambda item: item.name): record = dict(name=obj.name, type=obj.type, matrix=value(obj.matrix_world), parent=obj.parent.name if obj.parent else None) record['collections'] = sorted((c.name, c.hide_viewport, c.hide_render) for c in obj.users_collection) if obj.type == 'MESH': record['mesh'] = dict(vertices=[value(v.co) for v in obj.data.vertices], faces=[list(p.vertices) for p in obj.data.polygons], materials=[m.name if m else None for m in obj.data.materials]) record['mesh']['uv'] = [(layer.name, [value(loop.uv) for loop in layer.data]) for layer in obj.data.uv_layers] record['mesh']['groups'] = [(group.name, group.index) for group in obj.vertex_groups] record['mesh']['weights'] = [[(group.group, fmtf(group.weight)) for group in vertex.groups] for vertex in obj.data.vertices] record['mesh']['modifiers'] = [(m.name, m.type, getattr(m, 'object', None).name if getattr(m, 'object', None) else None) for m in obj.modifiers] if obj.type == 'ARMATURE': record['bones'] = [dict(name=b.name, parent=b.parent.name if b.parent else None, matrix=value(b.matrix_local), head=value(b.head_local), tail=value(b.tail_local), deform=b.use_deform) for b in obj.data.bones] animation = obj.animation_data record['animation'] = None if not animation else dict(action=animation.action.name if animation.action else None, nla=[(track.name, track.mute, [(s.name, s.action.name if s.action else None, fmtf(s.frame_start), fmtf(s.frame_end)) for s in track.strips]) for track in animation.nla_tracks]) objects.append(record) materials = [] for material in sorted(bpy.data.materials, key=lambda item: item.name): tree = material.node_tree nodes = [] if tree is None else [dict(name=n.name, type=n.bl_idname, image=n.image.name if getattr(n, 'image', None) else None, inputs=[(s.identifier, value(getattr(s, 'default_value', None))) for s in n.inputs]) for n in sorted(tree.nodes, key=lambda item: item.name)] links = [] if tree is None else sorted((link.from_node.name, link.from_socket.identifier, link.to_node.name, link.to_socket.identifier) for link in tree.links) materials.append(dict(name=material.name, nodes=nodes, links=links)) images = [] for image in sorted(bpy.data.images, key=lambda item: item.name): if image.type != 'IMAGE': continue pixels = hashlib.sha256(','.join(fmtf(p) for p in image.pixels[:]).encode()).hexdigest() packed = hashlib.sha256(image.packed_file.data).hexdigest() if image.packed_file else None images.append(dict(name=image.name, size=list(image.size), colorspace=image.colorspace_settings.name, packed=packed, pixels=pixels)) actions = [] for action in sorted(bpy.data.actions, key=lambda item: item.name): channels = [] for layer in action.layers: for strip in layer.strips: if strip.type != 'KEYFRAME': continue for bag in strip.channelbags: for curve in sorted(bag.fcurves, key=lambda c: (c.data_path, c.array_index)): channels.append(dict(layer=layer.name, slot=bag.slot.identifier if bag.slot else None, path=curve.data_path, index=curve.array_index, extrapolation=curve.extrapolation, keys=[(value(k.co), value(k.handle_left), value(k.handle_right), k.interpolation, k.handle_left_type, k.handle_right_type) for k in curve.keyframe_points])) actions.append(dict(name=action.name, slots=[s.identifier for s in action.slots], channels=channels)) print(json.dumps(dict(objects=objects, materials=materials, images=images, actions=actions), separators=(',', ':')))