assets/characters/infantry/post_rig.py
2024-02-20 19:21:41 -05:00

193 lines
6.4 KiB
Python

import bpy
from bpy.types import Constraint, PoseBone
rig = bpy.data.objects["infantry"]
## FIX PARENTS
def reparent(b: str, newParent: str = 'DEF-spine'):
rig.data.edit_bones[b].parent = rig.data.edit_bones[newParent]
def fix(b: str):
p = rig.data.edit_bones[b].parent.name.replace('ORG','DEF')
reparent(b, p)
# Switch to EDIT mode to modify bone hiearchy to be proper for Unreal
bpy.ops.object.mode_set(mode='EDIT')
# List of bones that need to be reparented to their deforming counterparts
fixList = [
# Hands
'DEF-thumb01.L',
'DEF-index01.L',
'DEF-middle01.L',
'DEF-ring01.L',
'DEF-pinky01.L',
# Arms
'shoulder.L',
'breast.L',
# Legs
'DEF-thigh.L',
]
# Iterate through and fix each bone
for item in fixList:
fix(item)
if item.endswith('.L'): # If it's left-sided, fix right-side counterparts too
fix(item.replace('.L','.R'))
# Pelvis parents work a little differently
reparent('DEF-pelvis.L', 'DEF-spine')
reparent('DEF-pelvis.R', 'DEF-spine')
# Deform parents on palms are actually parented to originals, so skip that layer
reparent('DEF-palm.01.L', 'DEF-hand.L')
reparent('DEF-palm.02.L', 'DEF-hand.L')
reparent('DEF-palm.03.L', 'DEF-hand.L')
reparent('DEF-palm.04.L', 'DEF-hand.L')
reparent('DEF-palm.01.R', 'DEF-hand.R')
reparent('DEF-palm.02.R', 'DEF-hand.R')
reparent('DEF-palm.03.R', 'DEF-hand.R')
reparent('DEF-palm.04.R', 'DEF-hand.R')
## Force axe to be exported by setting it as a deform bone
#rig.data.edit_bones['axe'].use_deform = True
## Switch into POSE mode to set up animation constraints
bpy.ops.object.mode_set(mode='POSE')
### Declare Functions for animation constraints
def arrcopy(copyTo, copyFrom):
for i in range(min(len(copyTo), len(copyFrom))):
copyTo[i] = copyFrom[i]
def drv_blend_1D(shape_target: str, key_target: str, bone_name: str, max_x: float, prop: str = 'LOC_Y', formula: str = ''):
block = bpy.data.shape_keys[shape_target].key_blocks[key_target]
bmin = block.slider_min
bmax = block.slider_max
block.driver_remove('value')
fcurve = block.driver_add('value')
d = fcurve.driver
d.type = 'SCRIPTED'
if formula == '':
d.expression = str(bmax / max_x) + '*x'
else:
d.expression = formula
v = d.variables.new()
v.name = 'x'
v.type = 'TRANSFORMS'
t = v.targets[0]
t.id = rig
t.bone_target = bone_name
t.transform_type = prop
t.transform_space = 'LOCAL_SPACE'
def drv_constraint_1D(c: Constraint, bone_name: str, max_x: float, prop: str = 'LOC_Y', formula: str = ''):
bmin = 0.0
bmax = 1.0
c.driver_remove('influence')
fcurve = c.driver_add('influence')
d = fcurve.driver
d.type = 'SCRIPTED'
if formula == '':
d.expression = str(bmax / max_x) + '*x'
else:
d.expression = formula
v = d.variables.new()
v.name = 'x'
v.type = 'TRANSFORMS'
t = v.targets[0]
t.id = rig
t.bone_target = bone_name
t.transform_type = prop
t.transform_space = 'LOCAL_SPACE'
def drv_toggle_1D():
pass
def constrain_slider(b: PoseBone, minimum: float = 0, maximum: float = 0.06):
c = b.constraints.new('LIMIT_LOCATION')
c.use_min_y = True
c.use_max_y = True
c.min_y = minimum
c.max_y = maximum
c.use_transform_limit = True
c.owner_space = 'LOCAL'
def cpy_transforms(b: PoseBone, subtarget, influence = 1.0):
constraint = b.constraints.new('COPY_TRANSFORMS')
constraint.target = rig
constraint.subtarget = subtarget # note subtarget uses name not object
constraint.target_space = 'POSE'
constraint.owner_space = 'POSE'
constraint.influence = influence
return constraint
## Fix widget scalings, and constrain them
for b in rig.pose.bones:
## MENUS / WIDGETS
if b.name.startswith("menu_"):
b.use_custom_shape_bone_size = False
b.custom_shape_translation = (0.0, 0.03, 0.0)
b.custom_shape_scale_xyz = (0.06, 0.06, 0.0)
arrcopy(b.lock_scale, [False, True, False])
elif b.name.startswith("slider1d"):
b.use_custom_shape_bone_size = False
b.custom_shape_scale_xyz = (0.02, 0.003, 0.005)
arrcopy(b.lock_location, [True, False, True])
arrcopy(b.lock_rotation, [True, True, True])
arrcopy(b.lock_scale, [True, True, True])
b.lock_rotation_w = True
## WEAPONS
elif b.name.startswith("grip_baton"):
b.custom_shape_scale_xyz = (0.2, 2.6, 0.2)
b.custom_shape_translation = (0.0, 0.25, 0.0)
if not b.name.endswith("_free"):
b.custom_shape_scale_xyz *= 0.9
## BODY
elif b.name == "neck.001":
arrcopy(b.lock_location, [True, True, True])
## Constrain menu sliders so they are limited to proper bounds
#constrain_slider(rig.pose.bones.get('slider1d_axe_gripadjust'))
#constrain_slider(rig.pose.bones.get('slider1d_axe_lefthand_grip'))
#constrain_slider(rig.pose.bones.get('slider1d_axe_smear'), -0.03, 0.03)
## Arm and Hand switch for Axe Base
## https://blender.stackexchange.com/questions/46928/set-bone-constraints-via-python-api#46986
#axe_base = rig.pose.bones.get("axe_base")
#axe_constraint: Constraint = None
#if axe_base is not None:
# axe_constraint = axe_base.constraints.new('COPY_TRANSFORMS')
# axe_constraint.target = rig
# axe_constraint.subtarget = 'DEF-hand.R' # note subtarget uses name not object
# axe_constraint.target_space = 'POSE'
# axe_constraint.owner_space = 'POSE'
# axe_constraint.influence = 0.0
## Left-Hand grip switch for Axe
#left_hand = rig.pose.bones.get("hand_ik.L")
#lh_constraint: Constraint = None
#if axe_base is not None:
# lh_constraint = left_hand.constraints.new('COPY_TRANSFORMS')
# lh_constraint.target = rig
# lh_constraint.subtarget = 'axe_grip_lefthand' # note subtarget uses name not object
# lh_constraint.target_space = 'POSE'
# lh_constraint.owner_space = 'POSE'
# lh_constraint.influence = 0.0
baton_grip = rig.pose.bones.get("grip_baton")
bg_constraint = cpy_transforms(baton_grip, 'grip_baton_free', 1.0)
drv_constrain_1D(bg_constraint, 'slider1d_baton_IK-FK', 0.06)
### Set up driver constraint for the switches
#drv_constraint_1D(axe_constraint, 'slider1d_axe_gripadjust', 0.06)
#drv_constraint_1D(lh_constraint, 'slider1d_axe_lefthand_grip', 0.06)
### Set up smear effect drivers for axe
#drv_blend_1D('Key', 'smear_down', 'slider1d_axe_smear', 0.03)
#drv_blend_1D('Key', 'smear_up', 'slider1d_axe_smear', -0.03)