Skip to content

Commit

Permalink
support for rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
artellblender authored Sep 20, 2019
1 parent 2cf1ac9 commit 331918f
Showing 1 changed file with 93 additions and 88 deletions.
181 changes: 93 additions & 88 deletions spring_bones.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
bl_info = {
"name": "Spring Bones",
"author": "Artell",
"version": (0, 1),
"version": (0, 2),
"blender": (2, 80, 0),
"location": "Properties > Bones",
"description": "Add a spring dynamic effect to a single/multiple bones",
Expand Down Expand Up @@ -33,41 +33,22 @@ def spring_bone():
for bone in scene.spring_bones:
armature = bpy.data.objects[bone.armature]
pose_bone = armature.pose.bones[bone.name]
head = pose_bone.head
arm_mat = armature.matrix_world
head = arm_mat @ head
emp_tail = bpy.data.objects.get(bone.name + '_spring_tail')
emp_head = bpy.data.objects.get(bone.name + '_spring')

emp1 = bpy.data.objects.get(bone.name + '_spring_tail')
emp2 = bpy.data.objects.get(bone.name + '_spring')

if emp1 == None or emp2 == None:
if emp_tail == None or emp_head == None:
print("no empties found, return")
return

emp1_loc, rot, scale = emp1.matrix_world.decompose()

if bone.last_loc == (0,0,0):
bone.last_loc = head

head_dir = (head - bone.last_loc)

bone.last_loc = head

dir = emp1_loc - emp2.location
emp_tail_loc, rot, scale = emp_tail.matrix_world.decompose()

dir = emp_tail_loc - emp_head.location
bone.speed += dir
bone.speed *= pose_bone.stiffness
emp2.location += bone.speed * pose_bone.damp
"""
if head_dir.magnitude != 0.0:
bone.speed = (emp1_loc -emp2.location)* pose_bone.damp
emp2.location += bone.speed
else:
dir = emp1_loc - emp2.location
bone.speed += dir
bone.speed *= pose_bone.stiffness
emp2.location += bone.speed * pose_bone.damp
"""
print("evaluating")
emp_head.location += bone.speed * pose_bone.damp


return None


Expand All @@ -76,7 +57,7 @@ def update_bone(self, context):
scene = bpy.context.scene

armature = bpy.context.active_object

#update collection
#delete all
if len(scene.spring_bones) > 0:
Expand All @@ -87,57 +68,81 @@ def update_bone(self, context):

#add
for bone in armature.pose.bones:
if len(bone.keys()) > 0:
if 'bone_spring' in bone.keys():
if bone['bone_spring']:
item = scene.spring_bones.add()
item.name = bone.name
#bone_tail = armature.matrix_world @ bone.tail
bone_head = armature.matrix_world @ bone.head
item.last_loc = bone_head
item.armature = armature.name
parent_name = bone.parent.name

#create empty helpers
if not bpy.data.objects.get(item.name + '_spring'):
bpy.ops.object.mode_set(mode='OBJECT')
print("create", item.name + '_spring')
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.empty_add(type='PLAIN_AXES', radius = 0.01, location=bone_head, rotation=(0,0,0))
empty = bpy.context.active_object
empty.name = item.name + '_spring'

if not bpy.data.objects.get(item.name + '_spring_tail'):
bpy.ops.object.mode_set(mode='OBJECT')
print("create", item.name + '_spring_tail')
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.empty_add(type='PLAIN_AXES', radius = 0.01, location=bone_head, rotation=(0,0,0))
empty = bpy.context.active_object
empty.name = item.name + '_spring_tail'
empty.parent = armature
empty.parent_type = 'BONE'
empty.parent_bone = parent_name
empty.matrix_world = bpy.data.objects[item.name + '_spring'].matrix_world

#create constraints
set_active_object(armature.name)
bpy.ops.object.mode_set(mode='POSE')
if bone.constraints.get('spring') == None:
#cns = bone.constraints.new('DAMPED_TRACK')
cns = bone.constraints.new('COPY_LOCATION')
cns.target = bpy.data.objects[item.name + '_spring']
cns.name = 'spring'
if len(bone.keys()) == 0:
continue
if not 'bone_spring' in bone.keys():
continue

if bone['bone_spring'] == False:
spring_cns = bone.constraints.get("spring")
if spring_cns:
bone.constraints.remove(spring_cns)
continue

item = scene.spring_bones.add()
item.name = bone.name
bone_tail = armature.matrix_world @ bone.tail
bone_head = armature.matrix_world @ bone.head
item.last_loc = bone_head
item.armature = armature.name
parent_name = bone.parent.name
rotation_enabled = False
if 'bone_rot' in bone.keys():
if bone["bone_rot"]:
rotation_enabled = True
item.bone_rot = rotation_enabled

#create empty helpers
if not bpy.data.objects.get(item.name + '_spring'):
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='DESELECT')
if rotation_enabled:
bpy.ops.object.empty_add(type='PLAIN_AXES', radius = 0.01, location=bone_tail, rotation=(0,0,0))
else:
bpy.ops.object.empty_add(type='PLAIN_AXES', radius = 0.01, location=bone_head, rotation=(0,0,0))
empty = bpy.context.active_object
empty.hide_select = True
empty.name = item.name + '_spring'

if not bpy.data.objects.get(item.name + '_spring_tail'):
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='DESELECT')
if rotation_enabled:
bpy.ops.object.empty_add(type='PLAIN_AXES', radius = 0.01, location=bone_tail, rotation=(0,0,0))
else:
bpy.ops.object.empty_add(type='PLAIN_AXES', radius = 0.01, location=bone_head, rotation=(0,0,0))
empty = bpy.context.active_object
empty.hide_select = True
mat = empty.matrix_world.copy()
empty.name = item.name + '_spring_tail'
empty.parent = armature
empty.parent_type = 'BONE'
empty.parent_bone = parent_name
empty.matrix_world = mat#bpy.data.objects[item.name + '_spring'].matrix_world

#create constraints
if bone['bone_spring']:
set_active_object(armature.name)
bpy.ops.object.mode_set(mode='POSE')
spring_cns = bone.constraints.get("spring")
if spring_cns:
bone.constraints.remove(spring_cns)
if bone.bone_rot:
cns = bone.constraints.new('DAMPED_TRACK')
cns.target = bpy.data.objects[item.name + '_spring']
else:
cns = bone.constraints.new('COPY_LOCATION')
cns.target = bpy.data.objects[item.name + '_spring']
cns.name = 'spring'

print('Bones Collection:')
for i, item in enumerate(scene.spring_bones):
print(item.name)

set_active_object(armature.name)
bpy.ops.object.mode_set(mode='POSE')

print("Updated.")





def end_spring_bone(context, self):
if self.timer_handler:
wm = context.window_manager
Expand All @@ -146,7 +151,6 @@ def end_spring_bone(context, self):
context.scene.global_spring = False

for item in context.scene.spring_bones:
print(item.name)

active_bone = bpy.context.active_object.pose.bones.get(item.name)
if active_bone == None:
Expand Down Expand Up @@ -179,8 +183,7 @@ def modal(self, context, event):
end_spring_bone(context, self)
return {'FINISHED'}

if event.type == 'TIMER':
print("spring bones...")
if event.type == 'TIMER':
spring_bone()

return {'PASS_THROUGH'}
Expand All @@ -189,7 +192,7 @@ def modal(self, context, event):
def execute(self, context):
args = (self, context)

# enable skin selection
# enable spring bone
if context.scene.global_spring == False:
wm = context.window_manager
self.timer_handler = wm.event_timer_add(0.02, window=context.window)
Expand All @@ -201,10 +204,10 @@ def execute(self, context):

return {'RUNNING_MODAL'}

# disable skin selection
# disable spring selection
else:
print("--End modal--")
context.scene.global_spring = False
end_spring_bone(context, self)
return {'FINISHED'}


Expand All @@ -215,8 +218,7 @@ class SB_PT_ui(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = 'bone'
bl_label = "Spring Bones"

bl_label = "Spring Bones"

@classmethod
def poll(cls, context):
Expand All @@ -238,11 +240,12 @@ def draw(self, context):
if context.scene.global_spring == False:
col.operator(SB_OT_spring_modal.bl_idname, text="Start", icon='PLAY')
if context.scene.global_spring == True:
col.operator(SB_OT_spring_modal.bl_idname, text="Start", icon='PAUSE')
col.operator(SB_OT_spring_modal.bl_idname, text="Stop", icon='PAUSE')
col = layout.column(align=True)

col.label(text='Bone Parameters:')
col.prop(active_bone, 'bone_spring', text="Enable Bone")
col.prop(active_bone, 'bone_rot', text="Rotation")
col.prop(active_bone, 'stiffness', text="Bouncy")
col.prop(active_bone,'damp', text="Speed")

Expand All @@ -255,6 +258,7 @@ class bones_collec(bpy.types.PropertyGroup):
speed : bpy.props.FloatVectorProperty(name="Speed", subtype='DIRECTION', default=(0,0,0), size = 3)
dist: bpy.props.FloatProperty(name="distance", default=1.0)
target_offset : bpy.props.FloatVectorProperty(name="TargetLoc", subtype='DIRECTION', default=(0,0,0), size = 3)
bone_rot : bpy.props.BoolProperty(name="Bone Rot", default=False)
matrix_offset = Matrix()
initial_matrix = Matrix()

Expand All @@ -270,10 +274,10 @@ def register():

bpy.types.Scene.spring_bones = bpy.props.CollectionProperty(type=bones_collec)
bpy.types.Scene.global_spring = bpy.props.BoolProperty(name="Enable spring", default = False)#, update=update_global_spring)
bpy.types.PoseBone.bone_spring = bpy.props.BoolProperty(name="Enabled", default=False, description="Enable this bone for spring", update=update_bone)
bpy.types.PoseBone.bone_spring = bpy.props.BoolProperty(name="Enabled", default=False, description="Enable this bone for spring")
bpy.types.PoseBone.stiffness = bpy.props.FloatProperty(name="Stiffness", default=0.5, min = 0.01, max = 1.0)
bpy.types.PoseBone.damp = bpy.props.FloatProperty(name="Damp", default=0.7, min=0.0, max = 1.0)

bpy.types.PoseBone.damp = bpy.props.FloatProperty(name="Damp", default=0.7, min=0.0, max = 10.0)
bpy.types.PoseBone.bone_rot = bpy.props.BoolProperty(name="Rotation", default=False, description="Enable spring rotation instead of location")

def unregister():
from bpy.utils import unregister_class
Expand All @@ -288,6 +292,7 @@ def unregister():
del bpy.types.PoseBone.stiffness
del bpy.types.PoseBone.damp
del bpy.types.PoseBone.bone_spring
del bpy.types.PoseBone.bone_rot


if __name__ == "__main__":
Expand Down

0 comments on commit 331918f

Please sign in to comment.