| 
						
						
							
								
							
						
						
					 | 
					@ -18,6 +18,8 @@ Usage: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					''' | 
					 | 
					 | 
					''' | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					import bpy | 
					 | 
					 | 
					import bpy | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					from mathutils import Vector, Quaternion | 
					 | 
					 | 
					from mathutils import Vector, Quaternion | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					import mathutils | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					import math | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					context = bpy.context | 
					 | 
					 | 
					context = bpy.context | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					print("") | 
					 | 
					 | 
					print("") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					print("[ EnlivenMinetest/utilities/blender/hierarchy_of_empties_to_bones.py ] started") | 
					 | 
					 | 
					print("[ EnlivenMinetest/utilities/blender/hierarchy_of_empties_to_bones.py ] started") | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -27,6 +29,7 @@ armature_display_type = 'OCTAHEDRAL' | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					# ^ Can be: ('OCTAHEDRAL', 'STICK', 'BBONE', 'ENVELOPE', 'WIRE') | 
					 | 
					 | 
					# ^ Can be: ('OCTAHEDRAL', 'STICK', 'BBONE', 'ENVELOPE', 'WIRE') | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#   default: 'OCTAHEDRAL' | 
					 | 
					 | 
					#   default: 'OCTAHEDRAL' | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					def mat3_to_vec_roll(mat): | 
					 | 
					 | 
					def mat3_to_vec_roll(mat): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    ''' | 
					 | 
					 | 
					    ''' | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    Convert a mat3 to a tuple containing a vec and roll. | 
					 | 
					 | 
					    Convert a mat3 to a tuple containing a vec and roll. | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -105,6 +108,7 @@ def vec_roll_to_mat3(vec, roll): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    mat = rMatrix * bMatrix | 
					 | 
					 | 
					    mat = rMatrix * bMatrix | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    return mat | 
					 | 
					 | 
					    return mat | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					def getFirstChild(parentName): | 
					 | 
					 | 
					def getFirstChild(parentName): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for obj in bpy.data.objects: | 
					 | 
					 | 
					    for obj in bpy.data.objects: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        if obj.parent is None: | 
					 | 
					 | 
					        if obj.parent is None: | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -113,6 +117,7 @@ def getFirstChild(parentName): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            return obj | 
					 | 
					 | 
					            return obj | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    return None | 
					 | 
					 | 
					    return None | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					def getRealRotation_broken(cumulative_rotation, empty): | 
					 | 
					 | 
					def getRealRotation_broken(cumulative_rotation, empty): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    if cumulative_rotation is None: | 
					 | 
					 | 
					    if cumulative_rotation is None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        cumulative_rotation = Quaternion((1, 0, 0, 0)) | 
					 | 
					 | 
					        cumulative_rotation = Quaternion((1, 0, 0, 0)) | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -164,6 +169,19 @@ def getRealRotation(empty): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    raise NotImplementedError("Fake recursion isn't implemented for hierarchies this deep.") | 
					 | 
					 | 
					    raise NotImplementedError("Fake recursion isn't implemented for hierarchies this deep.") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					def vectorDiff(v1, v2): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    if len(v1) != len(v2): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        raise ValueError("v1 length is {} but v2 length is {}".format(len(v1), len(v2))) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    if len(v1) == 4: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        return Vector((v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2], v1[3]-v2[3])) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    elif len(v1) == 3: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        return Vector((v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2])) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    else: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        raise ValueError("v1 and v1 are of length {} but that is not a known valid location vector length.".format(len(v1))) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    return None | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					def makeSameChildren(empty, armature, parent_bone, parent_empty, cumulative_rotation, cumulative_scale, depth=0): | 
					 | 
					 | 
					def makeSameChildren(empty, armature, parent_bone, parent_empty, cumulative_rotation, cumulative_scale, depth=0): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    ''' | 
					 | 
					 | 
					    ''' | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    Make a new bone for the given empty, then do the same | 
					 | 
					 | 
					    Make a new bone for the given empty, then do the same | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -212,8 +230,9 @@ def makeSameChildren(empty, armature, parent_bone, parent_empty, cumulative_rota | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					         | 
					 | 
					 | 
					         | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # create bone at armature origin and set its length | 
					 | 
					 | 
					        # create bone at armature origin and set its length | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        scale = cumulative_scale * empty.scale.z | 
					 | 
					 | 
					        scale = cumulative_scale * empty.scale.z | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        boneLength = length * scale | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        current_bone.head = [0, 0, 0] | 
					 | 
					 | 
					        current_bone.head = [0, 0, 0] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        current_bone.tail = [0, 0, length * scale] | 
					 | 
					 | 
					        current_bone.tail = [0, 0, boneLength] | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # rotate bone | 
					 | 
					 | 
					        # rotate bone | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # print(depth*" "+"  - empty.rotation_quaternion:{}".format(Quaternion(empty.rotation_quaternion))) | 
					 | 
					 | 
					        # print(depth*" "+"  - empty.rotation_quaternion:{}".format(Quaternion(empty.rotation_quaternion))) | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -231,15 +250,32 @@ def makeSameChildren(empty, armature, parent_bone, parent_empty, cumulative_rota | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # transform_quat = parent_bone_quat_armature_space @ current_bone_quat_parent_space | 
					 | 
					 | 
					        # transform_quat = parent_bone_quat_armature_space @ current_bone_quat_parent_space | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # transform_quat = current_bone_quat_parent_space @ cumulative_rotation | 
					 | 
					 | 
					        # transform_quat = current_bone_quat_parent_space @ cumulative_rotation | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # transform_quat = Quaternion(empty.rotation_quaternion) @ Quaternion(empty.parent.rotation_quaternion) | 
					 | 
					 | 
					        # transform_quat = Quaternion(empty.rotation_quaternion) @ Quaternion(empty.parent.rotation_quaternion) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        transform_quat = getRealRotation(empty) | 
					 | 
					 | 
					        # transform_quat = getRealRotation(empty) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # ^ getRealRotation(emtpy) gives same result as current_bone_quat_parent_space @ cumulative_rotation | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # transform_quat = current_bone_quat_parent_space | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # transform_quat = getRealRotation(empty) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        transform_quat = empty.rotation_quaternion | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        current_bone.transform(transform_quat.to_matrix()) | 
					 | 
					 | 
					        current_bone.transform(transform_quat.to_matrix()) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # current_bone.tail = transform_quat.to_matrix() @ current_bone.tail | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					         | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # matrix = transform_quat.to_matrix() | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # tail, roll = mat3_to_vec_roll(matrix) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # current_bone.head = matrix.to_translation() | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # ^ ValueError: Matrix.to_translation(): inappropriate matrix size | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # tail, roll = mat3_to_vec_roll(matrix.to_3x3()) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # current_bone.head = matrix.to_translation() | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # ^ ValueError: Matrix.to_translation(): inappropriate matrix size | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        #current_bone.tail = tail*boneLength + bone.head | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        #current_bone.roll = roll | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					         | 
					 | 
					 | 
					         | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # set position | 
					 | 
					 | 
					        # set position | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # new_relative_loc = Quaternion(empty.location) | 
					 | 
					 | 
					        # new_relative_loc = Quaternion(empty.location) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # ^ The empty.location is relative to the parent_empty's head | 
					 | 
					 | 
					        # ^ The empty.location is relative to the parent_empty's head | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # but must be made relative the parent_bone's tail. | 
					 | 
					 | 
					        # but must be made relative the parent_bone's tail. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        old_to_new = Vector(parent_bone.tail) - Vector(parent_empty.location) | 
					 | 
					 | 
					        # old_to_new = Vector(parent_empty.location) - Vector(parent_bone.tail) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        new_relative_loc = Vector(empty.location) - old_to_new | 
					 | 
					 | 
					        old_to_new = vectorDiff(parent_empty.location, parent_bone.tail) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        # new_relative_loc = old_to_new - Vector(empty.location) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        new_relative_loc = vectorDiff(old_to_new, empty.location) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # uhoh_if_nonzero = Vector(parent_bone.head) - Vector(parent_empty.location) | 
					 | 
					 | 
					        # uhoh_if_nonzero = Vector(parent_bone.head) - Vector(parent_empty.location) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # print(depth*" "+"  - uhoh_if_nonzero:{}".format(uhoh_if_nonzero)) | 
					 | 
					 | 
					        # print(depth*" "+"  - uhoh_if_nonzero:{}".format(uhoh_if_nonzero)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # ^ It is nonzero :( | 
					 | 
					 | 
					        # ^ It is nonzero :( | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -248,7 +284,7 @@ def makeSameChildren(empty, armature, parent_bone, parent_empty, cumulative_rota | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        print(depth*" "+"  - old_to_new:{}".format(old_to_new)) | 
					 | 
					 | 
					        print(depth*" "+"  - old_to_new:{}".format(old_to_new)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        print(depth*" "+"  - new_relative_loc:{}".format(new_relative_loc)) | 
					 | 
					 | 
					        print(depth*" "+"  - new_relative_loc:{}".format(new_relative_loc)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # print(depth*" "+"  - current_bone_offset:{}".format(current_bone_offset)) | 
					 | 
					 | 
					        # print(depth*" "+"  - current_bone_offset:{}".format(current_bone_offset)) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        current_bone.translate(Vector(new_relative_loc)) | 
					 | 
					 | 
					        current_bone.translate(new_relative_loc) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        # connect | 
					 | 
					 | 
					        # connect | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        current_bone.parent = parent_bone | 
					 | 
					 | 
					        current_bone.parent = parent_bone | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -290,8 +326,11 @@ def makeSameChildren(empty, armature, parent_bone, parent_empty, cumulative_rota | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                continue | 
					 | 
					 | 
					                continue | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            makeSameChildren(child, armature, current_bone, empty, transform_quat, scale, depth=depth+1) | 
					 | 
					 | 
					            makeSameChildren(child, armature, current_bone, empty, transform_quat, scale, depth=depth+1) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					def makeSameChildrenFromRootEmpty(obj): | 
					 | 
					 | 
					def makeSameChildrenFromRootEmpty(obj): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					# for obj in bpy.data.objects: | 
					 | 
					 | 
					    if obj is None: | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        print("Nothing is selected.") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        return | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    if obj.type != 'EMPTY': | 
					 | 
					 | 
					    if obj.type != 'EMPTY': | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        print("non-Empty {} type: {} isn't compatible with this script".format(obj.name, obj.type)) | 
					 | 
					 | 
					        print("non-Empty {} type: {} isn't compatible with this script".format(obj.name, obj.type)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        return | 
					 | 
					 | 
					        return | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -326,5 +365,6 @@ def makeSameChildrenFromRootEmpty(obj): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    # else: | 
					 | 
					 | 
					    # else: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    #     print("{} parent: {}".format(obj.name, obj.parent)) | 
					 | 
					 | 
					    #     print("{} parent: {}".format(obj.name, obj.parent)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					makeSameChildrenFromRootEmpty(context.view_layer.objects.active) | 
					 | 
					 | 
					makeSameChildrenFromRootEmpty(context.view_layer.objects.active) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
					 | 
					
  |