Skip to content

Instantly share code, notes, and snippets.

@UuuNyaa
Created September 16, 2020 14:12
Show Gist options
  • Select an option

  • Save UuuNyaa/299dcae8fe7f95cced4a8b8699cba447 to your computer and use it in GitHub Desktop.

Select an option

Save UuuNyaa/299dcae8fe7f95cced4a8b8699cba447 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
# Issue: https://github.com/powroupi/blender_mmd_tools/issues/185
# (patch script for model from https://free3d.com/3d-model/female-robot-39128.html)
#
# How to use:
# 1. Open robot.blend
# 2. Open this file in Blender Text Editor, and click [Run Script] to run this script
# 3. Import a VMD file with import option: [Scale] 0.48, enable [Treat Current Pose as Rest Pose]
import bpy
name_map_csv = '''
上半身,c_spine_01.x
上半身2,c_spine_02.x
首,c_neck.x
頭,c_head.x
左肩,c_shoulder.l
左腕,arm_ik_nostr.l
左ひじ,forearm_ik_nostr.l
左手首,hand.l
左人指1,c_index1.l
左人指2,c_index2.l
左人指3,c_index3.l
左中指1,c_middle1.l
左中指2,c_middle2.l
左中指3,c_middle3.l
左薬指1,c_ring1.l
左薬指2,c_ring2.l
左薬指3,c_ring3.l
左小指1,c_pinky1.l
左小指2,c_pinky2.l
左小指3,c_pinky3.l
左親指0,c_thumb1.l
左親指1,c_thumb2.l
左親指2,c_thumb3.l
右肩,c_shoulder.r
右腕,arm_ik_nostr.r
右ひじ,forearm_ik_nostr.r
右手首,hand.r
右人指1,c_index1.r
右人指2,c_index2.r
右人指3,c_index3.r
右中指1,c_middle1.r
右中指2,c_middle2.r
右中指3,c_middle3.r
右薬指1,c_ring1.r
右薬指2,c_ring2.r
右薬指3,c_ring3.r
右小指1,c_pinky1.r
右小指2,c_pinky2.r
右小指3,c_pinky3.r
右親指0,c_thumb1.r
右親指1,c_thumb2.r
右親指2,c_thumb3.r
下半身,c_root.x
左足,thigh_ik_nostr.l
左ひざ,leg_ik_nostr.l
左足首,foot.l
左足IK,heel_ik.l
左つま先IK,toe_ik.l
右足,thigh_ik_nostr.r
右ひざ,leg_ik_nostr.r
右足首,foot.r
右足IK,heel_ik.r
右つま先IK,toe_ik.r
センター,center
全ての親,c_pos
'''
def set_bone(target_edit_bones, **kwargs):
if kwargs['name'] not in target_edit_bones:
b = target_edit_bones.new(name=kwargs['name'])
for key in kwargs:
setattr(b, key, kwargs[key])
def patch_bones(armObj):
from math import radians
from mathutils import Vector
bpy.ops.object.mode_set(mode='EDIT')
edit_bones = armObj.data.edit_bones
set_bone(edit_bones,
name='center',
use_connect=False,
parent=edit_bones['c_pos'],
head=(0,0,0.76),
tail=(0,0,0.56)
)
set_bone(edit_bones,
name='heel_ik.l',
use_connect=False,
parent = edit_bones['c_traj'],
head = edit_bones['c_leg_fk.l'].tail,
tail = edit_bones['c_leg_fk.l'].tail - 0.1 * edit_bones['c_foot_ik.l'].vector.normalized()
)
set_bone(edit_bones,
name = 'toe_ik.l',
use_connect = False,
parent = edit_bones['heel_ik.l'],
head = edit_bones['foot.l'].tail,
tail = edit_bones['foot.l'].tail + Vector((0,0,-0.1))
)
set_bone(edit_bones,
name='heel_ik.r',
use_connect=False,
parent=edit_bones['c_traj'],
head = edit_bones['c_leg_fk.r'].tail,
tail = edit_bones['c_leg_fk.r'].tail - 0.1 * edit_bones['c_foot_ik.r'].vector.normalized()
)
set_bone(edit_bones,
name = 'toe_ik.r',
use_connect = False,
parent = edit_bones['heel_ik.r'],
head = edit_bones['foot.r'].tail,
tail = edit_bones['foot.r'].tail + Vector((0,0,-0.1))
)
# disable leg <-> foot IK
bpy.data.objects['Tifa_rig'].data.edit_bones['foot.r'].parent = bpy.data.objects['Tifa_rig'].data.edit_bones['leg_ik_nostr.r']
bpy.data.objects['Tifa_rig'].data.edit_bones['foot.r'].use_inherit_rotation = True
bpy.data.objects['Tifa_rig'].data.edit_bones['foot.l'].parent = bpy.data.objects['Tifa_rig'].data.edit_bones['leg_ik_nostr.l']
bpy.data.objects['Tifa_rig'].data.edit_bones['foot.l'].use_inherit_rotation = True
# neck <-> head connection
bpy.data.objects['Tifa_rig'].data.edit_bones['head_scale_fix.x'].parent = bpy.data.objects['Tifa_rig'].data.edit_bones['c_neck.x']
bpy.data.objects['Tifa_rig'].data.edit_bones['head_scale_fix.x'].use_inherit_rotation = True
def set_constraint(target_pose_bone, type, **kwargs):
if kwargs['name'] not in target_pose_bone.constraints:
c = target_pose_bone.constraints.new(type)
for key in kwargs:
setattr(c, key, kwargs[key])
def remove_all_constraints(armObj):
# remove all constraints
for (c,b) in [(c,b) for b in bpy.data.objects['Tifa_rig'].pose.bones for c in b.constraints if ('COPY_SCALE' in c.type or 'COPY_TRANS' in c.type )]:
b.constraints.remove(c)
def patch_ik(armObj):
from math import radians
bpy.ops.object.mode_set(mode='POSE')
pose_bones = armObj.pose.bones
## root
set_constraint(pose_bones['c_root_master.x'],'COPY_LOCATION',
name = 'MMD_loc',
target = armObj,
subtarget = 'center',
owner_space = 'LOCAL',
target_space = 'LOCAL',
invert_y = True,
invert_z = True
)
set_constraint(pose_bones['c_root_master.x'],'COPY_ROTATION',
name = 'MMD_rot',
target = armObj,
subtarget = 'center',
owner_space = 'LOCAL',
target_space = 'LOCAL',
invert_y = True
)
# fix neck <-> head connection
for (c,b) in [(c,b) for b in bpy.data.objects['Tifa_rig'].pose.bones if b.name == 'head_scale_fix.x' for c in b.constraints if c.type == 'CHILD_OF']:
b.constraints.remove(c)
## remove hand IK
for (c,b) in [(c,b) for b in bpy.data.objects['Tifa_rig'].pose.bones for c in b.constraints if hasattr(c,'subtarget') and 'c_hand_ik' in c.subtarget]:
b.constraints.remove(c)
## hand.[lr]
# disable Hand rotation lock
bpy.data.objects['Tifa_rig'].pose.bones['hand.l'].lock_rotation = (False,False,False)
# add 'Child Of' constraint
set_constraint(bpy.data.objects['Tifa_rig'].pose.bones['hand.l'],'CHILD_OF',
name = 'Child Of',
target = bpy.data.objects['Tifa_rig'],
subtarget = 'forearm_ik_nostr.l',
set_inverse_pending = True
)
# move 'Child Of' constraint on top
bpy.data.objects['Tifa_rig'].pose.bones['hand.l'].constraints.move(len(bpy.data.objects['Tifa_rig'].pose.bones['hand.l'].constraints)-1,0)
## forearm_ik_nostr.[lr]
# disable forearm rotation lock
bpy.data.objects['Tifa_rig'].pose.bones['forearm_ik_nostr.l'].lock_rotation = (False,False,False)
## arm_ik_nostr.[lr]
# disable arm rotation lock
bpy.data.objects['Tifa_rig'].pose.bones['arm_ik_nostr.l'].lock_rotation = (False,False,False)
## remove foot and leg IK
for (c,b) in [(c,b) for b in bpy.data.objects['Tifa_rig'].pose.bones for c in b.constraints if c.type == 'COPY_ROTATION' and 'foot_ik' in c.subtarget]:
b.constraints.remove(c)
for (c,b) in [(c,b) for b in bpy.data.objects['Tifa_rig'].pose.bones if 'leg_ik_nostr' in b.name for c in b.constraints if c.type == 'IK']:
b.constraints.remove(c)
for (c,b) in [(c,b) for b in bpy.data.objects['Tifa_rig'].pose.bones for c in b.constraints if hasattr(c,'subtarget') and 'c_toes_ik' in c.subtarget]:
b.constraints.remove(c)
## foot.[lr]
set_constraint(bpy.data.objects['Tifa_rig'].pose.bones['foot.l'],'IK',
name = 'MMD_IK',
target = bpy.data.objects['Tifa_rig'],
subtarget = 'toe_ik.l',
chain_count = 1,
iterations = 3
)
set_constraint(bpy.data.objects['Tifa_rig'].pose.bones['foot.r'],'IK',
name = 'MMD_IK',
target = bpy.data.objects['Tifa_rig'],
subtarget = 'toe_ik.r',
chain_count = 1,
iterations = 3
)
## leg_ik_nostr.[lr]
bpy.data.objects['Tifa_rig'].pose.bones['leg_ik_nostr.l'].rotation_mode = 'XYZ'
set_constraint(bpy.data.objects['Tifa_rig'].pose.bones['leg_ik_nostr.l'],'LIMIT_ROTATION',
name = 'Limit Rotation',
owner_space = 'LOCAL',
min_z = radians(0), max_z = radians(+180),
use_limit_x = True,
use_limit_y = True,
use_limit_z = True
)
set_constraint(bpy.data.objects['Tifa_rig'].pose.bones['leg_ik_nostr.l'],'IK',
name = 'MMD_IK',
target = bpy.data.objects['Tifa_rig'],
subtarget = 'heel_ik.l',
chain_count = 3,
iterations = 40
)
bpy.data.objects['Tifa_rig'].pose.bones['leg_ik_nostr.r'].rotation_mode = 'XYZ'
set_constraint(bpy.data.objects['Tifa_rig'].pose.bones['leg_ik_nostr.r'],'LIMIT_ROTATION',
name = 'Limit Rotation',
owner_space = 'LOCAL',
min_z = radians(0), max_z = radians(+180),
use_limit_x = True,
use_limit_y = True,
use_limit_z = True
)
set_constraint(bpy.data.objects['Tifa_rig'].pose.bones['leg_ik_nostr.r'],'IK',
name = 'MMD_IK',
target = bpy.data.objects['Tifa_rig'],
subtarget = 'heel_ik.r',
chain_count = 3,
iterations = 40
)
## thigh.[lr]
bpy.data.objects['Tifa_rig'].pose.bones['thigh_ik_nostr.l'].lock_rotation = (False,False,False)
bpy.data.objects['Tifa_rig'].pose.bones['thigh_ik_nostr.r'].lock_rotation = (False,False,False)
def patch_pose(armObj):
from math import radians
from mathutils import Euler, Quaternion
bpy.ops.object.mode_set(mode='POSE')
pose_bones = armObj.pose.bones
for b in pose_bones:
b.matrix_basis.identity()
pose_bones['heel_ik.l'].matrix = pose_bones['heel_ik.l'].matrix @ Euler((0.0,0.0,radians(-14.0))).to_matrix().to_4x4()
#pose_bones['heel_ik.l'].location = (-0.1,0.05,0) # (-0.10281755775213242, 0.03844242915511131, 0.03638792783021927)
#pose_bones['toe_ik.l'].location = (-0.005,0,0) # (+0.009050948545336723, 0.04268583655357361, -0.05635549873113632)
pose_bones['heel_ik.r'].matrix = pose_bones['heel_ik.r'].matrix @ Euler((0.0,0.0,radians(+14.0))).to_matrix().to_4x4()
#pose_bones['heel_ik.r'].location = (+0.1,0.05,0) # (+0.10281755775213242, 0.03844242915511131, 0.03638792783021927)
#pose_bones['toe_ik.r'].location = (+0.005,0,0) # (-0.009050948545336723, 0.04268583655357361, -0.05635549873113632)
pose_bones['center'].location = (0,-0.005,0) # (0, -0.03882210701704025, 0.011079655028879642)
pose_bones['thigh_ik_nostr.l'].rotation_mode = 'XYZ'
pose_bones['thigh_ik_nostr.l'].rotation_euler = (-0.021631652489304543, +0.2279348373413086, -0.025270408019423485)
pose_bones['heel_ik.l'].location = (-0.10281755775213242, 0.03844242915511131, 0.03638792783021927)
pose_bones['toe_ik.l'].location = (+0.009050948545336723, 0.04268583655357361, -0.05635549873113632)
pose_bones['thigh_ik_nostr.r'].rotation_mode = 'XYZ'
pose_bones['thigh_ik_nostr.r'].rotation_euler = (-0.021631654351949692, -0.2279348522424698, 0.025270409882068634)
pose_bones['heel_ik.r'].location = (+0.10281755775213242, 0.03844242915511131, 0.03638792783021927)
pose_bones['toe_ik.r'].location = (-0.009050948545336723, 0.04268583655357361, -0.05635549873113632)
pose_bones['center'].location = (0, -0.03882210701704025, 0.011079655028879642)
pose_bones['c_root.x'].location = (4.2299497238218464e-13, -0.005019493401050568, -0.03553156927227974)
def patch_mmd_name(armObj):
pose_bones = armObj.pose.bones
for l in name_map_csv.strip().split('\n'):
name_j, name_e = l.split(',')
if name_e in pose_bones:
pose_bones[name_e].mmd_bone.name_j = name_j
try:
bpy.ops.object.mode_set(mode='OBJECT')
except:
pass
armObj = bpy.data.objects['Tifa_rig']
armObj.hide = False
armObj.select = True
bpy.context.view_layer.objects.active = armObj
patch_bones(armObj)
patch_ik(armObj)
patch_pose(armObj)
patch_mmd_name(armObj)
bpy.ops.object.mode_set(mode='POSE')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment