|
@ -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) |
|
|
|
|
|
|
|
|