a929f68ad4
- Truly fixes PMX Import lol, i messed up completely - Updated MMD Tools to use Cats One
287 lines
8.7 KiB
Python
287 lines
8.7 KiB
Python
# Copyright 2014 MMD Tools authors
|
|
# This file is part of MMD Tools.
|
|
|
|
from typing import cast
|
|
|
|
import bpy
|
|
|
|
from ..core.bone import FnBone
|
|
from . import patch_library_overridable
|
|
|
|
|
|
def _mmd_bone_update_additional_transform(prop: "MMDBone", context: bpy.types.Context):
|
|
prop.is_additional_transform_dirty = True
|
|
# Apply additional transform (Assembly -> Bone button) (Very Slow)
|
|
p_bone = context.active_pose_bone
|
|
if p_bone and p_bone.mmd_bone.as_pointer() == prop.as_pointer():
|
|
FnBone.apply_additional_transformation(prop.id_data)
|
|
|
|
|
|
def _mmd_bone_update_additional_transform_influence(prop: "MMDBone", context: bpy.types.Context):
|
|
pose_bone = context.active_pose_bone
|
|
if pose_bone and pose_bone.mmd_bone.as_pointer() == prop.as_pointer():
|
|
FnBone.update_additional_transform_influence(pose_bone)
|
|
else:
|
|
prop.is_additional_transform_dirty = True
|
|
|
|
|
|
def _mmd_bone_get_additional_transform_bone(prop: "MMDBone"):
|
|
arm = prop.id_data
|
|
bone_id = prop.get("additional_transform_bone_id", -1)
|
|
if bone_id < 0:
|
|
return ""
|
|
pose_bone = FnBone.find_pose_bone_by_bone_id(arm, bone_id)
|
|
if pose_bone is None:
|
|
return ""
|
|
return pose_bone.name
|
|
|
|
|
|
def _mmd_bone_set_additional_transform_bone(prop: "MMDBone", value: str):
|
|
arm = prop.id_data
|
|
prop.is_additional_transform_dirty = True
|
|
|
|
if value not in arm.pose.bones.keys():
|
|
prop.additional_transform_bone_id = -1
|
|
return
|
|
|
|
pose_bone = arm.pose.bones[value]
|
|
target_bone_id = FnBone.get_or_assign_bone_id(pose_bone)
|
|
|
|
if prop.bone_id == target_bone_id:
|
|
prop.additional_transform_bone_id = -1
|
|
return
|
|
|
|
prop.additional_transform_bone_id = target_bone_id
|
|
|
|
|
|
def _mmd_bone_update_display_connection(prop: "MMDBone", context: bpy.types.Context):
|
|
pass # Empty function is sufficient to trigger UI update
|
|
|
|
|
|
def _mmd_bone_get_display_connection_bone(prop: "MMDBone"):
|
|
arm = prop.id_data
|
|
bone_id = prop.get("display_connection_bone_id", -1)
|
|
if bone_id < 0:
|
|
return ""
|
|
pose_bone = FnBone.find_pose_bone_by_bone_id(arm, bone_id)
|
|
if pose_bone is None:
|
|
return ""
|
|
return pose_bone.name
|
|
|
|
|
|
def _mmd_bone_set_display_connection_bone(prop: "MMDBone", value: str):
|
|
arm = prop.id_data
|
|
|
|
if value not in arm.pose.bones.keys():
|
|
prop.display_connection_bone_id = -1
|
|
return
|
|
|
|
pose_bone = arm.pose.bones[value]
|
|
target_bone_id = FnBone.get_or_assign_bone_id(pose_bone)
|
|
|
|
if prop.bone_id == target_bone_id:
|
|
prop.display_connection_bone_id = -1
|
|
return
|
|
|
|
prop.display_connection_bone_id = target_bone_id
|
|
|
|
|
|
class MMDBone(bpy.types.PropertyGroup):
|
|
name_j: bpy.props.StringProperty(
|
|
name="Name",
|
|
description="Japanese Name",
|
|
default="",
|
|
)
|
|
|
|
name_e: bpy.props.StringProperty(
|
|
name="Name(Eng)",
|
|
description="English Name",
|
|
default="",
|
|
)
|
|
|
|
bone_id: bpy.props.IntProperty(
|
|
name="Bone ID",
|
|
description="Unique ID for the reference of bone morph and rotate+/move+",
|
|
default=-1,
|
|
min=-1,
|
|
)
|
|
|
|
transform_order: bpy.props.IntProperty(
|
|
name="Transform Order",
|
|
description="Deformation tier",
|
|
min=0,
|
|
max=100,
|
|
soft_max=7,
|
|
)
|
|
|
|
is_controllable: bpy.props.BoolProperty(
|
|
name="Controllable",
|
|
description="Is controllable",
|
|
default=True,
|
|
)
|
|
|
|
transform_after_dynamics: bpy.props.BoolProperty(
|
|
name="After Dynamics",
|
|
description="After physics",
|
|
default=False,
|
|
)
|
|
|
|
enabled_fixed_axis: bpy.props.BoolProperty(
|
|
name="Fixed Axis",
|
|
description="Use fixed axis",
|
|
default=False,
|
|
)
|
|
|
|
fixed_axis: bpy.props.FloatVectorProperty(
|
|
name="Fixed Axis",
|
|
description="Fixed axis",
|
|
subtype="XYZ",
|
|
size=3,
|
|
precision=3,
|
|
step=0.1, # 0.1 / 100
|
|
default=[0, 0, 0],
|
|
)
|
|
|
|
enabled_local_axes: bpy.props.BoolProperty(
|
|
name="Local Axes",
|
|
description="Use local axes",
|
|
default=False,
|
|
)
|
|
|
|
local_axis_x: bpy.props.FloatVectorProperty(
|
|
name="Local X-Axis",
|
|
description="Local x-axis",
|
|
subtype="XYZ",
|
|
size=3,
|
|
precision=3,
|
|
step=0.1,
|
|
default=[1, 0, 0],
|
|
)
|
|
|
|
local_axis_z: bpy.props.FloatVectorProperty(
|
|
name="Local Z-Axis",
|
|
description="Local z-axis",
|
|
subtype="XYZ",
|
|
size=3,
|
|
precision=3,
|
|
step=0.1,
|
|
default=[0, 0, 1],
|
|
)
|
|
|
|
is_tip: bpy.props.BoolProperty(
|
|
name="Tip Bone",
|
|
description="Is zero length bone",
|
|
default=False,
|
|
)
|
|
|
|
ik_rotation_constraint: bpy.props.FloatProperty(
|
|
name="IK Rotation Constraint",
|
|
description="The unit angle of IK",
|
|
subtype="ANGLE",
|
|
soft_min=0,
|
|
soft_max=4,
|
|
default=1,
|
|
)
|
|
|
|
has_additional_rotation: bpy.props.BoolProperty(
|
|
name="Additional Rotation",
|
|
description="Additional rotation",
|
|
default=False,
|
|
update=_mmd_bone_update_additional_transform,
|
|
)
|
|
|
|
has_additional_location: bpy.props.BoolProperty(
|
|
name="Additional Location",
|
|
description="Additional location",
|
|
default=False,
|
|
update=_mmd_bone_update_additional_transform,
|
|
)
|
|
|
|
additional_transform_bone: bpy.props.StringProperty(
|
|
name="Additional Transform Bone",
|
|
description="Additional transform bone",
|
|
set=_mmd_bone_set_additional_transform_bone,
|
|
get=_mmd_bone_get_additional_transform_bone,
|
|
update=_mmd_bone_update_additional_transform,
|
|
)
|
|
|
|
additional_transform_bone_id: bpy.props.IntProperty(
|
|
name="Additional Transform Bone ID",
|
|
default=-1,
|
|
update=_mmd_bone_update_additional_transform,
|
|
)
|
|
|
|
additional_transform_influence: bpy.props.FloatProperty(
|
|
name="Additional Transform Influence",
|
|
description="Additional transform influence",
|
|
default=1,
|
|
soft_min=-1,
|
|
soft_max=1,
|
|
update=_mmd_bone_update_additional_transform_influence,
|
|
)
|
|
|
|
is_additional_transform_dirty: bpy.props.BoolProperty(name="", default=True)
|
|
|
|
display_connection_bone: bpy.props.StringProperty(
|
|
name="Display Connection Bone",
|
|
description="Target bone for display connection",
|
|
set=_mmd_bone_set_display_connection_bone,
|
|
get=_mmd_bone_get_display_connection_bone,
|
|
)
|
|
|
|
display_connection_bone_id: bpy.props.IntProperty(
|
|
name="Display Connection Bone ID",
|
|
description="Bone ID for display connection (PMX displayConnection)",
|
|
default=-1,
|
|
update=_mmd_bone_update_display_connection,
|
|
)
|
|
|
|
display_connection_type: bpy.props.EnumProperty(
|
|
name="Display Connection Type",
|
|
description="Type of display connection",
|
|
items=[
|
|
("BONE", "Bone", "Connected to a bone"),
|
|
("OFFSET", "Offset", "Connected to an offset position"),
|
|
],
|
|
default="OFFSET",
|
|
)
|
|
|
|
def is_id_unique(self):
|
|
return self.bone_id < 0 or not next((b for b in self.id_data.pose.bones if b.mmd_bone != self and b.mmd_bone.bone_id == self.bone_id), None)
|
|
|
|
@staticmethod
|
|
def register():
|
|
bpy.types.PoseBone.mmd_bone = patch_library_overridable(bpy.props.PointerProperty(type=MMDBone))
|
|
bpy.types.PoseBone.is_mmd_shadow_bone = patch_library_overridable(bpy.props.BoolProperty(name="is_mmd_shadow_bone", default=False))
|
|
bpy.types.PoseBone.mmd_shadow_bone_type = patch_library_overridable(bpy.props.StringProperty(name="mmd_shadow_bone_type"))
|
|
bpy.types.PoseBone.mmd_ik_toggle = patch_library_overridable(
|
|
bpy.props.BoolProperty(
|
|
name="MMD IK Toggle",
|
|
description="MMD IK toggle is used to import/export animation of IK on-off",
|
|
update=_pose_bone_update_mmd_ik_toggle,
|
|
default=True,
|
|
),
|
|
)
|
|
|
|
@staticmethod
|
|
def unregister():
|
|
del bpy.types.PoseBone.mmd_ik_toggle
|
|
del bpy.types.PoseBone.mmd_shadow_bone_type
|
|
del bpy.types.PoseBone.is_mmd_shadow_bone
|
|
del bpy.types.PoseBone.mmd_bone
|
|
|
|
|
|
def _pose_bone_update_mmd_ik_toggle(prop: bpy.types.PoseBone, _context):
|
|
v = prop.mmd_ik_toggle
|
|
armature_object = cast("bpy.types.Object", prop.id_data)
|
|
for b in armature_object.pose.bones:
|
|
for c in b.constraints:
|
|
if c.type == "IK" and c.subtarget == prop.name:
|
|
# logging.debug(' %s %s', b.name, c.name)
|
|
c.influence = v
|
|
b = b if c.use_tail else b.parent
|
|
for b in ([b] + b.parent_recursive)[: c.chain_count]:
|
|
c = next((c for c in b.constraints if c.type == "LIMIT_ROTATION" and not c.mute), None)
|
|
if c:
|
|
c.influence = v
|