auto_walk/fn.py

194 lines
5.6 KiB
Python
Raw Normal View History

2021-04-05 01:35:12 +02:00
import bpy
import re
2021-04-08 19:25:05 +02:00
import numpy as np
2022-03-29 18:46:33 +02:00
from mathutils import Matrix, Vector, Color
2021-04-05 01:35:12 +02:00
def get_addon_prefs():
'''
function to read current addon preferences properties
access with : get_addon_prefs().super_special_option
'''
import os
addon_name = os.path.splitext(__name__)[0]
preferences = bpy.context.preferences
addon_prefs = preferences.addons[addon_name].preferences
return (addon_prefs)
def helper(name: str = '') -> str:
'''Return name and arguments from calling obj as str
:name: - replace definition name by your own str
'''
if not get_addon_prefs().debug:
return
import inspect
func = inspect.currentframe().f_back
name = name or f'def {func.f_code.co_name}'
args = inspect.getargvalues(func).locals
arguments = ', '.join([f'{k}={v}' for k, v in args.items()])
return(f'{name}({arguments})')
2021-04-08 19:25:05 +02:00
def convertAttr(Attr):
'''Convert given value to a Json serializable format'''
2022-03-29 18:46:33 +02:00
if type(Attr) in [type(Vector()),type(Color())]:
2021-04-08 19:25:05 +02:00
if len(Attr) == 3:
return([Attr[0],Attr[1],Attr[2]])
elif len(Attr) == 2:
return([Attr[0],Attr[1]])
elif len(Attr) == 1:
return([Attr[0]])
elif len(Attr) == 4:
return([Attr[0],Attr[1],Attr[2],Attr[3]])
2022-03-29 18:46:33 +02:00
elif type(Attr) == type(Matrix()):
2021-04-08 19:25:05 +02:00
return (np.matrix(Attr).tolist())
else:
return(Attr)
2021-04-05 01:35:12 +02:00
def get_gnd():
for o in bpy.context.scene.objects:
if o.type == 'MESH' and o.name.lower() in ('ground', 'gnd'):
return o
# nothing found
print('ERROR', 'No "gnd" object found')
def get_follow_curve_from_armature(arm):
"""Return curve and constraint or a tuple of string ('error', 'message')
"""
pref = get_addon_prefs()
name = pref.tgt_bone
parents = []
2021-04-06 18:30:25 +02:00
# root = b.id_data.pose.bones.get(name)
root = arm.pose.bones.get(name)
2021-04-05 01:35:12 +02:00
for c in root.constraints:
if c.type == 'FOLLOW_PATH':
const = c
if c.type == 'CHILD_OF':
print(f'found child-of on {name}')
if c.target:
parents.append(c.target)
if not const:
for p in parents:
for c in p.constraints:
if c.type == 'FOLLOW_PATH':
print('INFO', f'follow_path found on "{p.name}" parent object')
const = c
break
if not const:
return ('ERROR', 'No constraints founds')
curve = const.target
if not curve:
return ('ERROR', f'no target set for {curve.name}')
return curve, const
2021-04-06 18:30:25 +02:00
# --- ACTIONS
2021-04-05 01:35:12 +02:00
def get_obj_action(obj):
print(helper())
act = obj.animation_data
if not act:
print('ERROR', f'no animation data on {obj.name}')
return
act = act.action
if not act:
print('ERROR', f'no action on {obj.name}')
return
return act
def set_generated_action(obj):
'''Backup object action and return a new action suffixed '_autogen'
associated with the object
'''
print(helper())
act = get_obj_action(obj)
if not act: return
regen = re.compile(r'_autogen\.?\d{0,3}$')
if regen.search(act.name):
# is an autogenerated one
org_action_name = regen.sub('', act.name)
org_action = bpy.data.actions.get(org_action_name)
if not org_action:
print('ERROR', f'{org_action_name} not found')
return
obj.animation_data.action = org_action
bpy.data.actions.remove(act)
act = org_action
# backup action before doing anything crazy
act.use_fake_user = True
new_act = act.copy()
new_act.name = act.name + '_autogen'
obj.animation_data.action = new_act
return new_act
2021-04-06 18:30:25 +02:00
def set_expanded_action(obj):
'''Backup object action and return a new action
associated with the object
'''
print(helper())
rexpand = re.compile(r'_expanded\.?\d{0,3}$')
act = obj.animation_data.action
if rexpand.search(act.name):
# is an autogenerated one
org_action_name = rexpand.sub('', act.name)
org_action = bpy.data.actions.get(org_action_name)
if not org_action:
print('ERROR', f'{org_action_name} not found')
return
obj.animation_data.action = org_action
bpy.data.actions.remove(act)
act = org_action
# backup action before doing anything crazy
act.use_fake_user = True
new_act = act.copy()
new_act.name = act.name + '_expanded'
obj.animation_data.action = new_act
return new_act
2021-04-05 01:35:12 +02:00
def get_curve_length(ob):
2022-03-29 18:46:33 +02:00
'''Get a curve object, return a float representing world space length'''
2021-04-05 01:35:12 +02:00
dg = bpy.context.evaluated_depsgraph_get()
obeval = ob.evaluated_get(dg)#.copy()
baked_me = obeval.to_mesh(preserve_all_data_layers=False, depsgraph=dg)
mat = obeval.matrix_world
total_length = 0
for i, _v in enumerate(baked_me.vertices):
if i == 0:
continue
total_length += ((mat @ baked_me.vertices[i-1].co) - (mat @ baked_me.vertices[i].co)).length
print("total_length", total_length)#Dbg
2022-03-29 18:46:33 +02:00
return total_length
def scale_matrix_from_vector(scale):
# recreate a neutral mat scale
matscale_x = Matrix.Scale(scale[0], 4,(1,0,0))
matscale_y = Matrix.Scale(scale[1], 4,(0,1,0))
matscale_z = Matrix.Scale(scale[2], 4,(0,0,1))
matscale = matscale_x @ matscale_y @ matscale_z
return matscale
def compose_matrix(loc, rot, scale):
loc_mat = Matrix.Translation(loc)
rot_mat = rot.to_matrix().to_4x4()
scale_mat = scale_matrix_from_vector(scale)
return loc_mat @ rot_mat @ scale_mat