13
$\begingroup$

Blender stores the session contents in a binary file format. But actually, much of that data is not really "binary" (like a e.g. a sound file), but structured data, similar to program code.

Are there any tools (either built-in or external), allowing to find out the precise difference between two blender files? And if so, when working with these tools, are spurious diffs an issue? (e.g. rounding errors in numbers, reordering of entries in collections).

Background information: I'm trying to build up a controlled work environment and workflow, as I know it from software development.

$\endgroup$

1 Answer 1

12
$\begingroup$

You would need to write an export script to dump all the data of the .blend files you want to compare into a text file.

From python you could use difflib to compare them like:

import difflib
import os

old_file = "C:\\Users\\user\Documents\\Blender\\dump1.txt"
new_file = "C:\\Users\\user\Documents\\Blender\\dump2.txt"
print(os.getcwd()) 
a = open(old_file).readlines()
b = open(new_file).readlines()
diff_string = difflib.unified_diff(a=a, b=b)

for line in diff_string:
    print(line)

While it makes almost no sense to compare the meshes between edited versions of a mesh (besides some stats like how the number of polygons has increased etc.) In this BA thread you find more thoughts on that. CoDEmanX linked his git project blend_stats there.

I started a script which is incomplete and has issues with links in objects. You could use it as a starting point and improve it:

import bpy
import mathutils

map={}
debug = False

def dump(obj, name="", level=0):
    if level > 10:
        return
    if debug:
        print("call %d obj=%s type=%s" % (level, str(obj), str(type(obj))))
    if str(type(obj)) in ("<class 'builtin_function_or_method'>",):
        return
    if isinstance(obj, mathutils.Vector):
        print("%s=%s" % (name,str(obj.to_tuple())))
        return

    if str(type(obj)) == "<class 'bpy_prop_collection'>":
        for item in obj:
            dump( item, name , level+1)
            return

    if str(type(obj)) == "<class 'tuple'>":
        idx=0
        for item in obj:
            dump( item, name + "[" +str(idx) + "]", level+1)
            idx = idx+1
            return;

    for attr in dir(obj):
       if not hasattr(obj, attr ) or attr.startswith("__") or attr in ("bl_rna","base","rna_type"):
           continue
       if attr == "particle_edit":
           return # crashes otherwise
       if name+"."+attr in map:
           if debug  or True:
               print("already dumped=%s" % name+"."+attr )
           return
       map[name+"."+attr]=obj     
       val = getattr(obj, attr)
       if isinstance(val, (int, float, str, bool)):
          print("%s.%s=%s" % (name,attr,val))
       else:
          dump( val, name + "." + attr, level+1)

print(60*"-")
dump(bpy.data,"bpy.data")
$\endgroup$
1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .