update ccic tools

This commit is contained in:
Nathan
2026-07-16 12:50:13 -06:00
parent 0f26db3345
commit c51a8313b5
81 changed files with 7341 additions and 1652 deletions
BIN
View File
Binary file not shown.
@@ -0,0 +1,173 @@
{
"Bones": {
"CC_Base_L_Clavicle": 1.0,
"CC_Base_L_Upperarm": 1.0,
"CC_Base_L_Forearm": 1.0,
"CC_Base_L_ForearmTwist01": 1.0,
"CC_Base_L_ForearmTwist02": 1.0,
"CC_Base_L_ElbowShareBone": 1.0,
"CC_Base_L_Hand": 1.0,
"CC_Base_L_Pinky1": 1.0,
"CC_Base_L_Pinky2": 1.0,
"CC_Base_L_Pinky3": 1.0,
"CC_Base_L_Ring1": 1.0,
"CC_Base_L_Ring2": 1.0,
"CC_Base_L_Ring3": 1.0,
"CC_Base_L_Mid1": 1.0,
"CC_Base_L_Mid2": 1.0,
"CC_Base_L_Mid3": 1.0,
"CC_Base_L_Index1": 1.0,
"CC_Base_L_Index2": 1.0,
"CC_Base_L_Index3": 1.0,
"CC_Base_L_Thumb1": 1.0,
"CC_Base_L_Thumb2": 1.0,
"CC_Base_L_Thumb3": 1.0,
"CC_Base_L_UpperarmTwist01": 1.0,
"CC_Base_L_UpperarmTwist02": 1.0,
"CC_Base_R_Clavicle": 1.0,
"CC_Base_R_Upperarm": 1.0,
"CC_Base_R_Forearm": 1.0,
"CC_Base_R_ElbowShareBone": 1.0,
"CC_Base_R_ForearmTwist01": 1.0,
"CC_Base_R_ForearmTwist02": 1.0,
"CC_Base_R_Hand": 1.0,
"CC_Base_R_Ring1": 1.0,
"CC_Base_R_Ring2": 1.0,
"CC_Base_R_Ring3": 1.0,
"CC_Base_R_Mid1": 1.0,
"CC_Base_R_Mid2": 1.0,
"CC_Base_R_Mid3": 1.0,
"CC_Base_R_Thumb1": 1.0,
"CC_Base_R_Thumb2": 1.0,
"CC_Base_R_Thumb3": 1.0,
"CC_Base_R_Index1": 1.0,
"CC_Base_R_Index2": 1.0,
"CC_Base_R_Index3": 1.0,
"CC_Base_R_Pinky1": 1.0,
"CC_Base_R_Pinky2": 1.0,
"CC_Base_R_Pinky3": 1.0,
"CC_Base_R_UpperarmTwist01": 1.0,
"CC_Base_R_UpperarmTwist02": 1.0,
"hand_tweak.L": 1.0,
"forearm_tweak.L": 1.0,
"forearm_tweak.L.001": 1.0,
"upper_arm_tweak.L.001": 1.0,
"upper_arm_parent.L": 1.0,
"upper_arm_fk.L": 1.0,
"forearm_fk.L": 1.0,
"hand_fk.L": 1.0,
"upper_arm_ik.L": 1.0,
"upper_arm_tweak.L": 1.0,
"f_index.01_master.L": 1.0,
"thumb.01_master.L": 1.0,
"f_index.01.L": 1.0,
"f_index.02.L": 1.0,
"f_index.03.L": 1.0,
"f_index.01.L.001": 1.0,
"thumb.01.L": 1.0,
"thumb.02.L": 1.0,
"thumb.03.L": 1.0,
"thumb.01.L.001": 1.0,
"f_middle.01_master.L": 1.0,
"f_middle.01.L": 1.0,
"f_middle.02.L": 1.0,
"f_middle.03.L": 1.0,
"f_middle.01.L.001": 1.0,
"f_ring.01_master.L": 1.0,
"f_ring.01.L": 1.0,
"f_ring.02.L": 1.0,
"f_ring.03.L": 1.0,
"f_ring.01.L.001": 1.0,
"f_pinky.01_master.L": 1.0,
"f_pinky.01.L": 1.0,
"f_pinky.02.L": 1.0,
"f_pinky.03.L": 1.0,
"f_pinky.01.L.001": 1.0,
"palm.L": 1.0,
"hand_tweak.R": 1.0,
"forearm_tweak.R": 1.0,
"forearm_tweak.R.001": 1.0,
"upper_arm_tweak.R.001": 1.0,
"upper_arm_parent.R": 1.0,
"upper_arm_fk.R": 1.0,
"forearm_fk.R": 1.0,
"hand_fk.R": 1.0,
"upper_arm_ik.R": 1.0,
"upper_arm_tweak.R": 1.0,
"f_index.01_master.R": 1.0,
"thumb.01_master.R": 1.0,
"f_index.01.R": 1.0,
"f_index.02.R": 1.0,
"f_index.03.R": 1.0,
"f_index.01.R.001": 1.0,
"thumb.01.R": 1.0,
"thumb.02.R": 1.0,
"thumb.03.R": 1.0,
"thumb.01.R.001": 1.0,
"f_middle.01_master.R": 1.0,
"f_middle.01.R": 1.0,
"f_middle.02.R": 1.0,
"f_middle.03.R": 1.0,
"f_middle.01.R.001": 1.0,
"f_ring.01_master.R": 1.0,
"f_ring.01.R": 1.0,
"f_ring.02.R": 1.0,
"f_ring.03.R": 1.0,
"f_ring.01.R.001": 1.0,
"f_pinky.01_master.R": 1.0,
"f_pinky.01.R": 1.0,
"f_pinky.02.R": 1.0,
"f_pinky.03.R": 1.0,
"f_pinky.01.R.001": 1.0,
"palm.R": 1.0,
"shoulder.L": 1.0,
"shoulder.R": 1.0,
"hand_ik.L": 1.0,
"upper_arm_ik_target.L": 1.0,
"hand_ik.R": 1.0,
"upper_arm_ik_target.R": 1.0,
"clavicle_l": 1.0,
"upperarm_l": 1.0,
"upperarm_twist_01_l": 1.0,
"lowerarm_l": 1.0,
"lowerarm_twist_01_l": 1.0,
"hand_l": 1.0,
"middle_01_l": 1.0,
"middle_02_l": 1.0,
"middle_03_l": 1.0,
"index_01_l": 1.0,
"index_02_l": 1.0,
"index_03_l": 1.0,
"ring_01_l": 1.0,
"ring_02_l": 1.0,
"ring_03_l": 1.0,
"pinky_01_l": 1.0,
"pinky_02_l": 1.0,
"pinky_03_l": 1.0,
"thumb_01_l": 1.0,
"thumb_02_l": 1.0,
"thumb_03_l": 1.0,
"clavicle_r": 1.0,
"upperarm_r": 1.0,
"upperarm_twist_01_r": 1.0,
"lowerarm_r": 1.0,
"lowerarm_twist_01_r": 1.0,
"hand_r": 1.0,
"middle_01_r": 1.0,
"middle_02_r": 1.0,
"middle_03_r": 1.0,
"ring_01_r": 1.0,
"ring_02_r": 1.0,
"ring_03_r": 1.0,
"thumb_01_r": 1.0,
"thumb_02_r": 1.0,
"thumb_03_r": 1.0,
"index_01_r": 1.0,
"index_02_r": 1.0,
"index_03_r": 1.0,
"pinky_01_r": 1.0,
"pinky_02_r": 1.0,
"pinky_03_r": 1.0
},
"Keys": {}
}
@@ -0,0 +1,840 @@
{
"Bones": {
"CTRL_L_brow_down": 1.0,
"CTRL_R_brow_down": 1.0,
"CTRL_L_brow_lateral": 1.0,
"CTRL_R_brow_lateral": 1.0,
"CTRL_L_brow_raiseIn": 1.0,
"CTRL_R_brow_raiseIn": 1.0,
"CTRL_L_brow_raiseOut": 1.0,
"CTRL_R_brow_raiseOut": 1.0,
"CTRL_L_eye_blink": 1.0,
"CTRL_R_eye_blink": 1.0,
"CTRL_L_eye_cheekRaise": 1.0,
"CTRL_R_eye_cheekRaise": 1.0,
"CTRL_L_eye_lidPress": 1.0,
"CTRL_R_eye_lidPress": 1.0,
"CTRL_L_eye_squintInner": 1.0,
"CTRL_R_eye_squintInner": 1.0,
"CTRL_C_eye": 1.0,
"CTRL_C_eye_parallelLook": 1.0,
"CTRL_L_eye": 1.0,
"CTRL_R_eye": 1.0,
"CTRL_L_eye_pupil": 1.0,
"CTRL_R_eye_pupil": 1.0,
"CTRL_L_ear_up": 1.0,
"CTRL_R_ear_up": 1.0,
"CTRL_L_nose": 1.0,
"CTRL_R_nose": 1.0,
"CTRL_L_nose_wrinkleUpper": 1.0,
"CTRL_R_nose_wrinkleUpper": 1.0,
"CTRL_L_mouth_suckBlow": 1.0,
"CTRL_R_mouth_suckBlow": 1.0,
"CTRL_C_mouth": 1.0,
"CTRL_L_mouth_cornerDepress": 1.0,
"CTRL_R_mouth_cornerDepress": 1.0,
"CTRL_L_mouth_cornerPull": 1.0,
"CTRL_R_mouth_cornerPull": 1.0,
"CTRL_L_mouth_dimple": 1.0,
"CTRL_R_mouth_dimple": 1.0,
"CTRL_L_mouth_lowerLipDepress": 1.0,
"CTRL_R_mouth_lowerLipDepress": 1.0,
"CTRL_L_mouth_sharpCornerPull": 1.0,
"CTRL_R_mouth_sharpCornerPull": 1.0,
"CTRL_L_mouth_stretch": 1.0,
"CTRL_R_mouth_stretch": 1.0,
"CTRL_L_mouth_stretchLipsClose": 1.0,
"CTRL_R_mouth_stretchLipsClose": 1.0,
"CTRL_L_mouth_upperLipRaise": 1.0,
"CTRL_R_mouth_upperLipRaise": 1.0,
"CTRL_L_mouth_funnelD": 1.0,
"CTRL_R_mouth_funnelD": 1.0,
"CTRL_L_mouth_funnelU": 1.0,
"CTRL_R_mouth_funnelU": 1.0,
"CTRL_L_mouth_lipBiteD": 1.0,
"CTRL_R_mouth_lipBiteD": 1.0,
"CTRL_L_mouth_lipBiteU": 1.0,
"CTRL_R_mouth_lipBiteU": 1.0,
"CTRL_L_mouth_lipsBlow": 1.0,
"CTRL_R_mouth_lipsBlow": 1.0,
"CTRL_L_mouth_lipsPressU": 1.0,
"CTRL_R_mouth_lipsPressU": 1.0,
"CTRL_L_mouth_pressD": 1.0,
"CTRL_R_mouth_pressD": 1.0,
"CTRL_L_mouth_pressU": 1.0,
"CTRL_R_mouth_pressU": 1.0,
"CTRL_L_mouth_purseD": 1.0,
"CTRL_R_mouth_purseD": 1.0,
"CTRL_L_mouth_purseU": 1.0,
"CTRL_R_mouth_purseU": 1.0,
"CTRL_L_mouth_tightenD": 1.0,
"CTRL_R_mouth_tightenD": 1.0,
"CTRL_L_mouth_tightenU": 1.0,
"CTRL_R_mouth_tightenU": 1.0,
"CTRL_L_mouth_towardsD": 1.0,
"CTRL_R_mouth_towardsD": 1.0,
"CTRL_L_mouth_towardsU": 1.0,
"CTRL_R_mouth_towardsU": 1.0,
"CTRL_L_mouth_lipsTogetherD": 1.0,
"CTRL_R_mouth_lipsTogetherD": 1.0,
"CTRL_L_mouth_lipsTogetherU": 1.0,
"CTRL_R_mouth_lipsTogetherU": 1.0,
"CTRL_C_mouth_stickyD": 1.0,
"CTRL_C_mouth_stickyU": 1.0,
"CTRL_L_mouth_lipSticky": 1.0,
"CTRL_R_mouth_lipSticky": 1.0,
"CTRL_L_mouth_stickyInnerD": 1.0,
"CTRL_R_mouth_stickyInnerD": 1.0,
"CTRL_L_mouth_stickyInnerU": 1.0,
"CTRL_R_mouth_stickyInnerU": 1.0,
"CTRL_L_mouth_stickyOuterD": 1.0,
"CTRL_R_mouth_stickyOuterD": 1.0,
"CTRL_L_mouth_stickyOuterU": 1.0,
"CTRL_R_mouth_stickyOuterU": 1.0,
"CTRL_C_jaw": 1.0,
"CTRL_C_jaw_fwdBack": 1.0,
"CTRL_C_jaw_openExtreme": 1.0,
"CTRL_L_jaw_ChinRaiseD": 1.0,
"CTRL_R_jaw_ChinRaiseD": 1.0,
"CTRL_L_jaw_ChinRaiseU": 1.0,
"CTRL_R_jaw_ChinRaiseU": 1.0,
"CTRL_L_jaw_chinCompress": 1.0,
"CTRL_R_jaw_chinCompress": 1.0,
"CTRL_L_jaw_clench": 1.0,
"CTRL_R_jaw_clench": 1.0,
"CTRL_C_neck_swallow": 1.0,
"CTRL_L_neck_mastoidContract": 1.0,
"CTRL_R_neck_mastoidContract": 1.0,
"CTRL_L_neck_stretch": 1.0,
"CTRL_R_neck_stretch": 1.0,
"CTRL_neck_digastricUpDown": 1.0,
"CTRL_neck_throatExhaleInhale": 1.0,
"CTRL_neck_throatUpDown": 1.0,
"CTRL_C_head_turn": 1.0,
"CTRL_C_head_move": 1.0,
"CTRL_C_head_tilt": 1.0,
"CTRL_C_head_fwdBack": 1.0,
"CTRL_L_eye_eyelidD": 1.0,
"CTRL_R_eye_eyelidD": 1.0,
"CTRL_L_eye_eyelidU": 1.0,
"CTRL_R_eye_eyelidU": 1.0,
"CTRL_L_eye_faceScrunch": 1.0,
"CTRL_R_eye_faceScrunch": 1.0,
"CTRL_L_eyelashes_tweakerIn": 1.0,
"CTRL_R_eyelashes_tweakerIn": 1.0,
"CTRL_L_eyelashes_tweakerOut": 1.0,
"CTRL_R_eyelashes_tweakerOut": 1.0,
"CTRL_L_nose_nasolabialDeepen": 1.0,
"CTRL_R_nose_nasolabialDeepen": 1.0,
"CTRL_L_mouth_pushPullD": 1.0,
"CTRL_R_mouth_pushPullD": 1.0,
"CTRL_L_mouth_pushPullU": 1.0,
"CTRL_R_mouth_pushPullU": 1.0,
"CTRL_C_mouth_lipShiftD": 1.0,
"CTRL_C_mouth_lipShiftU": 1.0,
"CTRL_L_mouth_lipsRollD": 1.0,
"CTRL_R_mouth_lipsRollD": 1.0,
"CTRL_L_mouth_lipsRollU": 1.0,
"CTRL_R_mouth_lipsRollU": 1.0,
"CTRL_L_mouth_corner": 1.0,
"CTRL_R_mouth_corner": 1.0,
"CTRL_L_mouth_cornerSharpnessD": 1.0,
"CTRL_R_mouth_cornerSharpnessD": 1.0,
"CTRL_L_mouth_cornerSharpnessU": 1.0,
"CTRL_R_mouth_cornerSharpnessU": 1.0,
"CTRL_L_mouth_lipsTowardsTeethD": 1.0,
"CTRL_R_mouth_lipsTowardsTeethD": 1.0,
"CTRL_L_mouth_lipsTowardsTeethU": 1.0,
"CTRL_R_mouth_lipsTowardsTeethU": 1.0,
"CTRL_L_mouth_thicknessD": 1.0,
"CTRL_R_mouth_thicknessD": 1.0,
"CTRL_L_mouth_thicknessInwardD": 1.0,
"CTRL_R_mouth_thicknessInwardD": 1.0,
"CTRL_L_mouth_thicknessInwardU": 1.0,
"CTRL_R_mouth_thicknessInwardU": 1.0,
"CTRL_L_mouth_thicknessU": 1.0,
"CTRL_R_mouth_thicknessU": 1.0,
"CTRL_C_tongue_bendTwist": 1.0,
"CTRL_C_tongue_inOut": 1.0,
"CTRL_C_tongue_move": 1.0,
"CTRL_C_tongue_press": 1.0,
"CTRL_C_tongue_roll": 1.0,
"CTRL_C_tongue_thickThin": 1.0,
"CTRL_C_tongue_tipMove": 1.0,
"CTRL_C_tongue_wideNarrow": 1.0,
"CTRL_C_teethD": 1.0,
"CTRL_C_teethU": 1.0,
"CTRL_C_teeth_fwdBackD": 1.0,
"CTRL_C_teeth_fwdBackU": 1.0,
"CTRL_eye_pupil": 1.0,
"CTRL_R_mouth_tighten": 1.0,
"CTRL_L_mouth_tighten": 1.0,
"CTRL_C_jaw_chinRaise": 1.0,
"CTRL_C_mouth_lipsTogether": 1.0,
"CTRL_R_mouth_press": 1.0,
"CTRL_L_mouth_press": 1.0,
"CTRL_C_tongue": 1.0,
"CTRL_C_tongue_tip": 1.0,
"CTRL_mouth_shrugDropU": 1.0,
"CTRL_mouth_shrugDropD": 1.0,
"CTRL_C_tongue_narrowWide": 1.0,
"CTRL_R_eyelashU": 1.0,
"CTRL_R_eyelashD": 1.0,
"CTRL_L_eyelashU": 1.0,
"CTRL_L_eyelashD": 1.0,
"CTRL_C_mouth_thickness": 1.0,
"CTRL_brow_raiseIn": 1.0,
"CTRL_mouth_purse_Std": 1.0,
"CTRL_mouth_funnel_Std": 1.0,
"CTRL_mouth_lipBiteU_Std": 1.0,
"CTRL_mouth_lipBiteD_Std": 1.0,
"CTRL_C_jaw_fwdBack_Std": 1.0,
"CTRL_mouth_puff_Std": 1.0,
"CTRL_C_tongue_Out_Std": 1.0,
"CTRL_C_tongue_tip_upDown_Std": 1.0,
"CTRL_C_tongue_roll_Std": 1.0,
"CTRL_mouth_shrugU_Std": 1.0,
"CTRL_mouth_shrugD_Std": 1.0,
"CTRL_mouth_lipsRollU_Std": 1.0,
"CTRL_mouth_lipsRollD_Std": 1.0,
"CTRL_R_mouth_corner_Std": 1.0,
"CTRL_L_mouth_corner_Std": 1.0
},
"Keys": {
"Brow_Compress_L": 1.0,
"Brow_Compress_R": 1.0,
"Brow_Drop_L": 1.0,
"Brow_Drop_R": 1.0,
"Brow_Raise_Inner_L": 1.0,
"Brow_Raise_Inner_R": 1.0,
"Brow_Raise_Outer_L": 1.0,
"Brow_Raise_Outer_R": 1.0,
"Cheek_Puff_L": 1.0,
"Cheek_Puff_R": 1.0,
"Cheek_Raise_L": 1.0,
"Cheek_Raise_R": 1.0,
"Cheek_Suck_L": 1.0,
"Cheek_Suck_R": 1.0,
"Ear_Down_L": 1.0,
"Ear_Down_R": 1.0,
"Ear_Out_L": 1.0,
"Ear_Out_R": 1.0,
"Ear_Up_L": 1.0,
"Ear_Up_R": 1.0,
"Eye_Blink_L": 1.0,
"Eye_Blink_R": 1.0,
"Eye_L_Look_Down": 1.0,
"Eye_L_Look_L": 1.0,
"Eye_L_Look_R": 1.0,
"Eye_L_Look_Up": 1.0,
"Eye_Pupil_Contract": 1.0,
"Eye_Pupil_Dilate": 1.0,
"Eye_R_Look_Down": 1.0,
"Eye_R_Look_L": 1.0,
"Eye_R_Look_R": 1.0,
"Eye_R_Look_Up": 1.0,
"Eye_Squint_L": 1.0,
"Eye_Squint_R": 1.0,
"Eye_Wide_L": 1.0,
"Eye_Wide_R": 1.0,
"Eyelash_Lower_Down_L": 1.0,
"Eyelash_Lower_Down_R": 1.0,
"Eyelash_Lower_Up_L": 1.0,
"Eyelash_Lower_Up_R": 1.0,
"Eyelash_Upper_Down_L": 1.0,
"Eyelash_Upper_Down_R": 1.0,
"Eyelash_Upper_Up_L": 1.0,
"Eyelash_Upper_Up_R": 1.0,
"Head_Backward": 1.0,
"Head_Forward": 1.0,
"Head_L": 1.0,
"Head_R": 1.0,
"Head_Tilt_L": 1.0,
"Head_Tilt_R": 1.0,
"Head_Turn_Down": 1.0,
"Head_Turn_L": 1.0,
"Head_Turn_R": 1.0,
"Head_Turn_Up": 1.0,
"Jaw_Backward": 1.0,
"Jaw_Down": 1.0,
"Jaw_Forward": 1.0,
"Jaw_L": 1.0,
"Jaw_Open": 1.0,
"Jaw_R": 1.0,
"Jaw_Up": 1.0,
"Mouth_Blow_L": 1.0,
"Mouth_Blow_R": 1.0,
"Mouth_Chin_Up": 1.0,
"Mouth_Close": 1.0,
"Mouth_Contract": 1.0,
"Mouth_Dimple_L": 1.0,
"Mouth_Dimple_R": 1.0,
"Mouth_Down": 1.0,
"Mouth_Down_Lower_L": 1.0,
"Mouth_Down_Lower_R": 1.0,
"Mouth_Drop_Lower": 1.0,
"Mouth_Drop_Upper": 1.0,
"Mouth_Frown_L": 1.0,
"Mouth_Frown_R": 1.0,
"Mouth_Funnel_Down_L": 1.0,
"Mouth_Funnel_Down_R": 1.0,
"Mouth_Funnel_Up_L": 1.0,
"Mouth_Funnel_Up_R": 1.0,
"Mouth_L": 1.0,
"Mouth_Lower_L": 1.0,
"Mouth_Lower_R": 1.0,
"Mouth_Press_L": 1.0,
"Mouth_Press_R": 1.0,
"Mouth_Pucker_Down_L": 1.0,
"Mouth_Pucker_Down_R": 1.0,
"Mouth_Pucker_Up_L": 1.0,
"Mouth_Pucker_Up_R": 1.0,
"Mouth_Pull_Lower_L": 1.0,
"Mouth_Pull_Lower_R": 1.0,
"Mouth_Pull_Upper_L": 1.0,
"Mouth_Pull_Upper_R": 1.0,
"Mouth_Push_Lower_L": 1.0,
"Mouth_Push_Lower_R": 1.0,
"Mouth_Push_Upper_L": 1.0,
"Mouth_Push_Upper_R": 1.0,
"Mouth_R": 1.0,
"Mouth_Roll_In_Lower_L": 1.0,
"Mouth_Roll_In_Lower_R": 1.0,
"Mouth_Roll_In_Upper_L": 1.0,
"Mouth_Roll_In_Upper_R": 1.0,
"Mouth_Roll_Out_Lower_L": 1.0,
"Mouth_Roll_Out_Lower_R": 1.0,
"Mouth_Roll_Out_Upper_L": 1.0,
"Mouth_Roll_Out_Upper_R": 1.0,
"Mouth_Shrug_Lower": 1.0,
"Mouth_Shrug_Upper": 1.0,
"Mouth_Smile_L": 1.0,
"Mouth_Smile_R": 1.0,
"Mouth_Smile_Sharp_L": 1.0,
"Mouth_Smile_Sharp_R": 1.0,
"Mouth_Stretch_L": 1.0,
"Mouth_Stretch_R": 1.0,
"Mouth_Tighten_L": 1.0,
"Mouth_Tighten_R": 1.0,
"Mouth_Up": 1.0,
"Mouth_Up_Upper_L": 1.0,
"Mouth_Up_Upper_R": 1.0,
"Mouth_Upper_L": 1.0,
"Mouth_Upper_R": 1.0,
"Neck_Swallow_Down": 1.0,
"Neck_Swallow_Up": 1.0,
"Neck_Tighten_L": 1.0,
"Neck_Tighten_R": 1.0,
"Nose_Crease_L": 1.0,
"Nose_Crease_R": 1.0,
"Nose_Nostril_Dilate_L": 1.0,
"Nose_Nostril_Dilate_R": 1.0,
"Nose_Nostril_Down_L": 1.0,
"Nose_Nostril_Down_R": 1.0,
"Nose_Nostril_In_L": 1.0,
"Nose_Nostril_In_R": 1.0,
"Nose_Nostril_Raise_L": 1.0,
"Nose_Nostril_Raise_R": 1.0,
"Nose_Sneer_L": 1.0,
"Nose_Sneer_R": 1.0,
"Nose_Tip_Down": 1.0,
"Nose_Tip_L": 1.0,
"Nose_Tip_R": 1.0,
"Nose_Tip_Up": 1.0,
"Tongue_Bulge_L": 1.0,
"Tongue_Bulge_R": 1.0,
"Tongue_Down": 1.0,
"Tongue_Enlarge": 1.0,
"Tongue_Extend": 1.0,
"Tongue_In": 1.0,
"Tongue_L": 1.0,
"Tongue_Mid_Up": 1.0,
"Tongue_Narrow": 1.0,
"Tongue_Out": 1.0,
"Tongue_R": 1.0,
"Tongue_Roll": 1.0,
"Tongue_Tip_Down": 1.0,
"Tongue_Tip_L": 1.0,
"Tongue_Tip_R": 1.0,
"Tongue_Tip_Up": 1.0,
"Tongue_Twist_L": 1.0,
"Tongue_Twist_R": 1.0,
"Tongue_Up": 1.0,
"Tongue_Wide": 1.0,
"Brow_Down_L": 1.0,
"Brow_Down_R": 1.0,
"Brow_Lateral_L": 1.0,
"Brow_Lateral_R": 1.0,
"Brow_Raise_In_L": 1.0,
"Brow_Raise_In_R": 1.0,
"C_BlinkL": 1.0,
"C_BlinkL_CheekRaiseL": 1.0,
"C_BlinkL_LookDownL": 1.0,
"C_BlinkL_LookLeftL": 1.0,
"C_BlinkL_LookRightL": 1.0,
"C_BlinkL_LookUpL": 1.0,
"C_BlinkL_SquintInnerL": 1.0,
"C_BlinkL_SquintInnerL_CheekRaiseL": 1.0,
"C_BlinkR": 1.0,
"C_BlinkR_CheekRaiseR": 1.0,
"C_BlinkR_LookDownR": 1.0,
"C_BlinkR_LookLeftR": 1.0,
"C_BlinkR_LookRightR": 1.0,
"C_BlinkR_LookUpR": 1.0,
"C_BlinkR_SquintInnerR": 1.0,
"C_BlinkR_SquintInnerR_CheekRaiseR": 1.0,
"C_CheekBlowL_CheekBlowR": 1.0,
"C_CheekRaiseL_CornerPullL": 1.0,
"C_CheekRaiseL_SquintInnerL": 1.0,
"C_CheekRaiseR_CornerPullR": 1.0,
"C_CheekRaiseR_SquintInnerR": 1.0,
"C_CornerPullL_CornerPullR": 1.0,
"C_CornerPullL_DimpleL": 1.0,
"C_CornerPullL_JawOpen": 1.0,
"C_CornerPullL_JawOpen_LowerLipDepressL": 1.0,
"C_CornerPullL_LowerLipDepressL": 1.0,
"C_CornerPullL_SharpCornerPullL": 1.0,
"C_CornerPullL_StretchL": 1.0,
"C_CornerPullL_StretchL_JawOpen": 1.0,
"C_CornerPullL_UpperLipRaiseL": 1.0,
"C_CornerPullRL_StretchRL_JawOpen": 1.0,
"C_CornerPullRL_StretchRL_JawOpen_LowerLipDepressRL": 1.0,
"C_CornerPullR_DimpleR": 1.0,
"C_CornerPullR_JawOpen": 1.0,
"C_CornerPullR_JawOpen_LowerLipDepressR": 1.0,
"C_CornerPullR_LowerLipDepressR": 1.0,
"C_CornerPullR_SharpCornerPullR": 1.0,
"C_CornerPullR_StretchR": 1.0,
"C_CornerPullR_StretchR_JawOpen": 1.0,
"C_CornerPullR_UpperLipRaiseR": 1.0,
"C_DimpleL_JawOpen": 1.0,
"C_DimpleL_LowerLipDepressL": 1.0,
"C_DimpleL_UpperLipRaiseL": 1.0,
"C_DimpleR_JawOpen": 1.0,
"C_DimpleR_LowerLipDepressR": 1.0,
"C_DimpleR_UpperLipRaiseR": 1.0,
"C_FunnelDL_CornerPullL": 1.0,
"C_FunnelDL_LipsPurseDL_CornerPullL": 1.0,
"C_FunnelDL_LipsTowardsDL": 1.0,
"C_FunnelDL_LowerLipDepressL": 1.0,
"C_FunnelDR_CornerPullR": 1.0,
"C_FunnelDR_LipsPurseDR_CornerPullR": 1.0,
"C_FunnelDR_LipsTowardsDR": 1.0,
"C_FunnelDR_LowerLipDepressR": 1.0,
"C_FunnelUL_ChinRaiseUL": 1.0,
"C_FunnelUL_CornerPullL": 1.0,
"C_FunnelUL_LipsPurseUL_CornerPullL": 1.0,
"C_FunnelUL_LipsTowardsUL": 1.0,
"C_FunnelUL_UpperLipRaiseL": 1.0,
"C_FunnelUR_ChinRaiseUR": 1.0,
"C_FunnelUR_CornerPullR": 1.0,
"C_FunnelUR_LipsPurseUR_CornerPullR": 1.0,
"C_FunnelUR_LipsTowardsUR": 1.0,
"C_FunnelUR_UpperLipRaiseR": 1.0,
"C_LipsPurseDL_CornerPullL": 1.0,
"C_LipsPurseDL_FunnelDL": 1.0,
"C_LipsPurseDL_JawOpen": 1.0,
"C_LipsPurseDL_LipsTogetherDL": 1.0,
"C_LipsPurseDL_LipsTowardsDL": 1.0,
"C_LipsPurseDL_LipsTowardsDL_FunnelDL": 1.0,
"C_LipsPurseDR_CornerPullR": 1.0,
"C_LipsPurseDR_FunnelDR": 1.0,
"C_LipsPurseDR_JawOpen": 1.0,
"C_LipsPurseDR_LipsTogetherDR": 1.0,
"C_LipsPurseDR_LipsTowardsDR": 1.0,
"C_LipsPurseDR_LipsTowardsDR_FunnelDR": 1.0,
"C_LipsPurseUL_CornerPullL": 1.0,
"C_LipsPurseUL_FunnelUL": 1.0,
"C_LipsPurseUL_JawOpen": 1.0,
"C_LipsPurseUL_LipsTogetherUL": 1.0,
"C_LipsPurseUL_LipsTowardsUL": 1.0,
"C_LipsPurseUL_LipsTowardsUL_FunnelUL": 1.0,
"C_LipsPurseUR_CornerPullR": 1.0,
"C_LipsPurseUR_FunnelUR": 1.0,
"C_LipsPurseUR_JawOpen": 1.0,
"C_LipsPurseUR_LipsTogetherUR": 1.0,
"C_LipsPurseUR_LipsTowardsUR": 1.0,
"C_LipsPurseUR_LipsTowardsUR_FunnelUR": 1.0,
"C_LowerLipBiteL_JawOpen": 1.0,
"C_LowerLipBiteR_JawOpen": 1.0,
"C_LowerLipDepressL_LowerLipDepressR": 1.0,
"C_NoseWrinkleL_BrowDownL": 1.0,
"C_NoseWrinkleR_BrowDownR": 1.0,
"C_PressDL_JawOpen": 1.0,
"C_PressDR_JawOpen": 1.0,
"C_PressUL_JawOpen": 1.0,
"C_PressUR_JawOpen": 1.0,
"C_StretchL_CornerPullL_LowerLipDepressL": 1.0,
"C_StretchL_JawOpen": 1.0,
"C_StretchL_LowerLipBite_L": 1.0,
"C_StretchL_LowerLipDepressL": 1.0,
"C_StretchL_LowerLipDepressL_JawOpen": 1.0,
"C_StretchL_StretchR": 1.0,
"C_StretchR_CornerPullR_LowerLipDepressR": 1.0,
"C_StretchR_JawOpen": 1.0,
"C_StretchR_LowerLipBite_R": 1.0,
"C_StretchR_LowerLipDepressR": 1.0,
"C_StretchR_LowerLipDepressR_JawOpen": 1.0,
"C_UpperLipBiteL_JawOpen": 1.0,
"C_UpperLipBiteR_JawOpen": 1.0,
"C_UpperLipRaiseL_UpperLipRaiseR": 1.0,
"C_WidenL_LookDownL": 1.0,
"C_WidenR_LookDownR": 1.0,
"C_WrinkleL_MouthCornerPullL": 1.0,
"C_WrinkleL_UpperLipRaiseL": 1.0,
"C_WrinkleR_MouthCornerPullR": 1.0,
"C_WrinkleR_UpperLipRaiseR": 1.0,
"Eye_Cheek_Raise_L": 1.0,
"Eye_Cheek_Raise_R": 1.0,
"Eye_Face_Scrunch_L": 1.0,
"Eye_Face_Scrunch_R": 1.0,
"Eye_Lid_Press_L": 1.0,
"Eye_Lid_Press_R": 1.0,
"Eye_Look_Down_L": 1.0,
"Eye_Look_Down_R": 1.0,
"Eye_Look_Left_L": 1.0,
"Eye_Look_Left_R": 1.0,
"Eye_Look_Right_L": 1.0,
"Eye_Look_Right_R": 1.0,
"Eye_Look_Up_L": 1.0,
"Eye_Look_Up_R": 1.0,
"Eye_LowerLid_Down_L": 1.0,
"Eye_LowerLid_Down_R": 1.0,
"Eye_LowerLid_Up_L": 1.0,
"Eye_LowerLid_Up_R": 1.0,
"Eye_Parallel_Look_Direction": 1.0,
"Eye_Pupil_Narrow_L": 1.0,
"Eye_Pupil_Narrow_R": 1.0,
"Eye_Pupil_Wide_L": 1.0,
"Eye_Pupil_Wide_R": 1.0,
"Eye_Relax_L": 1.0,
"Eye_Relax_R": 1.0,
"Eye_Squint_Inner_L": 1.0,
"Eye_Squint_Inner_R": 1.0,
"Eye_UpperLid_Up_L": 1.0,
"Eye_UpperLid_Up_R": 1.0,
"Eye_Widen_L": 1.0,
"Eye_Widen_R": 1.0,
"Eyelashes_Down_IN_L": 1.0,
"Eyelashes_Down_IN_R": 1.0,
"Eyelashes_Down_OUT_L": 1.0,
"Eyelashes_Down_OUT_R": 1.0,
"Eyelashes_Up_IN_L": 1.0,
"Eyelashes_Up_IN_R": 1.0,
"Eyelashes_Up_OUT_L": 1.0,
"Eyelashes_Up_OUT_R": 1.0,
"Jaw_Back": 1.0,
"Jaw_Chin_Compress_L": 1.0,
"Jaw_Chin_Compress_R": 1.0,
"Jaw_Chin_Raise_DL": 1.0,
"Jaw_Chin_Raise_DR": 1.0,
"Jaw_Chin_Raise_UL": 1.0,
"Jaw_Chin_Raise_UR": 1.0,
"Jaw_Clench_L": 1.0,
"Jaw_Clench_R": 1.0,
"Jaw_Fwd": 1.0,
"Jaw_Left": 1.0,
"Jaw_Open_Extreme": 1.0,
"Jaw_Right": 1.0,
"Mouth_Cheek_Blow_L": 1.0,
"Mouth_Cheek_Blow_R": 1.0,
"Mouth_Cheek_Suck_L": 1.0,
"Mouth_Cheek_Suck_R": 1.0,
"Mouth_Corner_Depress_L": 1.0,
"Mouth_Corner_Depress_R": 1.0,
"Mouth_Corner_Down_L": 1.0,
"Mouth_Corner_Down_R": 1.0,
"Mouth_Corner_Narrow_L": 1.0,
"Mouth_Corner_Narrow_R": 1.0,
"Mouth_Corner_Pull_L": 1.0,
"Mouth_Corner_Pull_R": 1.0,
"Mouth_Corner_Rounder_DL": 1.0,
"Mouth_Corner_Rounder_DR": 1.0,
"Mouth_Corner_Rounder_UL": 1.0,
"Mouth_Corner_Rounder_UR": 1.0,
"Mouth_Corner_Sharpen_DL": 1.0,
"Mouth_Corner_Sharpen_DR": 1.0,
"Mouth_Corner_Sharpen_UL": 1.0,
"Mouth_Corner_Sharpen_UR": 1.0,
"Mouth_Corner_Up_L": 1.0,
"Mouth_Corner_Up_R": 1.0,
"Mouth_Corner_Wide_L": 1.0,
"Mouth_Corner_Wide_R": 1.0,
"Mouth_Funnel_DL": 1.0,
"Mouth_Funnel_DR": 1.0,
"Mouth_Funnel_UL": 1.0,
"Mouth_Funnel_UR": 1.0,
"Mouth_Left": 1.0,
"Mouth_Lips_Blow_L": 1.0,
"Mouth_Lips_Blow_R": 1.0,
"Mouth_Lips_Press_L": 1.0,
"Mouth_Lips_Press_R": 1.0,
"Mouth_Lips_Pull_DL": 1.0,
"Mouth_Lips_Pull_DR": 1.0,
"Mouth_Lips_Pull_UL": 1.0,
"Mouth_Lips_Pull_UR": 1.0,
"Mouth_Lips_Purse_DL": 1.0,
"Mouth_Lips_Purse_DR": 1.0,
"Mouth_Lips_Purse_UL": 1.0,
"Mouth_Lips_Purse_UR": 1.0,
"Mouth_Lips_Push_DL": 1.0,
"Mouth_Lips_Push_DR": 1.0,
"Mouth_Lips_Push_UL": 1.0,
"Mouth_Lips_Push_UR": 1.0,
"Mouth_Lips_Sticky_L_Ph1": 1.0,
"Mouth_Lips_Sticky_L_Ph2": 1.0,
"Mouth_Lips_Sticky_L_Ph3": 1.0,
"Mouth_Lips_Sticky_R_Ph1": 1.0,
"Mouth_Lips_Sticky_R_Ph2": 1.0,
"Mouth_Lips_Sticky_R_Ph3": 1.0,
"Mouth_Lips_Thick_DL": 1.0,
"Mouth_Lips_Thick_DR": 1.0,
"Mouth_Lips_Thick_Inward_DL": 1.0,
"Mouth_Lips_Thick_Inward_DR": 1.0,
"Mouth_Lips_Thick_Inward_UL": 1.0,
"Mouth_Lips_Thick_Inward_UR": 1.0,
"Mouth_Lips_Thick_UL": 1.0,
"Mouth_Lips_Thick_UR": 1.0,
"Mouth_Lips_Thin_DL": 1.0,
"Mouth_Lips_Thin_DR": 1.0,
"Mouth_Lips_Thin_Inward_DL": 1.0,
"Mouth_Lips_Thin_Inward_DR": 1.0,
"Mouth_Lips_Thin_Inward_UL": 1.0,
"Mouth_Lips_Thin_Inward_UR": 1.0,
"Mouth_Lips_Thin_UL": 1.0,
"Mouth_Lips_Thin_UR": 1.0,
"Mouth_Lips_Tighten_DL": 1.0,
"Mouth_Lips_Tighten_DR": 1.0,
"Mouth_Lips_Tighten_UL": 1.0,
"Mouth_Lips_Tighten_UR": 1.0,
"Mouth_Lips_Together_DL": 1.0,
"Mouth_Lips_Together_DR": 1.0,
"Mouth_Lips_Together_UL": 1.0,
"Mouth_Lips_Together_UR": 1.0,
"Mouth_Lips_Towards_DL": 1.0,
"Mouth_Lips_Towards_DR": 1.0,
"Mouth_Lips_Towards_UL": 1.0,
"Mouth_Lips_Towards_UR": 1.0,
"Mouth_LowerLip_Bite_L": 1.0,
"Mouth_LowerLip_Bite_R": 1.0,
"Mouth_LowerLip_Depress_L": 1.0,
"Mouth_LowerLip_Depress_R": 1.0,
"Mouth_LowerLip_RollIn_L": 1.0,
"Mouth_LowerLip_RollIn_R": 1.0,
"Mouth_LowerLip_Roll_Out_L": 1.0,
"Mouth_LowerLip_Roll_Out_R": 1.0,
"Mouth_LowerLip_Shift_Left": 1.0,
"Mouth_LowerLip_Shift_Right": 1.0,
"Mouth_LowerLip_Towards_Teeth_L": 1.0,
"Mouth_LowerLip_Towards_Teeth_R": 1.0,
"Mouth_Mouth_Press_DL": 1.0,
"Mouth_Mouth_Press_DR": 1.0,
"Mouth_Mouth_Press_UL": 1.0,
"Mouth_Mouth_Press_UR": 1.0,
"Mouth_Right": 1.0,
"Mouth_SharpCorner_Pull_L": 1.0,
"Mouth_SharpCorner_Pull_R": 1.0,
"Mouth_Sticky_DC": 1.0,
"Mouth_Sticky_D_IN_L": 1.0,
"Mouth_Sticky_D_IN_R": 1.0,
"Mouth_Sticky_D_OUT_L": 1.0,
"Mouth_Sticky_D_OUT_R": 1.0,
"Mouth_Sticky_UC": 1.0,
"Mouth_Sticky_U_IN_L": 1.0,
"Mouth_Sticky_U_IN_R": 1.0,
"Mouth_Sticky_U_OUT_L": 1.0,
"Mouth_Sticky_U_OUT_R": 1.0,
"Mouth_StretchLips_Close_L": 1.0,
"Mouth_StretchLips_Close_R": 1.0,
"Mouth_UpperLip_Bite_L": 1.0,
"Mouth_UpperLip_Bite_R": 1.0,
"Mouth_UpperLip_Raise_L": 1.0,
"Mouth_UpperLip_Raise_R": 1.0,
"Mouth_UpperLip_RollIn_L": 1.0,
"Mouth_UpperLip_RollIn_R": 1.0,
"Mouth_UpperLip_Roll_Out_L": 1.0,
"Mouth_UpperLip_Roll_Out_R": 1.0,
"Mouth_UpperLip_Shift_Left": 1.0,
"Mouth_UpperLip_Shift_Right": 1.0,
"Mouth_UpperLip_Towards_Teeth_L": 1.0,
"Mouth_UpperLip_Towards_Teeth_R": 1.0,
"Neck_Digastric_Down": 1.0,
"Neck_Digastric_Up": 1.0,
"Neck_Mastoid_Contract_L": 1.0,
"Neck_Mastoid_Contract_R": 1.0,
"Neck_Stretch_L": 1.0,
"Neck_Stretch_R": 1.0,
"Neck_Swallow_Ph1": 1.0,
"Neck_Swallow_Ph2": 1.0,
"Neck_Swallow_Ph3": 1.0,
"Neck_Swallow_Ph4": 1.0,
"Neck_Swallow_Ph5": 1.0,
"Neck_Throat_Down": 1.0,
"Neck_Throat_Exhale": 1.0,
"Neck_Throat_Inhale": 1.0,
"Neck_Throat_Up": 1.0,
"Nose_Nasolabial_Deepen_L": 1.0,
"Nose_Nasolabial_Deepen_R": 1.0,
"Nose_Nostril_Compress_L": 1.0,
"Nose_Nostril_Compress_R": 1.0,
"Nose_Nostril_Depress_L": 1.0,
"Nose_Nostril_Depress_R": 1.0,
"Nose_Wrinkle_L": 1.0,
"Nose_Wrinkle_R": 1.0,
"Nose_Wrinkle_Upper_L": 1.0,
"Nose_Wrinkle_Upper_R": 1.0,
"Teeth_Back_D": 1.0,
"Teeth_Back_U": 1.0,
"Teeth_Down_D": 1.0,
"Teeth_Down_U": 1.0,
"Teeth_Fwd_D": 1.0,
"Teeth_Fwd_U": 1.0,
"Teeth_Left_D": 1.0,
"Teeth_Left_U": 1.0,
"Teeth_Right_D": 1.0,
"Teeth_Right_U": 1.0,
"Teeth_Up_D": 1.0,
"Teeth_Up_U": 1.0,
"Tongue_Bend_Down": 1.0,
"Tongue_Bend_Up": 1.0,
"Tongue_Left": 1.0,
"Tongue_Press": 1.0,
"Tongue_Right": 1.0,
"Tongue_Thick": 1.0,
"Tongue_Thin": 1.0,
"Tongue_Tip_Left": 1.0,
"Tongue_Tip_Right": 1.0,
"Tongue_Twist_Left": 1.0,
"Tongue_Twist_Right": 1.0,
"Brow_Drop_Left": 1.0,
"Brow_Drop_Right": 1.0,
"Brow_Raise_Inner_Left": 1.0,
"Brow_Raise_Inner_Right": 1.0,
"Brow_Raise_Left": 1.0,
"Brow_Raise_Outer_Left": 1.0,
"Brow_Raise_Outer_Right": 1.0,
"Brow_Raise_Right": 1.0,
"Cheek_Blow_L": 1.0,
"Cheek_Blow_R": 1.0,
"Cheeks_Suck": 1.0,
"Eyes_Blink": 1.0,
"Left_Eyeball_Look_Down": 1.0,
"Left_Eyeball_Look_L": 1.0,
"Left_Eyeball_Look_R": 1.0,
"Left_Eyeball_Look_Up": 1.0,
"Mouth_Blow": 1.0,
"Mouth_Bottom_Lip_Bite": 1.0,
"Mouth_Bottom_Lip_Down": 1.0,
"Mouth_Bottom_Lip_Trans": 1.0,
"Mouth_Bottom_Lip_Under": 1.0,
"Mouth_Frown": 1.0,
"Mouth_Lips_Jaw_Adjust": 1.0,
"Mouth_Lips_Open": 1.0,
"Mouth_Lips_Part": 1.0,
"Mouth_Lips_Tight": 1.0,
"Mouth_Lips_Tuck": 1.0,
"Mouth_Open": 1.0,
"Mouth_Plosive": 1.0,
"Mouth_Pucker": 1.0,
"Mouth_Pucker_Open": 1.0,
"Mouth_Skewer": 1.0,
"Mouth_Smile": 1.0,
"Mouth_Snarl_Lower_L": 1.0,
"Mouth_Snarl_Lower_R": 1.0,
"Mouth_Snarl_Upper_L": 1.0,
"Mouth_Snarl_Upper_R": 1.0,
"Mouth_Top_Lip_Under": 1.0,
"Mouth_Top_Lip_Up": 1.0,
"Mouth_Widen": 1.0,
"Mouth_Widen_Sides": 1.0,
"Move_Jaw_Down": 1.0,
"Move_Jaw_L": 1.0,
"Move_Jaw_R": 1.0,
"Nose_Flank_Raise_L": 1.0,
"Nose_Flank_Raise_R": 1.0,
"Nose_Flanks_Raise": 1.0,
"Nose_Nostrils_Flare": 1.0,
"Nose_Scrunch": 1.0,
"Right_Eyeball_Look_Down": 1.0,
"Right_Eyeball_Look_L": 1.0,
"Right_Eyeball_Look_R": 1.0,
"Right_Eyeball_Look_Up": 1.0,
"Turn_Jaw_Down": 1.0,
"Turn_Jaw_L": 1.0,
"Turn_Jaw_R": 1.0,
"A01_Brow_Inner_Up": 1.0,
"A02_Brow_Down_Left": 1.0,
"A03_Brow_Down_Right": 1.0,
"A04_Brow_Outer_Up_Left": 1.0,
"A05_Brow_Outer_Up_Right": 1.0,
"A06_Eye_Look_Up_Left": 1.0,
"A07_Eye_Look_Up_Right": 1.0,
"A08_Eye_Look_Down_Left": 1.0,
"A09_Eye_Look_Down_Right": 1.0,
"A10_Eye_Look_Out_Left": 1.0,
"A11_Eye_Look_In_Left": 1.0,
"A12_Eye_Look_In_Right": 1.0,
"A13_Eye_Look_Out_Right": 1.0,
"A14_Eye_Blink_Left": 1.0,
"A15_Eye_Blink_Right": 1.0,
"A16_Eye_Squint_Left": 1.0,
"A17_Eye_Squint_Right": 1.0,
"A18_Eye_Wide_Left": 1.0,
"A19_Eye_Wide_Right": 1.0,
"A20_Cheek_Puff": 1.0,
"A21_Cheek_Squint_Left": 1.0,
"A22_Cheek_Squint_Right": 1.0,
"A23_Nose_Sneer_Left": 1.0,
"A24_Nose_Sneer_Right": 1.0,
"A25_Jaw_Open": 1.0,
"A26_Jaw_Forward": 1.0,
"A27_Jaw_Left": 1.0,
"A28_Jaw_Right": 1.0,
"A29_Mouth_Funnel": 1.0,
"A30_Mouth_Pucker": 1.0,
"A31_Mouth_Left": 1.0,
"A32_Mouth_Right": 1.0,
"A33_Mouth_Roll_Upper": 1.0,
"A34_Mouth_Roll_Lower": 1.0,
"A35_Mouth_Shrug_Upper": 1.0,
"A36_Mouth_Shrug_Lower": 1.0,
"A37_Mouth_Close": 1.0,
"A38_Mouth_Smile_Left": 1.0,
"A39_Mouth_Smile_Right": 1.0,
"A40_Mouth_Frown_Left": 1.0,
"A41_Mouth_Frown_Right": 1.0,
"A42_Mouth_Dimple_Left": 1.0,
"A43_Mouth_Dimple_Right": 1.0,
"A44_Mouth_Upper_Up_Left": 1.0,
"A45_Mouth_Upper_Up_Right": 1.0,
"A46_Mouth_Lower_Down_Left": 1.0,
"A47_Mouth_Lower_Down_Right": 1.0,
"A48_Mouth_Press_Left": 1.0,
"A49_Mouth_Press_Right": 1.0,
"A50_Mouth_Stretch_Left": 1.0,
"A51_Mouth_Stretch_Right": 1.0,
"A52_Tongue_Out": 1.0,
"T01_Tongue_Up": 1.0,
"T02_Tongue_Down": 1.0,
"T03_Tongue_Left": 1.0,
"T04_Tongue_Right": 1.0,
"T05_Tongue_Roll": 1.0,
"T06_Tongue_Tip_Up": 1.0,
"T07_Tongue_Tip_Down": 1.0,
"T08_Tongue_Width": 1.0,
"T09_Tongue_Thickness": 1.0,
"T10_Tongue_Bulge_Left": 1.0,
"T11_Tongue_Bulge_Right": 1.0,
"OverBite": 1.0,
"Teeth Lower Depth": 1.0,
"Teeth Lower Height": 1.0,
"Teeth Lower Length": 1.0,
"Teeth Lower Scale Width": 1.0,
"Teeth Lower Sharp": 1.0,
"Teeth Upper Depth": 1.0,
"Teeth Upper Height": 1.0,
"Teeth Upper Length": 1.0,
"Teeth Upper Scale Width": 1.0,
"Teeth Upper Sharp": 1.0
}
}
@@ -0,0 +1,129 @@
{
"Bones": {
"CC_Base_L_Hand": 1.0,
"CC_Base_L_Pinky1": 1.0,
"CC_Base_L_Pinky2": 1.0,
"CC_Base_L_Pinky3": 1.0,
"CC_Base_L_Ring1": 1.0,
"CC_Base_L_Ring2": 1.0,
"CC_Base_L_Ring3": 1.0,
"CC_Base_L_Mid1": 1.0,
"CC_Base_L_Mid2": 1.0,
"CC_Base_L_Mid3": 1.0,
"CC_Base_L_Index1": 1.0,
"CC_Base_L_Index2": 1.0,
"CC_Base_L_Index3": 1.0,
"CC_Base_L_Thumb1": 1.0,
"CC_Base_L_Thumb2": 1.0,
"CC_Base_L_Thumb3": 1.0,
"CC_Base_R_Hand": 1.0,
"CC_Base_R_Ring1": 1.0,
"CC_Base_R_Ring2": 1.0,
"CC_Base_R_Ring3": 1.0,
"CC_Base_R_Mid1": 1.0,
"CC_Base_R_Mid2": 1.0,
"CC_Base_R_Mid3": 1.0,
"CC_Base_R_Thumb1": 1.0,
"CC_Base_R_Thumb2": 1.0,
"CC_Base_R_Thumb3": 1.0,
"CC_Base_R_Index1": 1.0,
"CC_Base_R_Index2": 1.0,
"CC_Base_R_Index3": 1.0,
"CC_Base_R_Pinky1": 1.0,
"CC_Base_R_Pinky2": 1.0,
"CC_Base_R_Pinky3": 1.0,
"hand_tweak.L": 1.0,
"hand_fk.L": 1.0,
"f_index.01_master.L": 1.0,
"thumb.01_master.L": 1.0,
"f_index.01.L": 1.0,
"f_index.02.L": 1.0,
"f_index.03.L": 1.0,
"f_index.01.L.001": 1.0,
"thumb.01.L": 1.0,
"thumb.02.L": 1.0,
"thumb.03.L": 1.0,
"thumb.01.L.001": 1.0,
"f_middle.01_master.L": 1.0,
"f_middle.01.L": 1.0,
"f_middle.02.L": 1.0,
"f_middle.03.L": 1.0,
"f_middle.01.L.001": 1.0,
"f_ring.01_master.L": 1.0,
"f_ring.01.L": 1.0,
"f_ring.02.L": 1.0,
"f_ring.03.L": 1.0,
"f_ring.01.L.001": 1.0,
"f_pinky.01_master.L": 1.0,
"f_pinky.01.L": 1.0,
"f_pinky.02.L": 1.0,
"f_pinky.03.L": 1.0,
"f_pinky.01.L.001": 1.0,
"palm.L": 1.0,
"hand_tweak.R": 1.0,
"hand_fk.R": 1.0,
"f_index.01_master.R": 1.0,
"thumb.01_master.R": 1.0,
"f_index.01.R": 1.0,
"f_index.02.R": 1.0,
"f_index.03.R": 1.0,
"f_index.01.R.001": 1.0,
"thumb.01.R": 1.0,
"thumb.02.R": 1.0,
"thumb.03.R": 1.0,
"thumb.01.R.001": 1.0,
"f_middle.01_master.R": 1.0,
"f_middle.01.R": 1.0,
"f_middle.02.R": 1.0,
"f_middle.03.R": 1.0,
"f_middle.01.R.001": 1.0,
"f_ring.01_master.R": 1.0,
"f_ring.01.R": 1.0,
"f_ring.02.R": 1.0,
"f_ring.03.R": 1.0,
"f_ring.01.R.001": 1.0,
"f_pinky.01_master.R": 1.0,
"f_pinky.01.R": 1.0,
"f_pinky.02.R": 1.0,
"f_pinky.03.R": 1.0,
"f_pinky.01.R.001": 1.0,
"palm.R": 1.0,
"hand_ik.L": 1.0,
"upper_arm_ik_target.L": 1.0,
"hand_ik.R": 1.0,
"upper_arm_ik_target.R": 1.0,
"hand_l": 1.0,
"middle_01_l": 1.0,
"middle_02_l": 1.0,
"middle_03_l": 1.0,
"index_01_l": 1.0,
"index_02_l": 1.0,
"index_03_l": 1.0,
"ring_01_l": 1.0,
"ring_02_l": 1.0,
"ring_03_l": 1.0,
"pinky_01_l": 1.0,
"pinky_02_l": 1.0,
"pinky_03_l": 1.0,
"thumb_01_l": 1.0,
"thumb_02_l": 1.0,
"thumb_03_l": 1.0,
"hand_r": 1.0,
"middle_01_r": 1.0,
"middle_02_r": 1.0,
"middle_03_r": 1.0,
"ring_01_r": 1.0,
"ring_02_r": 1.0,
"ring_03_r": 1.0,
"thumb_01_r": 1.0,
"thumb_02_r": 1.0,
"thumb_03_r": 1.0,
"index_01_r": 1.0,
"index_02_r": 1.0,
"index_03_r": 1.0,
"pinky_01_r": 1.0,
"pinky_02_r": 1.0,
"pinky_03_r": 1.0
},
"Keys": {}
}
@@ -0,0 +1,872 @@
{
"Bones": {
"CTRL_L_brow_down": 1.0,
"CTRL_R_brow_down": 1.0,
"CTRL_L_brow_lateral": 1.0,
"CTRL_R_brow_lateral": 1.0,
"CTRL_L_brow_raiseIn": 1.0,
"CTRL_R_brow_raiseIn": 1.0,
"CTRL_L_brow_raiseOut": 1.0,
"CTRL_R_brow_raiseOut": 1.0,
"CTRL_L_eye_blink": 1.0,
"CTRL_R_eye_blink": 1.0,
"CTRL_L_eye_cheekRaise": 1.0,
"CTRL_R_eye_cheekRaise": 1.0,
"CTRL_L_eye_lidPress": 1.0,
"CTRL_R_eye_lidPress": 1.0,
"CTRL_L_eye_squintInner": 1.0,
"CTRL_R_eye_squintInner": 1.0,
"CTRL_C_eye": 1.0,
"CTRL_C_eye_parallelLook": 1.0,
"CTRL_L_eye": 1.0,
"CTRL_R_eye": 1.0,
"CTRL_L_eye_pupil": 1.0,
"CTRL_R_eye_pupil": 1.0,
"CTRL_L_ear_up": 1.0,
"CTRL_R_ear_up": 1.0,
"CTRL_L_nose": 1.0,
"CTRL_R_nose": 1.0,
"CTRL_L_nose_wrinkleUpper": 1.0,
"CTRL_R_nose_wrinkleUpper": 1.0,
"CTRL_L_mouth_suckBlow": 1.0,
"CTRL_R_mouth_suckBlow": 1.0,
"CTRL_C_mouth": 1.0,
"CTRL_L_mouth_cornerDepress": 1.0,
"CTRL_R_mouth_cornerDepress": 1.0,
"CTRL_L_mouth_cornerPull": 1.0,
"CTRL_R_mouth_cornerPull": 1.0,
"CTRL_L_mouth_dimple": 1.0,
"CTRL_R_mouth_dimple": 1.0,
"CTRL_L_mouth_lowerLipDepress": 1.0,
"CTRL_R_mouth_lowerLipDepress": 1.0,
"CTRL_L_mouth_sharpCornerPull": 1.0,
"CTRL_R_mouth_sharpCornerPull": 1.0,
"CTRL_L_mouth_stretch": 1.0,
"CTRL_R_mouth_stretch": 1.0,
"CTRL_L_mouth_stretchLipsClose": 1.0,
"CTRL_R_mouth_stretchLipsClose": 1.0,
"CTRL_L_mouth_upperLipRaise": 1.0,
"CTRL_R_mouth_upperLipRaise": 1.0,
"CTRL_L_mouth_funnelD": 1.0,
"CTRL_R_mouth_funnelD": 1.0,
"CTRL_L_mouth_funnelU": 1.0,
"CTRL_R_mouth_funnelU": 1.0,
"CTRL_L_mouth_lipBiteD": 1.0,
"CTRL_R_mouth_lipBiteD": 1.0,
"CTRL_L_mouth_lipBiteU": 1.0,
"CTRL_R_mouth_lipBiteU": 1.0,
"CTRL_L_mouth_lipsBlow": 1.0,
"CTRL_R_mouth_lipsBlow": 1.0,
"CTRL_L_mouth_lipsPressU": 1.0,
"CTRL_R_mouth_lipsPressU": 1.0,
"CTRL_L_mouth_pressD": 1.0,
"CTRL_R_mouth_pressD": 1.0,
"CTRL_L_mouth_pressU": 1.0,
"CTRL_R_mouth_pressU": 1.0,
"CTRL_L_mouth_purseD": 1.0,
"CTRL_R_mouth_purseD": 1.0,
"CTRL_L_mouth_purseU": 1.0,
"CTRL_R_mouth_purseU": 1.0,
"CTRL_L_mouth_tightenD": 1.0,
"CTRL_R_mouth_tightenD": 1.0,
"CTRL_L_mouth_tightenU": 1.0,
"CTRL_R_mouth_tightenU": 1.0,
"CTRL_L_mouth_towardsD": 1.0,
"CTRL_R_mouth_towardsD": 1.0,
"CTRL_L_mouth_towardsU": 1.0,
"CTRL_R_mouth_towardsU": 1.0,
"CTRL_L_mouth_lipsTogetherD": 1.0,
"CTRL_R_mouth_lipsTogetherD": 1.0,
"CTRL_L_mouth_lipsTogetherU": 1.0,
"CTRL_R_mouth_lipsTogetherU": 1.0,
"CTRL_C_mouth_stickyD": 1.0,
"CTRL_C_mouth_stickyU": 1.0,
"CTRL_L_mouth_lipSticky": 1.0,
"CTRL_R_mouth_lipSticky": 1.0,
"CTRL_L_mouth_stickyInnerD": 1.0,
"CTRL_R_mouth_stickyInnerD": 1.0,
"CTRL_L_mouth_stickyInnerU": 1.0,
"CTRL_R_mouth_stickyInnerU": 1.0,
"CTRL_L_mouth_stickyOuterD": 1.0,
"CTRL_R_mouth_stickyOuterD": 1.0,
"CTRL_L_mouth_stickyOuterU": 1.0,
"CTRL_R_mouth_stickyOuterU": 1.0,
"CTRL_C_jaw": 1.0,
"CTRL_C_jaw_fwdBack": 1.0,
"CTRL_C_jaw_openExtreme": 1.0,
"CTRL_L_jaw_ChinRaiseD": 1.0,
"CTRL_R_jaw_ChinRaiseD": 1.0,
"CTRL_L_jaw_ChinRaiseU": 1.0,
"CTRL_R_jaw_ChinRaiseU": 1.0,
"CTRL_L_jaw_chinCompress": 1.0,
"CTRL_R_jaw_chinCompress": 1.0,
"CTRL_L_jaw_clench": 1.0,
"CTRL_R_jaw_clench": 1.0,
"CTRL_C_neck_swallow": 1.0,
"CTRL_L_neck_mastoidContract": 1.0,
"CTRL_R_neck_mastoidContract": 1.0,
"CTRL_L_neck_stretch": 1.0,
"CTRL_R_neck_stretch": 1.0,
"CTRL_neck_digastricUpDown": 1.0,
"CTRL_neck_throatExhaleInhale": 1.0,
"CTRL_neck_throatUpDown": 1.0,
"CTRL_C_head_turn": 1.0,
"CTRL_C_head_move": 1.0,
"CTRL_C_head_tilt": 1.0,
"CTRL_C_head_fwdBack": 1.0,
"CTRL_L_eye_eyelidD": 1.0,
"CTRL_R_eye_eyelidD": 1.0,
"CTRL_L_eye_eyelidU": 1.0,
"CTRL_R_eye_eyelidU": 1.0,
"CTRL_L_eye_faceScrunch": 1.0,
"CTRL_R_eye_faceScrunch": 1.0,
"CTRL_L_eyelashes_tweakerIn": 1.0,
"CTRL_R_eyelashes_tweakerIn": 1.0,
"CTRL_L_eyelashes_tweakerOut": 1.0,
"CTRL_R_eyelashes_tweakerOut": 1.0,
"CTRL_L_nose_nasolabialDeepen": 1.0,
"CTRL_R_nose_nasolabialDeepen": 1.0,
"CTRL_L_mouth_pushPullD": 1.0,
"CTRL_R_mouth_pushPullD": 1.0,
"CTRL_L_mouth_pushPullU": 1.0,
"CTRL_R_mouth_pushPullU": 1.0,
"CTRL_C_mouth_lipShiftD": 1.0,
"CTRL_C_mouth_lipShiftU": 1.0,
"CTRL_L_mouth_lipsRollD": 1.0,
"CTRL_R_mouth_lipsRollD": 1.0,
"CTRL_L_mouth_lipsRollU": 1.0,
"CTRL_R_mouth_lipsRollU": 1.0,
"CTRL_L_mouth_corner": 1.0,
"CTRL_R_mouth_corner": 1.0,
"CTRL_L_mouth_cornerSharpnessD": 1.0,
"CTRL_R_mouth_cornerSharpnessD": 1.0,
"CTRL_L_mouth_cornerSharpnessU": 1.0,
"CTRL_R_mouth_cornerSharpnessU": 1.0,
"CTRL_L_mouth_lipsTowardsTeethD": 1.0,
"CTRL_R_mouth_lipsTowardsTeethD": 1.0,
"CTRL_L_mouth_lipsTowardsTeethU": 1.0,
"CTRL_R_mouth_lipsTowardsTeethU": 1.0,
"CTRL_L_mouth_thicknessD": 1.0,
"CTRL_R_mouth_thicknessD": 1.0,
"CTRL_L_mouth_thicknessInwardD": 1.0,
"CTRL_R_mouth_thicknessInwardD": 1.0,
"CTRL_L_mouth_thicknessInwardU": 1.0,
"CTRL_R_mouth_thicknessInwardU": 1.0,
"CTRL_L_mouth_thicknessU": 1.0,
"CTRL_R_mouth_thicknessU": 1.0,
"CTRL_C_tongue_bendTwist": 1.0,
"CTRL_C_tongue_inOut": 1.0,
"CTRL_C_tongue_move": 1.0,
"CTRL_C_tongue_press": 1.0,
"CTRL_C_tongue_roll": 1.0,
"CTRL_C_tongue_thickThin": 1.0,
"CTRL_C_tongue_tipMove": 1.0,
"CTRL_C_tongue_wideNarrow": 1.0,
"CTRL_C_teethD": 1.0,
"CTRL_C_teethU": 1.0,
"CTRL_C_teeth_fwdBackD": 1.0,
"CTRL_C_teeth_fwdBackU": 1.0,
"CTRL_eye_pupil": 1.0,
"CTRL_R_mouth_tighten": 1.0,
"CTRL_L_mouth_tighten": 1.0,
"CTRL_C_jaw_chinRaise": 1.0,
"CTRL_C_mouth_lipsTogether": 1.0,
"CTRL_R_mouth_press": 1.0,
"CTRL_L_mouth_press": 1.0,
"CTRL_C_tongue": 1.0,
"CTRL_C_tongue_tip": 1.0,
"CTRL_mouth_shrugDropU": 1.0,
"CTRL_mouth_shrugDropD": 1.0,
"CTRL_C_tongue_narrowWide": 1.0,
"CTRL_R_eyelashU": 1.0,
"CTRL_R_eyelashD": 1.0,
"CTRL_L_eyelashU": 1.0,
"CTRL_L_eyelashD": 1.0,
"CTRL_C_mouth_thickness": 1.0,
"CTRL_brow_raiseIn": 1.0,
"CTRL_mouth_purse_Std": 1.0,
"CTRL_mouth_funnel_Std": 1.0,
"CTRL_mouth_lipBiteU_Std": 1.0,
"CTRL_mouth_lipBiteD_Std": 1.0,
"CTRL_C_jaw_fwdBack_Std": 1.0,
"CTRL_mouth_puff_Std": 1.0,
"CTRL_C_tongue_Out_Std": 1.0,
"CTRL_C_tongue_tip_upDown_Std": 1.0,
"CTRL_C_tongue_roll_Std": 1.0,
"CTRL_mouth_shrugU_Std": 1.0,
"CTRL_mouth_shrugD_Std": 1.0,
"CTRL_mouth_lipsRollU_Std": 1.0,
"CTRL_mouth_lipsRollD_Std": 1.0,
"CTRL_R_mouth_corner_Std": 1.0,
"CTRL_L_mouth_corner_Std": 1.0,
"CC_Base_NeckTwist01": 1.0,
"CC_Base_NeckTwist02": 1.0,
"CC_Base_Head": 1.0,
"CC_Base_FacialBone": 1.0,
"CC_Base_JawRoot": 1.0,
"CC_Base_Tongue01": 1.0,
"CC_Base_Tongue02": 1.0,
"CC_Base_Tongue03": 1.0,
"CC_Base_Teeth02": 1.0,
"CC_Base_R_Eye": 1.0,
"CC_Base_L_Eye": 1.0,
"CC_Base_UpperJaw": 1.0,
"CC_Base_Teeth01": 1.0,
"master_eye.L": 1.0,
"master_eye.R": 1.0,
"teeth.T": 1.0,
"jaw_master": 1.0,
"chin": 1.0,
"jaw": 1.0,
"teeth.B": 1.0,
"tongue.003": 1.0,
"tongue_master": 1.0,
"tongue": 1.0,
"tongue.001": 1.0,
"tongue.002": 1.0,
"neck": 1.0,
"head": 1.0,
"tweak_spine.005": 1.0,
"eyes": 1.0,
"eye.L": 1.0,
"eye.R": 1.0,
"neck_01": 1.0
},
"Keys": {
"Brow_Compress_L": 1.0,
"Brow_Compress_R": 1.0,
"Brow_Drop_L": 1.0,
"Brow_Drop_R": 1.0,
"Brow_Raise_Inner_L": 1.0,
"Brow_Raise_Inner_R": 1.0,
"Brow_Raise_Outer_L": 1.0,
"Brow_Raise_Outer_R": 1.0,
"Cheek_Puff_L": 1.0,
"Cheek_Puff_R": 1.0,
"Cheek_Raise_L": 1.0,
"Cheek_Raise_R": 1.0,
"Cheek_Suck_L": 1.0,
"Cheek_Suck_R": 1.0,
"Ear_Down_L": 1.0,
"Ear_Down_R": 1.0,
"Ear_Out_L": 1.0,
"Ear_Out_R": 1.0,
"Ear_Up_L": 1.0,
"Ear_Up_R": 1.0,
"Eye_Blink_L": 1.0,
"Eye_Blink_R": 1.0,
"Eye_L_Look_Down": 1.0,
"Eye_L_Look_L": 1.0,
"Eye_L_Look_R": 1.0,
"Eye_L_Look_Up": 1.0,
"Eye_Pupil_Contract": 1.0,
"Eye_Pupil_Dilate": 1.0,
"Eye_R_Look_Down": 1.0,
"Eye_R_Look_L": 1.0,
"Eye_R_Look_R": 1.0,
"Eye_R_Look_Up": 1.0,
"Eye_Squint_L": 1.0,
"Eye_Squint_R": 1.0,
"Eye_Wide_L": 1.0,
"Eye_Wide_R": 1.0,
"Eyelash_Lower_Down_L": 1.0,
"Eyelash_Lower_Down_R": 1.0,
"Eyelash_Lower_Up_L": 1.0,
"Eyelash_Lower_Up_R": 1.0,
"Eyelash_Upper_Down_L": 1.0,
"Eyelash_Upper_Down_R": 1.0,
"Eyelash_Upper_Up_L": 1.0,
"Eyelash_Upper_Up_R": 1.0,
"Head_Backward": 1.0,
"Head_Forward": 1.0,
"Head_L": 1.0,
"Head_R": 1.0,
"Head_Tilt_L": 1.0,
"Head_Tilt_R": 1.0,
"Head_Turn_Down": 1.0,
"Head_Turn_L": 1.0,
"Head_Turn_R": 1.0,
"Head_Turn_Up": 1.0,
"Jaw_Backward": 1.0,
"Jaw_Down": 1.0,
"Jaw_Forward": 1.0,
"Jaw_L": 1.0,
"Jaw_Open": 1.0,
"Jaw_R": 1.0,
"Jaw_Up": 1.0,
"Mouth_Blow_L": 1.0,
"Mouth_Blow_R": 1.0,
"Mouth_Chin_Up": 1.0,
"Mouth_Close": 1.0,
"Mouth_Contract": 1.0,
"Mouth_Dimple_L": 1.0,
"Mouth_Dimple_R": 1.0,
"Mouth_Down": 1.0,
"Mouth_Down_Lower_L": 1.0,
"Mouth_Down_Lower_R": 1.0,
"Mouth_Drop_Lower": 1.0,
"Mouth_Drop_Upper": 1.0,
"Mouth_Frown_L": 1.0,
"Mouth_Frown_R": 1.0,
"Mouth_Funnel_Down_L": 1.0,
"Mouth_Funnel_Down_R": 1.0,
"Mouth_Funnel_Up_L": 1.0,
"Mouth_Funnel_Up_R": 1.0,
"Mouth_L": 1.0,
"Mouth_Lower_L": 1.0,
"Mouth_Lower_R": 1.0,
"Mouth_Press_L": 1.0,
"Mouth_Press_R": 1.0,
"Mouth_Pucker_Down_L": 1.0,
"Mouth_Pucker_Down_R": 1.0,
"Mouth_Pucker_Up_L": 1.0,
"Mouth_Pucker_Up_R": 1.0,
"Mouth_Pull_Lower_L": 1.0,
"Mouth_Pull_Lower_R": 1.0,
"Mouth_Pull_Upper_L": 1.0,
"Mouth_Pull_Upper_R": 1.0,
"Mouth_Push_Lower_L": 1.0,
"Mouth_Push_Lower_R": 1.0,
"Mouth_Push_Upper_L": 1.0,
"Mouth_Push_Upper_R": 1.0,
"Mouth_R": 1.0,
"Mouth_Roll_In_Lower_L": 1.0,
"Mouth_Roll_In_Lower_R": 1.0,
"Mouth_Roll_In_Upper_L": 1.0,
"Mouth_Roll_In_Upper_R": 1.0,
"Mouth_Roll_Out_Lower_L": 1.0,
"Mouth_Roll_Out_Lower_R": 1.0,
"Mouth_Roll_Out_Upper_L": 1.0,
"Mouth_Roll_Out_Upper_R": 1.0,
"Mouth_Shrug_Lower": 1.0,
"Mouth_Shrug_Upper": 1.0,
"Mouth_Smile_L": 1.0,
"Mouth_Smile_R": 1.0,
"Mouth_Smile_Sharp_L": 1.0,
"Mouth_Smile_Sharp_R": 1.0,
"Mouth_Stretch_L": 1.0,
"Mouth_Stretch_R": 1.0,
"Mouth_Tighten_L": 1.0,
"Mouth_Tighten_R": 1.0,
"Mouth_Up": 1.0,
"Mouth_Up_Upper_L": 1.0,
"Mouth_Up_Upper_R": 1.0,
"Mouth_Upper_L": 1.0,
"Mouth_Upper_R": 1.0,
"Neck_Swallow_Down": 1.0,
"Neck_Swallow_Up": 1.0,
"Neck_Tighten_L": 1.0,
"Neck_Tighten_R": 1.0,
"Nose_Crease_L": 1.0,
"Nose_Crease_R": 1.0,
"Nose_Nostril_Dilate_L": 1.0,
"Nose_Nostril_Dilate_R": 1.0,
"Nose_Nostril_Down_L": 1.0,
"Nose_Nostril_Down_R": 1.0,
"Nose_Nostril_In_L": 1.0,
"Nose_Nostril_In_R": 1.0,
"Nose_Nostril_Raise_L": 1.0,
"Nose_Nostril_Raise_R": 1.0,
"Nose_Sneer_L": 1.0,
"Nose_Sneer_R": 1.0,
"Nose_Tip_Down": 1.0,
"Nose_Tip_L": 1.0,
"Nose_Tip_R": 1.0,
"Nose_Tip_Up": 1.0,
"Tongue_Bulge_L": 1.0,
"Tongue_Bulge_R": 1.0,
"Tongue_Down": 1.0,
"Tongue_Enlarge": 1.0,
"Tongue_Extend": 1.0,
"Tongue_In": 1.0,
"Tongue_L": 1.0,
"Tongue_Mid_Up": 1.0,
"Tongue_Narrow": 1.0,
"Tongue_Out": 1.0,
"Tongue_R": 1.0,
"Tongue_Roll": 1.0,
"Tongue_Tip_Down": 1.0,
"Tongue_Tip_L": 1.0,
"Tongue_Tip_R": 1.0,
"Tongue_Tip_Up": 1.0,
"Tongue_Twist_L": 1.0,
"Tongue_Twist_R": 1.0,
"Tongue_Up": 1.0,
"Tongue_Wide": 1.0,
"Brow_Down_L": 1.0,
"Brow_Down_R": 1.0,
"Brow_Lateral_L": 1.0,
"Brow_Lateral_R": 1.0,
"Brow_Raise_In_L": 1.0,
"Brow_Raise_In_R": 1.0,
"C_BlinkL": 1.0,
"C_BlinkL_CheekRaiseL": 1.0,
"C_BlinkL_LookDownL": 1.0,
"C_BlinkL_LookLeftL": 1.0,
"C_BlinkL_LookRightL": 1.0,
"C_BlinkL_LookUpL": 1.0,
"C_BlinkL_SquintInnerL": 1.0,
"C_BlinkL_SquintInnerL_CheekRaiseL": 1.0,
"C_BlinkR": 1.0,
"C_BlinkR_CheekRaiseR": 1.0,
"C_BlinkR_LookDownR": 1.0,
"C_BlinkR_LookLeftR": 1.0,
"C_BlinkR_LookRightR": 1.0,
"C_BlinkR_LookUpR": 1.0,
"C_BlinkR_SquintInnerR": 1.0,
"C_BlinkR_SquintInnerR_CheekRaiseR": 1.0,
"C_CheekBlowL_CheekBlowR": 1.0,
"C_CheekRaiseL_CornerPullL": 1.0,
"C_CheekRaiseL_SquintInnerL": 1.0,
"C_CheekRaiseR_CornerPullR": 1.0,
"C_CheekRaiseR_SquintInnerR": 1.0,
"C_CornerPullL_CornerPullR": 1.0,
"C_CornerPullL_DimpleL": 1.0,
"C_CornerPullL_JawOpen": 1.0,
"C_CornerPullL_JawOpen_LowerLipDepressL": 1.0,
"C_CornerPullL_LowerLipDepressL": 1.0,
"C_CornerPullL_SharpCornerPullL": 1.0,
"C_CornerPullL_StretchL": 1.0,
"C_CornerPullL_StretchL_JawOpen": 1.0,
"C_CornerPullL_UpperLipRaiseL": 1.0,
"C_CornerPullRL_StretchRL_JawOpen": 1.0,
"C_CornerPullRL_StretchRL_JawOpen_LowerLipDepressRL": 1.0,
"C_CornerPullR_DimpleR": 1.0,
"C_CornerPullR_JawOpen": 1.0,
"C_CornerPullR_JawOpen_LowerLipDepressR": 1.0,
"C_CornerPullR_LowerLipDepressR": 1.0,
"C_CornerPullR_SharpCornerPullR": 1.0,
"C_CornerPullR_StretchR": 1.0,
"C_CornerPullR_StretchR_JawOpen": 1.0,
"C_CornerPullR_UpperLipRaiseR": 1.0,
"C_DimpleL_JawOpen": 1.0,
"C_DimpleL_LowerLipDepressL": 1.0,
"C_DimpleL_UpperLipRaiseL": 1.0,
"C_DimpleR_JawOpen": 1.0,
"C_DimpleR_LowerLipDepressR": 1.0,
"C_DimpleR_UpperLipRaiseR": 1.0,
"C_FunnelDL_CornerPullL": 1.0,
"C_FunnelDL_LipsPurseDL_CornerPullL": 1.0,
"C_FunnelDL_LipsTowardsDL": 1.0,
"C_FunnelDL_LowerLipDepressL": 1.0,
"C_FunnelDR_CornerPullR": 1.0,
"C_FunnelDR_LipsPurseDR_CornerPullR": 1.0,
"C_FunnelDR_LipsTowardsDR": 1.0,
"C_FunnelDR_LowerLipDepressR": 1.0,
"C_FunnelUL_ChinRaiseUL": 1.0,
"C_FunnelUL_CornerPullL": 1.0,
"C_FunnelUL_LipsPurseUL_CornerPullL": 1.0,
"C_FunnelUL_LipsTowardsUL": 1.0,
"C_FunnelUL_UpperLipRaiseL": 1.0,
"C_FunnelUR_ChinRaiseUR": 1.0,
"C_FunnelUR_CornerPullR": 1.0,
"C_FunnelUR_LipsPurseUR_CornerPullR": 1.0,
"C_FunnelUR_LipsTowardsUR": 1.0,
"C_FunnelUR_UpperLipRaiseR": 1.0,
"C_LipsPurseDL_CornerPullL": 1.0,
"C_LipsPurseDL_FunnelDL": 1.0,
"C_LipsPurseDL_JawOpen": 1.0,
"C_LipsPurseDL_LipsTogetherDL": 1.0,
"C_LipsPurseDL_LipsTowardsDL": 1.0,
"C_LipsPurseDL_LipsTowardsDL_FunnelDL": 1.0,
"C_LipsPurseDR_CornerPullR": 1.0,
"C_LipsPurseDR_FunnelDR": 1.0,
"C_LipsPurseDR_JawOpen": 1.0,
"C_LipsPurseDR_LipsTogetherDR": 1.0,
"C_LipsPurseDR_LipsTowardsDR": 1.0,
"C_LipsPurseDR_LipsTowardsDR_FunnelDR": 1.0,
"C_LipsPurseUL_CornerPullL": 1.0,
"C_LipsPurseUL_FunnelUL": 1.0,
"C_LipsPurseUL_JawOpen": 1.0,
"C_LipsPurseUL_LipsTogetherUL": 1.0,
"C_LipsPurseUL_LipsTowardsUL": 1.0,
"C_LipsPurseUL_LipsTowardsUL_FunnelUL": 1.0,
"C_LipsPurseUR_CornerPullR": 1.0,
"C_LipsPurseUR_FunnelUR": 1.0,
"C_LipsPurseUR_JawOpen": 1.0,
"C_LipsPurseUR_LipsTogetherUR": 1.0,
"C_LipsPurseUR_LipsTowardsUR": 1.0,
"C_LipsPurseUR_LipsTowardsUR_FunnelUR": 1.0,
"C_LowerLipBiteL_JawOpen": 1.0,
"C_LowerLipBiteR_JawOpen": 1.0,
"C_LowerLipDepressL_LowerLipDepressR": 1.0,
"C_NoseWrinkleL_BrowDownL": 1.0,
"C_NoseWrinkleR_BrowDownR": 1.0,
"C_PressDL_JawOpen": 1.0,
"C_PressDR_JawOpen": 1.0,
"C_PressUL_JawOpen": 1.0,
"C_PressUR_JawOpen": 1.0,
"C_StretchL_CornerPullL_LowerLipDepressL": 1.0,
"C_StretchL_JawOpen": 1.0,
"C_StretchL_LowerLipBite_L": 1.0,
"C_StretchL_LowerLipDepressL": 1.0,
"C_StretchL_LowerLipDepressL_JawOpen": 1.0,
"C_StretchL_StretchR": 1.0,
"C_StretchR_CornerPullR_LowerLipDepressR": 1.0,
"C_StretchR_JawOpen": 1.0,
"C_StretchR_LowerLipBite_R": 1.0,
"C_StretchR_LowerLipDepressR": 1.0,
"C_StretchR_LowerLipDepressR_JawOpen": 1.0,
"C_UpperLipBiteL_JawOpen": 1.0,
"C_UpperLipBiteR_JawOpen": 1.0,
"C_UpperLipRaiseL_UpperLipRaiseR": 1.0,
"C_WidenL_LookDownL": 1.0,
"C_WidenR_LookDownR": 1.0,
"C_WrinkleL_MouthCornerPullL": 1.0,
"C_WrinkleL_UpperLipRaiseL": 1.0,
"C_WrinkleR_MouthCornerPullR": 1.0,
"C_WrinkleR_UpperLipRaiseR": 1.0,
"Eye_Cheek_Raise_L": 1.0,
"Eye_Cheek_Raise_R": 1.0,
"Eye_Face_Scrunch_L": 1.0,
"Eye_Face_Scrunch_R": 1.0,
"Eye_Lid_Press_L": 1.0,
"Eye_Lid_Press_R": 1.0,
"Eye_Look_Down_L": 1.0,
"Eye_Look_Down_R": 1.0,
"Eye_Look_Left_L": 1.0,
"Eye_Look_Left_R": 1.0,
"Eye_Look_Right_L": 1.0,
"Eye_Look_Right_R": 1.0,
"Eye_Look_Up_L": 1.0,
"Eye_Look_Up_R": 1.0,
"Eye_LowerLid_Down_L": 1.0,
"Eye_LowerLid_Down_R": 1.0,
"Eye_LowerLid_Up_L": 1.0,
"Eye_LowerLid_Up_R": 1.0,
"Eye_Parallel_Look_Direction": 1.0,
"Eye_Pupil_Narrow_L": 1.0,
"Eye_Pupil_Narrow_R": 1.0,
"Eye_Pupil_Wide_L": 1.0,
"Eye_Pupil_Wide_R": 1.0,
"Eye_Relax_L": 1.0,
"Eye_Relax_R": 1.0,
"Eye_Squint_Inner_L": 1.0,
"Eye_Squint_Inner_R": 1.0,
"Eye_UpperLid_Up_L": 1.0,
"Eye_UpperLid_Up_R": 1.0,
"Eye_Widen_L": 1.0,
"Eye_Widen_R": 1.0,
"Eyelashes_Down_IN_L": 1.0,
"Eyelashes_Down_IN_R": 1.0,
"Eyelashes_Down_OUT_L": 1.0,
"Eyelashes_Down_OUT_R": 1.0,
"Eyelashes_Up_IN_L": 1.0,
"Eyelashes_Up_IN_R": 1.0,
"Eyelashes_Up_OUT_L": 1.0,
"Eyelashes_Up_OUT_R": 1.0,
"Jaw_Back": 1.0,
"Jaw_Chin_Compress_L": 1.0,
"Jaw_Chin_Compress_R": 1.0,
"Jaw_Chin_Raise_DL": 1.0,
"Jaw_Chin_Raise_DR": 1.0,
"Jaw_Chin_Raise_UL": 1.0,
"Jaw_Chin_Raise_UR": 1.0,
"Jaw_Clench_L": 1.0,
"Jaw_Clench_R": 1.0,
"Jaw_Fwd": 1.0,
"Jaw_Left": 1.0,
"Jaw_Open_Extreme": 1.0,
"Jaw_Right": 1.0,
"Mouth_Cheek_Blow_L": 1.0,
"Mouth_Cheek_Blow_R": 1.0,
"Mouth_Cheek_Suck_L": 1.0,
"Mouth_Cheek_Suck_R": 1.0,
"Mouth_Corner_Depress_L": 1.0,
"Mouth_Corner_Depress_R": 1.0,
"Mouth_Corner_Down_L": 1.0,
"Mouth_Corner_Down_R": 1.0,
"Mouth_Corner_Narrow_L": 1.0,
"Mouth_Corner_Narrow_R": 1.0,
"Mouth_Corner_Pull_L": 1.0,
"Mouth_Corner_Pull_R": 1.0,
"Mouth_Corner_Rounder_DL": 1.0,
"Mouth_Corner_Rounder_DR": 1.0,
"Mouth_Corner_Rounder_UL": 1.0,
"Mouth_Corner_Rounder_UR": 1.0,
"Mouth_Corner_Sharpen_DL": 1.0,
"Mouth_Corner_Sharpen_DR": 1.0,
"Mouth_Corner_Sharpen_UL": 1.0,
"Mouth_Corner_Sharpen_UR": 1.0,
"Mouth_Corner_Up_L": 1.0,
"Mouth_Corner_Up_R": 1.0,
"Mouth_Corner_Wide_L": 1.0,
"Mouth_Corner_Wide_R": 1.0,
"Mouth_Funnel_DL": 1.0,
"Mouth_Funnel_DR": 1.0,
"Mouth_Funnel_UL": 1.0,
"Mouth_Funnel_UR": 1.0,
"Mouth_Left": 1.0,
"Mouth_Lips_Blow_L": 1.0,
"Mouth_Lips_Blow_R": 1.0,
"Mouth_Lips_Press_L": 1.0,
"Mouth_Lips_Press_R": 1.0,
"Mouth_Lips_Pull_DL": 1.0,
"Mouth_Lips_Pull_DR": 1.0,
"Mouth_Lips_Pull_UL": 1.0,
"Mouth_Lips_Pull_UR": 1.0,
"Mouth_Lips_Purse_DL": 1.0,
"Mouth_Lips_Purse_DR": 1.0,
"Mouth_Lips_Purse_UL": 1.0,
"Mouth_Lips_Purse_UR": 1.0,
"Mouth_Lips_Push_DL": 1.0,
"Mouth_Lips_Push_DR": 1.0,
"Mouth_Lips_Push_UL": 1.0,
"Mouth_Lips_Push_UR": 1.0,
"Mouth_Lips_Sticky_L_Ph1": 1.0,
"Mouth_Lips_Sticky_L_Ph2": 1.0,
"Mouth_Lips_Sticky_L_Ph3": 1.0,
"Mouth_Lips_Sticky_R_Ph1": 1.0,
"Mouth_Lips_Sticky_R_Ph2": 1.0,
"Mouth_Lips_Sticky_R_Ph3": 1.0,
"Mouth_Lips_Thick_DL": 1.0,
"Mouth_Lips_Thick_DR": 1.0,
"Mouth_Lips_Thick_Inward_DL": 1.0,
"Mouth_Lips_Thick_Inward_DR": 1.0,
"Mouth_Lips_Thick_Inward_UL": 1.0,
"Mouth_Lips_Thick_Inward_UR": 1.0,
"Mouth_Lips_Thick_UL": 1.0,
"Mouth_Lips_Thick_UR": 1.0,
"Mouth_Lips_Thin_DL": 1.0,
"Mouth_Lips_Thin_DR": 1.0,
"Mouth_Lips_Thin_Inward_DL": 1.0,
"Mouth_Lips_Thin_Inward_DR": 1.0,
"Mouth_Lips_Thin_Inward_UL": 1.0,
"Mouth_Lips_Thin_Inward_UR": 1.0,
"Mouth_Lips_Thin_UL": 1.0,
"Mouth_Lips_Thin_UR": 1.0,
"Mouth_Lips_Tighten_DL": 1.0,
"Mouth_Lips_Tighten_DR": 1.0,
"Mouth_Lips_Tighten_UL": 1.0,
"Mouth_Lips_Tighten_UR": 1.0,
"Mouth_Lips_Together_DL": 1.0,
"Mouth_Lips_Together_DR": 1.0,
"Mouth_Lips_Together_UL": 1.0,
"Mouth_Lips_Together_UR": 1.0,
"Mouth_Lips_Towards_DL": 1.0,
"Mouth_Lips_Towards_DR": 1.0,
"Mouth_Lips_Towards_UL": 1.0,
"Mouth_Lips_Towards_UR": 1.0,
"Mouth_LowerLip_Bite_L": 1.0,
"Mouth_LowerLip_Bite_R": 1.0,
"Mouth_LowerLip_Depress_L": 1.0,
"Mouth_LowerLip_Depress_R": 1.0,
"Mouth_LowerLip_RollIn_L": 1.0,
"Mouth_LowerLip_RollIn_R": 1.0,
"Mouth_LowerLip_Roll_Out_L": 1.0,
"Mouth_LowerLip_Roll_Out_R": 1.0,
"Mouth_LowerLip_Shift_Left": 1.0,
"Mouth_LowerLip_Shift_Right": 1.0,
"Mouth_LowerLip_Towards_Teeth_L": 1.0,
"Mouth_LowerLip_Towards_Teeth_R": 1.0,
"Mouth_Mouth_Press_DL": 1.0,
"Mouth_Mouth_Press_DR": 1.0,
"Mouth_Mouth_Press_UL": 1.0,
"Mouth_Mouth_Press_UR": 1.0,
"Mouth_Right": 1.0,
"Mouth_SharpCorner_Pull_L": 1.0,
"Mouth_SharpCorner_Pull_R": 1.0,
"Mouth_Sticky_DC": 1.0,
"Mouth_Sticky_D_IN_L": 1.0,
"Mouth_Sticky_D_IN_R": 1.0,
"Mouth_Sticky_D_OUT_L": 1.0,
"Mouth_Sticky_D_OUT_R": 1.0,
"Mouth_Sticky_UC": 1.0,
"Mouth_Sticky_U_IN_L": 1.0,
"Mouth_Sticky_U_IN_R": 1.0,
"Mouth_Sticky_U_OUT_L": 1.0,
"Mouth_Sticky_U_OUT_R": 1.0,
"Mouth_StretchLips_Close_L": 1.0,
"Mouth_StretchLips_Close_R": 1.0,
"Mouth_UpperLip_Bite_L": 1.0,
"Mouth_UpperLip_Bite_R": 1.0,
"Mouth_UpperLip_Raise_L": 1.0,
"Mouth_UpperLip_Raise_R": 1.0,
"Mouth_UpperLip_RollIn_L": 1.0,
"Mouth_UpperLip_RollIn_R": 1.0,
"Mouth_UpperLip_Roll_Out_L": 1.0,
"Mouth_UpperLip_Roll_Out_R": 1.0,
"Mouth_UpperLip_Shift_Left": 1.0,
"Mouth_UpperLip_Shift_Right": 1.0,
"Mouth_UpperLip_Towards_Teeth_L": 1.0,
"Mouth_UpperLip_Towards_Teeth_R": 1.0,
"Neck_Digastric_Down": 1.0,
"Neck_Digastric_Up": 1.0,
"Neck_Mastoid_Contract_L": 1.0,
"Neck_Mastoid_Contract_R": 1.0,
"Neck_Stretch_L": 1.0,
"Neck_Stretch_R": 1.0,
"Neck_Swallow_Ph1": 1.0,
"Neck_Swallow_Ph2": 1.0,
"Neck_Swallow_Ph3": 1.0,
"Neck_Swallow_Ph4": 1.0,
"Neck_Swallow_Ph5": 1.0,
"Neck_Throat_Down": 1.0,
"Neck_Throat_Exhale": 1.0,
"Neck_Throat_Inhale": 1.0,
"Neck_Throat_Up": 1.0,
"Nose_Nasolabial_Deepen_L": 1.0,
"Nose_Nasolabial_Deepen_R": 1.0,
"Nose_Nostril_Compress_L": 1.0,
"Nose_Nostril_Compress_R": 1.0,
"Nose_Nostril_Depress_L": 1.0,
"Nose_Nostril_Depress_R": 1.0,
"Nose_Wrinkle_L": 1.0,
"Nose_Wrinkle_R": 1.0,
"Nose_Wrinkle_Upper_L": 1.0,
"Nose_Wrinkle_Upper_R": 1.0,
"Teeth_Back_D": 1.0,
"Teeth_Back_U": 1.0,
"Teeth_Down_D": 1.0,
"Teeth_Down_U": 1.0,
"Teeth_Fwd_D": 1.0,
"Teeth_Fwd_U": 1.0,
"Teeth_Left_D": 1.0,
"Teeth_Left_U": 1.0,
"Teeth_Right_D": 1.0,
"Teeth_Right_U": 1.0,
"Teeth_Up_D": 1.0,
"Teeth_Up_U": 1.0,
"Tongue_Bend_Down": 1.0,
"Tongue_Bend_Up": 1.0,
"Tongue_Left": 1.0,
"Tongue_Press": 1.0,
"Tongue_Right": 1.0,
"Tongue_Thick": 1.0,
"Tongue_Thin": 1.0,
"Tongue_Tip_Left": 1.0,
"Tongue_Tip_Right": 1.0,
"Tongue_Twist_Left": 1.0,
"Tongue_Twist_Right": 1.0,
"Brow_Drop_Left": 1.0,
"Brow_Drop_Right": 1.0,
"Brow_Raise_Inner_Left": 1.0,
"Brow_Raise_Inner_Right": 1.0,
"Brow_Raise_Left": 1.0,
"Brow_Raise_Outer_Left": 1.0,
"Brow_Raise_Outer_Right": 1.0,
"Brow_Raise_Right": 1.0,
"Cheek_Blow_L": 1.0,
"Cheek_Blow_R": 1.0,
"Cheeks_Suck": 1.0,
"Eyes_Blink": 1.0,
"Left_Eyeball_Look_Down": 1.0,
"Left_Eyeball_Look_L": 1.0,
"Left_Eyeball_Look_R": 1.0,
"Left_Eyeball_Look_Up": 1.0,
"Mouth_Blow": 1.0,
"Mouth_Bottom_Lip_Bite": 1.0,
"Mouth_Bottom_Lip_Down": 1.0,
"Mouth_Bottom_Lip_Trans": 1.0,
"Mouth_Bottom_Lip_Under": 1.0,
"Mouth_Frown": 1.0,
"Mouth_Lips_Jaw_Adjust": 1.0,
"Mouth_Lips_Open": 1.0,
"Mouth_Lips_Part": 1.0,
"Mouth_Lips_Tight": 1.0,
"Mouth_Lips_Tuck": 1.0,
"Mouth_Open": 1.0,
"Mouth_Plosive": 1.0,
"Mouth_Pucker": 1.0,
"Mouth_Pucker_Open": 1.0,
"Mouth_Skewer": 1.0,
"Mouth_Smile": 1.0,
"Mouth_Snarl_Lower_L": 1.0,
"Mouth_Snarl_Lower_R": 1.0,
"Mouth_Snarl_Upper_L": 1.0,
"Mouth_Snarl_Upper_R": 1.0,
"Mouth_Top_Lip_Under": 1.0,
"Mouth_Top_Lip_Up": 1.0,
"Mouth_Widen": 1.0,
"Mouth_Widen_Sides": 1.0,
"Move_Jaw_Down": 1.0,
"Move_Jaw_L": 1.0,
"Move_Jaw_R": 1.0,
"Nose_Flank_Raise_L": 1.0,
"Nose_Flank_Raise_R": 1.0,
"Nose_Flanks_Raise": 1.0,
"Nose_Nostrils_Flare": 1.0,
"Nose_Scrunch": 1.0,
"Right_Eyeball_Look_Down": 1.0,
"Right_Eyeball_Look_L": 1.0,
"Right_Eyeball_Look_R": 1.0,
"Right_Eyeball_Look_Up": 1.0,
"Turn_Jaw_Down": 1.0,
"Turn_Jaw_L": 1.0,
"Turn_Jaw_R": 1.0,
"A01_Brow_Inner_Up": 1.0,
"A02_Brow_Down_Left": 1.0,
"A03_Brow_Down_Right": 1.0,
"A04_Brow_Outer_Up_Left": 1.0,
"A05_Brow_Outer_Up_Right": 1.0,
"A06_Eye_Look_Up_Left": 1.0,
"A07_Eye_Look_Up_Right": 1.0,
"A08_Eye_Look_Down_Left": 1.0,
"A09_Eye_Look_Down_Right": 1.0,
"A10_Eye_Look_Out_Left": 1.0,
"A11_Eye_Look_In_Left": 1.0,
"A12_Eye_Look_In_Right": 1.0,
"A13_Eye_Look_Out_Right": 1.0,
"A14_Eye_Blink_Left": 1.0,
"A15_Eye_Blink_Right": 1.0,
"A16_Eye_Squint_Left": 1.0,
"A17_Eye_Squint_Right": 1.0,
"A18_Eye_Wide_Left": 1.0,
"A19_Eye_Wide_Right": 1.0,
"A20_Cheek_Puff": 1.0,
"A21_Cheek_Squint_Left": 1.0,
"A22_Cheek_Squint_Right": 1.0,
"A23_Nose_Sneer_Left": 1.0,
"A24_Nose_Sneer_Right": 1.0,
"A25_Jaw_Open": 1.0,
"A26_Jaw_Forward": 1.0,
"A27_Jaw_Left": 1.0,
"A28_Jaw_Right": 1.0,
"A29_Mouth_Funnel": 1.0,
"A30_Mouth_Pucker": 1.0,
"A31_Mouth_Left": 1.0,
"A32_Mouth_Right": 1.0,
"A33_Mouth_Roll_Upper": 1.0,
"A34_Mouth_Roll_Lower": 1.0,
"A35_Mouth_Shrug_Upper": 1.0,
"A36_Mouth_Shrug_Lower": 1.0,
"A37_Mouth_Close": 1.0,
"A38_Mouth_Smile_Left": 1.0,
"A39_Mouth_Smile_Right": 1.0,
"A40_Mouth_Frown_Left": 1.0,
"A41_Mouth_Frown_Right": 1.0,
"A42_Mouth_Dimple_Left": 1.0,
"A43_Mouth_Dimple_Right": 1.0,
"A44_Mouth_Upper_Up_Left": 1.0,
"A45_Mouth_Upper_Up_Right": 1.0,
"A46_Mouth_Lower_Down_Left": 1.0,
"A47_Mouth_Lower_Down_Right": 1.0,
"A48_Mouth_Press_Left": 1.0,
"A49_Mouth_Press_Right": 1.0,
"A50_Mouth_Stretch_Left": 1.0,
"A51_Mouth_Stretch_Right": 1.0,
"A52_Tongue_Out": 1.0,
"T01_Tongue_Up": 1.0,
"T02_Tongue_Down": 1.0,
"T03_Tongue_Left": 1.0,
"T04_Tongue_Right": 1.0,
"T05_Tongue_Roll": 1.0,
"T06_Tongue_Tip_Up": 1.0,
"T07_Tongue_Tip_Down": 1.0,
"T08_Tongue_Width": 1.0,
"T09_Tongue_Thickness": 1.0,
"T10_Tongue_Bulge_Left": 1.0,
"T11_Tongue_Bulge_Right": 1.0,
"OverBite": 1.0,
"Teeth Lower Depth": 1.0,
"Teeth Lower Height": 1.0,
"Teeth Lower Length": 1.0,
"Teeth Lower Scale Width": 1.0,
"Teeth Lower Sharp": 1.0,
"Teeth Upper Depth": 1.0,
"Teeth Upper Height": 1.0,
"Teeth Upper Length": 1.0,
"Teeth Upper Scale Width": 1.0,
"Teeth Upper Sharp": 1.0
}
}
@@ -0,0 +1,88 @@
{
"Bones": {
"CC_Base_NeckTwist01": 1.0,
"CC_Base_NeckTwist02": 1.0,
"CC_Base_Head": 1.0,
"CC_Base_FacialBone": 1.0,
"CC_Base_JawRoot": 1.0,
"CC_Base_Tongue01": 1.0,
"CC_Base_Tongue02": 1.0,
"CC_Base_Tongue03": 1.0,
"CC_Base_Teeth02": 1.0,
"CC_Base_R_Eye": 1.0,
"CC_Base_L_Eye": 1.0,
"CC_Base_UpperJaw": 1.0,
"CC_Base_Teeth01": 1.0,
"master_eye.L": 1.0,
"master_eye.R": 1.0,
"teeth.T": 1.0,
"jaw_master": 1.0,
"chin": 1.0,
"jaw": 1.0,
"teeth.B": 1.0,
"tongue.003": 1.0,
"tongue_master": 1.0,
"tongue": 1.0,
"tongue.001": 1.0,
"tongue.002": 1.0,
"neck": 1.0,
"head": 1.0,
"tweak_spine.005": 1.0,
"eyes": 1.0,
"eye.L": 1.0,
"eye.R": 1.0,
"CTRL_C_head_turn": 1.0,
"CTRL_C_head_move": 1.0,
"CTRL_C_head_tilt": 1.0,
"CTRL_C_head_fwdBack": 1.0,
"CTRL_C_eye": 1.0,
"CTRL_L_eye": 1.0,
"CTRL_R_eye": 1.0,
"CTRL_C_eye_parallelLook": 1.0,
"neck_01": 1.0
},
"Keys": {
"Head_Backward": 1.0,
"Head_Forward": 1.0,
"Head_L": 1.0,
"Head_R": 1.0,
"Head_Tilt_L": 1.0,
"Head_Tilt_R": 1.0,
"Head_Turn_Down": 1.0,
"Head_Turn_L": 1.0,
"Head_Turn_R": 1.0,
"Head_Turn_Up": 1.0,
"Eye_Look_Down_L": 1.0,
"Eye_Look_Down_R": 1.0,
"Eye_Look_Left_L": 1.0,
"Eye_Look_Left_R": 1.0,
"Eye_Look_Right_L": 1.0,
"Eye_Look_Right_R": 1.0,
"Eye_Look_Up_L": 1.0,
"Eye_Look_Up_R": 1.0,
"Eye_L_Look_Down": 1.0,
"Eye_L_Look_L": 1.0,
"Eye_L_Look_R": 1.0,
"Eye_L_Look_Up": 1.0,
"Eye_R_Look_Down": 1.0,
"Eye_R_Look_L": 1.0,
"Eye_R_Look_R": 1.0,
"Eye_R_Look_Up": 1.0,
"A06_Eye_Look_Up_Left": 1.0,
"A07_Eye_Look_Up_Right": 1.0,
"A08_Eye_Look_Down_Left": 1.0,
"A09_Eye_Look_Down_Right": 1.0,
"A10_Eye_Look_Out_Left": 1.0,
"A11_Eye_Look_In_Left": 1.0,
"A12_Eye_Look_In_Right": 1.0,
"A13_Eye_Look_Out_Right": 1.0,
"Left_Eyeball_Look_Down": 1.0,
"Left_Eyeball_Look_L": 1.0,
"Left_Eyeball_Look_R": 1.0,
"Left_Eyeball_Look_Up": 1.0,
"Right_Eyeball_Look_Down": 1.0,
"Right_Eyeball_Look_L": 1.0,
"Right_Eyeball_Look_R": 1.0,
"Right_Eyeball_Look_Up": 1.0
}
}
@@ -0,0 +1,88 @@
{
"Bones": {
"CC_Base_L_Clavicle": 1.0,
"CC_Base_L_Upperarm": 1.0,
"CC_Base_L_Forearm": 1.0,
"CC_Base_L_ForearmTwist01": 1.0,
"CC_Base_L_ForearmTwist02": 1.0,
"CC_Base_L_ElbowShareBone": 1.0,
"CC_Base_L_Hand": 1.0,
"CC_Base_L_Pinky1": 1.0,
"CC_Base_L_Pinky2": 1.0,
"CC_Base_L_Pinky3": 1.0,
"CC_Base_L_Ring1": 1.0,
"CC_Base_L_Ring2": 1.0,
"CC_Base_L_Ring3": 1.0,
"CC_Base_L_Mid1": 1.0,
"CC_Base_L_Mid2": 1.0,
"CC_Base_L_Mid3": 1.0,
"CC_Base_L_Index1": 1.0,
"CC_Base_L_Index2": 1.0,
"CC_Base_L_Index3": 1.0,
"CC_Base_L_Thumb1": 1.0,
"CC_Base_L_Thumb2": 1.0,
"CC_Base_L_Thumb3": 1.0,
"CC_Base_L_UpperarmTwist01": 1.0,
"CC_Base_L_UpperarmTwist02": 1.0,
"hand_tweak.L": 1.0,
"forearm_tweak.L": 1.0,
"forearm_tweak.L.001": 1.0,
"upper_arm_tweak.L.001": 1.0,
"upper_arm_parent.L": 1.0,
"upper_arm_fk.L": 1.0,
"forearm_fk.L": 1.0,
"hand_fk.L": 1.0,
"upper_arm_ik.L": 1.0,
"upper_arm_tweak.L": 1.0,
"f_index.01_master.L": 1.0,
"thumb.01_master.L": 1.0,
"f_index.01.L": 1.0,
"f_index.02.L": 1.0,
"f_index.03.L": 1.0,
"f_index.01.L.001": 1.0,
"thumb.01.L": 1.0,
"thumb.02.L": 1.0,
"thumb.03.L": 1.0,
"thumb.01.L.001": 1.0,
"f_middle.01_master.L": 1.0,
"f_middle.01.L": 1.0,
"f_middle.02.L": 1.0,
"f_middle.03.L": 1.0,
"f_middle.01.L.001": 1.0,
"f_ring.01_master.L": 1.0,
"f_ring.01.L": 1.0,
"f_ring.02.L": 1.0,
"f_ring.03.L": 1.0,
"f_ring.01.L.001": 1.0,
"f_pinky.01_master.L": 1.0,
"f_pinky.01.L": 1.0,
"f_pinky.02.L": 1.0,
"f_pinky.03.L": 1.0,
"f_pinky.01.L.001": 1.0,
"palm.L": 1.0,
"hand_ik.L": 1.0,
"upper_arm_ik_target.L": 1.0,
"clavicle_l": 1.0,
"upperarm_l": 1.0,
"upperarm_twist_01_l": 1.0,
"lowerarm_l": 1.0,
"lowerarm_twist_01_l": 1.0,
"hand_l": 1.0,
"middle_01_l": 1.0,
"middle_02_l": 1.0,
"middle_03_l": 1.0,
"index_01_l": 1.0,
"index_02_l": 1.0,
"index_03_l": 1.0,
"ring_01_l": 1.0,
"ring_02_l": 1.0,
"ring_03_l": 1.0,
"pinky_01_l": 1.0,
"pinky_02_l": 1.0,
"pinky_03_l": 1.0,
"thumb_01_l": 1.0,
"thumb_02_l": 1.0,
"thumb_03_l": 1.0
},
"Keys": {}
}
@@ -0,0 +1,67 @@
{
"Bones": {
"CC_Base_L_Hand": 1.0,
"CC_Base_L_Pinky1": 1.0,
"CC_Base_L_Pinky2": 1.0,
"CC_Base_L_Pinky3": 1.0,
"CC_Base_L_Ring1": 1.0,
"CC_Base_L_Ring2": 1.0,
"CC_Base_L_Ring3": 1.0,
"CC_Base_L_Mid1": 1.0,
"CC_Base_L_Mid2": 1.0,
"CC_Base_L_Mid3": 1.0,
"CC_Base_L_Index1": 1.0,
"CC_Base_L_Index2": 1.0,
"CC_Base_L_Index3": 1.0,
"CC_Base_L_Thumb1": 1.0,
"CC_Base_L_Thumb2": 1.0,
"CC_Base_L_Thumb3": 1.0,
"hand_tweak.L": 1.0,
"hand_fk.L": 1.0,
"f_index.01_master.L": 1.0,
"thumb.01_master.L": 1.0,
"f_index.01.L": 1.0,
"f_index.02.L": 1.0,
"f_index.03.L": 1.0,
"f_index.01.L.001": 1.0,
"thumb.01.L": 1.0,
"thumb.02.L": 1.0,
"thumb.03.L": 1.0,
"thumb.01.L.001": 1.0,
"f_middle.01_master.L": 1.0,
"f_middle.01.L": 1.0,
"f_middle.02.L": 1.0,
"f_middle.03.L": 1.0,
"f_middle.01.L.001": 1.0,
"f_ring.01_master.L": 1.0,
"f_ring.01.L": 1.0,
"f_ring.02.L": 1.0,
"f_ring.03.L": 1.0,
"f_ring.01.L.001": 1.0,
"f_pinky.01_master.L": 1.0,
"f_pinky.01.L": 1.0,
"f_pinky.02.L": 1.0,
"f_pinky.03.L": 1.0,
"f_pinky.01.L.001": 1.0,
"palm.L": 1.0,
"hand_ik.L": 1.0,
"upper_arm_ik_target.L": 1.0,
"hand_l": 1.0,
"middle_01_l": 1.0,
"middle_02_l": 1.0,
"middle_03_l": 1.0,
"index_01_l": 1.0,
"index_02_l": 1.0,
"index_03_l": 1.0,
"ring_01_l": 1.0,
"ring_02_l": 1.0,
"ring_03_l": 1.0,
"pinky_01_l": 1.0,
"pinky_02_l": 1.0,
"pinky_03_l": 1.0,
"thumb_01_l": 1.0,
"thumb_02_l": 1.0,
"thumb_03_l": 1.0
},
"Keys": {}
}
@@ -0,0 +1,88 @@
{
"Bones": {
"CC_Base_BoneRoot": 1.0,
"CC_Base_Hip": 1.0,
"CC_Base_Pelvis": 1.0,
"CC_Base_L_Thigh": 1.0,
"CC_Base_L_Calf": 1.0,
"CC_Base_L_Foot": 1.0,
"CC_Base_L_ToeBaseShareBone": 1.0,
"CC_Base_L_ToeBase": 1.0,
"CC_Base_L_PinkyToe1": 1.0,
"CC_Base_L_RingToe1": 1.0,
"CC_Base_L_MidToe1": 1.0,
"CC_Base_L_IndexToe1": 1.0,
"CC_Base_L_BigToe1": 1.0,
"CC_Base_L_CalfTwist01": 1.0,
"CC_Base_L_CalfTwist02": 1.0,
"CC_Base_L_KneeShareBone": 1.0,
"CC_Base_L_ThighTwist01": 1.0,
"CC_Base_L_ThighTwist02": 1.0,
"CC_Base_R_Thigh": 1.0,
"CC_Base_R_Calf": 1.0,
"CC_Base_R_KneeShareBone": 1.0,
"CC_Base_R_Foot": 1.0,
"CC_Base_R_ToeBase": 1.0,
"CC_Base_R_BigToe1": 1.0,
"CC_Base_R_PinkyToe1": 1.0,
"CC_Base_R_RingToe1": 1.0,
"CC_Base_R_IndexToe1": 1.0,
"CC_Base_R_MidToe1": 1.0,
"CC_Base_R_ToeBaseShareBone": 1.0,
"CC_Base_R_CalfTwist01": 1.0,
"CC_Base_R_CalfTwist02": 1.0,
"CC_Base_R_ThighTwist01": 1.0,
"CC_Base_R_ThighTwist02": 1.0,
"CC_Base_Waist": 1.0,
"root": 1.0,
"hips": 1.0,
"torso": 1.0,
"foot_tweak.L": 1.0,
"shin_tweak.L": 1.0,
"shin_tweak.L.001": 1.0,
"thigh_tweak.L.001": 1.0,
"foot_tweak.R": 1.0,
"shin_tweak.R": 1.0,
"shin_tweak.R.001": 1.0,
"thigh_tweak.R.001": 1.0,
"thigh_parent.L": 1.0,
"thigh_fk.L": 1.0,
"shin_fk.L": 1.0,
"foot_fk.L": 1.0,
"toe_fk.L": 1.0,
"thigh_ik.L": 1.0,
"thigh_tweak.L": 1.0,
"thigh_parent.R": 1.0,
"thigh_fk.R": 1.0,
"shin_fk.R": 1.0,
"foot_fk.R": 1.0,
"toe_fk.R": 1.0,
"thigh_ik.R": 1.0,
"thigh_tweak.R": 1.0,
"foot_ik.L": 1.0,
"foot_spin_ik.L": 1.0,
"foot_heel_ik.L": 1.0,
"toe_ik.L": 1.0,
"thigh_ik_target.L": 1.0,
"foot_ik.R": 1.0,
"foot_spin_ik.R": 1.0,
"foot_heel_ik.R": 1.0,
"toe_ik.R": 1.0,
"thigh_ik_target.R": 1.0,
"RL_BoneRoot": 1.0,
"pelvis": 1.0,
"thigh_l": 1.0,
"thigh_twist_01_l": 1.0,
"calf_l": 1.0,
"calf_twist_01_l": 1.0,
"foot_l": 1.0,
"ball_l": 1.0,
"thigh_r": 1.0,
"thigh_twist_01_r": 1.0,
"calf_r": 1.0,
"calf_twist_01_r": 1.0,
"foot_r": 1.0,
"ball_r": 1.0
},
"Keys": {}
}
@@ -0,0 +1,89 @@
{
"Bones": {
"CC_Base_R_Clavicle": 1.0,
"CC_Base_R_Upperarm": 1.0,
"CC_Base_R_Forearm": 1.0,
"CC_Base_R_ElbowShareBone": 1.0,
"CC_Base_R_ForearmTwist01": 1.0,
"CC_Base_R_ForearmTwist02": 1.0,
"CC_Base_R_Hand": 1.0,
"CC_Base_R_Ring1": 1.0,
"CC_Base_R_Ring2": 1.0,
"CC_Base_R_Ring3": 1.0,
"CC_Base_R_Mid1": 1.0,
"CC_Base_R_Mid2": 1.0,
"CC_Base_R_Mid3": 1.0,
"CC_Base_R_Thumb1": 1.0,
"CC_Base_R_Thumb2": 1.0,
"CC_Base_R_Thumb3": 1.0,
"CC_Base_R_Index1": 1.0,
"CC_Base_R_Index2": 1.0,
"CC_Base_R_Index3": 1.0,
"CC_Base_R_Pinky1": 1.0,
"CC_Base_R_Pinky2": 1.0,
"CC_Base_R_Pinky3": 1.0,
"CC_Base_R_UpperarmTwist01": 1.0,
"CC_Base_R_UpperarmTwist02": 1.0,
"hand_tweak.R": 1.0,
"forearm_tweak.R": 1.0,
"forearm_tweak.R.001": 1.0,
"upper_arm_tweak.R.001": 1.0,
"upper_arm_parent.R": 1.0,
"upper_arm_fk.R": 1.0,
"forearm_fk.R": 1.0,
"hand_fk.R": 1.0,
"upper_arm_ik.R": 1.0,
"upper_arm_tweak.R": 1.0,
"f_index.01_master.R": 1.0,
"thumb.01_master.R": 1.0,
"f_index.01.R": 1.0,
"f_index.02.R": 1.0,
"f_index.03.R": 1.0,
"f_index.01.R.001": 1.0,
"thumb.01.R": 1.0,
"thumb.02.R": 1.0,
"thumb.03.R": 1.0,
"thumb.01.R.001": 1.0,
"f_middle.01_master.R": 1.0,
"f_middle.01.R": 1.0,
"f_middle.02.R": 1.0,
"f_middle.03.R": 1.0,
"f_middle.01.R.001": 1.0,
"f_ring.01_master.R": 1.0,
"f_ring.01.R": 1.0,
"f_ring.02.R": 1.0,
"f_ring.03.R": 1.0,
"f_ring.01.R.001": 1.0,
"f_pinky.01_master.R": 1.0,
"f_pinky.01.R": 1.0,
"f_pinky.02.R": 1.0,
"f_pinky.03.R": 1.0,
"f_pinky.01.R.001": 1.0,
"palm.R": 1.0,
"shoulder.R": 1.0,
"hand_ik.R": 1.0,
"upper_arm_ik_target.R": 1.0,
"clavicle_r": 1.0,
"upperarm_r": 1.0,
"upperarm_twist_01_r": 1.0,
"lowerarm_r": 1.0,
"lowerarm_twist_01_r": 1.0,
"hand_r": 1.0,
"middle_01_r": 1.0,
"middle_02_r": 1.0,
"middle_03_r": 1.0,
"ring_01_r": 1.0,
"ring_02_r": 1.0,
"ring_03_r": 1.0,
"thumb_01_r": 1.0,
"thumb_02_r": 1.0,
"thumb_03_r": 1.0,
"index_01_r": 1.0,
"index_02_r": 1.0,
"index_03_r": 1.0,
"pinky_01_r": 1.0,
"pinky_02_r": 1.0,
"pinky_03_r": 1.0
},
"Keys": {}
}
@@ -0,0 +1,67 @@
{
"Bones": {
"CC_Base_R_Hand": 1.0,
"CC_Base_R_Ring1": 1.0,
"CC_Base_R_Ring2": 1.0,
"CC_Base_R_Ring3": 1.0,
"CC_Base_R_Mid1": 1.0,
"CC_Base_R_Mid2": 1.0,
"CC_Base_R_Mid3": 1.0,
"CC_Base_R_Thumb1": 1.0,
"CC_Base_R_Thumb2": 1.0,
"CC_Base_R_Thumb3": 1.0,
"CC_Base_R_Index1": 1.0,
"CC_Base_R_Index2": 1.0,
"CC_Base_R_Index3": 1.0,
"CC_Base_R_Pinky1": 1.0,
"CC_Base_R_Pinky2": 1.0,
"CC_Base_R_Pinky3": 1.0,
"hand_tweak.R": 1.0,
"hand_fk.R": 1.0,
"f_index.01_master.R": 1.0,
"thumb.01_master.R": 1.0,
"f_index.01.R": 1.0,
"f_index.02.R": 1.0,
"f_index.03.R": 1.0,
"f_index.01.R.001": 1.0,
"thumb.01.R": 1.0,
"thumb.02.R": 1.0,
"thumb.03.R": 1.0,
"thumb.01.R.001": 1.0,
"f_middle.01_master.R": 1.0,
"f_middle.01.R": 1.0,
"f_middle.02.R": 1.0,
"f_middle.03.R": 1.0,
"f_middle.01.R.001": 1.0,
"f_ring.01_master.R": 1.0,
"f_ring.01.R": 1.0,
"f_ring.02.R": 1.0,
"f_ring.03.R": 1.0,
"f_ring.01.R.001": 1.0,
"f_pinky.01_master.R": 1.0,
"f_pinky.01.R": 1.0,
"f_pinky.02.R": 1.0,
"f_pinky.03.R": 1.0,
"f_pinky.01.R.001": 1.0,
"palm.R": 1.0,
"hand_ik.R": 1.0,
"upper_arm_ik_target.R": 1.0,
"hand_r": 1.0,
"middle_01_r": 1.0,
"middle_02_r": 1.0,
"middle_03_r": 1.0,
"ring_01_r": 1.0,
"ring_02_r": 1.0,
"ring_03_r": 1.0,
"thumb_01_r": 1.0,
"thumb_02_r": 1.0,
"thumb_03_r": 1.0,
"index_01_r": 1.0,
"index_02_r": 1.0,
"index_03_r": 1.0,
"pinky_01_r": 1.0,
"pinky_02_r": 1.0,
"pinky_03_r": 1.0
},
"Keys": {}
}
@@ -0,0 +1,278 @@
{
"Bones": {
"CC_Base_Spine01": 1.0,
"CC_Base_Spine02": 1.0,
"CC_Base_NeckTwist01": 1.0,
"CC_Base_NeckTwist02": 1.0,
"CC_Base_Head": 1.0,
"CC_Base_FacialBone": 1.0,
"CC_Base_JawRoot": 1.0,
"CC_Base_Tongue01": 1.0,
"CC_Base_Tongue02": 1.0,
"CC_Base_Tongue03": 1.0,
"CC_Base_Teeth02": 1.0,
"CC_Base_R_Eye": 1.0,
"CC_Base_L_Eye": 1.0,
"CC_Base_UpperJaw": 1.0,
"CC_Base_Teeth01": 1.0,
"CC_Base_L_Clavicle": 1.0,
"CC_Base_L_Upperarm": 1.0,
"CC_Base_L_Forearm": 1.0,
"CC_Base_L_ForearmTwist01": 1.0,
"CC_Base_L_ForearmTwist02": 1.0,
"CC_Base_L_ElbowShareBone": 1.0,
"CC_Base_L_Hand": 1.0,
"CC_Base_L_Pinky1": 1.0,
"CC_Base_L_Pinky2": 1.0,
"CC_Base_L_Pinky3": 1.0,
"CC_Base_L_Ring1": 1.0,
"CC_Base_L_Ring2": 1.0,
"CC_Base_L_Ring3": 1.0,
"CC_Base_L_Mid1": 1.0,
"CC_Base_L_Mid2": 1.0,
"CC_Base_L_Mid3": 1.0,
"CC_Base_L_Index1": 1.0,
"CC_Base_L_Index2": 1.0,
"CC_Base_L_Index3": 1.0,
"CC_Base_L_Thumb1": 1.0,
"CC_Base_L_Thumb2": 1.0,
"CC_Base_L_Thumb3": 1.0,
"CC_Base_L_UpperarmTwist01": 1.0,
"CC_Base_L_UpperarmTwist02": 1.0,
"CC_Base_L_RibsTwist": 1.0,
"CC_Base_L_Breast": 1.0,
"CC_Base_R_RibsTwist": 1.0,
"CC_Base_R_Breast": 1.0,
"CC_Base_R_Clavicle": 1.0,
"CC_Base_R_Upperarm": 1.0,
"CC_Base_R_Forearm": 1.0,
"CC_Base_R_ElbowShareBone": 1.0,
"CC_Base_R_ForearmTwist01": 1.0,
"CC_Base_R_ForearmTwist02": 1.0,
"CC_Base_R_Hand": 1.0,
"CC_Base_R_Ring1": 1.0,
"CC_Base_R_Ring2": 1.0,
"CC_Base_R_Ring3": 1.0,
"CC_Base_R_Mid1": 1.0,
"CC_Base_R_Mid2": 1.0,
"CC_Base_R_Mid3": 1.0,
"CC_Base_R_Thumb1": 1.0,
"CC_Base_R_Thumb2": 1.0,
"CC_Base_R_Thumb3": 1.0,
"CC_Base_R_Index1": 1.0,
"CC_Base_R_Index2": 1.0,
"CC_Base_R_Index3": 1.0,
"CC_Base_R_Pinky1": 1.0,
"CC_Base_R_Pinky2": 1.0,
"CC_Base_R_Pinky3": 1.0,
"CC_Base_R_UpperarmTwist01": 1.0,
"CC_Base_R_UpperarmTwist02": 1.0,
"torso": 1.0,
"chest": 1.0,
"spine_fk.001": 1.0,
"spine_fk": 1.0,
"tweak_spine": 1.0,
"tweak_spine.001": 1.0,
"spine_fk.002": 1.0,
"tweak_spine.002": 1.0,
"spine_fk.003": 1.0,
"master_eye.L": 1.0,
"master_eye.R": 1.0,
"teeth.T": 1.0,
"jaw_master": 1.0,
"chin": 1.0,
"jaw": 1.0,
"teeth.B": 1.0,
"tongue.003": 1.0,
"tongue_master": 1.0,
"tongue": 1.0,
"tongue.001": 1.0,
"tongue.002": 1.0,
"neck": 1.0,
"head": 1.0,
"tweak_spine.004": 1.0,
"tweak_spine.005": 1.0,
"tweak_spine.003": 1.0,
"hand_tweak.L": 1.0,
"forearm_tweak.L": 1.0,
"forearm_tweak.L.001": 1.0,
"upper_arm_tweak.L.001": 1.0,
"upper_arm_parent.L": 1.0,
"upper_arm_fk.L": 1.0,
"forearm_fk.L": 1.0,
"hand_fk.L": 1.0,
"upper_arm_ik.L": 1.0,
"upper_arm_tweak.L": 1.0,
"f_index.01_master.L": 1.0,
"thumb.01_master.L": 1.0,
"f_index.01.L": 1.0,
"f_index.02.L": 1.0,
"f_index.03.L": 1.0,
"f_index.01.L.001": 1.0,
"thumb.01.L": 1.0,
"thumb.02.L": 1.0,
"thumb.03.L": 1.0,
"thumb.01.L.001": 1.0,
"f_middle.01_master.L": 1.0,
"f_middle.01.L": 1.0,
"f_middle.02.L": 1.0,
"f_middle.03.L": 1.0,
"f_middle.01.L.001": 1.0,
"f_ring.01_master.L": 1.0,
"f_ring.01.L": 1.0,
"f_ring.02.L": 1.0,
"f_ring.03.L": 1.0,
"f_ring.01.L.001": 1.0,
"f_pinky.01_master.L": 1.0,
"f_pinky.01.L": 1.0,
"f_pinky.02.L": 1.0,
"f_pinky.03.L": 1.0,
"f_pinky.01.L.001": 1.0,
"palm.L": 1.0,
"hand_tweak.R": 1.0,
"forearm_tweak.R": 1.0,
"forearm_tweak.R.001": 1.0,
"upper_arm_tweak.R.001": 1.0,
"upper_arm_parent.R": 1.0,
"upper_arm_fk.R": 1.0,
"forearm_fk.R": 1.0,
"hand_fk.R": 1.0,
"upper_arm_ik.R": 1.0,
"upper_arm_tweak.R": 1.0,
"f_index.01_master.R": 1.0,
"thumb.01_master.R": 1.0,
"f_index.01.R": 1.0,
"f_index.02.R": 1.0,
"f_index.03.R": 1.0,
"f_index.01.R.001": 1.0,
"thumb.01.R": 1.0,
"thumb.02.R": 1.0,
"thumb.03.R": 1.0,
"thumb.01.R.001": 1.0,
"f_middle.01_master.R": 1.0,
"f_middle.01.R": 1.0,
"f_middle.02.R": 1.0,
"f_middle.03.R": 1.0,
"f_middle.01.R.001": 1.0,
"f_ring.01_master.R": 1.0,
"f_ring.01.R": 1.0,
"f_ring.02.R": 1.0,
"f_ring.03.R": 1.0,
"f_ring.01.R.001": 1.0,
"f_pinky.01_master.R": 1.0,
"f_pinky.01.R": 1.0,
"f_pinky.02.R": 1.0,
"f_pinky.03.R": 1.0,
"f_pinky.01.R.001": 1.0,
"palm.R": 1.0,
"breast.L": 1.0,
"breast.R": 1.0,
"shoulder.L": 1.0,
"shoulder.R": 1.0,
"hand_ik.L": 1.0,
"upper_arm_ik_target.L": 1.0,
"hand_ik.R": 1.0,
"upper_arm_ik_target.R": 1.0,
"eyes": 1.0,
"eye.L": 1.0,
"eye.R": 1.0,
"CTRL_C_head_turn": 1.0,
"CTRL_C_head_move": 1.0,
"CTRL_C_head_tilt": 1.0,
"CTRL_C_head_fwdBack": 1.0,
"CTRL_C_eye": 1.0,
"CTRL_L_eye": 1.0,
"CTRL_R_eye": 1.0,
"CTRL_C_eye_parallelLook": 1.0,
"spine_01": 1.0,
"spine_02": 1.0,
"spine_03": 1.0,
"clavicle_l": 1.0,
"upperarm_l": 1.0,
"upperarm_twist_01_l": 1.0,
"lowerarm_l": 1.0,
"lowerarm_twist_01_l": 1.0,
"hand_l": 1.0,
"middle_01_l": 1.0,
"middle_02_l": 1.0,
"middle_03_l": 1.0,
"index_01_l": 1.0,
"index_02_l": 1.0,
"index_03_l": 1.0,
"ring_01_l": 1.0,
"ring_02_l": 1.0,
"ring_03_l": 1.0,
"pinky_01_l": 1.0,
"pinky_02_l": 1.0,
"pinky_03_l": 1.0,
"thumb_01_l": 1.0,
"thumb_02_l": 1.0,
"thumb_03_l": 1.0,
"clavicle_r": 1.0,
"upperarm_r": 1.0,
"upperarm_twist_01_r": 1.0,
"lowerarm_r": 1.0,
"lowerarm_twist_01_r": 1.0,
"hand_r": 1.0,
"middle_01_r": 1.0,
"middle_02_r": 1.0,
"middle_03_r": 1.0,
"ring_01_r": 1.0,
"ring_02_r": 1.0,
"ring_03_r": 1.0,
"thumb_01_r": 1.0,
"thumb_02_r": 1.0,
"thumb_03_r": 1.0,
"index_01_r": 1.0,
"index_02_r": 1.0,
"index_03_r": 1.0,
"pinky_01_r": 1.0,
"pinky_02_r": 1.0,
"pinky_03_r": 1.0,
"neck_01": 1.0
},
"Keys": {
"Head_Backward": 1.0,
"Head_Forward": 1.0,
"Head_L": 1.0,
"Head_R": 1.0,
"Head_Tilt_L": 1.0,
"Head_Tilt_R": 1.0,
"Head_Turn_Down": 1.0,
"Head_Turn_L": 1.0,
"Head_Turn_R": 1.0,
"Head_Turn_Up": 1.0,
"Eye_Look_Down_L": 1.0,
"Eye_Look_Down_R": 1.0,
"Eye_Look_Left_L": 1.0,
"Eye_Look_Left_R": 1.0,
"Eye_Look_Right_L": 1.0,
"Eye_Look_Right_R": 1.0,
"Eye_Look_Up_L": 1.0,
"Eye_Look_Up_R": 1.0,
"Eye_L_Look_Down": 1.0,
"Eye_L_Look_L": 1.0,
"Eye_L_Look_R": 1.0,
"Eye_L_Look_Up": 1.0,
"Eye_R_Look_Down": 1.0,
"Eye_R_Look_L": 1.0,
"Eye_R_Look_R": 1.0,
"Eye_R_Look_Up": 1.0,
"A06_Eye_Look_Up_Left": 1.0,
"A07_Eye_Look_Up_Right": 1.0,
"A08_Eye_Look_Down_Left": 1.0,
"A09_Eye_Look_Down_Right": 1.0,
"A10_Eye_Look_Out_Left": 1.0,
"A11_Eye_Look_In_Left": 1.0,
"A12_Eye_Look_In_Right": 1.0,
"A13_Eye_Look_Out_Right": 1.0,
"Left_Eyeball_Look_Down": 1.0,
"Left_Eyeball_Look_L": 1.0,
"Left_Eyeball_Look_R": 1.0,
"Left_Eyeball_Look_Up": 1.0,
"Right_Eyeball_Look_Down": 1.0,
"Right_Eyeball_Look_L": 1.0,
"Right_Eyeball_Look_R": 1.0,
"Right_Eyeball_Look_Up": 1.0
}
}
@@ -0,0 +1,36 @@
{
"Bones": {},
"Keys": {
"AE": 1.0,
"Ah": 1.0,
"B_M_P": 1.0,
"Ch_J": 1.0,
"EE": 1.0,
"Er": 1.0,
"F_V": 1.0,
"IH": 1.0,
"K_G_H_NG": 1.0,
"Oh": 1.0,
"R": 1.0,
"S_Z": 1.0,
"TH": 1.0,
"W_OO": 1.0,
"T_L_D_N": 1.0,
"V_Wide": 1.0,
"V_Tongue_up": 1.0,
"V_Tongue_Raise": 1.0,
"V_Tongue_Out": 1.0,
"V_Tongue_Narrow": 1.0,
"V_Tongue_Lower": 1.0,
"V_Tongue_Curl_U": 1.0,
"V_Tongue_Curl_D": 1.0,
"V_Tight_O": 1.0,
"V_Tight": 1.0,
"V_Open": 1.0,
"V_None": 1.0,
"V_Lip_Open": 1.0,
"V_Explosive": 1.0,
"V_Dental_Lip": 1.0,
"V_Affricate": 1.0
}
}
@@ -33,6 +33,31 @@ Links
## Changelog ## Changelog
### 2.4.2
- Updated Morph export for Blender 5.1
- Fix to constraint driver setup with missing shape keys.
- Fix to Blender 5.1 import operator changes.
- Fix to Blender 4.5 import fbx.
- Fix to Blender 5+ grease pencil layers (Spring Rig Generation).
- Motion Sets & Blending update:
- Motion sets updated for lights and cameras.
- Motion blending for light & camera motion sets.
- Motion blending always generates a new motion (non-destructive)
- Datalink Pose and Sequence now write onto current motion.
### 2.4.1
- Mesh modify pipeline.
- Sends mesh only (no armature) for exact replace mesh updates.
- Used mainly for direct facial expression editing with the facial profile editor.
- Animation Import Options and Blending:
- Animations and be blended on import or existing motions can be blended together to create new motions.
- Root Relative: Source animation root bone is transformed relative to the starting frame on destination animation, so that the root bone follows on from the exiting animation.
- Motion Blending: Source animation blends in and out over the destination animation by the set number of frames and follows custom blend curves. For smooth transitions.
- Bone masking: Only the masked bones are blended into the destination animation. Each bone can be weighted individually.
- Shape Key masking: Only the masked shape keys are blended into the destination animation. Each shape key can be weighted individually.
- Blend mask presets: Can be applied, removed and saved.
- Fixes to compositor texture pack baking.
### 2.4.0 ### 2.4.0
- Displacement update for Skin and Pbr materials. - Displacement update for Skin and Pbr materials.
- Displacement added for Teeth and Hair. - Displacement added for Teeth and Hair.
@@ -21,6 +21,7 @@ if "bpy" in locals():
importlib.reload(vars) importlib.reload(vars)
importlib.reload(params) importlib.reload(params)
importlib.reload(utils) importlib.reload(utils)
importlib.reload(ui)
importlib.reload(lib) importlib.reload(lib)
importlib.reload(cc) importlib.reload(cc)
importlib.reload(jsonutils) importlib.reload(jsonutils)
@@ -69,6 +70,7 @@ from . import preferences
from . import vars from . import vars
from . import params from . import params
from . import utils from . import utils
from . import ui
from . import lib from . import lib
from . import cc from . import cc
from . import jsonutils from . import jsonutils
@@ -114,7 +116,7 @@ from . import rlx
bl_info = { bl_info = {
"name": "CC/iC Tools", "name": "CC/iC Tools",
"author": "Victor Soupday", "author": "Victor Soupday",
"version": (2, 4, 0), "version": (2, 4, 2),
"blender": (3, 4, 1), "blender": (3, 4, 1),
"category": "Characters", "category": "Characters",
"location": "3D View > Properties > CC/iC Pipeline", "location": "3D View > Properties > CC/iC Pipeline",
@@ -139,8 +141,8 @@ classes = (
properties.CCICBakeProps, properties.CCICBakeProps,
properties.CC3ActionList, properties.CC3ActionList,
properties.CC3ArmatureList, properties.CC3ArmatureList,
properties.CCICStringList,
properties.CCIC_UI_MixItem, properties.CCIC_UI_MixItem,
properties.CCIC_UI_MixList,
properties.CCICActionStore, properties.CCICActionStore,
properties.CCICActionOptions, properties.CCICActionOptions,
properties.CC3HeadParameters, properties.CC3HeadParameters,
@@ -168,6 +170,7 @@ classes = (
properties.CCICExpressionData, properties.CCICExpressionData,
properties.CC3ObjectCache, properties.CC3ObjectCache,
properties.CC3CharacterCache, properties.CC3CharacterCache,
properties.CC3StagingCache,
properties.CC3ImportProps, properties.CC3ImportProps,
importer.CC3Import, importer.CC3Import,
@@ -206,10 +209,12 @@ classes = (
rigutils.CCICMotionSetRename, rigutils.CCICMotionSetRename,
rigutils.CCICMotionSetInfo, rigutils.CCICMotionSetInfo,
rigutils.CCICRigUtils, rigutils.CCICRigUtils,
rigutils.CCIC_ImportMixBones_UL_List, rigutils.CCIC_IMPORTMIX_UL_List,
rigutils.CCIC_RigMixBones_UL_List, rigutils.CCIC_AVAILABLEMIX_UL_List,
rigutils.CCICActionImportFunctions, rigutils.CCICActionImportFunctions,
rigutils.CCICActionImportOptions, rigutils.CCICMotionBlendFunctions,
rigutils.CCICMotionPrefs,
rigutils.CCICMotionBlend,
facerig.CCICImportARKitCSV, facerig.CCICImportARKitCSV,
panels.ARMATURE_UL_List, panels.ARMATURE_UL_List,
@@ -19,7 +19,7 @@ import os
from mathutils import Vector from mathutils import Vector
from . import normal, colorspace, imageutils, wrinkle, nodeutils, materials, utils, params, vars from . import normal, colorspace, imageutils, wrinkle, nodeutils, materials, utils, params, vars
from .exporter import get_export_objects from .exporter import get_export_objects
from . utils import B500 from . utils import B500, B430
BAKE_SAMPLES = 4 BAKE_SAMPLES = 4
BAKE_INDEX = 1001 BAKE_INDEX = 1001
@@ -54,39 +54,7 @@ def prep_bake(context, mat: bpy.types.Material=None, samples=BAKE_SAMPLES, image
if not context: if not context:
context = bpy.context context = bpy.context
# cycles settings bake_state["render_settings"] = store_render_settings(context)
bake_state["samples"] = context.scene.cycles.samples
if utils.B500():
bake_state["use_bake_multires"] = context.scene.render.bake.use_multires
else:
bake_state["use_bake_multires"] = context.scene.render.use_bake_multires
# Blender 3.0
if utils.B300():
bake_state["preview_samples"] = context.scene.cycles.preview_samples
bake_state["use_adaptive_sampling"] = context.scene.cycles.use_adaptive_sampling
bake_state["use_preview_adaptive_sampling"] = context.scene.cycles.use_preview_adaptive_sampling
bake_state["use_denoising"] = context.scene.cycles.use_denoising
bake_state["use_preview_denoising"] = context.scene.cycles.use_preview_denoising
bake_state["use_auto_tile"] = context.scene.cycles.use_auto_tile
# render settings
bake_state["file_format"] = context.scene.render.image_settings.file_format
bake_state["color_depth"] = context.scene.render.image_settings.color_depth
bake_state["color_mode"] = context.scene.render.image_settings.color_mode
bake_state["use_selected_to_active"] = context.scene.render.bake.use_selected_to_active
bake_state["use_pass_direct"] = context.scene.render.bake.use_pass_direct
bake_state["use_pass_indirect"] = context.scene.render.bake.use_pass_indirect
bake_state["margin"] = context.scene.render.bake.margin
bake_state["use_clear"] = context.scene.render.bake.use_clear
bake_state["image_format"] = context.scene.render.image_settings.file_format
# Blender 2.92
if utils.B292():
bake_state["target"] = context.scene.render.bake.target
# color management
bake_state["view_transform"] = context.scene.view_settings.view_transform
bake_state["look"] = context.scene.view_settings.look
bake_state["gamma"] = context.scene.view_settings.gamma
bake_state["exposure"] = context.scene.view_settings.exposure
bake_state["colorspace"] = context.scene.sequencer_colorspace_settings.name
context.scene.cycles.samples = samples context.scene.cycles.samples = samples
context.scene.render.image_settings.file_format = image_format context.scene.render.image_settings.file_format = image_format
@@ -119,28 +87,36 @@ def prep_bake(context, mat: bpy.types.Material=None, samples=BAKE_SAMPLES, image
if utils.B292(): if utils.B292():
context.scene.render.bake.target = 'IMAGE_TEXTURES' context.scene.render.bake.target = 'IMAGE_TEXTURES'
# TODO Which blender versions for these?
context.scene.render.resolution_percentage = 100
if B500():
context.scene.render.image_settings.media_type = "IMAGE"
context.scene.display_settings.emulation = "AUTO"
context.scene.render.image_settings.compression = 15
context.scene.render.use_overwrite = True
context.scene.render.use_placeholder = False
context.scene.render.use_render_cache = False
context.scene.render.use_file_extension = True
if B430():
context.scene.view_settings.use_white_balance = False
# color management override
context.scene.render.image_settings.color_management = "FOLLOW_SCENE"
# post processing
context.scene.render.use_compositing = False
context.scene.render.use_sequencer = False
context.scene.render.dither_intensity = 0.0
# go into wireframe mode (so Blender doesn't update or recompile the material shaders while # go into wireframe mode (so Blender doesn't update or recompile the material shaders while
# we manipulate them for baking, and also so Blender doesn't fire up the cycles viewport...): # we manipulate them for baking, and also so Blender doesn't fire up the cycles viewport...):
shading: bpy.types.View3DShading = utils.get_view_3d_shading(context) shading: bpy.types.View3DShading = utils.get_view_3d_shading(context)
if shading: if shading:
bake_state["shading"] = shading.type
shading.type = 'WIREFRAME'
else:
bake_state["shading"] = 'MATERIAL'
shading.type = 'WIREFRAME' shading.type = 'WIREFRAME'
# set cycles rendering mode for baking # set cycles rendering mode for baking
bake_state["engine"] = context.scene.render.engine
context.scene.render.engine = 'CYCLES' context.scene.render.engine = 'CYCLES'
bake_state["cycles_bake_type"] = context.scene.cycles.bake_type
if utils.B500():
bake_state["render_bake_type"] = context.scene.render.bake.type
else:
bake_state["render_bake_type"] = context.scene.render.bake_type
context.scene.cycles.bake_type = "COMBINED" context.scene.cycles.bake_type = "COMBINED"
if make_surface: if make_surface:
# deselect everything # deselect everything
bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.select_all(action='DESELECT')
# create the baking plane, a single quad baking surface for an even sampling across the entire texture # create the baking plane, a single quad baking surface for an even sampling across the entire texture
@@ -160,6 +136,117 @@ def prep_bake(context, mat: bpy.types.Material=None, samples=BAKE_SAMPLES, image
return bake_state return bake_state
def get_context_setting(context, settings, path):
try:
settings[path] = eval(f"context.{path}", None, locals())
except: ...
#except Exception as e:
# utils.log_warn(f"context setting: {path} not found!")
def set_context_setting(context, settings, path):
try:
exec(f"context.{path} = settings[path]", None, locals())
except: ...
#except Exception as e:
# utils.log_warn(f"context setting: {path} not found!")
CONTEXT_SETTINGS = [
# cycles settings
"scene.cycles.samples",
"scene.render.bake.use_multires", # B500
"scene.render.use_bake_multires", # < B500
"scene.cycles.preview_samples", # B300
"scene.cycles.use_adaptive_sampling", # B300
"scene.cycles.use_preview_adaptive_sampling", # B300
"scene.cycles.use_denoising", # B300
"scene.cycles.use_preview_denoising", # B300
"scene.cycles.use_auto_tile", # B300
# render settings
"scene.render.resolution_x",
"scene.render.resolution_y",
"scene.render.resolution_percentage",
"scene.render.image_settings.media_type", ###!!!
"scene.render.image_settings.file_format",
"scene.render.image_settings.color_depth",
"scene.render.image_settings.color_mode",
"scene.render.image_settings.compression", ###!!!
"scene.render.bake.use_selected_to_active",
"scene.render.bake.use_pass_direct",
"scene.render.bake.use_pass_indirect",
"scene.render.bake.margin",
"scene.render.bake.use_clear",
"scene.render.use_overwrite", ###!!!
"scene.render.use_placeholder", ###!!!
"scene.render.use_render_cache", ###!!!
"scene.render.use_file_extension", ###!!!
"scene.render.bake.target", #B292
"scene.render.filepath",
# display settings
"scene.display_settings.display_device",
# color management
"scene.view_settings.use_curve_mapping",
"scene.view_settings.view_transform",
"scene.view_settings.look",
"scene.view_settings.gamma",
"scene.view_settings.exposure",
"scene.sequencer_colorspace_settings.name",
"scene.display_settings.emulation", # B???
"scene.view_settings.use_white_balance", # B???
"scene.view_settings.white_balance_temperature",
"scene.view_settings.white_balance_tint",
# color management override B???
"scene.render.image_settings.color_management",
"scene.render.image_settings.display_settings.display_device",
"scene.render.image_settings.view_settings.view_transform",
"scene.render.image_settings.view_settings.look",
"scene.render.image_settings.view_settings.exposure",
"scene.render.image_settings.view_settings.gamma",
"scene.render.image_settings.view_settings.use_curve_mapping",
"scene.render.image_settings.view_settings.use_white_balance",
# renderer
"scene.render.engine",
"scene.cycles.bake_type",
"scene.render.bake.type", #B500
"scene.render.bake_type", # < B500
# post processing
"scene.render.use_compositing", ###!!!
"scene.render.use_sequencer", ###!!!
"scene.render.dither_intensity", ###!!!
]
def store_render_settings(context):
settings = {}
if not context:
context = bpy.context
for path in CONTEXT_SETTINGS:
get_context_setting(context, settings, path)
# current viewport shading
shading: bpy.types.View3DShading = utils.get_view_3d_shading(context)
settings["shading.type"] = shading.type if shading else 'MATERIAL'
return settings
def restore_render_settings(context, settings):
if not context:
context = bpy.context
for path in CONTEXT_SETTINGS:
set_context_setting(context, settings, path)
# current viewport shading
shading: bpy.types.View3DShading = utils.get_view_3d_shading(context)
if shading:
shading.type = settings["shading.type"]
return settings
def set_bake_material(bake_state, mat): def set_bake_material(bake_state, mat):
if mat and bake_state and "bake_surface" in bake_state: if mat and bake_state and "bake_surface" in bake_state:
bake_surface = bake_state["bake_surface"] bake_surface = bake_state["bake_surface"]
@@ -179,52 +266,7 @@ def post_bake(context, state):
if not context: if not context:
context = bpy.context context = bpy.context
# cycles settings restore_render_settings(context, state["render_settings"])
context.scene.cycles.samples = state["samples"]
# Blender 3.0
if utils.B300():
context.scene.cycles.preview_samples = state["preview_samples"]
context.scene.cycles.use_adaptive_sampling = state["use_adaptive_sampling"]
context.scene.cycles.use_preview_adaptive_sampling = state["use_preview_adaptive_sampling"]
context.scene.cycles.use_denoising = state["use_denoising"]
context.scene.cycles.use_preview_denoising = state["use_preview_denoising"]
context.scene.cycles.use_auto_tile = state["use_auto_tile"]
# render settings
context.scene.render.image_settings.file_format = state["file_format"]
context.scene.render.image_settings.color_depth = state["color_depth"]
context.scene.render.image_settings.color_mode = state["color_mode"]
if utils.B500():
context.scene.render.bake.use_multires = state["use_bake_multires"]
else:
context.scene.render.use_bake_multires = state["use_bake_multires"]
context.scene.render.bake.use_selected_to_active = state["use_selected_to_active"]
context.scene.render.bake.use_pass_direct = state["use_pass_direct"]
context.scene.render.bake.use_pass_indirect = state["use_pass_indirect"]
context.scene.render.bake.margin = state["margin"]
context.scene.render.bake.use_clear = state["use_clear"]
context.scene.render.image_settings.file_format = state["image_format"]
# Blender 2.92
if utils.B292():
context.scene.render.bake.target = state["target"]
# color management
context.scene.view_settings.view_transform = state["view_transform"]
context.scene.view_settings.look = state["look"]
context.scene.view_settings.gamma = state["gamma"]
context.scene.view_settings.exposure = state["exposure"]
context.scene.sequencer_colorspace_settings.name = state["colorspace"]
# render engine
context.scene.render.engine = state["engine"]
# viewport shading
shading = utils.get_view_3d_shading(context)
if shading:
shading.type = state["shading"]
# bake type
context.scene.cycles.bake_type = state["cycles_bake_type"]
if utils.B500():
context.scene.render.bake.type = state["render_bake_type"]
else:
context.scene.render.bake_type = state["render_bake_type"]
# remove the bake surface # remove the bake surface
if "bake_surface" in state: if "bake_surface" in state:
@@ -632,8 +674,12 @@ def get_compositor_tree(context) -> bpy.types.NodeGroup:
return context.scene.node_tree return context.scene.node_tree
def compositing_setup(context): def compositing_setup(context: bpy.types.Context):
settings = store_render_settings(context)
if B500(): if B500():
# node tree
old_tree = context.scene.compositing_node_group old_tree = context.scene.compositing_node_group
tree = bpy.data.node_groups.new("Compositor Bake", "CompositorNodeTree") tree = bpy.data.node_groups.new("Compositor Bake", "CompositorNodeTree")
context.scene.compositing_node_group = tree context.scene.compositing_node_group = tree
@@ -650,10 +696,29 @@ def compositing_setup(context):
for node in nodes: for node in nodes:
store[node] = node.mute store[node] = node.mute
node.mute = True node.mute = True
return nodes, links, store, tree
# override context render settings
if B500():
context.scene.render.image_settings.media_type = "IMAGE"
context.scene.display_settings.emulation = "AUTO"
context.scene.render.image_settings.compression = 15
context.scene.render.use_overwrite = True
context.scene.render.use_placeholder = False
context.scene.render.use_render_cache = False
context.scene.render.use_file_extension = True
if B430():
context.scene.view_settings.use_white_balance = False
# color management override
context.scene.render.image_settings.color_management = "OVERRIDE"
# post processing
context.scene.render.use_compositing = True
context.scene.render.use_sequencer = False
context.scene.render.dither_intensity = 0.0
return nodes, links, store, tree, settings
def compositing_cleanup(context, store): def compositing_cleanup(context, store, settings):
if B500(): if B500():
context.scene.compositing_node_group = store[1] context.scene.compositing_node_group = store[1]
bpy.data.node_groups.remove(store[0]) bpy.data.node_groups.remove(store[0])
@@ -668,6 +733,7 @@ def compositing_cleanup(context, store):
clean_up.append(node) clean_up.append(node)
for node in clean_up: for node in clean_up:
nodes.remove(node) nodes.remove(node)
restore_render_settings(context, settings)
def compositor_pack_RGBA(mat, channel_id, pack_mode, bake_dir, def compositor_pack_RGBA(mat, channel_id, pack_mode, bake_dir,
@@ -706,7 +772,7 @@ def compositor_pack_RGBA(mat, channel_id, pack_mode, bake_dir,
utils.log_info(f"Resuing existing texture pack {image_name}, not baking.") utils.log_info(f"Resuing existing texture pack {image_name}, not baking.")
return imageutils.load_image(image_path, color_space) return imageutils.load_image(image_path, color_space)
nodes, links, store, node_tree = compositing_setup(context) nodes, links, store, node_tree, settings = compositing_setup(context)
CNCC_node = nodeutils.make_shader_node(nodes, "CompositorNodeCombineColor") CNCC_node = nodeutils.make_shader_node(nodes, "CompositorNodeCombineColor")
CNCGO_node = None CNCGO_node = None
@@ -831,30 +897,32 @@ def compositor_pack_RGBA(mat, channel_id, pack_mode, bake_dir,
nodeutils.link_nodes(links, CNI_A_node, "Image", CNCC_node, "Alpha") nodeutils.link_nodes(links, CNI_A_node, "Image", CNCC_node, "Alpha")
nodeutils.link_nodes(links, CNI_A_node, "Image", CNCGO_node, "Alpha") nodeutils.link_nodes(links, CNI_A_node, "Image", CNCGO_node, "Alpha")
X = context.scene.render.resolution_x
Y = context.scene.render.resolution_y
FP = context.scene.render.filepath
FF = context.scene.render.image_settings.file_format
CD = context.scene.render.image_settings.color_depth
CM = context.scene.render.image_settings.color_mode
VT = context.scene.view_settings.view_transform
LK = context.scene.view_settings.look
GA = context.scene.view_settings.gamma
EX = context.scene.view_settings.exposure
context.scene.render.resolution_x = width context.scene.render.resolution_x = width
context.scene.render.resolution_y = height context.scene.render.resolution_y = height
context.scene.render.resolution_percentage = 100
context.scene.render.image_settings.file_format = 'OPEN_EXR' context.scene.render.image_settings.file_format = 'OPEN_EXR'
context.scene.render.image_settings.color_depth = color_depth context.scene.render.image_settings.color_depth = color_depth
context.scene.render.image_settings.color_mode = 'RGBA' context.scene.render.image_settings.color_mode = 'RGBA'
context.scene.render.image_settings.exr_codec = 'ZIP' context.scene.render.image_settings.exr_codec = 'ZIP'
context.scene.render.image_settings.color_management = 'OVERRIDE'
context.scene.render.image_settings.linear_colorspace_settings.name = color_space context.scene.render.image_settings.linear_colorspace_settings.name = color_space
context.scene.render.filepath = image_path context.scene.render.filepath = image_path
context.scene.render.image_settings.color_management = 'OVERRIDE'
context.scene.render.image_settings.display_settings.display_device = "sRGB"
context.scene.render.image_settings.view_settings.view_transform = "Standard"
context.scene.render.image_settings.view_settings.look = "None"
context.scene.render.image_settings.view_settings.gamma = 1
context.scene.render.image_settings.view_settings.exposure = 0
context.scene.render.image_settings.view_settings.use_curve_mapping = False
if B430():
context.scene.render.image_settings.view_settings.use_white_balance = False
context.scene.display_settings.display_device = "sRGB"
context.scene.view_settings.view_transform = 'Standard' context.scene.view_settings.view_transform = 'Standard'
context.scene.view_settings.look = 'None' context.scene.view_settings.look = 'None'
context.scene.view_settings.gamma = 1 context.scene.view_settings.gamma = 1
context.scene.view_settings.exposure = 0 context.scene.view_settings.exposure = 0
context.scene.view_settings.use_curve_mapping = False
if B430():
context.scene.view_settings.use_white_balance = False
for node in nodes: for node in nodes:
node.select = False node.select = False
@@ -863,18 +931,7 @@ def compositor_pack_RGBA(mat, channel_id, pack_mode, bake_dir,
bpy.ops.render.render(write_still=True) bpy.ops.render.render(write_still=True)
context.scene.render.resolution_x = X compositing_cleanup(context, store, settings)
context.scene.render.resolution_y = Y
context.scene.render.filepath = FP
context.scene.render.image_settings.file_format = FF
context.scene.render.image_settings.color_depth = CD
context.scene.render.image_settings.color_mode = CM
context.scene.view_settings.view_transform = VT
context.scene.view_settings.look = LK
context.scene.view_settings.gamma = GA
context.scene.view_settings.exposure = EX
compositing_cleanup(context, store)
image: bpy.types.Image = imageutils.load_image(image_path, color_space) image: bpy.types.Image = imageutils.load_image(image_path, color_space)
return image return image
@@ -89,8 +89,8 @@ def duplicate_character(chr_cache):
new_id = utils.generate_random_id(20) new_id = utils.generate_random_id(20)
obj_cache.object_id = new_id obj_cache.object_id = new_id
for obj in objects: for obj in objects:
if utils.get_rl_object_id(obj) == old_id: if utils.get_rl_id(obj) == old_id:
utils.set_rl_object_id(obj, new_id) utils.set_rl_id(obj, new_id)
obj_cache.object = obj obj_cache.object = obj
if obj.type == "ARMATURE": if obj.type == "ARMATURE":
action, slot = utils.safe_get_action_slot(old_obj) action, slot = utils.safe_get_action_slot(old_obj)
@@ -112,9 +112,9 @@ def duplicate_character(chr_cache):
mat_cache.material = mat mat_cache.material = mat
chr_rig = utils.get_armature_from_objects(objects) chr_rig = utils.get_armature_from_objects(objects)
character_name = utils.unique_object_name(utils.un_suffix_name(old_cache.character_name)) character_name = utils.unique_object_name(utils.un_suffix_name(old_cache.get_name()))
utils.log_info(f"Using character name: {character_name}") utils.log_info(f"Using character name: {character_name}")
chr_cache.character_name = character_name chr_cache.set_name(character_name)
if chr_cache.rigified: if chr_cache.rigified:
rig_name = character_name + "_Rigify" rig_name = character_name + "_Rigify"
chr_rig["rig_id"] = utils.generate_random_id(20) chr_rig["rig_id"] = utils.generate_random_id(20)
@@ -344,7 +344,7 @@ def convert_generic_to_non_standard(objects, file_path=None, type_override=None,
chr_rig.data.name = chr_name chr_rig.data.name = chr_name
chr_cache = props.import_cache.add() chr_cache = props.import_cache.add()
chr_cache.import_file = "" chr_cache.import_file = ""
chr_cache.character_name = chr_name chr_cache.set_name(chr_name)
chr_cache.import_embedded = False chr_cache.import_embedded = False
chr_cache.generation = "Unknown" chr_cache.generation = "Unknown"
chr_cache.non_standard_type = chr_type chr_cache.non_standard_type = chr_type
@@ -416,7 +416,7 @@ def link_or_append_rl_character(op, context, blend_file, link=False):
for src_cache in src_props.import_cache: for src_cache in src_props.import_cache:
character_name = src_cache.character_name character_name = src_cache.get_name()
import_file = src_cache.import_file import_file = src_cache.import_file
chr_rig = src_cache.get_armature() chr_rig = src_cache.get_armature()
chr_objects = src_cache.get_all_objects(include_armature=False, chr_objects = src_cache.get_all_objects(include_armature=False,
@@ -575,6 +575,7 @@ def reconnect_rl_character_to_fbx(chr_rig, fbx_path):
rig_name = chr_rig.name rig_name = chr_rig.name
character_name = rig_name character_name = rig_name
is_rigify = rigutils.is_rigify_armature(chr_rig)
if "_Rigify" in character_name: if "_Rigify" in character_name:
character_name = character_name.replace("_Rigify", "") character_name = character_name.replace("_Rigify", "")
@@ -592,11 +593,11 @@ def reconnect_rl_character_to_fbx(chr_rig, fbx_path):
meta_rig = bpy.data.objects[meta_rig_name] meta_rig = bpy.data.objects[meta_rig_name]
chr_cache.import_file = fbx_path chr_cache.import_file = fbx_path
chr_cache.character_name = character_name chr_cache.set_name(character_name)
chr_cache.import_embedded = False chr_cache.import_embedded = False
chr_cache.generation = generation chr_cache.generation = generation
chr_cache.non_standard_type = "HUMANOID" chr_cache.non_standard_type = "HUMANOID"
chr_cache.rigified = True chr_cache.rigified = is_rigify
chr_cache.rig_meta_rig = meta_rig chr_cache.rig_meta_rig = meta_rig
chr_cache.rigified_full_face_rig = character_has_bones(chr_rig, ["nose", "lip.T", "lip.B"]) chr_cache.rigified_full_face_rig = character_has_bones(chr_rig, ["nose", "lip.T", "lip.B"])
chr_cache.add_object_cache(chr_rig) chr_cache.add_object_cache(chr_rig)
@@ -642,14 +643,14 @@ def reconnect_rl_character_to_blend(chr_rig, blend_file):
import_file = chr_rig["rl_import_file"] import_file = chr_rig["rl_import_file"]
for chr_cache in src_props.import_cache: for chr_cache in src_props.import_cache:
if chr_cache.import_file == import_file: if chr_cache.import_file == import_file:
utils.log_info(f"Found matching source character fbx: {chr_cache.character_name}") utils.log_info(f"Found matching source character fbx: {chr_cache.get_name()}")
src_cache = chr_cache src_cache = chr_cache
break break
# try to find the source cache by character name # try to find the source cache by character name
for chr_cache in src_props.import_cache: for chr_cache in src_props.import_cache:
if chr_cache.character_name == character_name: if chr_cache.get_name() == character_name:
utils.log_info(f"Found matching source character name: {chr_cache.character_name}") utils.log_info(f"Found matching source character name: {chr_cache.get_name()}")
src_cache = chr_cache src_cache = chr_cache
break break
@@ -683,7 +684,7 @@ def rebuild_character_cache(chr_cache, chr_rig, objects, src_cache=None):
processed = [] processed = []
defaults = [] defaults = []
for obj in objects: for obj in objects:
obj_id = utils.get_rl_object_id(obj) obj_id = utils.get_rl_id(obj)
if utils.object_exists_is_mesh(obj) and obj not in processed: if utils.object_exists_is_mesh(obj) and obj not in processed:
processed.append(obj) processed.append(obj)
src_obj_cache = src_cache.get_object_cache(obj, by_id=obj_id) if src_cache else None src_obj_cache = src_cache.get_object_cache(obj, by_id=obj_id) if src_cache else None
@@ -1826,7 +1827,7 @@ def remove_all_empty_shapekeys_vertex_groups(chr_cache):
key_count = 0 key_count = 0
group_count = 0 group_count = 0
if chr_cache: if chr_cache:
utils.log_info(f"Cleaning empty shape keys and vertex groups in character: {chr_cache.character_name}") utils.log_info(f"Cleaning empty shape keys and vertex groups in character: {chr_cache.get_name()}")
objects = chr_cache.get_cache_objects() objects = chr_cache.get_cache_objects()
body_objects = chr_cache.get_objects_of_type("BODY") body_objects = chr_cache.get_objects_of_type("BODY")
arm = chr_cache.get_armature() arm = chr_cache.get_armature()
@@ -2350,12 +2351,12 @@ class CCICCharacterRename(bpy.types.Operator):
meta_rig.data.name = metarig_name meta_rig.data.name = metarig_name
rig.name = rigify_name rig.name = rigify_name
rig.data.name = rigify_name rig.data.name = rigify_name
chr_cache.character_name = source_name chr_cache.set_name(source_name)
else: else:
rig_name = utils.unique_object_name(self.name, rig) rig_name = utils.unique_object_name(self.name, rig)
rig.name = rig_name rig.name = rig_name
rig.data.name = rig_name rig.data.name = rig_name
chr_cache.character_name = rig_name chr_cache.set_name(rig_name)
if chr_cache.is_non_standard(): if chr_cache.is_non_standard():
chr_cache.non_standard_type = self.non_standard_type chr_cache.non_standard_type = self.non_standard_type
return {"FINISHED"} return {"FINISHED"}
@@ -2364,7 +2365,7 @@ class CCICCharacterRename(bpy.types.Operator):
props = vars.props() props = vars.props()
prefs = vars.prefs() prefs = vars.prefs()
chr_cache = props.get_context_character_cache(context) chr_cache = props.get_context_character_cache(context)
self.name = chr_cache.character_name self.name = chr_cache.get_name()
self.non_standard_type = chr_cache.non_standard_type self.non_standard_type = chr_cache.non_standard_type
return context.window_manager.invoke_props_dialog(self) return context.window_manager.invoke_props_dialog(self)
@@ -909,12 +909,14 @@ def find_transform_var_def(var_defs, source_obj, transform_prop, space="LOCAL_SP
def make_shape_key_var_def(var_name, source_obj, key_name): def make_shape_key_var_def(var_name, source_obj, key_name):
key = get_shape_key(source_obj, key_name) key = get_shape_key(source_obj, key_name)
if key:
data_path = "shape_keys." + key.path_from_id("value") data_path = "shape_keys." + key.path_from_id("value")
var_def = [var_name, var_def = [var_name,
"SINGLE_PROP", "SINGLE_PROP",
source_obj.data, source_obj.data,
data_path] data_path]
return var_def return var_def
return None
def find_shape_key_var_def(var_defs, source_obj, key_name): def find_shape_key_var_def(var_defs, source_obj, key_name):
@@ -58,7 +58,7 @@ def check_valid_export_fbx(chr_cache, objects):
if standard and not arm: if standard and not arm:
if chr_cache: if chr_cache:
message = f"ERROR: Character {chr_cache.character_name} has no armature!" message = f"ERROR: Character {chr_cache.get_name()} has no armature!"
else: else:
message = f"ERROR: Character has no armature!" message = f"ERROR: Character has no armature!"
report.append(message) report.append(message)
@@ -1712,26 +1712,28 @@ def export_arp(file_path, arm, objects):
def obj_export(file_path, use_selection=False, use_animation=False, global_scale=100, def obj_export(file_path, use_selection=False, use_animation=False, global_scale=100,
use_vertex_colors=False, use_vertex_groups=False, apply_modifiers=True, use_vertex_colors=False, use_object_groups=True,
keep_vertex_order=False, use_materials=False): use_material_groups=False, use_vertex_groups=False,
if utils.B330(): apply_modifiers=True, use_materials=False):
bpy.ops.wm.obj_export(filepath=file_path, bpy.ops.wm.obj_export(filepath=file_path,
global_scale=global_scale,
export_selected_objects=use_selection, export_selected_objects=use_selection,
export_animation=use_animation,
export_materials=use_materials,
export_colors=use_vertex_colors,
export_vertex_groups=use_vertex_groups,
apply_modifiers=apply_modifiers)
else:
bpy.ops.export_scene.obj(filepath=file_path,
global_scale=global_scale, global_scale=global_scale,
use_selection=use_selection, forward_axis="NEGATIVE_Z",
use_materials=use_materials, up_axis="Y",
use_animation=use_animation, export_uv=True,
use_vertex_groups=use_vertex_groups, export_normals=True,
use_mesh_modifiers=apply_modifiers, export_colors=use_vertex_colors,
keep_vertex_order=keep_vertex_order) export_curves_as_nurbs=False,
export_triangulated_mesh=False,
apply_modifiers=apply_modifiers,
apply_transform=True,
export_object_groups=use_object_groups,
export_material_groups=use_material_groups,
export_vertex_groups=use_vertex_groups,
export_smooth_groups=False,
export_materials=use_materials,
export_animation=use_animation,
)
def export_standard(self, context, chr_cache, file_path, include_selected): def export_standard(self, context, chr_cache, file_path, include_selected):
@@ -1799,7 +1801,7 @@ def export_standard(self, context, chr_cache, file_path, include_selected):
if not os.path.exists(file_path): if not os.path.exists(file_path):
custom_export = False custom_export = False
# proceed with normal export # proceed with standard export
if not custom_export: if not custom_export:
bpy.ops.export_scene.fbx(filepath=file_path, bpy.ops.export_scene.fbx(filepath=file_path,
global_scale=1.0, global_scale=1.0,
@@ -1808,6 +1810,7 @@ def export_standard(self, context, chr_cache, file_path, include_selected):
bake_anim = export_anim, bake_anim = export_anim,
bake_anim_simplify_factor=self.animation_simplify, bake_anim_simplify_factor=self.animation_simplify,
add_leaf_bones = False, add_leaf_bones = False,
mesh_smooth_type = ("FACE" if self.export_face_smoothing else "OFF"), mesh_smooth_type = ("FACE" if self.export_face_smoothing else "OFF"),
use_mesh_modifiers = False) use_mesh_modifiers = False)
@@ -1855,13 +1858,7 @@ def export_standard(self, context, chr_cache, file_path, include_selected):
utils.unhide(p.object) utils.unhide(p.object)
p.object.select_set(True) p.object.select_set(True)
obj_export(file_path, use_selection=True, obj_export(file_path, use_selection=True)
global_scale=100,
use_materials=False,
keep_vertex_order=True,
use_vertex_colors=True,
use_vertex_groups=True,
apply_modifiers=True)
#export_copy_obj_key(chr_cache, dir, name) #export_copy_obj_key(chr_cache, dir, name)
export_copy_asset_file(chr_cache, dir, name, ".ObjKey", chr_cache.get_import_key_file()) export_copy_asset_file(chr_cache, dir, name, ".ObjKey", chr_cache.get_import_key_file())
@@ -2351,13 +2348,8 @@ def export_as_accessory(file_path, filename_ext):
) )
elif utils.is_file_ext(ext, "OBJ"): elif utils.is_file_ext(ext, "OBJ"):
obj_export(file_path, use_selection=True, obj_export(file_path, use_selection=True,
global_scale=100,
use_animation=False,
use_materials=True, use_materials=True,
keep_vertex_order=True, use_vertex_colors=True)
use_vertex_colors=True,
use_vertex_groups=False,
apply_modifiers=True)
# restore selection # restore selection
bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.select_all(action='DESELECT')
@@ -2374,13 +2366,8 @@ def export_as_replace_mesh(file_path):
state = utils.store_mode_selection_state() state = utils.store_mode_selection_state()
obj_export(file_path, use_selection=True, obj_export(file_path, use_selection=True,
global_scale=100,
use_animation=False,
use_materials=True, use_materials=True,
keep_vertex_order=True, use_vertex_colors=True)
use_vertex_colors=True,
use_vertex_groups=False,
apply_modifiers=True)
# restore selection # restore selection
utils.restore_mode_selection_state(state) utils.restore_mode_selection_state(state)
@@ -1556,19 +1556,21 @@ def build_expression_constraint_add_driver(chr_cache, rigify_rig, objects, head,
for key in source_keys: for key in source_keys:
source_obj = get_expression_shape_key_source_object(objects, head, key) source_obj = get_expression_shape_key_source_object(objects, head, key)
if source_obj:
var_name = f"V{vidx}" var_name = f"V{vidx}"
vidx += 1 vidx += 1
var_def = drivers.make_shape_key_var_def(var_name, source_obj, key) var_def = drivers.make_shape_key_var_def(var_name, source_obj, key)
if var_def:
var_defs.append(var_def) var_defs.append(var_def)
var_expression = get_expression_constraint_var_expression(var_name, points) var_expression = get_expression_constraint_var_expression(var_name, points)
if expression: if expression:
expression += "*" expression += "*"
expression += var_expression expression += var_expression
else:
utils.log_error(f"Unable to find source object for shape key: {key} in {[o.name for o in objects]}")
if expression:
driver_def = ["SCRIPTED", expression] driver_def = ["SCRIPTED", expression]
for obj in objects: for obj in objects:
if utils.object_has_shape_key(obj, target_key): if utils.object_has_shape_key(obj, target_key):
drivers.add_shape_key_driver(rigify_rig, obj, target_key, driver_def, var_defs, 1.0) drivers.add_shape_key_driver(rigify_rig, obj, target_key, driver_def, var_defs, 1.0)
@@ -1619,17 +1621,18 @@ def build_expression_constraint_limit_driver(chr_cache, rigify_rig, objects, hea
for key in source_keys: for key in source_keys:
source_obj = get_expression_shape_key_source_object(objects, head, key) source_obj = get_expression_shape_key_source_object(objects, head, key)
if source_obj:
var_name = f"lv{vidx}" var_name = f"lv{vidx}"
vidx += 1 vidx += 1
var_def = drivers.make_shape_key_var_def(var_name, source_obj, key) var_def = drivers.make_shape_key_var_def(var_name, source_obj, key)
if var_def:
var_defs.append(var_def) var_defs.append(var_def)
var_expression = get_expression_constraint_var_expression(var_name, points) var_expression = get_expression_constraint_var_expression(var_name, points)
if limit_expression: if limit_expression:
limit_expression += "*" limit_expression += "*"
limit_expression += var_expression limit_expression += var_expression
if limit_expression:
# limit facerig control movement ranges # limit facerig control movement ranges
if prefs.rigify_limit_control_range: if prefs.rigify_limit_control_range:
FACERIG_CONFIG = get_facerig_config(chr_cache) FACERIG_CONFIG = get_facerig_config(chr_cache)
@@ -1883,8 +1886,8 @@ def generate_arkit_proxy(chr_cache):
chr_collections = utils.get_object_scene_collections(rigify_rig) chr_collections = utils.get_object_scene_collections(rigify_rig)
objects = lib.get_object(["RL_ARKit_Proxy", "RL_ARKit_Proxy_Head"]) objects = lib.get_object(["RL_ARKit_Proxy", "RL_ARKit_Proxy_Head"])
rig_name = f"{chr_cache.character_name}_ARKit_Proxy" rig_name = f"{chr_cache.get_name()}_ARKit_Proxy"
mesh_name = f"{chr_cache.character_name}_ARKit_Proxy_Head" mesh_name = f"{chr_cache.get_name()}_ARKit_Proxy_Head"
proxy_rig = None proxy_rig = None
proxy_mesh = None proxy_mesh = None
for obj in objects: for obj in objects:
@@ -1908,7 +1911,7 @@ def generate_arkit_proxy(chr_cache):
build_arkit_proxy_drivers(chr_cache, rigify_rig, proxy_rig, proxy_mesh) build_arkit_proxy_drivers(chr_cache, rigify_rig, proxy_rig, proxy_mesh)
wgt_collection = rigutils.get_widget_rig_collection(chr_cache) wgt_collection = rigutils.get_widget_rig_collection(chr_cache)
wgt_root = bones.make_root_widget(f"WGT-{chr_cache.character_name}_rig_arkit_proxy_root", 3.25) wgt_root = bones.make_root_widget(f"WGT-{chr_cache.get_name()}_rig_arkit_proxy_root", 3.25)
if wgt_collection: if wgt_collection:
utils.remove_from_scene_collections(wgt_root) utils.remove_from_scene_collections(wgt_root)
bones.add_widget_to_collection(wgt_root, wgt_collection) bones.add_widget_to_collection(wgt_root, wgt_collection)
@@ -2076,8 +2079,8 @@ def load_csv(chr_cache, file_path):
facial_profile, viseme_profile = chr_cache.get_facial_profile() facial_profile, viseme_profile = chr_cache.get_facial_profile()
if facial_profile in facerig_data.ARKIT_SHAPE_KEY_TARGETS: if facial_profile in facerig_data.ARKIT_SHAPE_KEY_TARGETS:
keys = facerig_data.ARKIT_SHAPE_KEY_TARGETS[facial_profile].keys() keys = facerig_data.ARKIT_SHAPE_KEY_TARGETS[facial_profile].keys()
key_action = utils.make_action(f"{chr_cache.character_name}_ARKit_Proxy_Head", slot_type="KEY", clear=True, reuse=True) key_action = utils.make_action(f"{chr_cache.get_name()}_ARKit_Proxy_Head", slot_type="KEY", clear=True, reuse=True)
arm_action = utils.make_action(f"{chr_cache.character_name}_ARKit_Proxy", slot_type="OBJECT", clear=True, reuse=True) arm_action = utils.make_action(f"{chr_cache.get_name()}_ARKit_Proxy", slot_type="OBJECT", clear=True, reuse=True)
key_channel = utils.get_action_channelbag(key_action, slot_type="KEY") key_channel = utils.get_action_channelbag(key_action, slot_type="KEY")
if key_channel: if key_channel:
for key in keys: for key in keys:
@@ -1567,6 +1567,7 @@ def grease_pencil_to_length_loops(bone_length):
grease_pencil_layer = get_active_grease_pencil_layer() grease_pencil_layer = get_active_grease_pencil_layer()
if not grease_pencil_layer: if not grease_pencil_layer:
utils.log_error(f"Error finding grease pencil layer!")
return return
frame = grease_pencil_layer.active_frame frame = grease_pencil_layer.active_frame
@@ -1590,6 +1591,7 @@ def grease_pencil_to_bones(chr_cache, arm, parent_mode, bone_length = 0.05,
grease_pencil_layer = get_active_grease_pencil_layer() grease_pencil_layer = get_active_grease_pencil_layer()
if not grease_pencil_layer: if not grease_pencil_layer:
utils.log_error(f"Error finding grease pencil layer!")
return return
# turn off grease pencil on current object / mode (including object mode) # turn off grease pencil on current object / mode (including object mode)
@@ -1651,6 +1653,14 @@ def get_active_grease_pencil_layer():
#current_frame = bpy.context.scene.frame_current #current_frame = bpy.context.scene.frame_current
#note_layer = bpy.data.grease_pencils['Annotations'].layers.active #note_layer = bpy.data.grease_pencils['Annotations'].layers.active
#frame = note_layer.active_frame #frame = note_layer.active_frame
if utils.B500():
try:
layer_index = bpy.context.scene.annotation.layers.active_index
layer = bpy.context.scene.annotation.layers[layer_index]
return layer
except:
return None
else:
try: try:
layer_index = bpy.context.scene.grease_pencil.layers.active_index layer_index = bpy.context.scene.grease_pencil.layers.active_index
layer = bpy.context.scene.grease_pencil.layers[layer_index] layer = bpy.context.scene.grease_pencil.layers[layer_index]
@@ -1673,6 +1683,8 @@ def clear_grease_pencil():
active_layer.active_frame.clear() active_layer.active_frame.clear()
except: except:
utils.log_error("Unable to remove active grease pencil frame!") utils.log_error("Unable to remove active grease pencil frame!")
else:
utils.log_error(f"Error finding grease pencil layer!")
def add_custom_bone(chr_cache, arm, parent_mode, bone_length = 0.05, skip_length = 0.0): def add_custom_bone(chr_cache, arm, parent_mode, bone_length = 0.05, skip_length = 0.0):
@@ -20,7 +20,7 @@ import bpy
from enum import IntEnum, IntFlag from enum import IntEnum, IntFlag
from . import (rlx, characters, hik, rigging, rigutils, bones, bake, imageutils, jsonutils, materials, from . import (rlx, characters, hik, rigging, rigutils, bones, bake, imageutils, jsonutils, materials,
facerig, modifiers, wrinkle, drivers, nodeutils, physics, facerig, modifiers, meshutils, wrinkle, drivers, nodeutils, physics,
rigidbody, colorspace, scene, channel_mixer, shaders, rigidbody, colorspace, scene, channel_mixer, shaders,
basic, lib, cc, utils, vars) basic, lib, cc, utils, vars)
@@ -443,10 +443,10 @@ def remap_action_names(arm, objects, actions, source_id, motion_prefix=""):
utils.log_info(f"Armature: {source_id} => {rig_id}") utils.log_info(f"Armature: {source_id} => {rig_id}")
# don't change the armature id if it exists # don't change the armature id if it exists
rl_arm_id = utils.get_rl_object_id(arm) rl_id = utils.get_rl_id(arm)
if not rl_arm_id: if not rl_id:
rl_arm_id = utils.generate_random_id(20) rl_id = utils.generate_random_id(20)
utils.set_rl_object_id(arm, rl_arm_id) utils.set_rl_id(arm, rl_id)
# find all motions for this armature # find all motions for this armature
armature_actions = [] armature_actions = []
@@ -457,6 +457,11 @@ def remap_action_names(arm, objects, actions, source_id, motion_prefix=""):
for action in actions: for action in actions:
split = action.name.split("|") split = action.name.split("|")
action_arm_id = split[0] action_arm_id = split[0]
# Blender 5.1.0+ all actions import as slotted and,
# action names are *not* prefixed with armature name anymore
if utils.B510():
slotted_actions.append(action)
action_arm_id = source_id
motion_id = split[-1] motion_id = split[-1]
if action_arm_id == source_id: if action_arm_id == source_id:
utils.log_info(f"Motion ID: {motion_id}") utils.log_info(f"Motion ID: {motion_id}")
@@ -493,16 +498,16 @@ def remap_action_names(arm, objects, actions, source_id, motion_prefix=""):
utils.log_info(f"Renaming action: {action.name} to {action_name}") utils.log_info(f"Renaming action: {action.name} to {action_name}")
action.name = action_name action.name = action_name
rigutils.add_motion_set_data(action, set_id, set_generation, rigutils.add_motion_set_data(action, set_id, set_generation,
arm_id=rl_arm_id, arm_id=rl_id,
slotted=(action in slotted_actions)) slotted=(action in slotted_actions))
armature_actions.append(action)
else: else:
for obj_id, key_name in key_map.items(): for obj_id, key_name in key_map.items():
if action_key_name == key_name: if action_key_name == key_name:
action_name = rigutils.make_key_action_name(rig_id, motion_id, obj_id, motion_prefix) action_name = rigutils.make_key_action_name(rig_id, motion_id, obj_id, motion_prefix)
utils.log_info(f"Renaming action: {action.name} to {action_name}") utils.log_info(f"Renaming action: {action.name} to {action_name}")
action.name = action_name action.name = action_name
rigutils.add_motion_set_data(action, set_id, set_generation, obj_id=obj_id) rigutils.add_motion_set_data(action, set_id, set_generation,
key_id=obj_id, arm_id=rl_id, slotted=False)
shapekey_actions.append(action) shapekey_actions.append(action)
return armature_actions, shapekey_actions return armature_actions, shapekey_actions
@@ -588,7 +593,7 @@ def process_rl_import(file_path, import_flags, armatures, rl_armatures, cameras,
chr_cache.import_file = file_path chr_cache.import_file = file_path
chr_cache.import_flags = import_flags chr_cache.import_flags = import_flags
# display name of character # display name of character
chr_cache.character_name = character_name chr_cache.set_name(character_name)
arm["rl_import_file"] = file_path arm["rl_import_file"] = file_path
rigutils.fix_cc3_standard_rig(arm) rigutils.fix_cc3_standard_rig(arm)
@@ -607,7 +612,7 @@ def process_rl_import(file_path, import_flags, armatures, rl_armatures, cameras,
# in case of duplicate names: character_name contains the name currently in Blender. # in case of duplicate names: character_name contains the name currently in Blender.
# get_character_id() is the original name. # get_character_id() is the original name.
chr_cache.character_name = arm.name chr_cache.set_name(arm.name)
# add armature to object_cache # add armature to object_cache
chr_cache.add_object_cache(arm) chr_cache.add_object_cache(arm)
# assign bone collections # assign bone collections
@@ -636,13 +641,6 @@ def process_rl_import(file_path, import_flags, armatures, rl_armatures, cameras,
chr_cache.add_object_cache(obj) chr_cache.add_object_cache(obj)
character_meshes.append(obj) character_meshes.append(obj)
# clear custom normals option
if prefs.import_reset_custom_normals:
for obj in character_meshes:
bpy.context.view_layer.objects.active = obj
bpy.ops.mesh.customdata_custom_splitnormals_clear()
bpy.context.view_layer.objects.active = None
# remame actions # remame actions
utils.log_info("Renaming actions:") utils.log_info("Renaming actions:")
utils.log_indent() utils.log_indent()
@@ -652,7 +650,7 @@ def process_rl_import(file_path, import_flags, armatures, rl_armatures, cameras,
# determine character generation # determine character generation
chr_cache.generation = detect_generation(chr_cache, arm, json_data, chr_cache.get_character_id()) chr_cache.generation = detect_generation(chr_cache, arm, json_data, chr_cache.get_character_id())
utils.log_info("Generation: " + chr_cache.character_name + " (" + chr_cache.generation + ")") utils.log_info(f"Generation: {chr_cache.get_name()} ({chr_cache.generation})")
arm["rl_generation"] = chr_cache.generation arm["rl_generation"] = chr_cache.generation
# cache materials # cache materials
@@ -661,6 +659,23 @@ def process_rl_import(file_path, import_flags, armatures, rl_armatures, cameras,
obj = obj_cache.get_object() obj = obj_cache.get_object()
cache_object_materials(chr_cache, obj, chr_json, processed) cache_object_materials(chr_cache, obj, chr_json, processed)
# clear custom normals option
for obj_cache in chr_cache.object_cache:
if obj_cache.is_mesh():
obj = obj_cache.get_object()
fix_5_1_normals = (utils.B510() and prefs.import_fix_5_1_normals and
utils.object_has_shape_keys(obj) and
obj.data.has_custom_normals)
if prefs.import_reset_custom_normals or fix_5_1_normals:
utils.log_info(f"Cleaing custom normals on: {obj.name}")
bpy.context.view_layer.objects.active = obj
bpy.ops.mesh.customdata_custom_splitnormals_clear()
bpy.context.view_layer.objects.active = None
if fix_5_1_normals:
meshutils.set_shading(obj, True)
shaders.init_character_property_defaults(chr_cache, chr_json) shaders.init_character_property_defaults(chr_cache, chr_json)
basic.init_basic_default(chr_cache) basic.init_basic_default(chr_cache)
@@ -709,7 +724,7 @@ def process_rl_import(file_path, import_flags, armatures, rl_armatures, cameras,
chr_cache.import_file = file_path chr_cache.import_file = file_path
chr_cache.import_flags = import_flags chr_cache.import_flags = import_flags
# display name of character # display name of character
chr_cache.character_name = character_name chr_cache.set_name(character_name)
chr_id = chr_cache.get_character_id() chr_id = chr_cache.get_character_id()
# link_id # link_id
@@ -735,7 +750,7 @@ def process_rl_import(file_path, import_flags, armatures, rl_armatures, cameras,
# in case of duplicate names: character_name contains the name currently in Blender. # in case of duplicate names: character_name contains the name currently in Blender.
# import_name contains the original name. # import_name contains the original name.
chr_cache.character_name = arm.name chr_cache.set_name(arm.name)
# add armature to object_cache # add armature to object_cache
chr_cache.add_object_cache(arm) chr_cache.add_object_cache(arm)
@@ -828,7 +843,7 @@ def process_rl_import(file_path, import_flags, armatures, rl_armatures, cameras,
chr_cache.import_file = file_path chr_cache.import_file = file_path
chr_cache.import_flags = import_flags chr_cache.import_flags = import_flags
# display name of character # display name of character
chr_cache.character_name = character_name chr_cache.set_name(character_name)
# link_id (OBJ exports don't have json) # link_id (OBJ exports don't have json)
chr_cache.set_link_id(link_id) chr_cache.set_link_id(link_id)
@@ -1072,22 +1087,33 @@ class CC3Import(bpy.types.Operator):
# But the mesh is really all we need, so just keep going... # But the mesh is really all we need, so just keep going...
if colorspace.is_aces(): if colorspace.is_aces():
try: try:
bpy.ops.import_scene.fbx(filepath=filepath, bpy.ops.wm.fbx_import(filepath=filepath,
directory=dir, directory=dir,
use_anim=import_anim, use_anim=import_anim,
use_image_search=False, use_custom_normals=not prefs.import_reset_custom_normals,
use_custom_normals=True, mtl_name_collision_mode="MAKE_UNIQUE",
anim_offset=self.start_frame) anim_offset=self.start_frame)
#bpy.ops.import_scene.fbx(filepath=filepath,
# directory=dir,
# use_anim=import_anim,
# use_image_search=False,
# use_custom_normals=True,
# anim_offset=self.start_frame)
except: except:
utils.log_warn("FBX Import Error: This may be due to color space differences. Continuing...") utils.log_warn("FBX Import Error: This may be due to color space differences. Continuing...")
else: else:
try: try:
bpy.ops.import_scene.fbx(filepath=filepath, bpy.ops.wm.fbx_import(filepath=filepath,
directory=dir, directory=dir,
use_anim=import_anim, use_anim=import_anim,
use_image_search=False, use_custom_normals=not prefs.import_reset_custom_normals,
use_custom_normals=True,
anim_offset=self.start_frame) anim_offset=self.start_frame)
#bpy.ops.import_scene.fbx(filepath=filepath,
# directory=dir,
# use_anim=import_anim,
# use_image_search=False,
# use_custom_normals=True,
# anim_offset=self.start_frame)
except: except:
utils.log_error("FBX Import Error due to bad mesh?") utils.log_error("FBX Import Error due to bad mesh?")
@@ -1153,9 +1179,6 @@ class CC3Import(bpy.types.Operator):
# invoke the obj importer # invoke the obj importer
old_objects = utils.get_set(bpy.data.objects) old_objects = utils.get_set(bpy.data.objects)
old_images = utils.get_set(bpy.data.images) old_images = utils.get_set(bpy.data.images)
if ImportFlags.RL in import_flags and param == "IMPORT_MORPH":
obj_import(filepath, split_objects=False, split_groups=False, vgroups=True)
else:
obj_import(filepath, split_objects=True, split_groups=True, vgroups=False) obj_import(filepath, split_objects=True, split_groups=True, vgroups=False)
imported = utils.get_set_new(bpy.data.objects, old_objects) imported = utils.get_set_new(bpy.data.objects, old_objects)
@@ -1966,11 +1989,17 @@ class CC3ImportAnimations(bpy.types.Operator):
old_actions = utils.get_set(bpy.data.actions) old_actions = utils.get_set(bpy.data.actions)
old_materials = utils.get_set(bpy.data.materials) old_materials = utils.get_set(bpy.data.materials)
bpy.ops.import_scene.fbx(filepath=path, bpy.ops.wm.fbx_import(filepath=path,
directory=dir, directory=dir,
use_anim=True, use_anim=True,
use_image_search=False, use_custom_normals=False,
mtl_name_collision_mode="MAKE_UNIQUE",
anim_offset=self.start_frame) anim_offset=self.start_frame)
#bpy.ops.import_scene.fbx(filepath=path,
# directory=dir,
# use_anim=True,
# use_image_search=False,
# anim_offset=self.start_frame)
objects = utils.get_set_new(bpy.data.objects, old_objects) objects = utils.get_set_new(bpy.data.objects, old_objects)
actions = utils.get_set_new(bpy.data.actions, old_actions) actions = utils.get_set_new(bpy.data.actions, old_actions)
@@ -213,6 +213,7 @@ def set_facial_profile_categories_json(json_data, character_id, categories_json)
def has_node_type(chr_json, node_type): def has_node_type(chr_json, node_type):
if chr_json:
meshes_json = chr_json["Meshes"] meshes_json = chr_json["Meshes"]
for obj_name, obj_json in meshes_json.items(): for obj_name, obj_json in meshes_json.items():
if obj_json and "Materials" in obj_json: if obj_json and "Materials" in obj_json:
@@ -42,6 +42,7 @@ class OpCodes(IntEnum):
FPS = 80 FPS = 80
MORPH = 90 MORPH = 90
MORPH_UPDATE = 91 MORPH_UPDATE = 91
MESH = 92
REPLACE_MESH = 95 REPLACE_MESH = 95
MATERIALS = 96 MATERIALS = 96
CHARACTER = 100 CHARACTER = 100
@@ -104,33 +105,25 @@ VISEME_NAME_MAP = {
class LinkActor(): class LinkActor():
name: str = "Name"
chr_cache = None
object: bpy.types.Object = None
bones: list = None
meshes: list = None
id_tree: dict = None
id_map: dict = None
skin_meshes: dict = None
rig_bones: list = None
expressions: list = None
visemes: list = None
morphs: list = None
cache: dict = None
alias: list = None
shape_keys: dict = None
ik_store: dict = None
rigify_ik_fk: float = 0.0
action_store_id: str = ""
def __init__(self, obj_or_chr_cache): def __init__(self, obj_or_actor_cache):
if type(obj_or_chr_cache) is bpy.types.Object: props = vars.props()
self.object = obj_or_chr_cache self.name = ""
self.name = obj_or_chr_cache.name
else:
self.object = None self.object = None
self.chr_cache = obj_or_chr_cache self.actor_cache = None
self.name = obj_or_chr_cache.character_name if type(obj_or_actor_cache) is bpy.types.Object:
self.object = obj_or_actor_cache
rl_name = utils.get_prop(obj_or_actor_cache, "rl_name")
self.name = rl_name if rl_name else obj_or_actor_cache.name
if self.object.type == "LIGHT" or self.object.type == "CAMERA":
# force create an RLX Cache for staging cache
self.actor_cache = self.get_rlx_cache(create=True)
else:
self.actor_cache = props.get_character_cache(self.object)
else:
self.object = obj_or_actor_cache.get_primary_object()
self.actor_cache = obj_or_actor_cache
self.name = obj_or_actor_cache.get_name()
self.bones = [] self.bones = []
self.meshes = [] self.meshes = []
self.id_tree = None self.id_tree = None
@@ -143,79 +136,93 @@ class LinkActor():
self.cache = None self.cache = None
self.alias = [] self.alias = []
self.shape_keys = {} self.shape_keys = {}
self.ik_store = None
self.rigify_ik_fk: float = 0.0
self.action_store_id: str = ""
return return
def get_chr_cache(self): def get_actor_cache(self):
return self.chr_cache return self.actor_cache
def get_import_modes(self) -> Tuple[str, str]: def get_chr_cache(self):
"""return (action_mode, frame_mode)\n
action_mode = {"NEW", "REPLACE", "BLEND"}\n
frame_mode = {"START", "CURRENT", "MATCH"}
"""
chr_cache = self.get_chr_cache()
if chr_cache:
return chr_cache.action_options.get_action_mode(), chr_cache.action_options.get_frame_mode()
else:
props = vars.props() props = vars.props()
action_mode = props.action_options.get_action_mode() if self.object:
frame_mode = props.action_options.get_frame_mode() if self.actor_cache.cache_type() in ["AVATAR", "PROP"]:
return action_mode, frame_mode return self.actor_cache
if self.object.type == "ARMATURE" or self.object.type == "MESH":
self.actor_cache = props.get_character_cache(self.object)
return self.actor_cache
return None
def get_rlx_cache(self, create=False):
props = vars.props()
if self.object:
if self.actor_cache and self.actor_cache.cache_type() in ["LIGHT", "CAMERA"]:
return self.actor_cache
if self.object.type == "LIGHT" or self.object.type == "CAMERA":
self.actor_cache = props.get_staging_cache(self.object, create=create)
return self.actor_cache
return None
def get_link_id(self): def get_link_id(self):
if self.object: if self.object:
return utils.get_rl_link_id(self.object) return utils.get_rl_link_id(self.object)
elif self.chr_cache: elif self.actor_cache:
return self.chr_cache.get_link_id() return self.actor_cache.get_link_id()
return None return None
def get_primary_object(self):
if self.actor_cache:
return self.actor_cache.get_primary_object()
return self.object
def get_armature(self): def get_armature(self):
if self.chr_cache: if self.actor_cache:
return self.chr_cache.get_armature() return self.actor_cache.get_armature()
return None return None
def select(self): def select(self):
if self.chr_cache: if self.actor_cache:
self.chr_cache.select_all() self.actor_cache.select_all()
elif self.object: elif self.object:
utils.try_select_object(self.object) utils.try_select_object(self.object)
def get_type(self): def get_type(self):
"""AVATAR|PROP|LIGHT|CAMERA|NONE""" """AVATAR|PROP|LIGHT|CAMERA|NONE"""
if self.chr_cache: if self.actor_cache:
return self.chr_cache_type(self.chr_cache) return self.chr_cache_type(self.actor_cache)
elif self.object: elif self.object:
return self.object.type return self.object.type
return "NONE" return "NONE"
def add_alias(self, link_id): def add_alias(self, link_id):
chr_cache = self.get_chr_cache() actor_cache = self.get_actor_cache()
if chr_cache: if actor_cache:
actor_link_id = chr_cache.link_id actor_link_id = actor_cache.link_id
if not actor_link_id: if not actor_link_id:
utils.log_info(f"Assigning actor link_id: {chr_cache.character_name}: {link_id}") utils.log_info(f"Assigning actor link_id: {actor_cache.get_name()}: {link_id}")
chr_cache.set_link_id(link_id) actor_cache.set_link_id(link_id)
return return
if link_id not in self.alias and actor_link_id != link_id: if link_id not in self.alias and actor_link_id != link_id:
utils.log_info(f"Assigning actor alias: {chr_cache.character_name}: {link_id}") utils.log_info(f"Assigning actor alias: {actor_cache.get_name()}: {link_id}")
self.alias.append(link_id) self.alias.append(link_id)
return return
@staticmethod @staticmethod
def get_start_frame(actor: 'LinkActor', ccic_frame, blender_current): def get_start_frame(actor: 'LinkActor', ccic_frame, blender_current):
props = vars.props() props = vars.props()
chr_cache = actor.get_chr_cache() if actor else None actor_cache = actor.get_actor_cache() if actor else None
if chr_cache: if actor_cache:
return chr_cache.action_options.get_start_frame(ccic_frame, blender_current) return actor_cache.action_options.get_start_frame(ccic_frame, blender_current)
else: else:
return props.action_options.get_start_frame(ccic_frame, blender_current) return props.action_options.get_start_frame(ccic_frame, blender_current)
@staticmethod @staticmethod
def get_sequence_frame(actor: 'LinkActor', ccic_frame, ccic_frame_start, blender_current): def get_sequence_frame(actor: 'LinkActor', ccic_frame, ccic_frame_start, blender_current):
props = vars.props() props = vars.props()
chr_cache = actor.get_chr_cache() if actor else None actor_cache = actor.get_actor_cache() if actor else None
if chr_cache: if actor_cache:
return chr_cache.action_options.get_sequence_frame(ccic_frame, ccic_frame_start, blender_current) return actor_cache.action_options.get_sequence_frame(ccic_frame, ccic_frame_start, blender_current)
else: else:
return props.action_options.get_sequence_frame(ccic_frame, ccic_frame_start, blender_current) return props.action_options.get_sequence_frame(ccic_frame, ccic_frame_start, blender_current)
@@ -232,7 +239,7 @@ class LinkActor():
if obj.type == "LIGHT" or obj.type == "CAMERA": if obj.type == "LIGHT" or obj.type == "CAMERA":
if not search_type or (obj.type == search_type): if not search_type or (obj.type == search_type):
obj_link_id = utils.get_rl_link_id(obj) obj_link_id = utils.get_rl_link_id(obj)
if obj_link_id is not None and link_id == obj_link_id: if obj_link_id is not None and link_id is not None and link_id == obj_link_id:
actor = LinkActor(obj) actor = LinkActor(obj)
utils.log_detail(f"Staging (Light/Camera) found by link_id: {actor.name} / {link_id}") utils.log_detail(f"Staging (Light/Camera) found by link_id: {actor.name} / {link_id}")
return actor return actor
@@ -251,7 +258,7 @@ class LinkActor():
chr_cache = props.find_character_by_name(search_name) chr_cache = props.find_character_by_name(search_name)
if chr_cache: if chr_cache:
if not search_type or LinkActor.chr_cache_type(chr_cache) == search_type: if not search_type or LinkActor.chr_cache_type(chr_cache) == search_type:
utils.log_detail(f"Chr found by name: {chr_cache.character_name} / {chr_cache.link_id} -> {link_id}") utils.log_detail(f"Chr found by name: {chr_cache.get_name()} / {chr_cache.link_id} -> {link_id}")
actor = LinkActor(chr_cache) actor = LinkActor(chr_cache)
actor.add_alias(link_id) actor.add_alias(link_id)
return actor return actor
@@ -270,7 +277,7 @@ class LinkActor():
if context_chr_cache and context_chr_cache.is_avatar(): if context_chr_cache and context_chr_cache.is_avatar():
chr_cache = context_chr_cache chr_cache = context_chr_cache
if chr_cache: if chr_cache:
utils.log_detail(f"Falling back to first Chr Avatar: {chr_cache.character_name} / {chr_cache.link_id} -> {link_id}") utils.log_detail(f"Falling back to first Chr Avatar: {chr_cache.get_name()} / {chr_cache.link_id} -> {link_id}")
actor = LinkActor(chr_cache) actor = LinkActor(chr_cache)
actor.add_alias(link_id) actor.add_alias(link_id)
return actor return actor
@@ -393,20 +400,20 @@ class LinkActor():
def update_name(self, new_name): def update_name(self, new_name):
self.name = new_name self.name = new_name
chr_cache = self.get_chr_cache() actor_cache = self.get_actor_cache()
if chr_cache: if actor_cache:
chr_cache.character_name = new_name actor_cache.set_name(new_name)
def update_link_id(self, new_link_id): def update_link_id(self, new_link_id):
chr_cache = self.get_chr_cache() actor_cache = self.get_actor_cache()
if chr_cache: if actor_cache:
utils.log_info(f"Assigning new link_id: {chr_cache.character_name}: {new_link_id}") utils.log_info(f"Assigning new link_id: {actor_cache.get_name()}: {new_link_id}")
chr_cache.set_link_id(new_link_id) actor_cache.set_link_id(new_link_id)
def ready(self, require_cache=True): def ready(self, require_cache=True):
if require_cache and not self.cache: if require_cache and not self.cache:
return False return False
return (self.chr_cache and self.get_armature()) or self.object return (self.actor_cache and self.get_armature()) or self.object
def is_rigified(self): def is_rigified(self):
chr_cache = self.get_chr_cache() chr_cache = self.get_chr_cache()
@@ -432,6 +439,21 @@ class LinkActor():
return chr_cache.can_go_ic() return chr_cache.can_go_ic()
return False return False
def is_obj(self):
chr_cache = self.get_chr_cache()
if chr_cache:
return chr_cache.is_obj()
return False
def is_posable(self):
actor_type = self.get_type()
if actor_type == "LIGHT" or actor_type == "CAMERA":
return True
else:
chr_cache = self.get_chr_cache()
if chr_cache:
return chr_cache.get_armature() is not None
return False
class LinkData(): class LinkData():
actors: list = [] actors: list = []
@@ -441,11 +463,9 @@ class LinkData():
sequence_end_frame: int = 0 sequence_end_frame: int = 0
sequence_actors: list = None sequence_actors: list = None
sequence_type: str = None sequence_type: str = None
sequence_selection: List[bpy.types.Object] = None
scene_current_frame: int = 0 scene_current_frame: int = 0
# #
sequence_action_mode: str = ""
sequence_frame_mode: str = ""
#
preview_shape_keys: bool = True preview_shape_keys: bool = True
preview_skip_frames: bool = False preview_skip_frames: bool = False
# remote props # remote props
@@ -645,7 +665,7 @@ def make_datalink_import_rig(actor: LinkActor, objects: list):
utils.restore_render_visibility_state(RV) utils.restore_render_visibility_state(RV)
return chr_cache.rig_datalink_rig return chr_cache.rig_datalink_rig
rig_name = f"{chr_cache.character_name}_Link_Rig" rig_name = f"{chr_cache.get_name()}_Link_Rig"
utils.log_info(f"Creating datalink transfer rig: {rig_name}") utils.log_info(f"Creating datalink transfer rig: {rig_name}")
# create pose armature # create pose armature
@@ -883,14 +903,16 @@ def prep_pose_actor(actor: LinkActor, start_frame, end_frame):
motion_id = "Pose" if LINK_DATA.sequence_type == "POSE" else "Sequence" motion_id = "Pose" if LINK_DATA.sequence_type == "POSE" else "Sequence"
chr_cache = actor.get_chr_cache() chr_cache = actor.get_chr_cache()
rigutils.ensure_motion_set(actor.get_primary_object(), motion_id, LINK_DATA.motion_prefix)
action_mode, frame_mode = actor.get_import_modes()
if actor and actor.get_type() == "LIGHT": if actor and actor.get_type() == "LIGHT":
# create keyframe cache for light animation sequences # create keyframe cache for light animation sequences
if LINK_DATA.set_keyframes: if LINK_DATA.set_keyframes:
# store current actions for replacing or mixing
actor.action_store_id = props.store_actions(actor.object)
rlx.prep_rlx_actions(actor, motion_id, rlx.prep_rlx_actions(actor, motion_id,
timestamp=False, timestamp=False,
motion_prefix=LINK_DATA.motion_prefix) motion_prefix=LINK_DATA.motion_prefix)
@@ -927,6 +949,9 @@ def prep_pose_actor(actor: LinkActor, start_frame, end_frame):
# create keyframe cache for camera animation sequences # create keyframe cache for camera animation sequences
if LINK_DATA.set_keyframes: if LINK_DATA.set_keyframes:
# store current actions for replacing or mixing
actor.action_store_id = props.store_actions(actor.object)
rlx.prep_rlx_actions(actor, motion_id, rlx.prep_rlx_actions(actor, motion_id,
timestamp=False, timestamp=False,
motion_prefix=LINK_DATA.motion_prefix) motion_prefix=LINK_DATA.motion_prefix)
@@ -950,7 +975,6 @@ def prep_pose_actor(actor: LinkActor, start_frame, end_frame):
camera_cache["focus_distance"] = create_fcurves_cache(count, 1, [1]) camera_cache["focus_distance"] = create_fcurves_cache(count, 1, [1])
camera_cache["f_stop"] = create_fcurves_cache(count, 1, [2.8]) camera_cache["f_stop"] = create_fcurves_cache(count, 1, [2.8])
actor.set_cache(actor_cache) actor.set_cache(actor_cache)
actor.action_store_id = props.store_actions(actor.object)
else: else:
# when not setting keyframes remove all actions from the camera # when not setting keyframes remove all actions from the camera
@@ -972,7 +996,7 @@ def prep_pose_actor(actor: LinkActor, start_frame, end_frame):
objects, none_objects = actor.get_sequence_objects() objects, none_objects = actor.get_sequence_objects()
if rig: if rig:
rig_id = rigutils.get_rig_id(rig) rig_id = rigutils.get_rig_id(rig)
rl_arm_id = utils.get_rl_object_id(rig) rl_id = utils.get_rl_id(rig)
use_slotted = prefs.use_action_slots() use_slotted = prefs.use_action_slots()
utils.log_info(f"Preparing Character Rig: {actor.name} {rig_id} / {len(actor.bones)} bones") utils.log_info(f"Preparing Character Rig: {actor.name} {rig_id} / {len(actor.bones)} bones")
@@ -980,12 +1004,12 @@ def prep_pose_actor(actor: LinkActor, start_frame, end_frame):
# generate new action set data # generate new action set data
# always import into a new action set, then decide what to do with it after writing the action # always import into a new action set, then decide what to do with it after writing the action
motion_id = rigutils.get_unique_set_motion_id(rig_id, motion_id, LINK_DATA.motion_prefix, slotted=use_slotted) motion_id = rigutils.get_unique_set_motion_id(rig_id, motion_id, LINK_DATA.motion_prefix, slotted=use_slotted, rlob=rig)
set_id, set_generation = rigutils.generate_motion_set(rig, motion_id, LINK_DATA.motion_prefix) set_id, set_generation = rigutils.generate_motion_set(rig, motion_id, LINK_DATA.motion_prefix)
# rig action # rig action
action = get_datalink_rig_action(rig, motion_id, slotted=use_slotted) action = get_datalink_rig_action(rig, motion_id, slotted=use_slotted)
rigutils.add_motion_set_data(action, set_id, set_generation, arm_id=rl_arm_id, slotted=use_slotted) rigutils.add_motion_set_data(action, set_id, set_generation, arm_id=rl_id, slotted=use_slotted)
utils.log_info(f"Preparing rig action: {action.name}") utils.log_info(f"Preparing rig action: {action.name}")
# shape key actions # shape key actions
@@ -1003,7 +1027,7 @@ def prep_pose_actor(actor: LinkActor, start_frame, end_frame):
utils.log_info(f"Preparing shape key action: {action_name} / {num_expressions}+{num_visemes} shape keys") utils.log_info(f"Preparing shape key action: {action_name} / {num_expressions}+{num_visemes} shape keys")
action = bpy.data.actions.new(action_name) action = bpy.data.actions.new(action_name)
slot, channel = rigutils.add_action_key_slot_channelbag(action, obj) slot, channel = rigutils.add_action_key_slot_channelbag(action, obj)
rigutils.add_motion_set_data(action, set_id, set_generation, obj_id=obj_id) rigutils.add_motion_set_data(action, set_id, set_generation, key_id=obj_id, arm_id=rl_id)
utils.safe_set_action(obj.data.shape_keys, action, slot=slot) utils.safe_set_action(obj.data.shape_keys, action, slot=slot)
action.use_fake_user = LINK_DATA.use_fake_user action.use_fake_user = LINK_DATA.use_fake_user
# remove actions from non sequence objects # remove actions from non sequence objects
@@ -1386,17 +1410,17 @@ def write_sequence_actions(actor: LinkActor, num_frames, start_frame):
utils.safe_set_action(obj.data.shape_keys, None) utils.safe_set_action(obj.data.shape_keys, None)
if rig_action: if rig_action:
action_mode, frame_mode = actor.get_import_modes()
rigutils.load_motion_set(rig, rig_action) rigutils.load_motion_set(rig, rig_action)
rigutils.finalize_motion_import(rig, rig_action, actor.action_store_id, action_mode) rigutils.finalize_motion_import(actor.get_chr_cache(), rig, rig_action, actor.action_store_id,
overwrite=True)
elif actor.get_type() == "LIGHT": elif actor.get_type() == "LIGHT":
light = actor.object light = actor.object
ob_action = utils.safe_get_action(light) ob_action = utils.safe_get_action(light)
light_action = utils.safe_get_action(light.data) light_action = utils.safe_get_action(light.data)
ob_slot = utils.get_action_slot(ob_action, "OBJECT") ob_slot = utils.get_action_slot(ob_action, slot_type="OBJECT")
light_slot = utils.get_action_slot(light_action, "LIGHT") light_slot = utils.get_action_slot(light_action, slot_type="LIGHT")
write_action_cache_curve(ob_action, actor.cache["transform"], "loc", "location", num_frames, "Location", slot=ob_slot, reduce=True) write_action_cache_curve(ob_action, actor.cache["transform"], "loc", "location", num_frames, "Location", slot=ob_slot, reduce=True)
write_action_rotation_cache_curve(ob_action, actor.cache["transform"], "rot", light, num_frames, slot=ob_slot, reduce=True) write_action_rotation_cache_curve(ob_action, actor.cache["transform"], "rot", light, num_frames, slot=ob_slot, reduce=True)
write_action_cache_curve(ob_action, actor.cache["transform"], "sca", "scale", num_frames, "Scale", slot=ob_slot, reduce=True) write_action_cache_curve(ob_action, actor.cache["transform"], "sca", "scale", num_frames, "Scale", slot=ob_slot, reduce=True)
@@ -1410,16 +1434,16 @@ def write_sequence_actions(actor: LinkActor, num_frames, start_frame):
utils.safe_set_action(light, ob_action, slot=ob_slot) utils.safe_set_action(light, ob_action, slot=ob_slot)
utils.safe_set_action(light.data, light_action, slot=light_slot) utils.safe_set_action(light.data, light_action, slot=light_slot)
action_mode, frame_mode = actor.get_import_modes() rlx_cache = actor.get_rlx_cache(create=True)
rigutils.finalize_rlx_import(light, [ob_action, light_action], actor.action_store_id, action_mode) rigutils.finalize_rlx_import(rlx_cache, light, [ob_action, light_action], actor.action_store_id, overwrite=True)
elif actor.get_type() == "CAMERA": elif actor.get_type() == "CAMERA":
camera = actor.object camera = actor.object
ob_action = utils.safe_get_action(camera) ob_action = utils.safe_get_action(camera)
cam_action = utils.safe_get_action(camera.data) cam_action = utils.safe_get_action(camera.data)
ob_slot = utils.get_action_slot(ob_action, "OBJECT") ob_slot = utils.get_action_slot(ob_action, slot_type="OBJECT")
cam_slot = utils.get_action_slot(cam_action, "CAMERA") cam_slot = utils.get_action_slot(cam_action, slot_type="CAMERA")
write_action_cache_curve(ob_action, actor.cache["transform"], "loc", "location", num_frames, "Location", slot=ob_slot, reduce=True) write_action_cache_curve(ob_action, actor.cache["transform"], "loc", "location", num_frames, "Location", slot=ob_slot, reduce=True)
write_action_rotation_cache_curve(ob_action, actor.cache["transform"], "rot", camera, num_frames, slot=ob_slot, reduce=True) write_action_rotation_cache_curve(ob_action, actor.cache["transform"], "rot", camera, num_frames, slot=ob_slot, reduce=True)
write_action_cache_curve(ob_action, actor.cache["transform"], "sca", "scale", num_frames, "Scale", slot=ob_slot, reduce=True) write_action_cache_curve(ob_action, actor.cache["transform"], "sca", "scale", num_frames, "Scale", slot=ob_slot, reduce=True)
@@ -1431,8 +1455,8 @@ def write_sequence_actions(actor: LinkActor, num_frames, start_frame):
utils.safe_set_action(camera, ob_action, slot=ob_slot) utils.safe_set_action(camera, ob_action, slot=ob_slot)
utils.safe_set_action(camera.data, cam_action, slot=cam_slot) utils.safe_set_action(camera.data, cam_action, slot=cam_slot)
action_mode, frame_mode = actor.get_import_modes() rlx_cache = actor.get_rlx_cache(create=True)
rigutils.finalize_rlx_import(camera, [ob_action, cam_action], actor.action_store_id, action_mode) rigutils.finalize_rlx_import(rlx_cache, camera, [ob_action, cam_action], actor.action_store_id)
actor.clear_cache() actor.clear_cache()
@@ -1885,6 +1909,9 @@ class LinkService():
elif op_code == OpCodes.MORPH_UPDATE: elif op_code == OpCodes.MORPH_UPDATE:
self.receive_morph(data, update=True) self.receive_morph(data, update=True)
elif op_code == OpCodes.MESH:
self.receive_mesh_modify(data)
elif op_code == OpCodes.CHARACTER: elif op_code == OpCodes.CHARACTER:
self.receive_actor_import(data) self.receive_actor_import(data)
@@ -2258,6 +2285,13 @@ class LinkService():
return actor return actor
return None return None
def actors_contains_id(self, actors, link_id):
actor: LinkActor = None
for actor in actors:
if actor.get_link_id() == link_id:
return True
return False
def get_selected_actors(self): def get_selected_actors(self):
global LINK_DATA global LINK_DATA
props = vars.props() props = vars.props()
@@ -2282,7 +2316,10 @@ class LinkService():
actors.append(actor) actors.append(actor)
for obj in selected_objects: for obj in selected_objects:
if obj.type == "LIGHT" or obj.type == "CAMERA" and utils.get_rl_link_id(obj): link_id = utils.get_rl_link_id(obj)
if link_id:
if obj.type == "LIGHT" or obj.type == "CAMERA" or utils.get_prop(obj, "rl_mesh_modify"):
if not self.actors_contains_id(actors, link_id):
actor = LinkActor(obj) actor = LinkActor(obj)
actors.append(actor) actors.append(actor)
@@ -2418,12 +2455,59 @@ class LinkService():
use_normals=True, use_normals=True,
keep_vertex_order=keep_vertex_order) keep_vertex_order=keep_vertex_order)
def send_replace_mesh(self): def send_mesh_modify_request(self):
self.send_request("MESH_MODIFY")
def send_mesh_modify(self):
global LINK_DATA
state = utils.store_mode_selection_state() state = utils.store_mode_selection_state()
objects = utils.get_selected_meshes() objects = utils.get_selected_meshes(selection=LINK_DATA.sequence_selection)
count = 0
for obj in objects:
if obj.type == "MESH":
if utils.get_prop(obj, "rl_mesh_modify"):
link_id = utils.get_prop(obj, "rl_link_id")
type = utils.get_prop(obj, "rl_type")
name = utils.get_prop(obj, "rl_name")
if link_id:
object_name = utils.strip_name(obj.name)
mesh_name = utils.strip_name(obj.data.name)
export_path = self.get_export_path("Meshes", f"{obj.name}_mesh.obj",
reuse_folder=True, reuse_file=True)
utils.set_active_object(obj, deselect_all=True)
self.obj_export(export_path, use_selection=True, use_vertex_colors=False)
export_data = encode_from_json({
"path": export_path,
"actor_name": name,
"object_name": object_name,
"mesh_name": mesh_name,
"type": type,
"morph": False,
"link_id": link_id,
})
self.send(OpCodes.REPLACE_MESH, export_data)
update_link_status(f"Sent Mesh: {obj.name}")
count += 1
utils.restore_mode_selection_state(state)
LINK_DATA.sequence_selection = None
LINK_DATA.sequence_actors = None
LINK_DATA.sequence_type = None
return count
def send_replace_mesh_request(self):
self.send_request("REPLACE_MESH")
def send_replace_mesh(self):
global LINK_DATA
state = utils.store_mode_selection_state()
objects = utils.get_selected_meshes(selection=LINK_DATA.sequence_selection)
# important that character is in the exact same pose on both sides, # important that character is in the exact same pose on both sides,
# so make sure the character is on the same frame in the animation. # so make sure the character is on the same frame in the animation.
self.send_frame_sync() # send pose updates for actors
self.send_pose()
count = 0 count = 0
for obj in objects: for obj in objects:
if obj.type == "MESH": if obj.type == "MESH":
@@ -2445,6 +2529,7 @@ class LinkService():
"object_name": object_name, "object_name": object_name,
"mesh_name": mesh_name, "mesh_name": mesh_name,
"type": actor.get_type(), "type": actor.get_type(),
"morph": actor.is_obj(),
"link_id": actor.get_link_id(), "link_id": actor.get_link_id(),
}) })
self.send(OpCodes.REPLACE_MESH, export_data) self.send(OpCodes.REPLACE_MESH, export_data)
@@ -2525,6 +2610,8 @@ class LinkService():
actor: LinkActor actor: LinkActor
for actor in actors: for actor in actors:
if not actor.is_posable(): continue
if actor.get_type() in ["PROP", "AVATAR"]: if actor.get_type() in ["PROP", "AVATAR"]:
chr_cache = actor.get_chr_cache() chr_cache = actor.get_chr_cache()
@@ -2643,6 +2730,7 @@ class LinkService():
} }
actor: LinkActor actor: LinkActor
for actor in actors: for actor in actors:
if actor.is_posable():
actors_data.append({ actors_data.append({
"name": actor.name, "name": actor.name,
"type": actor.get_type(), "type": actor.get_type(),
@@ -2653,9 +2741,13 @@ class LinkService():
def encode_pose_frame_data(self, actors: list): def encode_pose_frame_data(self, actors: list):
pose_bone: bpy.types.PoseBone pose_bone: bpy.types.PoseBone
data = bytearray() data = bytearray()
data += struct.pack("!II", len(actors), BFA(bpy.context.scene.frame_current)) pose_actors = [ a for a in actors if a.is_posable() ]
data += struct.pack("!II", len(pose_actors), BFA(bpy.context.scene.frame_current))
actor: LinkActor actor: LinkActor
for actor in actors: for actor in pose_actors:
if not actor.is_posable(): continue
actor_type = actor.get_type() actor_type = actor.get_type()
data += pack_string(actor.name) data += pack_string(actor.name)
@@ -2789,6 +2881,7 @@ class LinkService():
} }
actor: LinkActor actor: LinkActor
for actor in actors: for actor in actors:
if actor.is_posable():
actors_data.append({ actors_data.append({
"name": actor.name, "name": actor.name,
"type": actor.get_type(), "type": actor.get_type(),
@@ -2808,20 +2901,22 @@ class LinkService():
# remove the export rigs # remove the export rigs
utils.delete_armature_object(chr_cache.rig_export_rig) utils.delete_armature_object(chr_cache.rig_export_rig)
def send_request(self, request_type): def send_request(self, request_type, actors=None):
global LINK_DATA global LINK_DATA
# get actors # get actors
if not actors:
actors = self.get_selected_actors() actors = self.get_selected_actors()
if actors: if actors:
mode_selection = utils.store_mode_selection_state() mode_selection = utils.store_mode_selection_state()
update_link_status(f"Sending Request") update_link_status(f"Sending Request")
self.send_notify(f"Request") self.send_notify(f"Request")
# send request # send request
pose_data = self.encode_request_data(actors, request_type) request_data = self.encode_request_data(actors, request_type)
self.send(OpCodes.REQUEST, pose_data) self.send(OpCodes.REQUEST, request_data)
# store the actors # store the actors
LINK_DATA.sequence_actors = actors LINK_DATA.sequence_actors = actors
LINK_DATA.sequence_type = request_type LINK_DATA.sequence_type = request_type
LINK_DATA.sequence_selection = bpy.context.selected_objects.copy()
# restore # restore
utils.restore_mode_selection_state(mode_selection) utils.restore_mode_selection_state(mode_selection)
@@ -2876,6 +2971,10 @@ class LinkService():
self.send_pose() self.send_pose()
elif request_type == "SEQUENCE": elif request_type == "SEQUENCE":
self.send_sequence() self.send_sequence()
elif request_type == "REPLACE_MESH":
self.send_replace_mesh()
elif request_type == "MESH_MODIFY":
self.send_mesh_modify()
return return
def send_pose(self): def send_pose(self):
@@ -2883,7 +2982,7 @@ class LinkService():
# get actors # get actors
if not LINK_DATA.sequence_actors: if not LINK_DATA.sequence_actors:
LINK_DATA.sequence_actors = self.get_selected_actors() LINK_DATA.sequence_actors = self.get_selected_actors(pose_only=True)
actors = LINK_DATA.sequence_actors actors = LINK_DATA.sequence_actors
if actors: if actors:
@@ -2908,6 +3007,7 @@ class LinkService():
self.restore_actor_rigs(LINK_DATA.sequence_actors) self.restore_actor_rigs(LINK_DATA.sequence_actors)
LINK_DATA.sequence_actors = None LINK_DATA.sequence_actors = None
LINK_DATA.sequence_type = None LINK_DATA.sequence_type = None
LINK_DATA.sequence_selection = None
# restore # restore
utils.restore_mode_selection_state(mode_selection) utils.restore_mode_selection_state(mode_selection)
@@ -2930,7 +3030,7 @@ class LinkService():
# get actors # get actors
if not LINK_DATA.sequence_actors: if not LINK_DATA.sequence_actors:
LINK_DATA.sequence_actors = self.get_selected_actors() LINK_DATA.sequence_actors = self.get_selected_actors(pose_only=True)
actors = LINK_DATA.sequence_actors actors = LINK_DATA.sequence_actors
if actors: if actors:
@@ -2978,6 +3078,7 @@ class LinkService():
self.restore_actor_rigs(LINK_DATA.sequence_actors) self.restore_actor_rigs(LINK_DATA.sequence_actors)
LINK_DATA.sequence_actors = None LINK_DATA.sequence_actors = None
LINK_DATA.sequence_type = None LINK_DATA.sequence_type = None
LINK_DATA.sequence_selection = None
def send_sequence_ack(self, frame): def send_sequence_ack(self, frame):
global LINK_DATA global LINK_DATA
@@ -3002,10 +3103,7 @@ class LinkService():
offset = 0 offset = 0
count, frame = struct.unpack_from("!II", pose_data, offset) count, frame = struct.unpack_from("!II", pose_data, offset)
frame = RLFA(frame) frame = RLFA(frame)
opt_frame = LinkActor.get_sequence_frame(None, frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame) least_frame = None
opt_start_frame = LinkActor.get_sequence_frame(None, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
if LINK_DATA.set_keyframes:
ensure_current_frame(opt_frame)
LINK_DATA.sequence_current_frame = frame LINK_DATA.sequence_current_frame = frame
offset = 8 offset = 8
actors = [] actors = []
@@ -3030,6 +3128,15 @@ class LinkService():
rig = None rig = None
is_prop = False is_prop = False
if actor:
opt_frame = LinkActor.get_sequence_frame(actor, frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
opt_start_frame = LinkActor.get_sequence_frame(actor, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
least_frame = opt_frame if least_frame is None or opt_frame < least_frame else least_frame
else:
opt_frame = LinkActor.get_sequence_frame(None, frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
opt_start_frame = LinkActor.get_sequence_frame(None, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
least_frame = opt_frame
# unpack rig transform # unpack rig transform
tx,ty,tz,rx,ry,rz,rw,sx,sy,sz = struct.unpack_from("!ffffffffff", pose_data, offset) tx,ty,tz,rx,ry,rz,rw,sx,sy,sz = struct.unpack_from("!ffffffffff", pose_data, offset)
loc = Vector((tx, ty, tz)) * 0.01 loc = Vector((tx, ty, tz)) * 0.01
@@ -3124,6 +3231,12 @@ class LinkService():
if rig: if rig:
rig.pose.bones.update() rig.pose.bones.update()
if least_frame is None:
least_frame = LinkActor.get_sequence_frame(None, frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
if LINK_DATA.set_keyframes:
ensure_current_frame(least_frame)
return actors return actors
def reposition_prop_meshes(self, actors): def reposition_prop_meshes(self, actors):
@@ -3457,11 +3570,18 @@ class LinkService():
else: else:
actors = None actors = None
least_start_frame = None
most_end_frame = None
least_current_frame = None
if actors: if actors:
for actor in actors: for actor in actors:
opt_start_frame = LinkActor.get_sequence_frame(actor, start_frame, start_frame, current_frame) opt_start_frame = LinkActor.get_sequence_frame(actor, start_frame, start_frame, current_frame)
opt_end_frame = LinkActor.get_sequence_frame(actor, end_frame, start_frame, current_frame) opt_end_frame = LinkActor.get_sequence_frame(actor, end_frame, start_frame, current_frame)
opt_frame = LinkActor.get_sequence_frame(actor, frame, start_frame, current_frame) opt_frame = LinkActor.get_sequence_frame(actor, frame, start_frame, current_frame)
least_start_frame = opt_start_frame if least_start_frame is None or opt_start_frame < least_start_frame else least_start_frame
most_end_frame = opt_end_frame if most_end_frame is None or opt_end_frame > most_end_frame else most_end_frame
least_current_frame = opt_frame if least_current_frame is None or opt_frame < least_current_frame else least_current_frame
if expand_range: if expand_range:
if opt_start_frame < bpy.context.scene.frame_start: if opt_start_frame < bpy.context.scene.frame_start:
bpy.context.scene.frame_start = opt_start_frame bpy.context.scene.frame_start = opt_start_frame
@@ -3473,25 +3593,24 @@ class LinkService():
if opt_frame > bpy.context.scene.frame_end: if opt_frame > bpy.context.scene.frame_end:
bpy.context.scene.frame_end = opt_frame bpy.context.scene.frame_end = opt_frame
opt_start_frame = LinkActor.get_sequence_frame(actors[0], start_frame, start_frame, current_frame) if least_start_frame is None:
opt_end_frame = LinkActor.get_sequence_frame(actors[0], end_frame, start_frame, current_frame) least_start_frame = LinkActor.get_sequence_frame(None, start_frame, start_frame, current_frame)
opt_frame = LinkActor.get_sequence_frame(actors[0], frame, start_frame, current_frame) if most_end_frame is None:
else: most_end_frame = LinkActor.get_sequence_frame(None, end_frame, start_frame, current_frame)
opt_start_frame = LinkActor.get_sequence_frame(None, start_frame, start_frame, current_frame) if least_current_frame is None:
opt_end_frame = LinkActor.get_sequence_frame(None, end_frame, start_frame, current_frame) least_current_frame = LinkActor.get_sequence_frame(None, frame, start_frame, current_frame)
opt_frame = LinkActor.get_sequence_frame(None, frame, start_frame, current_frame)
if set_preview: if set_preview:
set_frame_range(opt_start_frame, opt_end_frame, preview=True) set_frame_range(least_start_frame, most_end_frame, preview=True)
if set_current: if set_current:
set_frame(opt_frame) set_frame(least_current_frame)
elif set_start: elif set_start:
set_frame(opt_start_frame) set_frame(least_start_frame)
elif set_end: elif set_end:
set_frame(opt_end_frame) set_frame(most_end_frame)
return opt_frame, opt_start_frame, opt_end_frame return least_current_frame, least_start_frame, most_end_frame
def receive_pose(self, data): def receive_pose(self, data):
props = vars.props() props = vars.props()
@@ -3526,8 +3645,7 @@ class LinkService():
if actor: if actor:
actors.append(actor) actors.append(actor)
opt_frame, opt_start_frame, opt_end_frame = \ self.get_actors_frame_range(actors, frame, start_frame, end_frame, current_frame,
self.get_actors_frame_range(None, frame, start_frame, end_frame, current_frame,
expand_frame=True, set_current=True) expand_frame=True, set_current=True)
# set pose frame # set pose frame
@@ -3547,9 +3665,6 @@ class LinkService():
actors = self.decode_pose_frame_data(data) actors = self.decode_pose_frame_data(data)
utils.log_info(f"Receive Pose Frame: {frame}") utils.log_info(f"Receive Pose Frame: {frame}")
opt_frame = LinkActor.get_sequence_frame(None, frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
opt_start_frame = LinkActor.get_sequence_frame(None, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
# force recalculate all transforms (lights and cameras seem to need this) # force recalculate all transforms (lights and cameras seem to need this)
bpy.context.view_layer.update() bpy.context.view_layer.update()
self.reposition_prop_meshes(actors) self.reposition_prop_meshes(actors)
@@ -3558,9 +3673,17 @@ class LinkService():
update_link_status(f"Pose Frame: {frame}") update_link_status(f"Pose Frame: {frame}")
self.select_actor_rigs(actors) self.select_actor_rigs(actors)
opt_frame = LinkActor.get_sequence_frame(None, frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
opt_start_frame = LinkActor.get_sequence_frame(None, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
least_frame = None
actor: LinkActor actor: LinkActor
if LINK_DATA.set_keyframes: if LINK_DATA.set_keyframes:
for actor in actors: for actor in actors:
opt_frame = LinkActor.get_sequence_frame(actor, frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
opt_start_frame = LinkActor.get_sequence_frame(actor, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
least_frame = opt_frame if least_frame is None or opt_frame < least_frame else least_frame
if actor.ready(require_cache=LINK_DATA.set_keyframes): if actor.ready(require_cache=LINK_DATA.set_keyframes):
if actor.get_type() == "PROP" or actor.get_type() == "AVATAR": if actor.get_type() == "PROP" or actor.get_type() == "AVATAR":
store_bone_cache_keyframes(actor, opt_frame, opt_start_frame) store_bone_cache_keyframes(actor, opt_frame, opt_start_frame)
@@ -3569,9 +3692,13 @@ class LinkService():
elif actor.get_type() == "CAMERA": elif actor.get_type() == "CAMERA":
store_camera_cache_keyframes(actor, opt_frame, opt_start_frame) store_camera_cache_keyframes(actor, opt_frame, opt_start_frame)
if least_frame is None:
least_frame = LinkActor.get_sequence_frame(None, frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
# write pose action # write pose action
for actor in actors: for actor in actors:
if actor.ready(require_cache=LINK_DATA.set_keyframes): if actor.ready(require_cache=LINK_DATA.set_keyframes):
opt_start_frame = LinkActor.get_sequence_frame(actor, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
if LINK_DATA.set_keyframes: if LINK_DATA.set_keyframes:
write_sequence_actions(actor, 1, opt_start_frame) write_sequence_actions(actor, 1, opt_start_frame)
if actor.get_type() == "PROP" or actor.get_type() == "AVATAR": if actor.get_type() == "PROP" or actor.get_type() == "AVATAR":
@@ -3585,8 +3712,9 @@ class LinkService():
# finish # finish
LINK_DATA.sequence_actors = None LINK_DATA.sequence_actors = None
LINK_DATA.sequence_type = None LINK_DATA.sequence_type = None
LINK_DATA.sequence_selection = None
if LINK_DATA.set_keyframes: if LINK_DATA.set_keyframes:
bpy.context.scene.frame_current = opt_frame bpy.context.scene.frame_current = least_frame
utils.restore_mode_selection_state(state, include_frames=False) utils.restore_mode_selection_state(state, include_frames=False)
# doesn't work with existing actions, the pose is reset back to action after execution. # doesn't work with existing actions, the pose is reset back to action after execution.
@@ -3630,8 +3758,7 @@ class LinkService():
if actor: if actor:
actors.append(actor) actors.append(actor)
opt_frame, opt_start_frame, opt_end_frame = \ self.get_actors_frame_range(actors, frame, start_frame, end_frame, current_frame,
self.get_actors_frame_range(None, frame, start_frame, end_frame, current_frame,
expand_range=True, set_preview=True, set_start=True) expand_range=True, set_preview=True, set_start=True)
LINK_DATA.sequence_actors = actors LINK_DATA.sequence_actors = actors
@@ -3667,9 +3794,6 @@ class LinkService():
actors = self.decode_pose_frame_data(data) actors = self.decode_pose_frame_data(data)
utils.update_timer("DECODE") utils.update_timer("DECODE")
opt_frame = LinkActor.get_sequence_frame(None, frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
opt_start_frame = LinkActor.get_sequence_frame(None, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
utils.mark_timer("REPOSITION") utils.mark_timer("REPOSITION")
self.reposition_prop_meshes(actors) self.reposition_prop_meshes(actors)
utils.update_timer("REPOSITION") utils.update_timer("REPOSITION")
@@ -3690,6 +3814,8 @@ class LinkService():
for actor in actors: for actor in actors:
if actor.ready(require_cache=LINK_DATA.set_keyframes): if actor.ready(require_cache=LINK_DATA.set_keyframes):
if LINK_DATA.set_keyframes: if LINK_DATA.set_keyframes:
opt_frame = LinkActor.get_sequence_frame(actor, frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
opt_start_frame = LinkActor.get_sequence_frame(actor, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
if actor.get_type() == "PROP" or actor.get_type() == "AVATAR": if actor.get_type() == "PROP" or actor.get_type() == "AVATAR":
store_bone_cache_keyframes(actor, opt_frame, opt_start_frame) store_bone_cache_keyframes(actor, opt_frame, opt_start_frame)
elif actor.get_type() == "LIGHT": elif actor.get_type() == "LIGHT":
@@ -3731,11 +3857,13 @@ class LinkService():
else: else:
update_link_status(f"Live Sequence Aborted!") update_link_status(f"Live Sequence Aborted!")
opt_start_frame = LinkActor.get_sequence_frame(None, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame) least_start_frame = None
# write actions # write actions
utils.mark_timer("WRITE") utils.mark_timer("WRITE")
for actor in actors: for actor in actors:
opt_start_frame = LinkActor.get_sequence_frame(actor, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
least_start_frame = opt_start_frame if least_start_frame is None or opt_start_frame < least_start_frame else least_start_frame
if LINK_DATA.set_keyframes: if LINK_DATA.set_keyframes:
write_sequence_actions(actor, num_frames, opt_start_frame) write_sequence_actions(actor, num_frames, opt_start_frame)
if actor.get_type() == "PROP" or actor.get_type() == "AVATAR": if actor.get_type() == "PROP" or actor.get_type() == "AVATAR":
@@ -3744,6 +3872,10 @@ class LinkService():
rigutils.update_prop_rig(actor.get_armature()) rigutils.update_prop_rig(actor.get_armature())
elif actor.get_type() == "AVATAR": elif actor.get_type() == "AVATAR":
rigutils.update_avatar_rig(actor.get_armature()) rigutils.update_avatar_rig(actor.get_armature())
if least_start_frame is None:
least_start_frame = LinkActor.get_sequence_frame(None, LINK_DATA.sequence_start_frame, LINK_DATA.sequence_start_frame, LINK_DATA.scene_current_frame)
utils.update_timer("WRITE") utils.update_timer("WRITE")
utils.log_timer("Frame", name="FRAME") utils.log_timer("Frame", name="FRAME")
@@ -3758,6 +3890,7 @@ class LinkService():
self.stop_sequence() self.stop_sequence()
LINK_DATA.sequence_actors = None LINK_DATA.sequence_actors = None
LINK_DATA.sequence_type = None LINK_DATA.sequence_type = None
LINK_DATA.sequence_selection = None
#bpy.context.scene.frame_current = LINK_DATA.sequence_start_frame #bpy.context.scene.frame_current = LINK_DATA.sequence_start_frame
# play the recorded sequence # play the recorded sequence
@@ -3797,7 +3930,9 @@ class LinkService():
else: else:
self.update_sequence(5, delta_frames) self.update_sequence(5, delta_frames)
def get_remote_file(self, remote_id, source_path, file_override=None): def get_remote_file(self, remote_id: str, source_path: str, file_override=None):
if os.path.sep != "\\":
source_path = source_path.replace("\\", os.path.sep)
if remote_id: if remote_id:
remote_files_folder = get_unpacked_tar_file_folder(remote_id) remote_files_folder = get_unpacked_tar_file_folder(remote_id)
if file_override: if file_override:
@@ -3991,6 +4126,7 @@ class LinkService():
character_type = character_types[i] character_type = character_types[i]
file = name + ".rlx" file = name + ".rlx"
rlx_path = self.get_remote_file(remote_id, base_path, file_override=file) rlx_path = self.get_remote_file(remote_id, base_path, file_override=file)
actor = LinkActor.find_actor(link_id, search_name=name, search_type=character_type)
utils.log_info(f"Receive Light / Camera Import: {name} / {link_id} / {rlx_path}") utils.log_info(f"Receive Light / Camera Import: {name} / {link_id} / {rlx_path}")
@@ -3999,6 +4135,7 @@ class LinkService():
utils.log_error(f"Invalid Import Path: {rlx_path}") utils.log_error(f"Invalid Import Path: {rlx_path}")
continue continue
opt_start_frame = LinkActor.get_sequence_frame(actor, start_frame, start_frame, current_frame)
self.do_file_import(rlx_path, link_id, save_after_import, opt_start_frame) self.do_file_import(rlx_path, link_id, save_after_import, opt_start_frame)
def receive_motion_import(self, data): def receive_motion_import(self, data):
@@ -4043,13 +4180,13 @@ class LinkService():
if chr_cache and LinkActor.chr_cache_type(chr_cache) == character_type: if chr_cache and LinkActor.chr_cache_type(chr_cache) == character_type:
link_id = chr_cache.link_id link_id = chr_cache.link_id
if link_id: if link_id:
utils.log_info(f"Redirecting to active character: {chr_cache.character_name}") utils.log_info(f"Redirecting to active character: {chr_cache.get_name()}")
opt_frame, opt_start_frame, opt_end_frame = \ opt_frame, opt_start_frame, opt_end_frame = \
self.get_actors_frame_range(chr_cache, frame, start_frame, end_frame, current_frame, self.get_actors_frame_range(chr_cache, frame, start_frame, end_frame, current_frame,
expand_range=True, set_preview=True, set_start=True) expand_range=True, set_preview=True, set_start=True)
if prefs.datalink_confirm_mismatch: if prefs.datalink_confirm_mismatch:
bpy.ops.ccic.link_confirm_dialog("INVOKE_DEFAULT", bpy.ops.ccic.link_confirm_dialog("INVOKE_DEFAULT",
message=f"Character {name} not found, do you want to apply the motion to the current character: {chr_cache.character_name}?", message=f"Character {name} not found, do you want to apply the motion to the current character: {chr_cache.get_name()}?",
mode="MOTION", mode="MOTION",
name=name, name=name,
filepath=fbx_path, filepath=fbx_path,
@@ -4086,7 +4223,7 @@ class LinkService():
use_fake_user=LINK_DATA.use_fake_user) use_fake_user=LINK_DATA.use_fake_user)
except Exception as e: except Exception as e:
utils.log_error(f"Error importing {fbx_path}", e) utils.log_error(f"Error importing {fbx_path}", e)
motion_rig = utils.get_active_object() motion_rig = utils.first(utils.get_selected_armatures())
if motion_rig: if motion_rig:
self.replace_actor_motion(actor, motion_rig) self.replace_actor_motion(actor, motion_rig)
update_link_status(f"Motion Imported: {actor.name}") update_link_status(f"Motion Imported: {actor.name}")
@@ -4110,12 +4247,12 @@ class LinkService():
actor_rig = actor.get_armature() actor_rig = actor.get_armature()
chr_cache = actor.get_chr_cache() chr_cache = actor.get_chr_cache()
actor_rig_id = rigutils.get_rig_id(actor_rig) actor_rig_id = rigutils.get_rig_id(actor_rig)
arm_id = utils.get_rl_object_id(actor_rig) rl_id = utils.get_rl_id(actor_rig)
# store existing motion # store existing motion
action_store_id = props.store_actions(actor_rig) action_store_id = props.store_actions(actor_rig)
# generate new action set data # generate new action set data
motion_id = rigutils.get_unique_set_motion_id(actor_rig_id, motion_id, LINK_DATA.motion_prefix, slotted=use_slotted) motion_id = rigutils.get_unique_set_motion_id(actor_rig_id, motion_id, LINK_DATA.motion_prefix, slotted=use_slotted, rlob=actor_rig)
set_id, set_generation = rigutils.generate_motion_set(actor_rig, motion_id, LINK_DATA.motion_prefix) set_id, set_generation = rigutils.generate_motion_set(actor_rig, motion_id, LINK_DATA.motion_prefix)
remove_actions = [] remove_actions = []
@@ -4130,7 +4267,7 @@ class LinkService():
update_link_status(f"Retargeting Motion...") update_link_status(f"Retargeting Motion...")
baked_action = rigutils.bake_rig_action_from_source(motion_rig, actor_rig) baked_action = rigutils.bake_rig_action_from_source(motion_rig, actor_rig)
baked_action.use_fake_user = LINK_DATA.use_fake_user baked_action.use_fake_user = LINK_DATA.use_fake_user
rigutils.add_motion_set_data(baked_action, set_id, set_generation, arm_id=arm_id, slotted=use_slotted) rigutils.add_motion_set_data(baked_action, set_id, set_generation, arm_id=rl_id, slotted=use_slotted)
rigutils.set_armature_action_name(baked_action, actor_rig_id, motion_id, LINK_DATA.motion_prefix, slotted=use_slotted) rigutils.set_armature_action_name(baked_action, actor_rig_id, motion_id, LINK_DATA.motion_prefix, slotted=use_slotted)
rigutils.copy_action_shape_key_channels(actor_rig, motion_rig_action, baked_action, fake_user=LINK_DATA.use_fake_user) rigutils.copy_action_shape_key_channels(actor_rig, motion_rig_action, baked_action, fake_user=LINK_DATA.use_fake_user)
rigutils.delete_motion_set(motion_rig_action) rigutils.delete_motion_set(motion_rig_action)
@@ -4148,13 +4285,16 @@ class LinkService():
if chr_cache.rigified: if chr_cache.rigified:
update_link_status(f"Retargeting Motion...") update_link_status(f"Retargeting Motion...")
baked_action = rigging.adv_bake_retarget_to_rigify(None, chr_cache, motion_rig, motion_rig_action) baked_action = rigging.adv_bake_retarget_to_rigify(None, chr_cache, motion_rig, motion_rig_action)
if baked_action:
baked_action.use_fake_user = LINK_DATA.use_fake_user baked_action.use_fake_user = LINK_DATA.use_fake_user
rigutils.add_motion_set_data(baked_action, set_id, set_generation, arm_id=arm_id, slotted=use_slotted) rigutils.add_motion_set_data(baked_action, set_id, set_generation, arm_id=rl_id, slotted=use_slotted)
rigutils.set_armature_action_name(baked_action, actor_rig_id, motion_id, LINK_DATA.motion_prefix, slotted=use_slotted) rigutils.set_armature_action_name(baked_action, actor_rig_id, motion_id, LINK_DATA.motion_prefix, slotted=use_slotted)
rigutils.copy_action_shape_key_channels(actor_rig, motion_rig_action, baked_action, fake_user=LINK_DATA.use_fake_user) rigutils.copy_action_shape_key_channels(actor_rig, motion_rig_action, baked_action, fake_user=LINK_DATA.use_fake_user)
rigutils.delete_motion_set(motion_rig_action) rigutils.delete_motion_set(motion_rig_action)
rigutils.load_motion_set(actor_rig, baked_action) rigutils.load_motion_set(actor_rig, baked_action)
incoming_motion_action = baked_action incoming_motion_action = baked_action
else:
utils.log_error(f"Unable to bake replacement action: {motion_rig} / {motion_rig_action}")
else: else:
actor_rig_action = utils.safe_get_action(actor_rig) actor_rig_action = utils.safe_get_action(actor_rig)
motion_rig_action.use_fake_user = LINK_DATA.use_fake_user motion_rig_action.use_fake_user = LINK_DATA.use_fake_user
@@ -4168,8 +4308,7 @@ class LinkService():
utils.delete_armature_object(motion_rig) utils.delete_armature_object(motion_rig)
if actor_rig and incoming_motion_action: if actor_rig and incoming_motion_action:
action_mode, frame_mode = actor.get_import_modes() rigutils.finalize_motion_import(actor.get_chr_cache(), actor_rig, incoming_motion_action, action_store_id)
rigutils.finalize_motion_import(actor_rig, incoming_motion_action, action_store_id, action_mode)
utils.log_recess() utils.log_recess()
@@ -4247,6 +4386,45 @@ class LinkService():
geom.copy_vert_positions_by_index(source, dest) geom.copy_vert_positions_by_index(source, dest)
utils.delete_mesh_object(source) utils.delete_mesh_object(source)
def receive_mesh_modify(self, data):
props = vars.props()
global LINK_DATA
props.validate_and_clean_up()
# decode receive morph
json_data = decode_to_json(data)
obj_path = json_data.get("path")
remote_id = json_data.get("remote_id")
obj_path = self.get_remote_file(remote_id, obj_path)
name = json_data["name"]
character_type = json_data["type"]
link_id = json_data["link_id"]
utils.log_info(f"Receive Mesh Modify: {name} / {link_id} / {obj_path}")
update_link_status(f"Receving Mesh Modify: {name}")
if os.path.exists(obj_path):
mss = utils.store_mode_selection_state()
# remove old mesh modify
remove = []
for obj in bpy.data.objects:
if utils.get_prop(obj, "rl_mesh_modify") and utils.get_prop(obj, "rl_link_id") == link_id:
remove.append(obj)
for obj in remove:
utils.delete_object(obj)
# import new mesh modify
old_objects = utils.get_set(bpy.data.objects)
importer.obj_import(obj_path, split_objects=True, split_groups=True, vgroups=False)
objects = utils.get_set_new(bpy.data.objects, old_objects)
# update mesh modify
for source in objects:
utils.set_rl_link_id(source, link_id)
utils.set_prop(source, "rl_mesh_modify", True)
utils.set_prop(source, "rl_name", name)
utils.set_prop(source, "rl_type", character_type)
source.scale = (0.01, 0.01, 0.01)
utils.restore_mode_selection_state(mss)
def receive_update_replace(self, data): def receive_update_replace(self, data):
props = vars.props() props = vars.props()
props.validate_and_clean_up() props.validate_and_clean_up()
@@ -4395,7 +4573,7 @@ class LinkService():
if temp_obj_cache.source_name in original_data: if temp_obj_cache.source_name in original_data:
utils.force_object_name(child, original_data[temp_obj_cache.source_name]["name"]) utils.force_object_name(child, original_data[temp_obj_cache.source_name]["name"])
new_obj_cache.object_id = original_data[temp_obj_cache.source_name]["object_id"] new_obj_cache.object_id = original_data[temp_obj_cache.source_name]["object_id"]
utils.set_rl_object_id(child, new_obj_cache.object_id) utils.set_rl_id(child, new_obj_cache.object_id)
for mat in child.data.materials: for mat in child.data.materials:
if utils.material_exists(mat): if utils.material_exists(mat):
temp_mat_cache = temp_chr_cache.get_material_cache(mat) temp_mat_cache = temp_chr_cache.get_material_cache(mat)
@@ -4502,17 +4680,17 @@ class LinkService():
rigutils.delete_motion_set(temp_rig_action) rigutils.delete_motion_set(temp_rig_action)
link_id = chr_cache.link_id link_id = chr_cache.link_id
character_name = chr_cache.character_name character_name = chr_cache.get_name()
rig_name = rig.name rig_name = rig.name
rig_data_name = rig.data.name rig_data_name = rig.data.name
rl_armature_id = utils.get_rl_object_id(rig) rl_id = utils.get_rl_id(rig)
temp_chr_cache.set_link_id(link_id) temp_chr_cache.set_link_id(link_id)
temp_chr_cache.character_name = character_name temp_chr_cache.set_name(character_name)
utils.set_rl_object_id(temp_rig, rl_armature_id) utils.set_rl_id(temp_rig, rl_id)
rig_obj_cache = temp_chr_cache.get_object_cache(temp_rig) rig_obj_cache = temp_chr_cache.get_object_cache(temp_rig)
if rig_obj_cache: if rig_obj_cache:
rig_obj_cache.object_id = rl_armature_id rig_obj_cache.object_id = rl_id
utils.force_object_name(temp_rig, rig_name) utils.force_object_name(temp_rig, rig_name)
utils.force_armature_name(temp_rig.data, rig_data_name) utils.force_armature_name(temp_rig.data, rig_data_name)
@@ -4703,18 +4881,15 @@ class CCICDataLink(bpy.types.Operator):
self.report({'ERROR'}, f"Morph not sent!") self.report({'ERROR'}, f"Morph not sent!")
return {'FINISHED'} return {'FINISHED'}
elif self.param == "SEND_MESH_MODIFY":
LINK_SERVICE.send_mesh_modify_request()
elif self.param == "SYNC_CAMERA": elif self.param == "SYNC_CAMERA":
LINK_SERVICE.send_camera_sync() LINK_SERVICE.send_camera_sync()
return {'FINISHED'} return {'FINISHED'}
elif self.param == "SEND_REPLACE_MESH": elif self.param == "SEND_REPLACE_MESH":
count = LINK_SERVICE.send_replace_mesh() LINK_SERVICE.send_replace_mesh_request()
if count == 1:
self.report({'INFO'}, f"Replace Mesh sent ...")
elif count > 1:
self.report({'INFO'}, f"{count} Replace Meshes sent ...")
else:
self.report({'ERROR'}, f"No Replace Meshes sent!")
return {'FINISHED'} return {'FINISHED'}
elif self.param == "SEND_MATERIAL_UPDATE": elif self.param == "SEND_MATERIAL_UPDATE":
@@ -597,7 +597,7 @@ def get_head_body_object(chr_cache):
if body_cache: if body_cache:
body_id = body_cache.object_id body_id = body_cache.object_id
for child in arm.children: for child in arm.children:
if utils.get_rl_object_id(child) == body_id and child not in body_objects: if utils.get_rl_id(child) == body_id and child not in body_objects:
body_objects[child] = total_vertex_group_weight(child, head_bones) body_objects[child] = total_vertex_group_weight(child, head_bones)
else: else:
for child in arm.children: for child in arm.children:
@@ -18,7 +18,7 @@ import bpy
import textwrap import textwrap
import os import os
from . import addon_updater_ops, iconutils, rigging, rigutils from . import addon_updater_ops, iconutils, rigging, rigutils, rlx
from . import (link, rigify_mapping_data, bones, characters, sculpting, springbones, from . import (link, rigify_mapping_data, bones, characters, sculpting, springbones,
bake, rigidbody, physics, colorspace, modifiers, channel_mixer, nodeutils, bake, rigidbody, physics, colorspace, modifiers, channel_mixer, nodeutils,
utils, params, vars) utils, params, vars)
@@ -91,7 +91,7 @@ def character_info_box(chr_cache, chr_rig, layout, show_name = True, show_type =
is_non_standard = True is_non_standard = True
is_morph = False is_morph = False
if chr_cache: if chr_cache:
character_name = chr_cache.character_name character_name = chr_cache.get_name()
is_non_standard = chr_cache.is_non_standard() is_non_standard = chr_cache.is_non_standard()
if chr_cache.is_standard(): if chr_cache.is_standard():
type_text = f"Standard ({chr_cache.generation})" type_text = f"Standard ({chr_cache.generation})"
@@ -527,7 +527,7 @@ def character_tools_ui(context, layout: bpy.types.UILayout):
rig = generic_rig rig = generic_rig
if chr_cache: if chr_cache:
chr_name = chr_cache.character_name chr_name = chr_cache.get_name()
elif generic_rig: elif generic_rig:
chr_name = generic_rig.name chr_name = generic_rig.name
elif non_chr_objects: elif non_chr_objects:
@@ -829,7 +829,7 @@ class ACTION_UL_List(bpy.types.UIList):
if arm_object.type == "ARMATURE": if arm_object.type == "ARMATURE":
arm_name = arm_object.name arm_name = arm_object.name
arm_set_generation = rigutils.get_set_generation(arm_object) arm_set_generation = rigutils.get_set_generation(arm_object)
rl_arm_id = utils.get_rl_object_id(arm_object) rl_arm_id = utils.get_rl_id(arm_object)
items = getattr(data, propname) items = getattr(data, propname)
filtered = [self.bitflag_filter_item] * len(items) filtered = [self.bitflag_filter_item] * len(items)
item : bpy.types.Action item : bpy.types.Action
@@ -837,13 +837,13 @@ class ACTION_UL_List(bpy.types.UIList):
allowed = False allowed = False
action_set_generation = rigutils.get_set_generation(item) action_set_generation = rigutils.get_set_generation(item)
action_type = utils.get_prop(item, "rl_action_type") action_type = utils.get_prop(item, "rl_action_type")
action_armature_id = utils.get_prop(item, "rl_armature_id") action_rl_id = utils.get_rl_id(item)
channel = utils.get_action_channelbag(item, slot_type="OBJECT") channel = utils.get_action_channelbag(item, slot_type="OBJECT")
if props.armature_action_filter and arm_object: if props.armature_action_filter and arm_object:
if arm_set_generation and action_set_generation and action_type and rl_arm_id and action_armature_id: if arm_set_generation and action_set_generation and action_type and rl_arm_id and action_rl_id:
if (arm_set_generation == action_set_generation and if (arm_set_generation == action_set_generation and
(action_type == "ARM" or action_type == "SLOTTED") and (action_type == "ARM" or action_type == "SLOTTED") and
action_armature_id == rl_arm_id): action_rl_id == rl_arm_id):
allowed = True allowed = True
elif channel and len(channel.fcurves) > 0: elif channel and len(channel.fcurves) > 0:
if channel.fcurves[0].data_path.startswith("key_blocks"): if channel.fcurves[0].data_path.startswith("key_blocks"):
@@ -877,23 +877,30 @@ class ACTION_SET_UL_List(bpy.types.UIList):
items = getattr(data, propname) items = getattr(data, propname)
filtered = [self.bitflag_filter_item] * len(items) filtered = [self.bitflag_filter_item] * len(items)
item : bpy.types.Action item : bpy.types.Action
rlx_cache = props.get_context_staging_cache(context)
chr_cache = props.get_context_character_cache(context) chr_cache = props.get_context_character_cache(context)
arm_set_generation = None set_generation = None
arm_rig_id = None rig_id = None
if chr_cache: arm = None
rob = None
if rlx_cache:
rob = rlx_cache.get_rlx_object()
set_generation = rlx.get_rlx_generation(rob)
rig_id = utils.get_rl_id(rob)
elif chr_cache:
arm = chr_cache.get_armature() arm = chr_cache.get_armature()
arm_set_generation = rigutils.get_set_generation(arm) set_generation = rigutils.get_set_generation(arm)
arm_rig_id = utils.get_prop(arm, "rl_armature_id") rig_id = utils.get_rl_id(arm)
for i, item in enumerate(items): for i, item in enumerate(items):
allowed = False allowed = False
action_set_generation = rigutils.get_set_generation(item) action_set_generation = rigutils.get_set_generation(item)
action_type = utils.get_prop(item, "rl_action_type") action_type = utils.get_prop(item, "rl_action_type")
action_rig_id = utils.get_prop(item, "rl_armature_id") action_rig_id = utils.get_rl_id(item)
if action_type == "ARM" or action_type == "SLOTTED": if action_type == "ARM" or action_type == "SLOTTED" or action_type == "RLX":
if props.filter_motion_set_type == "RIG": if props.filter_motion_set_type == "RIG":
allowed = arm_rig_id and action_rig_id and arm_rig_id == action_rig_id allowed = rig_id and action_rig_id and rig_id == action_rig_id
elif props.filter_motion_set_type == "GEN": elif props.filter_motion_set_type == "GEN":
allowed = arm_set_generation and action_set_generation and arm_set_generation == action_set_generation allowed = set_generation and action_set_generation and set_generation == action_set_generation
else: else:
allowed = True allowed = True
# filter by name # filter by name
@@ -961,7 +968,7 @@ class CC3CharacterSettingsPanel(bpy.types.Panel):
# import details # import details
if chr_cache: if chr_cache:
if fake_drop_down(box.row(), "Import Details", "stage1_details", props.stage1_details): if fake_drop_down(box.row(), "Import Details", "stage1_details", props.stage1_details):
box.label(text="Name: " + chr_cache.character_name) box.label(text="Name: " + chr_cache.get_name())
box.label(text="Type: " + chr_cache.get_import_type().upper()) box.label(text="Type: " + chr_cache.get_import_type().upper())
split = box.split(factor=0.4) split = box.split(factor=0.4)
col_1 = split.column() col_1 = split.column()
@@ -979,7 +986,7 @@ class CC3CharacterSettingsPanel(bpy.types.Panel):
#if o: #if o:
box.prop(obj_cache, "object", text="") box.prop(obj_cache, "object", text="")
else: else:
box.label(text="Name: " + chr_cache.character_name) box.label(text="Name: " + chr_cache.get_name())
else: else:
box.label(text="No Character") box.label(text="No Character")
disable_on_linked(box, chr_cache) disable_on_linked(box, chr_cache)
@@ -994,6 +1001,7 @@ class CC3CharacterSettingsPanel(bpy.types.Panel):
column.prop(PREFS, "import_deduplicate") column.prop(PREFS, "import_deduplicate")
column.prop(PREFS, "import_auto_convert") column.prop(PREFS, "import_auto_convert")
column.prop(PREFS, "import_reset_custom_normals") column.prop(PREFS, "import_reset_custom_normals")
column.prop(PREFS, "import_fix_5_1_normals")
column.prop(PREFS, "clean_empty_mesh_data") column.prop(PREFS, "clean_empty_mesh_data")
column.prop(PREFS, "action_use_action_slots") column.prop(PREFS, "action_use_action_slots")
column.prop(PREFS, "action_add_key_slots_per_obj") column.prop(PREFS, "action_add_key_slots_per_obj")
@@ -2185,7 +2193,8 @@ class CC3RigifyPanel(bpy.types.Panel):
props = vars.props() props = vars.props()
prefs = vars.prefs() prefs = vars.prefs()
chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context) chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context, strict=True)
rlx_cache = props.get_context_staging_cache(context)
missing_materials = characters.has_missing_materials(chr_cache) missing_materials = characters.has_missing_materials(chr_cache)
layout = self.layout layout = self.layout
@@ -2211,7 +2220,7 @@ class CC3RigifyPanel(bpy.types.Panel):
col_1 = split.column() col_1 = split.column()
col_2 = split.column() col_2 = split.column()
col_1.label(text = "Character:") col_1.label(text = "Character:")
col_2.label(text = chr_cache.character_name) col_2.label(text = chr_cache.get_name())
col_1.label(text = "Generation:") col_1.label(text = "Generation:")
col_2.label(text = chr_cache.generation) col_2.label(text = chr_cache.generation)
col_1.label(text = "Face Profile:") col_1.label(text = "Face Profile:")
@@ -2313,7 +2322,7 @@ class CC3RigifyPanel(bpy.types.Panel):
icon = "FAKE_USER_OFF" if not props.rigify_retarget_use_fake_user else "FAKE_USER_ON" icon = "FAKE_USER_OFF" if not props.rigify_retarget_use_fake_user else "FAKE_USER_ON"
row.prop(props, "rigify_retarget_use_fake_user", text="", icon=icon, toggle=True) row.prop(props, "rigify_retarget_use_fake_user", text="", icon=icon, toggle=True)
if chr_cache.can_expression_rig() or chr_cache.can_rigify_face(): # Always show rigify expression rig type (so AccuRig without facial profile can switch to None)
col = layout.column(align=True) col = layout.column(align=True)
col.label(text="Expression Rig:") col.label(text="Expression Rig:")
col.row(align=True).prop(prefs, "rigify_expression_rig", expand=True) col.row(align=True).prop(prefs, "rigify_expression_rig", expand=True)
@@ -2322,12 +2331,10 @@ class CC3RigifyPanel(bpy.types.Panel):
if allow_rigify: if allow_rigify:
col.row().prop(prefs, "rigify_face_control_color") col.row().prop(prefs, "rigify_face_control_color")
else: else:
wrapped_text_box(layout, "Invalid Facial Profile!", width, alert=True) wrapped_text_box(layout, "Invalid Facial Profile!", width, alert=True, icon="ERROR", )
elif prefs.rigify_expression_rig == "RIGIFY": elif prefs.rigify_expression_rig == "RIGIFY":
if not chr_cache.can_rigify_face(): if not chr_cache.can_rigify_face():
wrapped_text_box(layout, "Note: Full face rig cannot be auto-detected for this character.", width) wrapped_text_box(layout, "Note: Full face rig cannot be auto-detected for this character.", width)
else:
grid = layout.grid_flow(columns=1, row_major=True, align=True)
col = layout.column(align=True) col = layout.column(align=True)
col.label(text="Bone Alignment:") col.label(text="Bone Alignment:")
@@ -2599,12 +2606,15 @@ class CC3RigifyPanel(bpy.types.Panel):
props.section_rigify_action_sets, props.section_rigify_action_sets,
icon="ANIM_DATA", icon_closed="ANIM_DATA"): icon="ANIM_DATA", icon_closed="ANIM_DATA"):
layout.label(text="Import Options:") row = layout.row()
row.label(text="Import Options:")
row.operator("ccic.motion_prefs", icon="MODIFIER_ON", text="")
row = layout.row(align=True) row = layout.row(align=True)
label = rigutils.CCICActionImportOptions.label(context) label = rigutils.CCICMotionBlend.label(context)
row.operator("ccic.action_import_options", icon="COLLAPSEMENU", text=label) row.operator("ccic.motion_blend", icon="COLLAPSEMENU", text=label)
row.operator("ccic.motion_blend_funcs", icon="LOOP_BACK", text="").param = "RESET_OPTS"
column = layout.column() column = layout.column()
motion_set_ui(column, chr_cache) motion_set_ui(column, chr_cache, rlx_cache)
box_row = layout.box().row() box_row = layout.box().row()
if fake_drop_down(box_row, if fake_drop_down(box_row,
@@ -2690,17 +2700,19 @@ class CC3RigifyPanel(bpy.types.Panel):
wrapped_text_box(layout, "Rigify add-on is not enabled.", width, True) wrapped_text_box(layout, "Rigify add-on is not enabled.", width, True)
def motion_set_ui(layout: bpy.types.UILayout, chr_cache, show_nla=False): def motion_set_ui(layout: bpy.types.UILayout, chr_cache, rlx_cache, show_nla=False):
props = vars.props() props = vars.props()
# current selected motion set action # current selected motion set action
action_set_list_action = utils.collection_at_index(props.action_set_list_index, bpy.data.actions) action_set_list_action = utils.collection_at_index(props.action_set_list_index, bpy.data.actions)
action_set_generation = rigutils.get_set_generation(action_set_list_action) action_set_generation = rigutils.get_set_generation(action_set_list_action)
rig = None rig = None
rig_set_generation = None set_generation = None
if chr_cache: if rlx_cache:
set_generation = rlx_cache.get_generation()
elif chr_cache:
rig = chr_cache.get_armature() rig = chr_cache.get_armature()
rig_set_generation = rigutils.get_set_generation(rig) set_generation = rigutils.get_set_generation(rig)
col = layout.column(align=True) col = layout.column(align=True)
split = col.split(factor=0.4) split = col.split(factor=0.4)
@@ -2721,26 +2733,26 @@ def motion_set_ui(layout: bpy.types.UILayout, chr_cache, show_nla=False):
param = "SET_FAKE_USER_OFF" if depress else "SET_FAKE_USER_ON" param = "SET_FAKE_USER_OFF" if depress else "SET_FAKE_USER_ON"
row.operator("ccic.rigutils", icon=icon, text="", depress=depress).param = param row.operator("ccic.rigutils", icon=icon, text="", depress=depress).param = param
split = col.split(factor=0.5, align=True) split = col.split(factor=0.5, align=True)
split.scale_y = 1.5 split.scale_y = 1.25
col_1 = split.column(align=True) col_1 = split.column(align=True)
col_2 = split.column(align=True) col_2 = split.column(align=True)
row = col_1.row(align=True) row = col_1.row(align=True)
row.operator("ccic.rigutils", icon="ACTION_TWEAK", text="Load").param = "LOAD_MOTION_SET" row.operator("ccic.rigutils", icon="ACTION_TWEAK", text="Load").param = "LOAD_MOTION_SET"
if rig_set_generation != action_set_generation: if set_generation != action_set_generation:
row.enabled = False row.enabled = False
col_2.operator("ccic.rigutils", icon="REMOVE", text="Clear").param = "CLEAR_ACTION_SET" col_2.operator("ccic.rigutils", icon="REMOVE", text="Clear").param = "CLEAR_ACTION_SET"
col_1.separator()
col_2.separator()
col_1.operator("ccic.rigutils", icon="PLUS", text="New").param = "NEW_ACTION_SET" col_1.operator("ccic.rigutils", icon="PLUS", text="New").param = "NEW_ACTION_SET"
col_2.operator("ccic.rigutils", icon="MODIFIER_ON", text="Clean").param = "CLEAN_ACTIONS" col_2.operator("ccic.rigutils", icon="MODIFIER_ON", text="Clean").param = "CLEAN_ACTIONS"
row = col.row(align=True)
row.scale_y = 2.0
row.operator("ccic.motion_blend", icon="MOD_ENVELOPE", text="Blend Motions").param="BLEND"
col.enabled = chr_cache is not None or rlx_cache is not None
if show_nla: if show_nla:
row = col_1.row(align=True) row = col_1.row(align=True)
row.operator("ccic.rigutils", icon="NLA_PUSHDOWN", text="Push").param = "PUSH_ACTION_SET" row.operator("ccic.rigutils", icon="NLA_PUSHDOWN", text="Push").param = "PUSH_ACTION_SET"
if rig_set_generation != action_set_generation: if set_generation != action_set_generation:
row.enabled = False row.enabled = False
col_2.operator("ccic.rigutils", icon="RESTRICT_SELECT_OFF", text="Select").param = "SELECT_SET_STRIPS" col_2.operator("ccic.rigutils", icon="RESTRICT_SELECT_OFF", text="Select").param = "SELECT_SET_STRIPS"
@@ -2772,7 +2784,7 @@ def motion_set_ui(layout: bpy.types.UILayout, chr_cache, show_nla=False):
if not bpy.context.selected_nla_strips: if not bpy.context.selected_nla_strips:
split.enabled = False split.enabled = False
if not chr_cache: if not chr_cache and not rlx_cache:
split.enabled = False split.enabled = False
@@ -2787,20 +2799,24 @@ class CCICAnimationToolsPanel(bpy.types.Panel):
props = vars.props() props = vars.props()
prefs = vars.prefs() prefs = vars.prefs()
chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context) chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context, strict=True)
rlx_cache = props.get_context_staging_cache(context)
layout = self.layout layout = self.layout
layout.use_property_split = False layout.use_property_split = False
layout.use_property_decorate = False layout.use_property_decorate = False
layout.label(text="Import Options:") row = layout.row()
row.label(text="Import Options:")
row.operator("ccic.motion_prefs", icon="MODIFIER_ON", text="")
row = layout.row(align=True) row = layout.row(align=True)
label = rigutils.CCICActionImportOptions.label(context) label = rigutils.CCICMotionBlend.label(context)
row.operator("ccic.action_import_options", icon="COLLAPSEMENU", text=label) row.operator("ccic.motion_blend", icon="COLLAPSEMENU", text=label).param="NONE"
row.operator("ccic.motion_blend_funcs", icon="LOOP_BACK", text="").param = "RESET_OPTS"
column = layout.column() column = layout.column()
motion_set_ui(column, chr_cache) motion_set_ui(column, chr_cache, rlx_cache)
class CCICNLASetsPanel(bpy.types.Panel): class CCICNLASetsPanel(bpy.types.Panel):
@@ -2814,13 +2830,14 @@ class CCICNLASetsPanel(bpy.types.Panel):
props = vars.props() props = vars.props()
prefs = vars.prefs() prefs = vars.prefs()
chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context) chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context, strict=True)
rlx_cache = props.get_context_staging_cache(context)
layout = self.layout layout = self.layout
layout.use_property_split = False layout.use_property_split = False
layout.use_property_decorate = False layout.use_property_decorate = False
motion_set_ui(layout, chr_cache, show_nla=True) motion_set_ui(layout, chr_cache, rlx_cache, show_nla=True)
class CCICNLABakePanel(bpy.types.Panel): class CCICNLABakePanel(bpy.types.Panel):
@@ -3816,6 +3833,12 @@ class CCICDataLinkPanel(bpy.types.Panel):
chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context, strict=True) chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context, strict=True)
selected_meshes = [ obj for obj in bpy.context.selected_objects if obj.type == "MESH"] selected_meshes = [ obj for obj in bpy.context.selected_objects if obj.type == "MESH"]
mesh_modify_id = None
for obj in bpy.context.selected_objects:
if utils.get_prop(obj, "rl_mesh_modify"):
mesh_modify_id = utils.get_prop(obj, "rl_link_id")
break
#active_chr_cache = props.get_character_cache(obj, mat) #active_chr_cache = props.get_character_cache(obj, mat)
all_valid_topography = True all_valid_topography = True
if chr_cache and selected_meshes: if chr_cache and selected_meshes:
@@ -3966,6 +3989,11 @@ class CCICDataLinkPanel(bpy.types.Panel):
text = "Go CC" text = "Go CC"
param = "SEND_ACTOR" param = "SEND_ACTOR"
icon = "COMMUNITY" icon = "COMMUNITY"
if mesh_modify_id:
param = "SEND_MESH_MODIFY"
icon = "MESH_ICOSPHERE"
text = "Update Mesh"
grid.enabled = True
if chr_cache and chr_cache.is_morph(): if chr_cache and chr_cache.is_morph():
param = "SEND_MORPH" param = "SEND_MORPH"
icon="MESH_ICOSPHERE" icon="MESH_ICOSPHERE"
@@ -3977,7 +4005,7 @@ class CCICDataLinkPanel(bpy.types.Panel):
text = "Invalid Character!" text = "Invalid Character!"
param += "_INVALID" param += "_INVALID"
grid.operator("ccic.datalink", icon=icon, text=text).param = param grid.operator("ccic.datalink", icon=icon, text=text).param = param
if not (chr_cache and chr_cache.can_go_cc()): if not mesh_modify_id and not (chr_cache and chr_cache.can_go_cc()):
grid.enabled = False grid.enabled = False
elif is_iclone: elif is_iclone:
@@ -4091,7 +4119,7 @@ class CC3ToolsPipelineImportPanel(bpy.types.Panel):
chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context) chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context)
if chr_cache: if chr_cache:
character_name = chr_cache.character_name character_name = chr_cache.get_name()
else: else:
character_name = "No Character" character_name = "No Character"
@@ -4128,6 +4156,7 @@ class CC3ToolsPipelineImportPanel(bpy.types.Panel):
column.prop(PREFS, "import_deduplicate") column.prop(PREFS, "import_deduplicate")
column.prop(PREFS, "import_auto_convert") column.prop(PREFS, "import_auto_convert")
column.prop(PREFS, "import_reset_custom_normals") column.prop(PREFS, "import_reset_custom_normals")
column.prop(PREFS, "import_fix_5_1_normals")
column.prop(PREFS, "clean_empty_mesh_data") column.prop(PREFS, "clean_empty_mesh_data")
column.prop(PREFS, "action_use_action_slots") column.prop(PREFS, "action_use_action_slots")
column.prop(PREFS, "action_add_key_slots_per_obj") column.prop(PREFS, "action_add_key_slots_per_obj")
@@ -4204,7 +4233,7 @@ class CC3ToolsPipelineExportPanel(bpy.types.Panel):
chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context) chr_cache, obj, mat, obj_cache, mat_cache = utils.get_context_character(context)
if chr_cache: if chr_cache:
character_name = chr_cache.character_name character_name = chr_cache.get_name()
else: else:
character_name = "No Character" character_name = "No Character"
@@ -1449,7 +1449,7 @@ SHADER_MATRIX = [
["eye_iris_brightness", 1, "", "Custom/Iris Color Brightness"], ["eye_iris_brightness", 1, "", "Custom/Iris Color Brightness"],
["eye_pupil_scale", 1, "", "Custom/Pupil Scale"], ["eye_pupil_scale", 1, "", "Custom/Pupil Scale"],
["eye_ior", 1.4, "", "Custom/_IoR"], ["eye_ior", 1.4, "", "Custom/_IoR"],
["eye_iris_radius", 0.24, "", "Custom/Iris UV Radius"], ["eye_iris_radius", 0.16, "", "Custom/Iris UV Radius"],
["eye_iris_color", (1.0, 1.0, 1.0, 1.0), "func_color_bytes", "Custom/Iris Color"], ["eye_iris_color", (1.0, 1.0, 1.0, 1.0), "func_color_bytes", "Custom/Iris Color"],
["eye_iris_inner_color", (1.0, 1.0, 1.0, 1.0), "func_color_bytes", "Custom/Iris Inner Color"], ["eye_iris_inner_color", (1.0, 1.0, 1.0, 1.0), "func_color_bytes", "Custom/Iris Inner Color"],
["eye_iris_inner_scale", 0, "", "Custom/Iris Inner Scale"], ["eye_iris_inner_scale", 0, "", "Custom/Iris Inner Scale"],
@@ -1309,7 +1309,7 @@ def apply_all_physics(chr_cache):
props = vars.props() props = vars.props()
if chr_cache: if chr_cache:
utils.log_info(f"Adding all Physics modifiers to: {chr_cache.character_name}") utils.log_info(f"Adding all Physics modifiers to: {chr_cache.get_name()}")
utils.log_indent() utils.log_indent()
arm = chr_cache.get_armature() arm = chr_cache.get_armature()
objects = chr_cache.get_all_objects(include_armature=False, objects = chr_cache.get_all_objects(include_armature=False,
@@ -1393,7 +1393,7 @@ def arrange_physics_modifiers(obj):
def remove_all_physics(chr_cache): def remove_all_physics(chr_cache):
if chr_cache: if chr_cache:
utils.log_info(f"Removing all Physics modifiers from: {chr_cache.character_name}") utils.log_info(f"Removing all Physics modifiers from: {chr_cache.get_name()}")
utils.log_indent() utils.log_indent()
objects_processed = [] objects_processed = []
for obj in chr_cache.get_cache_objects(): for obj in chr_cache.get_cache_objects():
@@ -1600,27 +1600,27 @@ def set_physics_settings(op, context, param):
if chr_cache: if chr_cache:
restore_collision_proxy_view(context, chr_cache) restore_collision_proxy_view(context, chr_cache)
disable_physics(chr_cache) disable_physics(chr_cache)
op.report({'INFO'}, f"Physics disabled for {chr_cache.character_name}") op.report({'INFO'}, f"Physics disabled for {chr_cache.get_name()}")
elif param == "ENABLE_PHYSICS": elif param == "ENABLE_PHYSICS":
if chr_cache: if chr_cache:
restore_collision_proxy_view(context, chr_cache) restore_collision_proxy_view(context, chr_cache)
enable_physics(chr_cache) enable_physics(chr_cache)
reset_physics(context) reset_physics(context)
op.report({'INFO'}, f"Physics enabled for {chr_cache.character_name}") op.report({'INFO'}, f"Physics enabled for {chr_cache.get_name()}")
elif param == "REMOVE_PHYSICS": elif param == "REMOVE_PHYSICS":
if chr_cache: if chr_cache:
restore_collision_proxy_view(context, chr_cache) restore_collision_proxy_view(context, chr_cache)
remove_all_physics(chr_cache) remove_all_physics(chr_cache)
op.report({'INFO'}, f"Physics removed for {chr_cache.character_name}") op.report({'INFO'}, f"Physics removed for {chr_cache.get_name()}")
elif param == "APPLY_PHYSICS": elif param == "APPLY_PHYSICS":
if chr_cache: if chr_cache:
restore_collision_proxy_view(context, chr_cache) restore_collision_proxy_view(context, chr_cache)
apply_all_physics(chr_cache) apply_all_physics(chr_cache)
reset_physics(context) reset_physics(context)
op.report({'INFO'}, f"Physics applied to {chr_cache.character_name}") op.report({'INFO'}, f"Physics applied to {chr_cache.get_name()}")
elif param == "PHYSICS_INC_STRENGTH": elif param == "PHYSICS_INC_STRENGTH":
strength = float(round(props.physics_paint_strength * 10)) / 10.0 strength = float(round(props.physics_paint_strength * 10)) / 10.0
@@ -100,7 +100,7 @@ def reset_rigify():
def reset_datalink(): def reset_datalink():
prefs: CC3ToolsAddonPreferences = vars.prefs() prefs: CC3ToolsAddonPreferences = vars.prefs()
prefs.datalink_auto_start = False prefs.datalink_auto_start = False
prefs.datalink_frame_sync = True prefs.datalink_frame_sync = False
prefs.datalink_preview_shape_keys = True prefs.datalink_preview_shape_keys = True
prefs.datalink_match_client_rate = True prefs.datalink_match_client_rate = True
prefs.datalink_retarget_prop_actions = True prefs.datalink_retarget_prop_actions = True
@@ -140,6 +140,7 @@ def reset_preferences():
prefs.auto_convert_materials = True prefs.auto_convert_materials = True
prefs.import_deduplicate = True prefs.import_deduplicate = True
prefs.import_reset_custom_normals = False prefs.import_reset_custom_normals = False
prefs.import_fix_5_1_normals = True
prefs.build_pack_texture_channels = False prefs.build_pack_texture_channels = False
prefs.build_pack_wrinkle_diffuse_roughness = False prefs.build_pack_wrinkle_diffuse_roughness = False
prefs.build_reuse_baked_channel_packs = True prefs.build_reuse_baked_channel_packs = True
@@ -274,8 +275,8 @@ class CC3ToolsAddonPreferences(bpy.types.AddonPreferences):
description="When importing and retargeting animations, use action slots to combine armature and shape key actions into a single action", description="When importing and retargeting animations, use action slots to combine armature and shape key actions into a single action",
name="Use Action Slots") name="Use Action Slots")
action_add_key_slots_per_obj: bpy.props.BoolProperty(default=True, action_add_key_slots_per_obj: bpy.props.BoolProperty(default=True,
description="When using action slots, generate an slot channel specifically for each object's shape keys. " \ description="When using action slots, generate a shape key slot for each object. " \
"Otherwise, use only a single shapekey channel for all mesh obejcts", "Otherwise, use only a single shape key slot for all mesh objects",
name="Action Key Slots Per Obj") name="Action Key Slots Per Obj")
action_clean_actions: bpy.props.BoolProperty(default=False, action_clean_actions: bpy.props.BoolProperty(default=False,
description="When loading motions onto character, clean up (remove redundant) action keyframes", description="When loading motions onto character, clean up (remove redundant) action keyframes",
@@ -376,6 +377,8 @@ class CC3ToolsAddonPreferences(bpy.types.AddonPreferences):
import_reset_custom_normals: bpy.props.BoolProperty(default=False, name="Reset Custom Normals", import_reset_custom_normals: bpy.props.BoolProperty(default=False, name="Reset Custom Normals",
description="Reset the custom normals on all imported meshes (can help resolve lighting artifacts)") description="Reset the custom normals on all imported meshes (can help resolve lighting artifacts)")
import_fix_5_1_normals: bpy.props.BoolProperty(default=True, name="Fix Blender 5.1 Normals",
description="Blender 5.1 introduced an export bug that fails to export custom normals on meshes with shape-keys, this option will remove custom normals from all meshes with shape keys on import")
import_deduplicate: bpy.props.BoolProperty(default=True, name="De-duplicate Materials", import_deduplicate: bpy.props.BoolProperty(default=True, name="De-duplicate Materials",
description="Detects and re-uses duplicate textures and consolidates materials with same name, textures and parameters into a single material") description="Detects and re-uses duplicate textures and consolidates materials with same name, textures and parameters into a single material")
import_auto_convert: bpy.props.BoolProperty(default=True, name="Auto Convert Generic", import_auto_convert: bpy.props.BoolProperty(default=True, name="Auto Convert Generic",
@@ -629,6 +632,7 @@ class CC3ToolsAddonPreferences(bpy.types.AddonPreferences):
layout.label(text="Import:") layout.label(text="Import:")
grid = layout.grid_flow(row_major=True, columns=2) grid = layout.grid_flow(row_major=True, columns=2)
grid.prop(self, "import_reset_custom_normals") grid.prop(self, "import_reset_custom_normals")
grid.prop(self, "import_fix_5_1_normals")
grid.prop(self, "import_deduplicate") grid.prop(self, "import_deduplicate")
grid.prop(self, "import_auto_convert") grid.prop(self, "import_auto_convert")
grid.prop(self, "auto_convert_materials") grid.prop(self, "auto_convert_materials")
@@ -20,6 +20,7 @@ from mathutils import Vector
from . import (channel_mixer, imageutils, meshutils, sculpting, materials, rigidbody, from . import (channel_mixer, imageutils, meshutils, sculpting, materials, rigidbody,
facerig, facerig_data, springbones, rigify_mapping_data, modifiers, nodeutils, shaders, facerig, facerig_data, springbones, rigify_mapping_data, modifiers, nodeutils, shaders,
params, physics, basic, jsonutils, utils, vars) params, physics, basic, jsonutils, utils, vars)
from . rlx import get_rlx_generation
from .meshutils import get_head_body_object_quick from .meshutils import get_head_body_object_quick
@@ -599,6 +600,38 @@ def clean_collection_property(collection_prop):
break break
def blend_mask_preset_list(self, context):
preset_list = [("NONE", "Blend Mask Presets ...", "Blend Presets ...", 0)]
folder = utils.get_resource_folder("Blend Presets")
json_files = [f for f in os.listdir(folder) if os.path.isfile(os.path.join(folder, f)) and f.endswith(".json")]
i = 1
for file in json_files:
preset_name = file[:-5]
preset_list.append((preset_name, preset_name, preset_name, i))
i += 1
return preset_list
def update_blend_root_relative(self, context):
props = vars.props()
prefs = vars.prefs()
chr_cache = props.get_context_character_cache(context, strict=True)
if chr_cache:
opts = chr_cache.action_options
if opts.relative_root:
opts.current_root = False
def update_blend_root_current(self, context):
props = vars.props()
prefs = vars.prefs()
chr_cache = props.get_context_character_cache(context, strict=True)
if chr_cache:
opts = chr_cache.action_options
if opts.current_root:
opts.relative_root = False
class CC3OperatorProperties(bpy.types.Operator): class CC3OperatorProperties(bpy.types.Operator):
"""CC3 Property Functions""" """CC3 Property Functions"""
bl_idname = "cc3.setproperties" bl_idname = "cc3.setproperties"
@@ -684,46 +717,70 @@ class CC3ArmatureList(bpy.types.PropertyGroup):
actions: bpy.props.CollectionProperty(type=CC3ActionList) actions: bpy.props.CollectionProperty(type=CC3ActionList)
class CCICStringList(bpy.types.PropertyGroup):
name: bpy.props.StringProperty(default="")
index: bpy.props.IntProperty(default=0)
visible: bpy.props.BoolProperty(default=True)
class CCIC_UI_MixItem(bpy.types.PropertyGroup): class CCIC_UI_MixItem(bpy.types.PropertyGroup):
name: bpy.props.StringProperty(default="") name: bpy.props.StringProperty(default="")
weight: bpy.props.FloatProperty(default=1.0) weight: bpy.props.FloatProperty(default=1.0, min=0.0, max=1.0)
class CCIC_UI_MixList(bpy.types.PropertyGroup):
bones: bpy.props.CollectionProperty(type=CCIC_UI_MixItem)
class CCICActionOptions(bpy.types.PropertyGroup): class CCICActionOptions(bpy.types.PropertyGroup):
action_mode: bpy.props.EnumProperty(items=[
("NEW","New","Import actions as a new set of actions and keep the existing actions"),
("REPLACE","Replace","Import new actions to replace the existing actions"),
("BLEND","Overwrite","Import the new actions into the existing actions keeping the keyframes not overwritten by the import"),
], default="NEW", name = "Import Action Mode")
frame_mode: bpy.props.EnumProperty(items=[ frame_mode: bpy.props.EnumProperty(items=[
("START","Start","Import keyframes into Blender starting at the start frame"), ("MATCH","Match","Import / Blend keyframes matching keyframes with source motion\n*Note: +1 as Blender starts at frame 1*"),
("CURRENT","Current","Import keyframes into Blender starting at the current frame"), ("CURRENT","Current","Import / Blend keyframes starting at the current frame"),
("MATCH","Match","Import keyframes into Blender matching keyframes with CC/iClone \n*Note: +1 as Blender starts at frame 1*"), ("START","Start","Import / Blend keyframes starting at the start frame (frame 1)"),
], default="MATCH", name = "Import Frame Mode") ], default="MATCH", name = "Import Frame Mode")
use_masking: bpy.props.BoolProperty(default=False, name="Use Bone / Shape-Key Masking", use_bone_masking: bpy.props.BoolProperty(default=False, name="Use Bone Masking",
description="Only import the keyframes from the masked bones and shape-keys") description="Only import the keyframes from the masked bones")
override_global: bpy.props.BoolProperty(default=False, name="Character Motion Override:", use_key_masking: bpy.props.BoolProperty(default=False, name="Use Shape-Key Masking",
description="Override the global action options for this character or prop") description="Only import the keyframes from the masked shape-keys")
import_mix_bones: bpy.props.CollectionProperty(type=CCIC_UI_MixItem) import_bones: bpy.props.CollectionProperty(type=CCIC_UI_MixItem)
rig_mix_bones_list_index: bpy.props.IntProperty(default=-1) import_keys: bpy.props.CollectionProperty(type=CCIC_UI_MixItem)
import_mix_bones_list_index: bpy.props.IntProperty(default=-1) available_bones: bpy.props.CollectionProperty(type=CCICStringList)
available_keys: bpy.props.CollectionProperty(type=CCICStringList)
import_bones_index: bpy.props.IntProperty(default=-1)
import_keys_index: bpy.props.IntProperty(default=-1)
available_bones_index: bpy.props.IntProperty(default=-1)
available_keys_index: bpy.props.IntProperty(default=-1)
relative_root: bpy.props.BoolProperty(default=False, name="Relative Root",
description="Source motion root bone transform will match the destination motion at the starting frame",
update=update_blend_root_relative)
current_root: bpy.props.BoolProperty(default=False, name="Current Root",
description="Source motion root bone transform will match the current root bone transform in the scene",
update=update_blend_root_current)
use_blend: bpy.props.BoolProperty(default=False, name="Blend Frames",
description="Blend Frames from the source motion into the destination motion")
blend_strength: bpy.props.FloatProperty(default=1.0, name="Blend Strength",
min=0.0, soft_min=0.0, soft_max=1.0,
description="Blend Strength")
blend_in_frames: bpy.props.IntProperty(default=0, name="Blend In Frames",
min=0, soft_max=1000,
description="The number of frames at the start of the source or imported motion to blend in from the target motion")
blend_out_frames: bpy.props.IntProperty(default=0, name="Blend Out Frames",
min=0, soft_max=1000,
description="The number of frames at the end of the source or imported motion to blend out to the target motion")
action_store: bpy.props.CollectionProperty(type=CCICActionStore) action_store: bpy.props.CollectionProperty(type=CCICActionStore)
source_motion: bpy.props.PointerProperty(type=bpy.types.Action)
target_motion: bpy.props.PointerProperty(type=bpy.types.Action)
motion_prefix: bpy.props.StringProperty(default="Blend")
motion_id: bpy.props.StringProperty(default="New Motion")
show_motion_options: bpy.props.BoolProperty(default=True)
show_blend_options: bpy.props.BoolProperty(default=True)
show_bone_mask_options: bpy.props.BoolProperty(default=True)
show_key_mask_options: bpy.props.BoolProperty(default=True)
mode_save_mask_preset: bpy.props.BoolProperty(default=False)
preset_mask_name: bpy.props.StringProperty(default="New Blend Mask Preset")
# some masking settings ... # some masking settings ...
# some masking presets ... # some masking presets ...
# export / import presets ... # export / import presets ...
def get_action_mode(self):
props = vars.props()
action_mode = self.action_mode if self.override_global else props.action_options.action_mode
return action_mode
def get_frame_mode(self): def get_frame_mode(self):
props = vars.props() props = vars.props()
frame_mode = self.frame_mode if self.override_global else props.action_options.frame_mode frame_mode = self.frame_mode
return frame_mode return frame_mode
def get_start_frame(self, ccic_start_frame, blender_current_frame): def get_start_frame(self, ccic_start_frame, blender_current_frame):
@@ -1601,6 +1658,12 @@ class CC3ObjectCache(bpy.types.PropertyGroup):
def is_armature(self): def is_armature(self):
return utils.object_exists_is_armature(self.object) return utils.object_exists_is_armature(self.object)
def is_light(self):
return utils.object_exists_is_light(self.object)
def is_camera(self):
return utils.object_exists_is_camera(self.object)
def get_object(self, return_invalid=False): def get_object(self, return_invalid=False):
if utils.object_exists(self.object): if utils.object_exists(self.object):
return self.object return self.object
@@ -1633,7 +1696,7 @@ class CC3ObjectCache(bpy.types.PropertyGroup):
if self.object_id == "": if self.object_id == "":
self.object_id = utils.generate_random_id(20) self.object_id = utils.generate_random_id(20)
if self.object: if self.object:
utils.set_rl_object_id(self.object, self.object_id) utils.set_rl_id(self.object, self.object_id)
self.object["rl_object_type"] = self.object_type self.object["rl_object_type"] = self.object_type
def validate(self, report=None, split_objects=None): def validate(self, report=None, split_objects=None):
@@ -1688,6 +1751,174 @@ class CCICExpressionData(bpy.types.PropertyGroup):
offset_rotation: bpy.props.FloatVectorProperty() offset_rotation: bpy.props.FloatVectorProperty()
# endregion # endregion
# region Staging Cache
class CC3StagingCache(bpy.types.PropertyGroup):
object_cache: bpy.props.CollectionProperty(type=CC3ObjectCache)
link_id: bpy.props.StringProperty(default="")
staging_name: bpy.props.StringProperty(default="")
action_options: bpy.props.PointerProperty(type=CCICActionOptions)
disabled: bpy.props.BoolProperty(default=False)
def set_link_id(self, link_id):
self.link_id = link_id
arm = self.get_armature()
utils.set_rl_link_id(arm, link_id)
def get_generation(self):
rob = self.get_rlx_object()
return get_rlx_generation(rob)
def get_link_id(self):
if not self.link_id:
self.link_id = utils.generate_random_id(20)
return self.link_id
def get_name(self):
return self.staging_name
def set_name(self, name):
self.staging_name = name
def get_rlx_object(self, include_disabled=False):
for obj_cache in self.object_cache:
obj = obj_cache.get_object()
if obj and (include_disabled or not obj_cache.disabled):
return obj
return None
def get_primary_object(self, include_disabled=False):
return self.get_rlx_object(include_disabled=include_disabled)
def get_armature(self, include_disabled=False):
return None
def is_avatar(self):
return False
def is_prop(self):
return False
def is_light(self):
for obj_cache in self.object_cache:
if obj_cache.is_light():
return True
return False
def is_camera(self):
for obj_cache in self.object_cache:
if obj_cache.is_camera():
return True
return False
def cache_type(self):
if self.is_light():
return "LIGHT"
else:
return "CAMERA"
def get_object_cache(self, obj, include_disabled=False, by_id=None, strict=False) -> CC3ObjectCache:
"""Returns the object cache for this object.
"""
if utils.object_exists(obj):
# by object
if not strict and not by_id:
by_id = utils.get_rl_id(obj)
for obj_cache in self.object_cache:
if include_disabled or not obj_cache.disabled:
cache_object = obj_cache.get_object()
if cache_object and cache_object == obj:
return obj_cache
# by id
if by_id:
for obj_cache in self.object_cache:
if include_disabled or not obj_cache.disabled:
if obj_cache.object_id == by_id:
return obj_cache
return None
def update_object(self, obj):
obj_cache: CC3ObjectCache = None
for obj_cache in self.object_cache:
if ((obj.type == "CAMERA" and obj_cache.is_camera()) or
(obj.type == "LIGHT" and obj_cache.is_light())):
obj_cache.object = obj
self.set_name(obj.name)
obj_cache.check_id()
return
obj_cache = self.add_object_cache(obj)
self.set_name(obj.name)
def remove_object_cache(self, obj):
"""Removes the object from the object cache.
Note this will invalidate all current object cache references!
"""
if obj:
for obj_cache in self.object_cache:
cache_object = obj_cache.get_object()
if cache_object and cache_object == obj:
utils.remove_from_collection(self.object_cache, obj_cache)
return
def add_object_cache(self, obj, copy_from=None, user=False):
"""Returns the object cache for this object.
Fetches or creates an object cache for the object. Always returns an object cache collection.
"""
obj_cache: CC3ObjectCache = self.get_object_cache(obj)
if obj_cache is None:
utils.log_info(f"Creating Object Cache for: {obj.name}")
obj_cache = self.object_cache.add()
obj_cache.object_id = utils.generate_random_id(20)
if copy_from:
utils.log_info(f"Copying object cache from: {copy_from}")
utils.copy_property_group(copy_from, obj_cache)
if user:
obj_cache.user_added = True
obj_cache.object_id = utils.generate_random_id(20)
obj_cache.set_object(obj)
obj_cache.set_object_type("LIGHT" if obj.type == "LIGHT" else "CAMERA")
obj_cache.source_name = utils.strip_name(obj.name)
obj_cache.check_id()
return obj_cache
def validate(self, report=None):
"""Checks character object is still valid.
Returns True if any objects in the character are still valid"""
obj_cache: CC3ObjectCache = None
any_valid = False
for obj_cache in self.object_cache:
obj_valid = obj_cache.validate(report=report)
any_valid = any_valid or obj_valid
if not any_valid:
rep = f"Staging Cache: {self.get_name()} is no longer valid!"
utils.log_info(rep)
if report is not None:
report.append(rep)
self.invalidate()
return not self.disabled
def invalidate(self):
utils.log_info(f"Invalidating Staging cache: {self.get_name()}")
self.disabled = True
obj_cache: CC3ObjectCache = None
for obj_cache in self.object_cache:
obj_cache.invalidate()
def delete(self):
obj_cache: CC3ObjectCache = None
for obj_cache in self.object_cache:
obj_cache.delete()
def clean_up(self):
obj_cache: CC3ObjectCache = None
for obj_cache in self.object_cache:
obj_cache.clean_up()
utils.log_detail(f"Cleaning up object cache.")
clean_collection_property(self.object_cache)
# endregion
# region CharacterCache # region CharacterCache
class CC3CharacterCache(bpy.types.PropertyGroup): class CC3CharacterCache(bpy.types.PropertyGroup):
open_mouth: bpy.props.FloatProperty(default=0.0, min=0, max=1, update=open_mouth_update) open_mouth: bpy.props.FloatProperty(default=0.0, min=0, max=1, update=open_mouth_update)
@@ -1863,6 +2094,17 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
arm = self.get_armature() arm = self.get_armature()
utils.set_rl_link_id(arm, link_id) utils.set_rl_link_id(arm, link_id)
def get_link_id(self):
if not self.link_id:
self.link_id = utils.generate_random_id(20)
return self.link_id
def get_name(self):
return self.character_name
def set_name(self, name):
self.character_name = name
def get_auto_index(self): def get_auto_index(self):
self.auto_index += 1 self.auto_index += 1
return self.auto_index return self.auto_index
@@ -1919,6 +2161,10 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
import_type = import_type[1:] import_type = import_type[1:]
return self.get_import_type().lower() == import_type.lower() return self.get_import_type().lower() == import_type.lower()
def is_obj(self):
res = (self.import_flags & 2 > 0)
return res
def get_character_id(self): def get_character_id(self):
dir, file = os.path.split(self.import_file) dir, file = os.path.split(self.import_file)
name, ext = os.path.splitext(file) name, ext = os.path.splitext(file)
@@ -1985,6 +2231,12 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
return True return True
return False return False
def is_light(self):
return False
def is_camera(self):
return False
def cache_type(self): def cache_type(self):
if self.is_avatar(): if self.is_avatar():
return "AVATAR" return "AVATAR"
@@ -2057,7 +2309,7 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
can_expresion_rig = self.can_expression_rig() can_expresion_rig = self.can_expression_rig()
can_rigify_face = self.can_rigify_face() can_rigify_face = self.can_rigify_face()
return ((prefs.rigify_expression_rig == "META" and can_expresion_rig) or return ((prefs.rigify_expression_rig == "META" and can_expresion_rig) or
(prefs.rigify_expression_rig == "RIGIFY" and can_rigify_face) or (prefs.rigify_expression_rig == "RIGIFY") or
(prefs.rigify_expression_rig == "NONE")) (prefs.rigify_expression_rig == "NONE"))
def get_facial_profile(self, update=True): def get_facial_profile(self, update=True):
@@ -2254,7 +2506,7 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
obj_cache = self.get_object_cache(obj) obj_cache = self.get_object_cache(obj)
arm = self.get_armature() arm = self.get_armature()
for child in arm.children: for child in arm.children:
if obj_cache.object_id == utils.get_rl_object_id(child): if obj_cache.object_id == utils.get_rl_id(child):
if "rl_collision_proxy" in child and child["rl_collision_proxy"] == obj.name: if "rl_collision_proxy" in child and child["rl_collision_proxy"] == obj.name:
return child return child
proxy_name = obj.name + ".Collision_Proxy" proxy_name = obj.name + ".Collision_Proxy"
@@ -2322,7 +2574,7 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
if utils.object_exists(obj): if utils.object_exists(obj):
# by object # by object
if not strict and not by_id: if not strict and not by_id:
by_id = utils.get_rl_object_id(obj) by_id = utils.get_rl_id(obj)
for obj_cache in self.object_cache: for obj_cache in self.object_cache:
if include_disabled or not obj_cache.disabled: if include_disabled or not obj_cache.disabled:
cache_object = obj_cache.get_object() cache_object = obj_cache.get_object()
@@ -2351,7 +2603,7 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
def has_cache_objects(self, objects, include_disabled=False): def has_cache_objects(self, objects, include_disabled=False):
"""Returns True if *any* of the objects are actively the object cache. """Returns True if *any* of the objects are actively the object cache.
""" """
object_ids = [ utils.get_rl_object_id(o) for o in objects ] object_ids = [ utils.get_rl_id(o) for o in objects ]
for obj_cache in self.object_cache: for obj_cache in self.object_cache:
if include_disabled or not obj_cache.disabled: if include_disabled or not obj_cache.disabled:
cache_object = obj_cache.get_object() cache_object = obj_cache.get_object()
@@ -2373,11 +2625,11 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
"""Returns True if the object is in the object cache. """Returns True if the object is in the object cache.
""" """
if obj: if obj:
object_id = utils.get_rl_object_id(obj) object_id = utils.get_rl_id(obj)
for obj_cache in self.object_cache: for obj_cache in self.object_cache:
if include_disabled or not obj_cache.disabled: if include_disabled or not obj_cache.disabled:
cache_object = obj_cache.get_object() cache_object = obj_cache.get_object()
cache_object_id = utils.get_rl_object_id(cache_object) cache_object_id = utils.get_rl_id(cache_object)
if cache_object == obj or cache_object_id == object_id: if cache_object == obj or cache_object_id == object_id:
return True return True
return False return False
@@ -2388,12 +2640,12 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
obj = obj.get_object() obj = obj.get_object()
if obj: if obj:
split_objects.append(obj) split_objects.append(obj)
obj_id = utils.get_rl_object_id(obj) obj_id = utils.get_rl_id(obj)
arm = self.get_armature() arm = self.get_armature()
if arm: if arm:
for child in arm.children: for child in arm.children:
if child not in split_objects: if child not in split_objects:
child_id = utils.get_rl_object_id(child) child_id = utils.get_rl_id(child)
if child_id == obj_id: if child_id == obj_id:
split_objects.append(obj) split_objects.append(obj)
return split_objects return split_objects
@@ -2409,6 +2661,12 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
pass pass
return None return None
def get_rlx_object(self, include_disabled=False):
return None
def get_primary_object(self, include_disabled=False):
return self.get_armature(include_disabled=include_disabled)
def get_body(self): def get_body(self):
return self.get_object_of_type("BODY") return self.get_object_of_type("BODY")
@@ -2422,7 +2680,7 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
body_id = obj_cache.object_id body_id = obj_cache.object_id
chr_objects = self.get_cache_objects() chr_objects = self.get_cache_objects()
for obj in chr_objects: for obj in chr_objects:
if utils.get_rl_object_id(obj) == body_id: if utils.get_rl_id(obj) == body_id:
objects.append(obj) objects.append(obj)
return objects return objects
@@ -2453,12 +2711,12 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
for obj_cache in self.object_cache: for obj_cache in self.object_cache:
if not obj_cache.disabled: if not obj_cache.disabled:
cache_object = obj_cache.get_object() cache_object = obj_cache.get_object()
if cache_object.type == "ARMATURE": if cache_object and cache_object.type == "ARMATURE":
self.rig_original_rig = cache_object self.rig_original_rig = cache_object
obj_cache.set_object(new_arm) obj_cache.set_object(new_arm)
# update the object id # update the object id
obj_cache.object_id = utils.generate_random_id(20) obj_cache.object_id = utils.generate_random_id(20)
utils.set_rl_object_id(new_arm, obj_cache.object_id) utils.set_rl_id(new_arm, obj_cache.object_id)
utils.set_rl_link_id(new_arm, self.link_id) utils.set_rl_link_id(new_arm, self.link_id)
except: except:
pass pass
@@ -2688,7 +2946,10 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
if chr_json and "Expression" in chr_json: if chr_json and "Expression" in chr_json:
expression_json = chr_json["Expression"] expression_json = chr_json["Expression"]
return copy.deepcopy(expression_json) return copy.deepcopy(expression_json)
else:
return self.get_default_expression_json()
def get_default_expression_json(self):
facial_profile, viseme_profile = self.get_facial_profile() facial_profile, viseme_profile = self.get_facial_profile()
if facial_profile == "MH": if facial_profile == "MH":
# MH profile has complete expression json # MH profile has complete expression json
@@ -2718,7 +2979,7 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
self.link_id = utils.generate_random_id(20) self.link_id = utils.generate_random_id(20)
utils.set_rl_link_id(rig, self.link_id) utils.set_rl_link_id(rig, self.link_id)
# if rigified, ensure the face rig type is on the rig # if rigified, ensure the face rig type is on the rig
if self.rigified: if rig and self.rigified:
if not utils.get_prop(rig, "rl_face_rig"): if not utils.get_prop(rig, "rl_face_rig"):
bone_collection = rig.data.edit_bones if utils.get_mode() == "EDIT" else rig.pose.bones bone_collection = rig.data.edit_bones if utils.get_mode() == "EDIT" else rig.pose.bones
if "facerig" in bone_collection: if "facerig" in bone_collection:
@@ -2857,11 +3118,11 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
def find_object_from_proxy(self, proxy, include_disabled=False): def find_object_from_proxy(self, proxy, include_disabled=False):
if "rl_collision_proxy" in proxy: if "rl_collision_proxy" in proxy:
proxy_object_id = utils.get_rl_object_id(proxy) proxy_object_id = utils.get_rl_id(proxy)
for obj in self.get_cache_objects(): for obj in self.get_cache_objects():
obj_cache = self.get_object_cache(obj) obj_cache = self.get_object_cache(obj)
if include_disabled or not obj_cache.disabled: if include_disabled or not obj_cache.disabled:
if utils.get_rl_object_id(obj) == proxy_object_id and obj.name == proxy["rl_collision_proxy"]: if utils.get_rl_id(obj) == proxy_object_id and obj.name == proxy["rl_collision_proxy"]:
return obj return obj
if proxy.name.endswith(".Collision_Proxy"): if proxy.name.endswith(".Collision_Proxy"):
obj_name = proxy.name[:-16] obj_name = proxy.name[:-16]
@@ -2911,11 +3172,6 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
else: else:
return True return True
def get_link_id(self):
if not self.link_id:
self.link_id = utils.generate_random_id(20)
return self.link_id
def validate(self, report=None): def validate(self, report=None):
"""Checks character objects and materials are still valid. """Checks character objects and materials are still valid.
Returns True if any objects in the character are still valid""" Returns True if any objects in the character are still valid"""
@@ -2930,7 +3186,7 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
for mat_cache in all_materials_cache: for mat_cache in all_materials_cache:
mat_valid = mat_cache.validate(report) mat_valid = mat_cache.validate(report)
if not any_valid: if not any_valid:
rep = f"Character Cache: {self.character_name} is no longer valid!" rep = f"Character Cache: {self.get_name()} is no longer valid!"
utils.log_info(rep) utils.log_info(rep)
if report is not None: if report is not None:
report.append(rep) report.append(rep)
@@ -2938,7 +3194,7 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
return not self.disabled return not self.disabled
def invalidate(self): def invalidate(self):
utils.log_info(f"Invalidating Character cache: {self.character_name}") utils.log_info(f"Invalidating Character cache: {self.get_name()}")
self.disabled = True self.disabled = True
obj_cache: CC3ObjectCache obj_cache: CC3ObjectCache
mat_cache: CC3MaterialCache mat_cache: CC3MaterialCache
@@ -2961,7 +3217,7 @@ class CC3CharacterCache(bpy.types.PropertyGroup):
for mat_cache in all_materials_cache: for mat_cache in all_materials_cache:
mat_cache.delete() mat_cache.delete()
if self.disabled: if self.disabled:
utils.log_info(f"Deleting Character Meta Objects: {self.character_name}") utils.log_info(f"Deleting Character Meta Objects: {self.get_name()}")
utils.delete_object_tree(self.rig_meta_rig) utils.delete_object_tree(self.rig_meta_rig)
utils.delete_object_tree(self.arkit_proxy) utils.delete_object_tree(self.arkit_proxy)
utils.delete_object_tree(self.rig_export_rig) utils.delete_object_tree(self.rig_export_rig)
@@ -3039,6 +3295,7 @@ class CC3ImportProps(bpy.types.PropertyGroup):
import_file: bpy.props.StringProperty(default="", subtype="FILE_PATH") import_file: bpy.props.StringProperty(default="", subtype="FILE_PATH")
import_cache: bpy.props.CollectionProperty(type=CC3CharacterCache) import_cache: bpy.props.CollectionProperty(type=CC3CharacterCache)
staging_cache: bpy.props.CollectionProperty(type=CC3StagingCache)
dummy_slider: bpy.props.FloatProperty(default=0.5, min=0, max=1) dummy_slider: bpy.props.FloatProperty(default=0.5, min=0, max=1)
@@ -3258,6 +3515,8 @@ class CC3ImportProps(bpy.types.PropertyGroup):
rigified_action_list_index: bpy.props.IntProperty(default=-1) rigified_action_list_index: bpy.props.IntProperty(default=-1)
rigified_action_list_action: bpy.props.PointerProperty(type=bpy.types.Action) rigified_action_list_action: bpy.props.PointerProperty(type=bpy.types.Action)
blend_mask_presets: bpy.props.EnumProperty(items=blend_mask_preset_list, default=0, description="Presets for motion blend masking", name="Blend Mask Presets")
wrinkle_regions: bpy.props.EnumProperty(items=[ wrinkle_regions: bpy.props.EnumProperty(items=[
("ALL", "All", "All Regions"), ("ALL", "All", "All Regions"),
("01", " 1 - Brow Raise", "Brow Raise"), ("01", " 1 - Brow Raise", "Brow Raise"),
@@ -3300,15 +3559,22 @@ class CC3ImportProps(bpy.types.PropertyGroup):
action_options: bpy.props.PointerProperty(type=CCICActionOptions) action_options: bpy.props.PointerProperty(type=CCICActionOptions)
def add_character_cache(self, copy_from=None): def add_character_cache(self, copy_from=None) -> 'CC3CharacterCache':
chr_cache = self.import_cache.add() chr_cache = self.import_cache.add()
if copy_from: if copy_from:
exclude_list = ["*_material_cache", "object_cache"] exclude_list = ["*_material_cache", "object_cache"]
utils.copy_property_group(copy_from, chr_cache, exclude=exclude_list) utils.copy_property_group(copy_from, chr_cache, exclude=exclude_list)
return chr_cache return chr_cache
def get_character_cache_from_objects(self, objects, search_materials=False): def add_staging_cache(self, copy_from=None) -> 'CC3StagingCache':
chr_cache : CC3CharacterCache rlx_cache = self.staging_cache.add()
if copy_from:
exclude_list = ["object_cache"]
utils.copy_property_group(copy_from, rlx_cache, exclude=exclude_list)
return rlx_cache
def get_character_cache_from_objects(self, objects, search_materials=False) -> 'CC3CharacterCache':
chr_cache : CC3CharacterCache = None
if objects: if objects:
for chr_cache in self.import_cache: for chr_cache in self.import_cache:
@@ -3333,10 +3599,10 @@ class CC3ImportProps(bpy.types.PropertyGroup):
return chr_cache return chr_cache
return None return None
def get_character_cache(self, obj, mat, by_id=None): def get_character_cache(self, obj, mat, by_id=None) -> 'CC3CharacterCache':
if obj: if obj:
if not by_id: if not by_id:
by_id = utils.get_rl_object_id(obj) by_id = utils.get_rl_id(obj)
for chr_cache in self.import_cache: for chr_cache in self.import_cache:
if not chr_cache.disabled: if not chr_cache.disabled:
obj_cache = chr_cache.get_object_cache(obj, by_id=by_id) obj_cache = chr_cache.get_object_cache(obj, by_id=by_id)
@@ -3357,6 +3623,21 @@ class CC3ImportProps(bpy.types.PropertyGroup):
characters.append(chr_cache) characters.append(chr_cache)
return characters return characters
def get_staging_cache(self, obj, by_id=None, create=False) -> 'CC3StagingCache':
if obj:
if not by_id:
by_id = utils.get_rl_id(obj)
for rlx_cache in self.staging_cache:
if not rlx_cache.disabled:
obj_cache = rlx_cache.get_object_cache(obj, by_id=by_id)
if obj_cache and not obj_cache.disabled:
return rlx_cache
if create:
rlx_cache = self.add_staging_cache()
rlx_cache.update_object(obj)
return rlx_cache
return None
def get_avatars(self): def get_avatars(self):
avatars = [] avatars = []
chr_cache: CC3CharacterCache chr_cache: CC3CharacterCache
@@ -3375,7 +3656,7 @@ class CC3ImportProps(bpy.types.PropertyGroup):
def find_character_by_name(self, name): def find_character_by_name(self, name):
if name: if name:
for chr_cache in self.import_cache: for chr_cache in self.import_cache:
if not chr_cache.disabled and chr_cache.character_name == name: if not chr_cache.disabled and chr_cache.get_name() == name:
return chr_cache return chr_cache
return None return None
@@ -3406,6 +3687,31 @@ class CC3ImportProps(bpy.types.PropertyGroup):
return chr_cache return chr_cache
def ensure_context_object(self, context=None):
"""Ensure lights and cameras have staging_cache data"""
context = vars.get_context(context)
obj = context.object
if utils.object_exists_is_camera(obj) or utils.object_exists_is_light(obj):
if not self.get_staging_cache(obj) and utils.get_rl_link_id(obj):
rlx_cache = self.add_staging_cache()
rlx_cache.update_object(obj)
def get_context_staging_cache(self, context=None) -> CC3StagingCache:
context = vars.get_context(context)
obj = context.object
rlx_cache = self.get_staging_cache(obj)
return rlx_cache
def get_context_actor_cache(self, context=None) -> CC3CharacterCache:
rlx_cache = self.get_context_staging_cache(context=context)
if rlx_cache:
return rlx_cache
chr_cache = self.get_context_character_cache(context=context)
if chr_cache:
return chr_cache
else:
return None
def get_object_cache(self, obj, include_disabled=False): def get_object_cache(self, obj, include_disabled=False):
if obj: if obj:
for chr_cache in self.import_cache: for chr_cache in self.import_cache:
@@ -3452,16 +3758,81 @@ class CC3ImportProps(bpy.types.PropertyGroup):
restored = True restored = True
return restored return restored
def fetch_stored_rig_action(self, store_id): def fetch_stored_motion_set_id(self, store_id):
action_store: CCICActionStore action_store: CCICActionStore
for action_store in self.action_options.action_store: for action_store in self.action_options.action_store:
if action_store.store_id == store_id: if action_store.store_id == store_id:
if (utils.object_exists_is_armature(action_store.object) or if (utils.object_exists_is_armature(action_store.object) or
utils.object_exists_is_light(action_store.object) or utils.object_exists_is_light(action_store.object) or
utils.object_exists_is_camera(action_store.object)): utils.object_exists_is_camera(action_store.object)):
return action_store.object_action obj_action = action_store.object_action
data_action = action_store.data_action
if obj_action and "rl_set_id" in obj_action:
return obj_action["rl_set_id"]
elif data_action and "rl_set_id" in data_action:
return data_action["rl_set_id"]
return None return None
def fetch_stored_rig_action(self, store_id):
action_store: CCICActionStore
first_action = None
for action_store in self.action_options.action_store:
if action_store.store_id == store_id:
action = action_store.object_action
if utils.action_exists(action):
if (utils.object_exists_is_armature(action_store.object) or
utils.object_exists_is_light(action_store.object) or
utils.object_exists_is_camera(action_store.object)):
return action
if not first_action:
first_action = action
return first_action
def fetch_stored_rig_channel(self, store_id):
action_store: CCICActionStore
for action_store in self.action_options.action_store:
if action_store.store_id == store_id:
if (utils.object_exists_is_armature(action_store.object) or
utils.object_exists_is_light(action_store.object) or
utils.object_exists_is_camera(action_store.object)):
action = action_store.object_action
if utils.action_exists(action):
slot_id = action_store.object_slot_id
slot = utils.get_action_slot(action, slot_id=slot_id)
channelbag = utils.get_action_channelbag(action, slot)
return action, slot, channelbag
return None, None, None
def fetch_stored_key_channels(self, store_id):
action_store: CCICActionStore
key_actions = {}
for action_store in self.action_options.action_store:
if action_store.store_id == store_id:
if (utils.object_exists_has_shape_keys(action_store.object)):
obj = action_store.object
action = action_store.object_action
if utils.action_exists(action):
slot_id = action_store.object_slot_id
slot = utils.get_action_slot(action, slot_id=slot_id)
channelbag = utils.get_action_channelbag(action, slot)
key_actions[obj.name] = (action, slot, channelbag)
return key_actions
def fetch_stored_data_channel(self, store_id):
action_store: CCICActionStore
for action_store in self.action_options.action_store:
if action_store.store_id == store_id:
if (utils.object_exists_is_light(action_store.object) or
utils.object_exists_is_camera(action_store.object)):
action = action_store.data_action
if utils.action_exists(action):
slot_id = action_store.data_slot_id
slot = utils.get_action_slot(action, slot_id=slot_id)
channelbag = utils.get_action_channelbag(action, slot)
return action, slot, channelbag
return None, None, None
def fetch_action_stores(self, store_id: str): def fetch_action_stores(self, store_id: str):
"""This returns a list of the action store Property Collection items directly""" """This returns a list of the action store Property Collection items directly"""
action_stores = [] action_stores = []
@@ -1338,6 +1338,44 @@ def store_source_bone_data(chr_cache, cc3_rig, rigify_rig, rigify_data):
store_expression_set(chr_cache, cc3_rig, rigify_rig, rigify_data) store_expression_set(chr_cache, cc3_rig, rigify_rig, rigify_data)
def is_valid_expression_def(expression, expression_def):
if "Bones" in expression_def:
for bone_name, bone_def in expression_def["Bones"].items():
if "Translate" in bone_def and "Rotation" in bone_def:
tra = utils.array_to_vector(bone_def["Translate"])
rot = utils.array_to_quaternion(bone_def["Rotation"])
if tra.length > 0.001 or rot.angle > 0.001:
return True
else:
utils.log_detail(f"{expression}/{bone_name} has missing translate/rotate data")
return False
utils.log_detail(f"{expression} has bad translate/rotate data")
return False
utils.log_detail(f"{expression} has missing bone data")
return False
def merge_missing_expression_set(expression_json, default_expression_json):
# merge missing values from default expression set
if default_expression_json:
for expression, default_expression_def in default_expression_json.items():
if expression not in expression_json:
expression_json[expression] = copy.deepcopy(default_expression_def)
expression_def = expression_json[expression]
if (not is_valid_expression_def(expression, expression_def) and
"Bones" in default_expression_def):
expression_def["Bones"] = copy.deepcopy(default_expression_def["Bones"])
if False:
for bone_name, default_bone_def in default_expression_def["Bones"].items():
if bone_name not in expression_def["Bones"]:
expression_def["Bones"][bone_name] = copy.deepcopy(default_expression_def["Bones"][bone_name])
else:
bone_def = expression_def["Bones"][bone_name]
if "Translate" in default_bone_def and "Translate" not in bone_def:
bone_def["Translate"] = default_bone_def["Translate"].copy()
if "Rotation" in default_bone_def and "Rotation" not in bone_def:
bone_def["Rotation"] = default_bone_def["Rotation"].copy()
def store_expression_set(chr_cache, cc3_rig, rigify_rig=None, rigify_data=None): def store_expression_set(chr_cache, cc3_rig, rigify_rig=None, rigify_data=None):
"""Store source bone data from the cc3 rig in the org and def bones of rigify rig. """Store source bone data from the cc3 rig in the org and def bones of rigify rig.
@@ -1364,6 +1402,9 @@ def store_expression_set(chr_cache, cc3_rig, rigify_rig=None, rigify_data=None):
json_data = chr_cache.get_json_data() json_data = chr_cache.get_json_data()
expression_json = chr_cache.get_expression_json(json_data) expression_json = chr_cache.get_expression_json(json_data)
default_expression_json = chr_cache.get_default_expression_json()
if default_expression_json:
merge_missing_expression_set(expression_json, default_expression_json)
utils.clear_prop_collection(chr_cache.expression_set) utils.clear_prop_collection(chr_cache.expression_set)
if expression_json: if expression_json:
@@ -1406,8 +1447,14 @@ def store_expression_set(chr_cache, cc3_rig, rigify_rig=None, rigify_data=None):
expression_cache.offset_translation = OR_tra expression_cache.offset_translation = OR_tra
expression_cache.offset_rotation = OR_euler expression_cache.offset_rotation = OR_euler
else: else:
try:
tra = utils.array_to_vector(expression_def["Bones"][bone_name]["Translate"]) tra = utils.array_to_vector(expression_def["Bones"][bone_name]["Translate"])
except:
tra = Vector((0,0,0))
try:
rot = utils.array_to_quaternion(expression_def["Bones"][bone_name]["Rotation"]) rot = utils.array_to_quaternion(expression_def["Bones"][bone_name]["Rotation"])
except:
rot = Quaternion((1,0,0,0))
pba: bpy.types.PoseBone = cc3_rig.pose.bones[bone_name] pba: bpy.types.PoseBone = cc3_rig.pose.bones[bone_name]
tra_local = pba.bone.matrix.inverted() @ tra tra_local = pba.bone.matrix.inverted() @ tra
rot_euler = rot.to_euler("XYZ") rot_euler = rot.to_euler("XYZ")
@@ -2054,7 +2101,7 @@ def generate_retargeting_rig(chr_cache, source_rig, rigify_rig, retarget_data, t
utils.unhide(rigify_rig) utils.unhide(rigify_rig)
rigify_rig.data.pose_position = "POSE" rigify_rig.data.pose_position = "POSE"
retarget_rig = bpy.data.objects.new(chr_cache.character_name + "_Retarget", bpy.data.armatures.new(chr_cache.character_name + "_Retarget")) retarget_rig = bpy.data.objects.new(chr_cache.get_name() + "_Retarget", bpy.data.armatures.new(chr_cache.get_name() + "_Retarget"))
bpy.context.collection.objects.link(retarget_rig) bpy.context.collection.objects.link(retarget_rig)
if retarget_rig: if retarget_rig:
@@ -2715,7 +2762,7 @@ def adv_retarget_pair_rigs(op, chr_cache, source_rig=None, source_action=None, t
# if op: op.report({'ERROR'}, "No Source Action!") # if op: op.report({'ERROR'}, "No Source Action!")
# utils.log_error("No Source Action!") # utils.log_error("No Source Action!")
# return None # return None
if source_action and not check_armature_action(source_rig, source_action, fix_rotation_mode=True): if source_rig and source_action and not check_armature_action(source_rig, source_action, fix_rotation_mode=True):
if op: op.report({'ERROR'}, "Source Action does not match Source Armature!") if op: op.report({'ERROR'}, "Source Action does not match Source Armature!")
utils.log_error("Source Action does not match Source Armature!") utils.log_error("Source Action does not match Source Armature!")
return None return None
@@ -2800,25 +2847,28 @@ def full_retarget_source_rig_action(op, chr_cache, src_rig=None, src_action=None
if rigify_rig and src_rig and src_action: if rigify_rig and src_rig and src_action:
armature_action = adv_bake_retarget_to_rigify(op, chr_cache, src_rig, src_action) armature_action = adv_bake_retarget_to_rigify(op, chr_cache, src_rig, src_action)
if armature_action:
utils.log_info(f"Armature action retargetted to: {armature_action.name}") utils.log_info(f"Armature action retargetted to: {armature_action.name}")
# assign names and set data # assign names and set data
rig_id = rigutils.get_rig_id(rigify_rig) rig_id = rigutils.get_rig_id(rigify_rig)
rl_arm_id = utils.get_rl_object_id(rigify_rig) rl_id = utils.get_rl_id(rigify_rig)
motion_prefix = rigutils.get_motion_prefix(src_action) motion_prefix = rigutils.get_motion_prefix(src_action)
custom_prefix = props.rigify_retarget_motion_prefix.strip() custom_prefix = props.rigify_retarget_motion_prefix.strip()
if use_ui_options and custom_prefix: if use_ui_options and custom_prefix:
motion_prefix = custom_prefix motion_prefix = custom_prefix
motion_id = rigutils.get_motion_id(src_action, "Retarget") motion_id = rigutils.get_motion_id(src_action, "Retarget")
motion_id = rigutils.get_unique_set_motion_id(rig_id, motion_id, motion_prefix, slotted=use_slotted) motion_id = rigutils.get_unique_set_motion_id(rig_id, motion_id, motion_prefix, slotted=use_slotted, rlob=rigify_rig)
set_id, set_generation = rigutils.generate_motion_set(rigify_rig, motion_id, motion_prefix) set_id, set_generation = rigutils.generate_motion_set(rigify_rig, motion_id, motion_prefix)
rigutils.set_armature_action_name(armature_action, rig_id, motion_id, motion_prefix, slotted=use_slotted) rigutils.set_armature_action_name(armature_action, rig_id, motion_id, motion_prefix, slotted=use_slotted)
rigutils.add_motion_set_data(armature_action, set_id, set_generation, arm_id=rl_arm_id, slotted=use_slotted) rigutils.add_motion_set_data(armature_action, set_id, set_generation, arm_id=rl_id, slotted=use_slotted)
armature_action.use_fake_user = props.rigify_retarget_use_fake_user if use_ui_options else True armature_action.use_fake_user = props.rigify_retarget_use_fake_user if use_ui_options else True
utils.log_info(f"Renaming armature action to: {armature_action.name}") utils.log_info(f"Renaming armature action to: {armature_action.name}")
use_fake_user = props.rigify_retarget_use_fake_user if use_ui_options else True use_fake_user = props.rigify_retarget_use_fake_user if use_ui_options else True
rigutils.copy_action_shape_key_channels(rigify_rig, src_action, armature_action, fake_user=use_fake_user) rigutils.copy_action_shape_key_channels(rigify_rig, src_action, armature_action, fake_user=use_fake_user)
rigutils.load_motion_set(rigify_rig, armature_action) rigutils.load_motion_set(rigify_rig, armature_action)
rigutils.update_motion_set_index(armature_action) rigutils.update_motion_set_index(armature_action)
else:
utils.log_error(f"Unable to bake retargetted action: {src_rig} / {src_action}")
FK_BONE_GROUPS = ["FK", "Special", "Tweak", "Extra", "Root", "Face"] FK_BONE_GROUPS = ["FK", "Special", "Tweak", "Extra", "Root", "Face"]
@@ -2850,6 +2900,9 @@ def adv_bake_retarget_to_rigify(op, chr_cache, source_rig, source_action):
rigify_rig = chr_cache.get_armature() rigify_rig = chr_cache.get_armature()
# make sure preview range is off
bpy.context.scene.use_preview_range = False
# generate (or re-use) retargeting rig # generate (or re-use) retargeting rig
retarget_rig = adv_retarget_pair_rigs(op, chr_cache, source_rig, source_action) retarget_rig = adv_retarget_pair_rigs(op, chr_cache, source_rig, source_action)
temp_action, temp_slot = utils.safe_get_action_slot(retarget_rig) temp_action, temp_slot = utils.safe_get_action_slot(retarget_rig)
@@ -3118,8 +3171,8 @@ def generate_export_rig(chr_cache, use_t_pose=False, t_pose_action=None,
EXPORT_RIG = rigify_mapping_data.METARIG_EXPORT_RIG EXPORT_RIG = rigify_mapping_data.METARIG_EXPORT_RIG
if export_rig: if export_rig:
utils.force_object_name(export_rig, chr_cache.character_name + "_Export") utils.force_object_name(export_rig, chr_cache.get_name() + "_Export")
utils.force_armature_name(export_rig.data, chr_cache.character_name + "_Export") utils.force_armature_name(export_rig.data, chr_cache.get_name() + "_Export")
else: else:
return None return None
@@ -3646,8 +3699,8 @@ def bake_rig_animation(chr_cache, rig, source_rig, source_action,
set_id = rigutils.generate_set_id() set_id = rigutils.generate_set_id()
rig_id = rigutils.get_rig_id(rig) rig_id = rigutils.get_rig_id(rig)
arm_id = rigutils.get_armature_id(rig) rl_id = rigutils.get_armature_id(rig)
motion_id = rigutils.get_unique_set_motion_id(rig_id, motion_id, motion_prefix) motion_id = rigutils.get_unique_set_motion_id(rig_id, motion_id, motion_prefix, rlob=rig)
is_slotted = prefs.use_action_slots() is_slotted = prefs.use_action_slots()
if utils.try_select_object(rig, True) and utils.set_active_object(rig): if utils.try_select_object(rig, True) and utils.set_active_object(rig):
@@ -3700,14 +3753,14 @@ def bake_rig_animation(chr_cache, rig, source_rig, source_action,
# armature action # armature action
baked_action = utils.safe_get_action(rig) baked_action = utils.safe_get_action(rig)
if baked_action: if baked_action:
rigutils.add_motion_set_data(baked_action, set_id, "Rigify+", arm_id=arm_id, slotted=is_slotted) rigutils.add_motion_set_data(baked_action, set_id, "Rigify+", arm_id=rl_id, slotted=is_slotted)
baked_action.name = armature_action_name baked_action.name = armature_action_name
baked_action.use_fake_user = True baked_action.use_fake_user = True
armature_action = baked_action armature_action = baked_action
utils.log_info(f"Baked armature action: {baked_action.name}") utils.log_info(f"Baked armature action: {baked_action.name}")
for obj_id, key_action in shape_key_actions.items(): for obj_id, key_action in shape_key_actions.items():
rigutils.set_key_action_name(key_action, rig_id, motion_id, obj_id, motion_prefix) rigutils.set_key_action_name(key_action, rig_id, motion_id, obj_id, motion_prefix)
rigutils.add_motion_set_data(baked_action, set_id, "Rigify+", obj_id=obj_id, arm_id=arm_id, slotted=is_slotted) rigutils.add_motion_set_data(baked_action, set_id, "Rigify+", key_id=obj_id, arm_id=rl_id, slotted=is_slotted)
utils.log_info(f"Baked key action: {key_action.name}") utils.log_info(f"Baked key action: {key_action.name}")
# restore view layers # restore view layers
@@ -3844,7 +3897,7 @@ def check_armature_action(rig, action, fix_rotation_mode=True):
elif data_path.endswith("rotation_axis_angle") and pose_bone.rotation_mode != "AXIS_ANGLE": elif data_path.endswith("rotation_axis_angle") and pose_bone.rotation_mode != "AXIS_ANGLE":
pose_bone.rotation_mode = "AXIS_ANGLE" pose_bone.rotation_mode = "AXIS_ANGLE"
matching += 1 matching += 1
if total == 0 or matching == 0: if total == 0:
return False return False
return matching > 0 return matching > 0
@@ -4145,7 +4198,7 @@ class CC3Rigifier(bpy.types.Operator):
fix_rigify_bones(chr_cache, self.rigify_rig) fix_rigify_bones(chr_cache, self.rigify_rig)
add_def_bones(chr_cache, self.cc3_rig, self.rigify_rig) add_def_bones(chr_cache, self.cc3_rig, self.rigify_rig)
add_extension_bones(chr_cache, self.cc3_rig, self.rigify_rig, self.rigify_data.bone_mapping, acc_vertex_group_map) add_extension_bones(chr_cache, self.cc3_rig, self.rigify_rig, self.rigify_data.bone_mapping, acc_vertex_group_map)
store_source_bone_data(self.cc3_rig, self.rigify_rig, self.rigify_data) store_source_bone_data(chr_cache, self.cc3_rig, self.rigify_rig, self.rigify_data)
rigify_spring_rigs(chr_cache, self.cc3_rig, self.rigify_rig, self.rigify_data.bone_mapping) rigify_spring_rigs(chr_cache, self.cc3_rig, self.rigify_rig, self.rigify_data.bone_mapping)
if self.use_expression_rig(chr_cache): if self.use_expression_rig(chr_cache):
facerig.build_facerig_drivers(chr_cache, self.rigify_rig) facerig.build_facerig_drivers(chr_cache, self.rigify_rig)
@@ -4588,6 +4641,7 @@ class CC3RigifierModal(bpy.types.Operator):
def voxel_heat_skinning_start(self, context): def voxel_heat_skinning_start(self, context):
# fix cc3 rig (bone lengths & deform settings) # fix cc3 rig (bone lengths & deform settings)
arm = self.chr_cache.get_armature() arm = self.chr_cache.get_armature()
utils.unhide(arm)
rigutils.fix_cc3_standard_rig(arm) rigutils.fix_cc3_standard_rig(arm)
# unparent object(s) keep transform # unparent object(s) keep transform
@@ -130,6 +130,43 @@ def remap_file(file_path, data_folder):
return file_path return file_path
def get_rlx_generation(obj):
data_type = str.capitalize(str(obj.type))
if obj.type == "LIGHT":
data_type = str.capitalize(str(obj.data.type)) + data_type
return data_type
def add_rlx_motion_set_data(obj, actions, old_action=None):
acts = set()
data_action = actions[1]
if actions is None:
acts = set([utils.safe_get_action(obj), utils.safe_get_action(obj.data)])
if type(actions) is bpy.types.Action:
acts.add(actions)
else:
acts = set(actions)
if None in acts:
acts.remove(None)
actions = list(acts)
if obj:
obj_id = utils.get_rl_id(obj)
set_generation = get_rlx_generation(obj)
if old_action:
set_id = rigutils.get_motion_set_ids(old_action)[0]
else:
set_id = rigutils.generate_set_id()
is_slotted = len(actions) == 1 and rigutils.is_slotted_action(actions[0])
for action in actions:
is_light = action == data_action and obj.type == "LIGHT"
is_camera = action == data_action and obj.type == "CAMERA"
rigutils.add_motion_set_data(action, set_id, set_generation,
rlx_id=obj_id, slotted=is_slotted,
is_light=is_light, is_camera=is_camera)
return True
return False
def prep_rlx_actions(actor: 'RLXActor', motion_id, timestamp=False, motion_prefix=None): def prep_rlx_actions(actor: 'RLXActor', motion_id, timestamp=False, motion_prefix=None):
props = vars.props() props = vars.props()
prefs = vars.prefs() prefs = vars.prefs()
@@ -144,17 +181,24 @@ def prep_rlx_actions(actor: 'RLXActor', motion_id, timestamp=False, motion_prefi
actor.action_store_id = props.store_actions(obj) actor.action_store_id = props.store_actions(obj)
# generate names # generate names
T = utils.get_slot_type_for(obj.data) T = utils.get_slot_type_for(obj.data)
ob_name = rigutils.generate_action_name(name, "O", "", motion_id, motion_prefix) use_slotted = prefs.use_action_slots()
data_name = rigutils.generate_action_name(name, T[0], "", motion_id, motion_prefix) ob_name = rigutils.make_rlx_action_name(name, motion_id, motion_prefix, slotted=use_slotted)
ob_slot_name = f"{obj.name} (Object)"
data_name = rigutils.make_data_action_name(obj, name, motion_id, motion_prefix)
data_slot_name = f"{obj.name} ({obj.type.capitalize()})"
ob_action = bpy.data.actions.new(ob_name) ob_action = bpy.data.actions.new(ob_name)
if prefs.use_action_slots(): if use_slotted:
data_action = ob_action data_action = ob_action
ob_slot = ob_action.slots.new("OBJECT", ob_name)
data_slot = data_action.slots.new(T, data_name)
else: else:
data_action = bpy.data.actions.new(data_name) data_action = bpy.data.actions.new(data_name)
if utils.B440():
ob_slot = ob_action.slots.new("OBJECT", ob_slot_name)
data_slot = data_action.slots.new(T, data_slot_name)
else:
ob_slot = None ob_slot = None
data_slot = None data_slot = None
# motion set ids
add_rlx_motion_set_data(obj, [ob_action, data_action])
# set the actions # set the actions
utils.safe_set_action(obj, ob_action, slot=ob_slot) utils.safe_set_action(obj, ob_action, slot=ob_slot)
utils.safe_set_action(obj.data, data_action, slot=data_slot) utils.safe_set_action(obj.data, data_action, slot=data_slot)
@@ -168,15 +212,25 @@ class RLXActor():
def __init__(self, object): def __init__(self, object):
self.object = object self.object = object
self.name = object.name self.name = object.name
self.get_rlx_cache(create=True)
def get_import_modes(self): def get_rlx_cache(self, create=False):
props = vars.props() props = vars.props()
action_mode = props.action_options.get_action_mode() return props.get_staging_cache(self.object, create=create)
frame_mode = props.action_options.get_frame_mode()
return action_mode, frame_mode def get_link_id(self):
if self.object:
return utils.get_rl_link_id(self.object)
else:
rlx_cache = self.get_rlx_cache()
if rlx_cache:
return rlx_cache.get_link_id()
return None
def import_rlx_light(data: BinaryData, data_folder, start_frame=1): def import_rlx_light(data: BinaryData, data_folder, start_frame=1):
props = vars.props()
light_data = data.json() light_data = data.json()
# make the light # make the light
link_id = light_data["link_id"] link_id = light_data["link_id"]
@@ -257,13 +311,14 @@ def import_rlx_light(data: BinaryData, data_folder, start_frame=1):
store_frame(light, render_cache, frame, start_frame, 0.0 if active else 1.0) store_frame(light, render_cache, frame, start_frame, 0.0 if active else 1.0)
actor = RLXActor(light) actor = RLXActor(light)
rlx_cache = actor.get_rlx_cache(create=True)
ob_action, light_action, ob_slot, light_slot = prep_rlx_actions(actor, "Export", ob_action, light_action, ob_slot, light_slot = prep_rlx_actions(actor, "Export",
timestamp=True) timestamp=True)
add_cache_fcurves(ob_action, light.path_from_id("location"), loc_cache, num_frames, "Location", slot=ob_slot) add_cache_fcurves(ob_action, light.path_from_id("location"), loc_cache, num_frames, "Location", slot=ob_slot)
add_cache_rotation_fcurves(light, ob_action, rot_cache, num_frames, slot=ob_slot) add_cache_rotation_fcurves(light, ob_action, rot_cache, num_frames, slot=ob_slot)
add_cache_fcurves(ob_action, light.path_from_id("scale"), sca_cache, num_frames, "Scale", slot=ob_slot) add_cache_fcurves(ob_action, light.path_from_id("scale"), sca_cache, num_frames, "Scale", slot=ob_slot)
add_cache_fcurves(light_action, light.path_from_id("hide_viewport"), visible_cache, num_frames, "Hide Viewport", slot=ob_slot, interpolation="CONSTANT") add_cache_fcurves(ob_action, light.path_from_id("hide_viewport"), visible_cache, num_frames, "Hide Viewport", slot=ob_slot, interpolation="CONSTANT")
add_cache_fcurves(light_action, light.path_from_id("hide_render"), render_cache, num_frames, "Hide Render", slot=ob_slot, interpolation="CONSTANT") add_cache_fcurves(ob_action, light.path_from_id("hide_render"), render_cache, num_frames, "Hide Render", slot=ob_slot, interpolation="CONSTANT")
add_cache_fcurves(light_action, light.data.path_from_id("color"), color_cache, num_frames, "Color", slot=light_slot) add_cache_fcurves(light_action, light.data.path_from_id("color"), color_cache, num_frames, "Color", slot=light_slot)
add_cache_fcurves(light_action, light.data.path_from_id("energy"), energy_cache, num_frames, "Energy", slot=light_slot) add_cache_fcurves(light_action, light.data.path_from_id("energy"), energy_cache, num_frames, "Energy", slot=light_slot)
add_cache_fcurves(light_action, light.data.path_from_id("cutoff_distance"), cutoff_distance_cache, num_frames, "Cutoff Distance", slot=light_slot) add_cache_fcurves(light_action, light.data.path_from_id("cutoff_distance"), cutoff_distance_cache, num_frames, "Cutoff Distance", slot=light_slot)
@@ -271,8 +326,7 @@ def import_rlx_light(data: BinaryData, data_folder, start_frame=1):
add_cache_fcurves(light_action, light.data.path_from_id("spot_blend"), spot_blend_cache, num_frames, "Spot Blend", slot=light_slot) add_cache_fcurves(light_action, light.data.path_from_id("spot_blend"), spot_blend_cache, num_frames, "Spot Blend", slot=light_slot)
add_cache_fcurves(light_action, light.data.path_from_id("spot_size"), spot_size_cache, num_frames, "Spot Size", slot=light_slot) add_cache_fcurves(light_action, light.data.path_from_id("spot_size"), spot_size_cache, num_frames, "Spot Size", slot=light_slot)
action_mode, frame_mode = actor.get_import_modes() rigutils.finalize_rlx_import(rlx_cache, light, [ob_action, light_action], actor.action_store_id)
rigutils.finalize_rlx_import(light, [ob_action, light_action], actor.action_store_id, action_mode)
def import_rlx_camera(data: BinaryData, data_folder, start_frame=1): def import_rlx_camera(data: BinaryData, data_folder, start_frame=1):
@@ -338,6 +392,7 @@ def import_rlx_camera(data: BinaryData, data_folder, start_frame=1):
active_cache.append((frame, time, active)) active_cache.append((frame, time, active))
actor = RLXActor(camera) actor = RLXActor(camera)
rlx_cache = actor.get_rlx_cache(create=True)
ob_action, cam_action, ob_slot, cam_slot = prep_rlx_actions(actor, "Export", ob_action, cam_action, ob_slot, cam_slot = prep_rlx_actions(actor, "Export",
timestamp=True) timestamp=True)
add_cache_fcurves(ob_action, "location", loc_cache, num_frames, "Location", slot=ob_slot) add_cache_fcurves(ob_action, "location", loc_cache, num_frames, "Location", slot=ob_slot)
@@ -349,9 +404,7 @@ def import_rlx_camera(data: BinaryData, data_folder, start_frame=1):
add_cache_fcurves(cam_action, "dof.aperture_fstop", f_stop_cache, num_frames, "DOF", slot=cam_slot) add_cache_fcurves(cam_action, "dof.aperture_fstop", f_stop_cache, num_frames, "DOF", slot=cam_slot)
add_camera_markers(camera, active_cache, num_frames, start_frame) add_camera_markers(camera, active_cache, num_frames, start_frame)
rigutils.finalize_rlx_import(rlx_cache, camera, [ob_action, cam_action], actor.action_store_id)
action_mode, frame_mode = actor.get_import_modes()
rigutils.finalize_rlx_import(camera, [ob_action, cam_action], actor.action_store_id, action_mode)
def frame_rotation_cache(obj, frames): def frame_rotation_cache(obj, frames):
@@ -503,6 +556,9 @@ def add_camera_markers(camera, cache, num_frames, start):
def decode_rlx_light(light_data, light: bpy.types.Object=None, container=None): def decode_rlx_light(light_data, light: bpy.types.Object=None, container=None):
props = vars.props()
rlx_cache = props.get_staging_cache(light)
# static properties # static properties
link_id = light_data["link_id"] link_id = light_data["link_id"]
name: str = light_data["name"] name: str = light_data["name"]
@@ -548,6 +604,14 @@ def decode_rlx_light(light_data, light: bpy.types.Object=None, container=None):
light = add_spot_light(light_data["name"], container) light = add_spot_light(light_data["name"], container)
utils.set_rl_link_id(light, link_id) utils.set_rl_link_id(light, link_id)
utils.set_prop(light, "rl_set_generation", get_rlx_generation(light))
if rlx_cache:
rlx_cache.update_object(light)
else:
rlx_cache = props.add_staging_cache()
rlx_cache.update_object(light)
utils.safe_set_action(light, ob_action, slot=ob_slot) utils.safe_set_action(light, ob_action, slot=ob_slot)
utils.safe_set_action(light.data, light_action, light_slot) utils.safe_set_action(light.data, light_action, light_slot)
@@ -635,6 +699,9 @@ def apply_light_pose(light, loc, rot, sca, color, active, multiplier, range, ang
def decode_rlx_camera(camera_data, camera): def decode_rlx_camera(camera_data, camera):
props = vars.props()
rlx_cache = props.get_staging_cache(camera)
# static properties # static properties
link_id = camera_data["link_id"] link_id = camera_data["link_id"]
name: str = camera_data["name"] name: str = camera_data["name"]
@@ -673,6 +740,14 @@ def decode_rlx_camera(camera_data, camera):
camera = add_camera(name) camera = add_camera(name)
utils.set_rl_link_id(camera, link_id) utils.set_rl_link_id(camera, link_id)
utils.set_prop(camera, "rl_set_generation", get_rlx_generation(camera))
if rlx_cache:
rlx_cache.update_object(camera)
else:
rlx_cache = props.add_staging_cache()
rlx_cache.update_object(camera)
utils.safe_set_action(camera, ob_action, slot=ob_slot) utils.safe_set_action(camera, ob_action, slot=ob_slot)
utils.safe_set_action(camera.data, cam_action, slot=cam_slot) utils.safe_set_action(camera.data, cam_action, slot=cam_slot)
@@ -247,7 +247,7 @@ def save_skin_gen_bake(chr_cache, body, layer_target):
utils.log_info(f"Texture save path: {bake_dir}") utils.log_info(f"Texture save path: {bake_dir}")
os.makedirs(bake_dir, exist_ok=True) os.makedirs(bake_dir, exist_ok=True)
character_name = chr_cache.character_name character_name = chr_cache.get_name()
if body: if body:
for mat in body.data.materials: for mat in body.data.materials:
@@ -398,7 +398,7 @@ def setup_bake_nodes(context, chr_cache, multires_mesh, layer_target):
bsdf_node, shader_node, mixer_node = nodeutils.get_shader_nodes(mat, shader_name) bsdf_node, shader_node, mixer_node = nodeutils.get_shader_nodes(mat, shader_name)
# base the image name on the character name # base the image name on the character name
character_name = chr_cache.character_name character_name = chr_cache.get_name()
mix_node_name = f"{layer_target}_{LAYER_MIX_SUFFIX}" mix_node_name = f"{layer_target}_{LAYER_MIX_SUFFIX}"
sculpt_mix_node_name = f"{LAYER_TARGET_SCULPT}_{LAYER_MIX_SUFFIX}" sculpt_mix_node_name = f"{LAYER_TARGET_SCULPT}_{LAYER_MIX_SUFFIX}"
detail_mix_node_name = f"{LAYER_TARGET_DETAIL}_{LAYER_MIX_SUFFIX}" detail_mix_node_name = f"{LAYER_TARGET_DETAIL}_{LAYER_MIX_SUFFIX}"
@@ -557,7 +557,7 @@ def flatten_bake_layers(context, chr_cache):
prefs = vars.prefs() prefs = vars.prefs()
bake_dir = get_bake_dir(chr_cache) bake_dir = get_bake_dir(chr_cache)
prefix = chr_cache.character_name + "_Flattened" prefix = chr_cache.get_name() + "_Flattened"
context_obj = utils.get_context_mesh(context) context_obj = utils.get_context_mesh(context)
if context_obj: if context_obj:
@@ -774,7 +774,7 @@ def add_multires_mesh(context, chr_cache, layer_target, sub_target = "ALL"):
body_id = body_cache.object_id if body_cache else None body_id = body_cache.object_id if body_cache else None
body_objects = chr_cache.get_objects_of_type("BODY") body_objects = chr_cache.get_objects_of_type("BODY")
cache_objects = chr_cache.get_cache_objects() cache_objects = chr_cache.get_cache_objects()
is_body_type = body_id and utils.get_rl_object_id(context_object) == body_id is_body_type = body_id and utils.get_rl_id(context_object) == body_id
multires_mesh = None multires_mesh = None
multires_source = None multires_source = None
@@ -0,0 +1,50 @@
import bpy
DATA_NODE_GROUP = "RL_Data_Group"
def get_data_group():
if DATA_NODE_GROUP not in bpy.data.node_groups:
bpy.data.node_groups.new(DATA_NODE_GROUP, 'ShaderNodeTree')
data_group = bpy.data.node_groups[DATA_NODE_GROUP]
return data_group
def get_node_id(chr_cache, id):
if id:
chr_id = "Global" if chr_cache is None else chr_cache.get_name()
return f"RL_{chr_id}_{id}"
return ""
def get_rgbcurve_node(data_group, node_id, shape=None):
if data_group and node_id:
for node in data_group.nodes:
if node.name == node_id:
return node
node: bpy.types.ShaderNodeRGBCurve = data_group.nodes.new("ShaderNodeRGBCurve")
node.name = node_id
if shape == "IN":
P = node.mapping.curves[3].points
P[0].location = (0, 0)
P[1].location = (1, 1)
elif shape == "OUT":
P = node.mapping.curves[3].points
P[0].location = (0, 1)
P[1].location = (1, 0)
return node
return None
def eval_curve(fcurve_data: bpy.types.ShaderNodeRGBCurve, position: float):
return fcurve_data.mapping.evaluate(fcurve_data.mapping.curves[3], position)
def get_fcurve_data(chr_cache, id, shape=None):
data_group = get_data_group()
node_id = get_node_id(chr_cache, id)
node = get_rgbcurve_node(data_group, node_id, shape=shape)
return node
@@ -22,6 +22,7 @@ import difflib
import random import random
import re, json import re, json
import traceback import traceback
import math
from mathutils import Vector, Quaternion, Matrix, Euler, Color from mathutils import Vector, Quaternion, Matrix, Euler, Color
from hashlib import md5 from hashlib import md5
import bpy import bpy
@@ -264,7 +265,7 @@ def unique_object_name(name, obj=None, capitalize=False, start_index=1, suffix="
def un_suffix_name(name): def un_suffix_name(name):
"""Removes any combination of numerical suffixes from the end of a string""" """Removes any combination of numerical suffixes from the end of a string"""
base_name = re.sub("([._+|/\,]\d+)*$", "", name) base_name = re.sub("([._+|/\\,]\\d+)*$", "", name)
return base_name return base_name
@@ -372,6 +373,21 @@ def object_exists_is_mesh(obj):
return False return False
def object_exists_has_shape_keys(obj):
"""Test if Object: obj still exists as an object in the scene, and is a mesh."""
if obj is None:
return False
try:
name = obj.name
return (len(obj.users_scene) > 0 and
obj.type == "MESH" and
obj.data.shape_keys is not None and
obj.data.shape_keys.key_blocks is not None and
len(obj.data.shape_keys.key_blocks) > 1)
except:
return False
def object_exists_is_armature(obj) -> bool: def object_exists_is_armature(obj) -> bool:
"""Test if Object: obj still exists as an object in the scene, and is an armature.""" """Test if Object: obj still exists as an object in the scene, and is an armature."""
if obj is None: if obj is None:
@@ -475,9 +491,11 @@ def get_selected_mesh():
return None return None
def get_selected_meshes(context = None): def get_selected_meshes(context=None, selection=None):
"""Gets selected meshes and includes any current context mesh""" """Gets selected meshes and includes any current context mesh"""
objects = [ obj for obj in bpy.context.selected_objects if object_exists_is_mesh(obj) ] if not selection:
selection = bpy.context.selected_objects
objects = [ obj for obj in selection if object_exists_is_mesh(obj) ]
if context and context.object: if context and context.object:
if object_exists_is_mesh(context.object): if object_exists_is_mesh(context.object):
if context.object not in objects: if context.object not in objects:
@@ -617,6 +635,37 @@ def remap(from_min, from_max, to_min, to_max, x):
return to_min + ((x - from_min) * (to_max - to_min) / (from_max - from_min)) return to_min + ((x - from_min) * (to_max - to_min) / (from_max - from_min))
def slerp(q0: Quaternion, q1: Quaternion, t: float, dot_threshold=0.9995):
omt = max(0, 1.0 - t)
q0.normalize()
q1.normalize()
dot = q0.dot(q1)
if dot < 0.0:
q1 = -q1
dot = -dot
dot = max(min(dot, 1.0), -1.0)
if dot > dot_threshold:
# LERP then normalize
out = (q0 * (omt)) + (q1 * t)
return out.normalized()
theta_0 = math.acos(dot) # angle between input quaternions
sin_theta_0 = math.sin(theta_0)
theta = theta_0 * t
sin_theta = math.sin(theta)
s0 = math.cos(theta) - dot * sin_theta / sin_theta_0
s1 = sin_theta / sin_theta_0
out = (q0 * s0) + (q1 * s1)
return out.normalized()
def lerp(v0, v1, t, clamp=True): def lerp(v0, v1, t, clamp=True):
if clamp: if clamp:
t = max(0, min(1, t)) t = max(0, min(1, t))
@@ -1820,16 +1869,23 @@ def move_object_to_scene_collections(obj, collections, exclude_rbw = True):
def store_mode_selection_state(): def store_mode_selection_state():
mode = get_mode() mode = get_mode()
active = get_active_object() active = get_active_object()
selection = bpy.context.selected_objects.copy() selection = [ o.name for o in bpy.context.selected_objects ]
return [mode, active, selection, return [mode, active.name if active else "", selection,
(bpy.context.scene.frame_current, bpy.context.scene.frame_start, bpy.context.scene.frame_end)] (bpy.context.scene.frame_current, bpy.context.scene.frame_start, bpy.context.scene.frame_end)]
def restore_mode_selection_state(store, include_frames=True): def restore_mode_selection_state(store, include_frames=True):
try: try:
set_mode("OBJECT") set_mode("OBJECT")
try_select_objects(store[2], True) objects = []
set_active_object(store[1]) for obj_name in store[2]:
if obj_name in bpy.data.objects:
objects.append(bpy.data.objects[obj_name])
active = None
if store[1] in bpy.data.objects:
active = bpy.data.objects[store[1]]
try_select_objects(objects, clear_selection=True)
set_active_object(active)
set_mode(store[0]) set_mode(store[0])
if include_frames: if include_frames:
bpy.context.scene.frame_current = store[3][0] bpy.context.scene.frame_current = store[3][0]
@@ -2036,6 +2092,7 @@ def has_data_path(obj: bpy.types.Object, path: str):
def get_data_path_object_name(data_path: str): def get_data_path_object_name(data_path: str):
try:
if data_path.startswith("pose.bones["): if data_path.startswith("pose.bones["):
start = data_path.find('"', 0) + 1 start = data_path.find('"', 0) + 1
end = data_path.find('"', start) end = data_path.find('"', start)
@@ -2044,6 +2101,11 @@ def get_data_path_object_name(data_path: str):
start = data_path.find('"', 0) + 1 start = data_path.find('"', 0) + 1
end = data_path.find('"', start) end = data_path.find('"', start)
return data_path[start:end] return data_path[start:end]
else:
names = data_path.split(".")
last = names[-1].replace("_", " ")
return last.title()
except:
return "" return ""
@@ -2085,11 +2147,17 @@ def make_action_slot(action, slot_type, slot_name):
return None return None
def get_action_slot(action, slot_type): def get_action_slot(action: bpy.types.Action, slot_type: str=None, slot_id=None):
if action and B440(): if action and B440():
for slot in action.slots: for slot in action.slots:
if slot.target_id_type == slot_type: print(f"slot.target_id_type={slot.target_id_type}, slot.identifier={slot.identifier} == slot_type={slot_type}, slot_id={slot_id}")
if slot_type and slot.target_id_type == slot_type:
return slot return slot
if slot_id and slot.identifier == slot_id:
return slot
# fall back to creating a slot if the type is supplied
if slot_type:
action.slots.new(slot_type, slot_id if slot_id else slot_type.capitalize())
return None return None
@@ -2136,21 +2204,15 @@ def set_action_slot(obj, action, slot=None):
the first action slot with the matching slot_type""" the first action slot with the matching slot_type"""
if obj and action and B440(): if obj and action and B440():
if slot: if slot:
try:
obj.animation_data.action_slot = slot obj.animation_data.action_slot = slot
except Exception as e:
log_error(f"Unable to set action slot {action} / {slot}", e)
return True return True
else: else:
slot_type = get_slot_type_for(obj) slot_type = get_slot_type_for(obj)
slot = get_action_slot(action, slot_type) slot = get_action_slot(action, slot_type=slot_type)
if slot: if slot:
try:
obj.animation_data.action_slot = slot obj.animation_data.action_slot = slot
except:
log_error(f"Unable to set action slot by type: {slot_type} / {action} / {slot}")
return False
return True return True
return False
def safe_get_action(obj) -> bpy.types.Action: def safe_get_action(obj) -> bpy.types.Action:
@@ -2178,17 +2240,15 @@ def safe_get_action_slot(obj) -> bpy.types.Action:
def safe_set_action(obj, action, create=True, slot=None): def safe_set_action(obj, action, create=True, slot=None):
result = False result = False
if obj: if obj:
try: #try:
if create and not obj.animation_data: if create and not obj.animation_data:
obj.animation_data_create() obj.animation_data_create()
if obj.animation_data: if obj.animation_data:
obj.animation_data.action = action obj.animation_data.action = action
set_action_slot(obj, action, slot) result = set_action_slot(obj, action, slot)
result = True #except Exception as e:
except Exception as e: # action_name = action.name if action else "None"
action_name = action.name if action else "None" # log_error(f"Unable to set action {action_name} to {obj.name}", e)
log_error(f"Unable to set action {action_name} to {obj.name}", e)
result = False
return result return result
@@ -2277,7 +2337,7 @@ def get_action_channelbag(action: bpy.types.Action, slot=None, slot_type=None):
else: else:
strip = layer.strips[0] strip = layer.strips[0]
if slot_type and not slot: if slot_type and not slot:
slot = get_action_slot(action, slot_type) slot = get_action_slot(action, slot_type=slot_type)
if slot: if slot:
channelbag = strip.channelbag(slot, ensure=True) channelbag = strip.channelbag(slot, ensure=True)
if channelbag: if channelbag:
@@ -2445,6 +2505,9 @@ def B440():
def B500(): def B500():
return is_blender_version("5.0.0") return is_blender_version("5.0.0")
def B510():
return is_blender_version("5.1.0")
VER_CACHE = {} VER_CACHE = {}
def is_blender_version(version: str, test = "GTE"): def is_blender_version(version: str, test = "GTE"):
"""e.g. is_blender_version("3.0.0", "GTE")""" """e.g. is_blender_version("3.0.0", "GTE")"""
@@ -2727,7 +2790,61 @@ def reset_shape_keys(objects, exclude=None):
key.value = 0.0 key.value = 0.0
INVALID_EXPORT_CHARACTERS = "`¬!\"£$%^&*()+-=[]{}:@~;'#<>?,./\| " def ui_two_column_layout(layout: bpy.types.UILayout, widths: tuple, align=False):
factor = widths[0] / (widths[0] + widths[1])
split = layout.split(factor=factor, align=align)
col_1 = split.column(align=align)
col_2 = split.column(align=align)
return col_1, col_2
def ui_three_column_layout(layout: bpy.types.UILayout, widths: tuple, align=False):
factor_1 = widths[0] / (widths[0] + widths[1] + widths[2])
factor_2 = widths[1] / (widths[1] + widths[2])
split_1 = layout.split(factor=factor_1, align=align)
col_1 = split_1.column(align=align)
col_2 = split_1.column(align=align)
split_2 = col_2.split(factor=factor_2, align=align)
col_3 = split_2.column(align=align)
col_4 = split_2.column(align=align)
return col_1, col_3, col_4
def ui_four_column_layout(layout: bpy.types.UILayout, widths: tuple, align=False):
factor_1 = widths[0] / (widths[0] + widths[1] + widths[2] + widths[3])
factor_2 = widths[1] / (widths[1] + widths[2] + widths[3])
factor_3 = widths[2] / (widths[2] + widths[3])
split_1 = layout.split(factor=factor_1, align=align)
col_1 = split_1.column(align=align)
col_2 = split_1.column(align=align)
split_2 = col_2.split(factor=factor_2, align=align)
col_3 = split_2.column(align=align)
col_4 = split_2.column(align=align)
split_3 = col_4.split(factor=factor_3, align=align)
col_5 = split_3.column(align=align)
col_6 = split_3.column(align=align)
return col_1, col_3, col_5, col_6
def ui_fake_drop_down(layout: bpy.types.UILayout, label: str,
props: any, prop_name: str,
icon = "TRIA_DOWN", icon_closed = "TRIA_RIGHT",
align="LEFT"):
row = layout.row()
row.alignment="LEFT"
prop_bool_value = getattr(props, prop_name)
if prop_bool_value:
row.prop(props, prop_name, icon=icon, text=label, emboss=False)
else:
row.prop(props, prop_name, icon=icon_closed, text=label, emboss=False)
if icon != "TRIA_DOWN":
if prop_bool_value:
row.prop(props, prop_name, icon="TRIA_DOWN", icon_only=True, emboss=False)
else:
row.prop(props, prop_name, icon="TRIA_RIGHT", icon_only=True, emboss=False)
return prop_bool_value
INVALID_EXPORT_CHARACTERS = "`¬!\"£$%^&*()+-=[]{}:@~;'#<>?,./\\| "
DIGITS = "0123456789" DIGITS = "0123456789"
@@ -3012,7 +3129,7 @@ def get_rl_link_id(obj):
return None return None
def set_rl_object_id(obj, new_id=None): def set_rl_id(obj, new_id=None):
if new_id is None: if new_id is None:
new_id = generate_random_id(20) new_id = generate_random_id(20)
if obj: if obj:
@@ -3025,12 +3142,19 @@ def set_rl_object_id(obj, new_id=None):
return new_id return new_id
def get_rl_object_id(obj): def get_rl_id(obj):
if object_exists(obj): if object_exists(obj):
if obj.type == "ARMATURE" and "rl_armature_id" in obj: if "rl_armature_id" in obj:
return obj["rl_armature_id"] return obj["rl_armature_id"]
if "rl_object_id" in obj: if "rl_object_id" in obj:
return obj["rl_object_id"] return obj["rl_object_id"]
if action_exists(obj):
if "rl_armature_id" in obj:
return obj["rl_armature_id"]
if "rl_object_id" in obj:
return obj["rl_object_id"]
if "rl_rlx_id" in obj:
return obj["rl_rlx_id"]
return None return None
@@ -3042,6 +3166,24 @@ def merge(a: list, b: list):
return c return c
def append_if(l: list, *args):
def append_if_item(l, a):
T = type(a)
if T is tuple or T is list:
for b in a:
append_if_item(l, b)
elif a is not None:
l.append(a)
for a in args:
append_if_item(l, a)
def list_if(*args) -> list:
l = []
append_if(l, *args)
return l
def fix_texture_rel_path(rel_path: str): def fix_texture_rel_path(rel_path: str):
"""Fixes json texture relative path export bug in CC4 when exporting character directly """Fixes json texture relative path export bug in CC4 when exporting character directly
to the root folder of a drive""" to the root folder of a drive"""
@@ -3152,6 +3294,21 @@ def smallest_index(items: list):
return index return index
def any_in(a: list, b: list):
for c in a:
if c in b:
return True
return False
def first(a: list):
if a is not None:
for i in a:
if i is not None:
return i
return None
def safe_free_bake(point_cache): def safe_free_bake(point_cache):
if B320(): if B320():
with bpy.context.temp_override(point_cache=point_cache): with bpy.context.temp_override(point_cache=point_cache):
@@ -18,11 +18,11 @@
import bpy import bpy
VERSION_STRING = "v2.4.0" VERSION_STRING = "v2.4.2"
DEV = False DEV = False
#DEV = True #DEV = True
PLUGIN_COMPATIBLE = [ PLUGIN_COMPATIBLE = [
"2.4.0", "2.4.1", "2.4.2",
] ]
def set_version_string(bl_info): def set_version_string(bl_info):
@@ -136,6 +136,8 @@ ENUM_OBJECT_TYPES = [
("OCCLUSION_PLUS", "Eye Occlusion Plus", "Eye occlusion plus object"), ("OCCLUSION_PLUS", "Eye Occlusion Plus", "Eye occlusion plus object"),
("TEARLINE", "Tearline", "Tear line object"), ("TEARLINE", "Tearline", "Tear line object"),
("TEARLINE_PLUS", "Tearline Plus", "Tear line plus object"), ("TEARLINE_PLUS", "Tearline Plus", "Tear line plus object"),
("LIGHT", "Light", "Light"),
("CAMERA", "Camera", "Camera"),
] ]
CHARACTER_GENERATION = { CHARACTER_GENERATION = {
@@ -274,6 +274,7 @@ def add_wrinkle_mappings(mat, node, body_obj, mat_json):
def add_wrinkle_node_driver(mat, node, socket_name, obj, expr_macro : str, wrinkle_defs, overall_weight): def add_wrinkle_node_driver(mat, node, socket_name, obj, expr_macro : str, wrinkle_defs, overall_weight):
source_macro = expr_macro
s = expr_macro.find(r"{") s = expr_macro.find(r"{")
if s == -1: if s == -1:
utils.log_error(f"No braces in wrinkle macro expression! {expr_macro}") utils.log_error(f"No braces in wrinkle macro expression! {expr_macro}")
@@ -297,6 +298,10 @@ def add_wrinkle_node_driver(mat, node, socket_name, obj, expr_macro : str, wrink
socket: bpy.types.NodeSocket = node.inputs[socket_name] socket: bpy.types.NodeSocket = node.inputs[socket_name]
expr_code = f"{WRINKLE_STRENGTH_VAR} * ({expr_macro})" expr_code = f"{WRINKLE_STRENGTH_VAR} * ({expr_macro})"
if len(expr_code) >= 255:
utils.log_error(f"wrinkle driver ({socket_name}, {source_macro}) too long: {expr_code}")
else:
utils.log_info(f"wrinkle driver ({len(expr_code)}) ({socket_name}, {source_macro}) OK: {expr_code}")
driver = drivers.make_driver(socket, "default_value", "SCRIPTED", expr_code) driver = drivers.make_driver(socket, "default_value", "SCRIPTED", expr_code)
# global vars # global vars