PMX Import now works
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 MMD Tools authors
|
||||
# This file was originally part of the MMD Tools add-on for Blender
|
||||
# You can find MMD Tools here: https://github.com/MMD-Blender/blender_mmd_tools
|
||||
# Neoneko has modified this file to work with Avatar Toolkit and may of made changes or improvements.
|
||||
# MMD Tools is licensed under the terms of the GNU General Public License version 3 (GPLv3) same as Avatar Toolkit.
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
def patch_library_overridable(property: "bpy.props._PropertyDeferred") -> "bpy.props._PropertyDeferred":
|
||||
"""Apply recursively for each mmd_tools property class annotations.
|
||||
Args:
|
||||
property: The property to be patched.
|
||||
|
||||
Returns:
|
||||
The patched property.
|
||||
"""
|
||||
property.keywords.setdefault("override", set()).add("LIBRARY_OVERRIDABLE")
|
||||
|
||||
if property.function.__name__ not in {"PointerProperty", "CollectionProperty"}:
|
||||
return property
|
||||
|
||||
property_type = property.keywords["type"]
|
||||
# The __annotations__ cannot be inherited. Manually search for base classes.
|
||||
for inherited_type in (property_type, *property_type.__bases__):
|
||||
if not inherited_type.__module__.startswith("mmd_tools.properties"):
|
||||
continue
|
||||
for annotation in inherited_type.__annotations__.values():
|
||||
if not isinstance(annotation, bpy.props._PropertyDeferred):
|
||||
continue
|
||||
patch_library_overridable(annotation)
|
||||
|
||||
return property
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 MMD Tools authors
|
||||
# This file was originally part of the MMD Tools add-on for Blender
|
||||
# You can find MMD Tools here: https://github.com/MMD-Blender/blender_mmd_tools
|
||||
# Neoneko has modified this file to work with Avatar Toolkit and may of made changes or improvements.
|
||||
# MMD Tools is licensed under the terms of the GNU General Public License version 3 (GPLv3) same as Avatar Toolkit.
|
||||
|
||||
import bpy
|
||||
|
||||
from .. import utils
|
||||
from ..core import material
|
||||
from ..core.material import FnMaterial
|
||||
from ..core.model import FnModel
|
||||
from . import patch_library_overridable
|
||||
|
||||
|
||||
def _mmd_material_update_ambient_color(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_ambient_color()
|
||||
|
||||
|
||||
def _mmd_material_update_diffuse_color(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_diffuse_color()
|
||||
|
||||
|
||||
def _mmd_material_update_alpha(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_alpha()
|
||||
|
||||
|
||||
def _mmd_material_update_specular_color(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_specular_color()
|
||||
|
||||
|
||||
def _mmd_material_update_shininess(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_shininess()
|
||||
|
||||
|
||||
def _mmd_material_update_is_double_sided(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_is_double_sided()
|
||||
|
||||
|
||||
def _mmd_material_update_sphere_texture_type(prop: "MMDMaterial", context):
|
||||
FnMaterial(prop.id_data).update_sphere_texture_type(context.active_object)
|
||||
|
||||
|
||||
def _mmd_material_update_toon_texture(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_toon_texture()
|
||||
|
||||
|
||||
def _mmd_material_update_enabled_drop_shadow(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_drop_shadow()
|
||||
|
||||
|
||||
def _mmd_material_update_enabled_self_shadow_map(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_self_shadow_map()
|
||||
|
||||
|
||||
def _mmd_material_update_enabled_self_shadow(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_self_shadow()
|
||||
|
||||
|
||||
def _mmd_material_update_enabled_toon_edge(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_enabled_toon_edge()
|
||||
|
||||
|
||||
def _mmd_material_update_edge_color(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_edge_color()
|
||||
|
||||
|
||||
def _mmd_material_update_edge_weight(prop: "MMDMaterial", _context):
|
||||
FnMaterial(prop.id_data).update_edge_weight()
|
||||
|
||||
|
||||
def _mmd_material_get_name_j(prop: "MMDMaterial"):
|
||||
return prop.get("name_j", "")
|
||||
|
||||
|
||||
def _mmd_material_set_name_j(prop: "MMDMaterial", value: str):
|
||||
prop_value = value
|
||||
if prop_value and prop_value != prop.get("name_j"):
|
||||
root = FnModel.find_root_object(bpy.context.active_object)
|
||||
if root is None:
|
||||
prop_value = utils.unique_name(value, {mat.mmd_material.name_j for mat in bpy.data.materials})
|
||||
else:
|
||||
prop_value = utils.unique_name(value, {mat.mmd_material.name_j for mat in FnModel.iterate_materials(root)})
|
||||
|
||||
prop["name_j"] = prop_value
|
||||
|
||||
|
||||
# ===========================================
|
||||
# Property classes
|
||||
# ===========================================
|
||||
|
||||
|
||||
class MMDMaterial(bpy.types.PropertyGroup):
|
||||
"""マテリアル"""
|
||||
|
||||
name_j: bpy.props.StringProperty(
|
||||
name="Name",
|
||||
description="Japanese Name",
|
||||
default="",
|
||||
set=_mmd_material_set_name_j,
|
||||
get=_mmd_material_get_name_j,
|
||||
)
|
||||
|
||||
name_e: bpy.props.StringProperty(
|
||||
name="Name(Eng)",
|
||||
description="English Name",
|
||||
default="",
|
||||
)
|
||||
|
||||
material_id: bpy.props.IntProperty(
|
||||
name="Material ID",
|
||||
description="Unique ID for the reference of material morph",
|
||||
default=-1,
|
||||
min=-1,
|
||||
)
|
||||
|
||||
ambient_color: bpy.props.FloatVectorProperty(
|
||||
name="Ambient Color",
|
||||
description="Ambient color",
|
||||
subtype="COLOR",
|
||||
size=3,
|
||||
min=0,
|
||||
max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=[0.4, 0.4, 0.4],
|
||||
update=_mmd_material_update_ambient_color,
|
||||
)
|
||||
|
||||
diffuse_color: bpy.props.FloatVectorProperty(
|
||||
name="Diffuse Color",
|
||||
description="Diffuse color",
|
||||
subtype="COLOR",
|
||||
size=3,
|
||||
min=0,
|
||||
max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=[0.8, 0.8, 0.8],
|
||||
update=_mmd_material_update_diffuse_color,
|
||||
)
|
||||
|
||||
alpha: bpy.props.FloatProperty(
|
||||
name="Alpha",
|
||||
description="Alpha transparency",
|
||||
min=0,
|
||||
max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=1.0,
|
||||
update=_mmd_material_update_alpha,
|
||||
)
|
||||
|
||||
specular_color: bpy.props.FloatVectorProperty(
|
||||
name="Specular Color",
|
||||
description="Specular color",
|
||||
subtype="COLOR",
|
||||
size=3,
|
||||
min=0,
|
||||
max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=[0.625, 0.625, 0.625],
|
||||
update=_mmd_material_update_specular_color,
|
||||
)
|
||||
|
||||
shininess: bpy.props.FloatProperty(
|
||||
name="Reflect",
|
||||
description="Sharpness of reflected highlights",
|
||||
min=0,
|
||||
soft_max=512,
|
||||
step=100.0,
|
||||
default=50.0,
|
||||
update=_mmd_material_update_shininess,
|
||||
)
|
||||
|
||||
is_double_sided: bpy.props.BoolProperty(
|
||||
name="Double Sided",
|
||||
description="Both sides of mesh should be rendered",
|
||||
default=False,
|
||||
update=_mmd_material_update_is_double_sided,
|
||||
)
|
||||
|
||||
enabled_drop_shadow: bpy.props.BoolProperty(
|
||||
name="Ground Shadow",
|
||||
description="Display ground shadow",
|
||||
default=True,
|
||||
update=_mmd_material_update_enabled_drop_shadow,
|
||||
)
|
||||
|
||||
enabled_self_shadow_map: bpy.props.BoolProperty(
|
||||
name="Self Shadow Map",
|
||||
description="Object can become shadowed by other objects",
|
||||
default=True,
|
||||
update=_mmd_material_update_enabled_self_shadow_map,
|
||||
)
|
||||
|
||||
enabled_self_shadow: bpy.props.BoolProperty(
|
||||
name="Self Shadow",
|
||||
description="Object can cast shadows",
|
||||
default=True,
|
||||
update=_mmd_material_update_enabled_self_shadow,
|
||||
)
|
||||
|
||||
enabled_toon_edge: bpy.props.BoolProperty(
|
||||
name="Toon Edge",
|
||||
description="Use toon edge",
|
||||
default=False,
|
||||
update=_mmd_material_update_enabled_toon_edge,
|
||||
)
|
||||
|
||||
edge_color: bpy.props.FloatVectorProperty(
|
||||
name="Edge Color",
|
||||
description="Toon edge color",
|
||||
subtype="COLOR",
|
||||
size=4,
|
||||
min=0,
|
||||
max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=[0, 0, 0, 1],
|
||||
update=_mmd_material_update_edge_color,
|
||||
)
|
||||
|
||||
edge_weight: bpy.props.FloatProperty(
|
||||
name="Edge Weight",
|
||||
description="Toon edge size",
|
||||
min=0,
|
||||
max=100,
|
||||
soft_max=2,
|
||||
step=1.0,
|
||||
default=1.0,
|
||||
update=_mmd_material_update_edge_weight,
|
||||
)
|
||||
|
||||
sphere_texture_type: bpy.props.EnumProperty(
|
||||
name="Sphere Map Type",
|
||||
description="Choose sphere texture blend type",
|
||||
items=[
|
||||
(str(material.SPHERE_MODE_OFF), "Off", "", 1),
|
||||
(str(material.SPHERE_MODE_MULT), "Multiply", "", 2),
|
||||
(str(material.SPHERE_MODE_ADD), "Add", "", 3),
|
||||
(str(material.SPHERE_MODE_SUBTEX), "SubTexture", "", 4),
|
||||
],
|
||||
update=_mmd_material_update_sphere_texture_type,
|
||||
)
|
||||
|
||||
is_shared_toon_texture: bpy.props.BoolProperty(
|
||||
name="Use Shared Toon Texture",
|
||||
description="Use shared toon texture or custom toon texture",
|
||||
default=False,
|
||||
update=_mmd_material_update_toon_texture,
|
||||
)
|
||||
|
||||
toon_texture: bpy.props.StringProperty(
|
||||
name="Toon Texture",
|
||||
subtype="FILE_PATH",
|
||||
description="The file path of custom toon texture",
|
||||
default="",
|
||||
update=_mmd_material_update_toon_texture,
|
||||
)
|
||||
|
||||
shared_toon_texture: bpy.props.IntProperty(
|
||||
name="Shared Toon Texture",
|
||||
description="Shared toon texture id (toon01.bmp ~ toon10.bmp)",
|
||||
default=0,
|
||||
min=0,
|
||||
max=9,
|
||||
update=_mmd_material_update_toon_texture,
|
||||
)
|
||||
|
||||
comment: bpy.props.StringProperty(
|
||||
name="Comment",
|
||||
description="Comment",
|
||||
)
|
||||
|
||||
def is_id_unique(self):
|
||||
return self.material_id < 0 or not next((m for m in bpy.data.materials if m.mmd_material != self and m.mmd_material.material_id == self.material_id), None)
|
||||
|
||||
@staticmethod
|
||||
def register():
|
||||
bpy.types.Material.mmd_material = patch_library_overridable(bpy.props.PointerProperty(type=MMDMaterial))
|
||||
|
||||
@staticmethod
|
||||
def unregister():
|
||||
del bpy.types.Material.mmd_material
|
||||
@@ -0,0 +1,488 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 MMD Tools authors
|
||||
# This file was originally part of the MMD Tools add-on for Blender
|
||||
# You can find MMD Tools here: https://github.com/MMD-Blender/blender_mmd_tools
|
||||
# Neoneko has modified this file to work with Avatar Toolkit and may of made changes or improvements.
|
||||
# MMD Tools is licensed under the terms of the GNU General Public License version 3 (GPLv3) same as Avatar Toolkit.
|
||||
|
||||
import bpy
|
||||
|
||||
from .. import utils
|
||||
from ..core.bone import FnBone
|
||||
from ..core.material import FnMaterial
|
||||
from ..core.model import FnModel, Model
|
||||
from ..core.morph import FnMorph
|
||||
|
||||
|
||||
def _morph_base_get_name(prop: "_MorphBase") -> str:
|
||||
return prop.get("name", "")
|
||||
|
||||
|
||||
def _morph_base_set_name(prop: "_MorphBase", value: str):
|
||||
mmd_root = prop.id_data.mmd_root
|
||||
# morph_type = mmd_root.active_morph_type
|
||||
morph_type = "%s_morphs" % prop.bl_rna.identifier[:-5].lower()
|
||||
# assert(prop.bl_rna.identifier.endswith('Morph'))
|
||||
# logging.debug('_set_name: %s %s %s', prop, value, morph_type)
|
||||
prop_name = prop.get("name", None)
|
||||
if prop_name == value:
|
||||
return
|
||||
|
||||
used_names = {x.name for x in getattr(mmd_root, morph_type) if x != prop}
|
||||
value = utils.unique_name(value, used_names)
|
||||
if prop_name is not None:
|
||||
if morph_type == "vertex_morphs":
|
||||
kb_list = {}
|
||||
for mesh in FnModel.iterate_mesh_objects(prop.id_data):
|
||||
for kb in getattr(mesh.data.shape_keys, "key_blocks", ()):
|
||||
kb_list.setdefault(kb.name, []).append(kb)
|
||||
|
||||
if prop_name in kb_list:
|
||||
value = utils.unique_name(value, used_names | kb_list.keys())
|
||||
for kb in kb_list[prop_name]:
|
||||
kb.name = value
|
||||
|
||||
elif morph_type == "uv_morphs":
|
||||
vg_list = {}
|
||||
for mesh in FnModel.iterate_mesh_objects(prop.id_data):
|
||||
for vg, n, x in FnMorph.get_uv_morph_vertex_groups(mesh):
|
||||
vg_list.setdefault(n, []).append(vg)
|
||||
|
||||
if prop_name in vg_list:
|
||||
value = utils.unique_name(value, used_names | vg_list.keys())
|
||||
for vg in vg_list[prop_name]:
|
||||
vg.name = vg.name.replace(prop_name, value)
|
||||
|
||||
if 1: # morph_type != 'group_morphs':
|
||||
for m in mmd_root.group_morphs:
|
||||
for d in m.data:
|
||||
if d.name == prop_name and d.morph_type == morph_type:
|
||||
d.name = value
|
||||
|
||||
frame_facial = mmd_root.display_item_frames.get("表情")
|
||||
for item in getattr(frame_facial, "data", []):
|
||||
if item.name == prop_name and item.morph_type == morph_type:
|
||||
item.name = value
|
||||
break
|
||||
|
||||
obj = Model(prop.id_data).morph_slider.placeholder()
|
||||
if obj and value not in obj.data.shape_keys.key_blocks:
|
||||
kb = obj.data.shape_keys.key_blocks.get(prop_name, None)
|
||||
if kb:
|
||||
kb.name = value
|
||||
|
||||
prop["name"] = value
|
||||
|
||||
|
||||
class _MorphBase:
|
||||
name: bpy.props.StringProperty(
|
||||
name="Name",
|
||||
description="Japanese Name",
|
||||
set=_morph_base_set_name,
|
||||
get=_morph_base_get_name,
|
||||
)
|
||||
name_e: bpy.props.StringProperty(
|
||||
name="Name(Eng)",
|
||||
description="English Name",
|
||||
default="",
|
||||
)
|
||||
category: bpy.props.EnumProperty(
|
||||
name="Category",
|
||||
description="Select category",
|
||||
items=[
|
||||
("SYSTEM", "Hidden", "", 0),
|
||||
("EYEBROW", "Eye Brow", "", 1),
|
||||
("EYE", "Eye", "", 2),
|
||||
("MOUTH", "Mouth", "", 3),
|
||||
("OTHER", "Other", "", 4),
|
||||
],
|
||||
default="OTHER",
|
||||
)
|
||||
|
||||
|
||||
def _bone_morph_data_get_bone(prop: "BoneMorphData") -> str:
|
||||
bone_id = prop.get("bone_id", -1)
|
||||
if bone_id < 0:
|
||||
return ""
|
||||
root_object = prop.id_data
|
||||
armature_object = FnModel.find_armature_object(root_object)
|
||||
if armature_object is None:
|
||||
return ""
|
||||
pose_bone = FnBone.find_pose_bone_by_bone_id(armature_object, bone_id)
|
||||
if pose_bone is None:
|
||||
return ""
|
||||
return pose_bone.name
|
||||
|
||||
|
||||
def _bone_morph_data_set_bone(prop: "BoneMorphData", value: str):
|
||||
root = prop.id_data
|
||||
arm = FnModel.find_armature_object(root)
|
||||
|
||||
# Load the library_override file. This function is triggered when loading, but the arm obj cannot be found.
|
||||
# The arm obj is exist, but the relative relationship has not yet been established.
|
||||
if arm is None:
|
||||
return
|
||||
|
||||
if value not in arm.pose.bones.keys():
|
||||
prop["bone_id"] = -1
|
||||
return
|
||||
pose_bone = arm.pose.bones[value]
|
||||
prop["bone_id"] = FnBone.get_or_assign_bone_id(pose_bone)
|
||||
|
||||
|
||||
def _bone_morph_data_update_location_or_rotation(prop: "BoneMorphData", _context):
|
||||
if not prop.name.startswith("mmd_bind"):
|
||||
return
|
||||
arm = FnModel(prop.id_data).morph_slider.dummy_armature
|
||||
if arm:
|
||||
bone = arm.pose.bones.get(prop.name, None)
|
||||
if bone:
|
||||
bone.location = prop.location
|
||||
bone.rotation_quaternion = prop.rotation.__class__(*prop.rotation.to_axis_angle()) # Fix for consistency
|
||||
|
||||
|
||||
class BoneMorphData(bpy.types.PropertyGroup):
|
||||
""" """
|
||||
|
||||
bone: bpy.props.StringProperty(
|
||||
name="Bone",
|
||||
description="Target bone",
|
||||
set=_bone_morph_data_set_bone,
|
||||
get=_bone_morph_data_get_bone,
|
||||
)
|
||||
|
||||
bone_id: bpy.props.IntProperty(
|
||||
name="Bone ID",
|
||||
)
|
||||
|
||||
location: bpy.props.FloatVectorProperty(
|
||||
name="Location",
|
||||
description="Location",
|
||||
subtype="TRANSLATION",
|
||||
size=3,
|
||||
default=[0, 0, 0],
|
||||
update=_bone_morph_data_update_location_or_rotation,
|
||||
)
|
||||
|
||||
rotation: bpy.props.FloatVectorProperty(
|
||||
name="Rotation",
|
||||
description="Rotation in quaternions",
|
||||
subtype="QUATERNION",
|
||||
size=4,
|
||||
default=[1, 0, 0, 0],
|
||||
update=_bone_morph_data_update_location_or_rotation,
|
||||
)
|
||||
|
||||
|
||||
class BoneMorph(_MorphBase, bpy.types.PropertyGroup):
|
||||
"""Bone Morph"""
|
||||
|
||||
data: bpy.props.CollectionProperty(
|
||||
name="Morph Data",
|
||||
type=BoneMorphData,
|
||||
)
|
||||
active_data: bpy.props.IntProperty(
|
||||
name="Active Bone Data",
|
||||
min=0,
|
||||
default=0,
|
||||
)
|
||||
|
||||
|
||||
def _material_morph_data_get_material(prop: "MaterialMorphData"):
|
||||
mat_p = prop.get("material_data", None)
|
||||
if mat_p is not None:
|
||||
return mat_p.name
|
||||
return ""
|
||||
|
||||
|
||||
def _material_morph_data_set_material(prop: "MaterialMorphData", value: str):
|
||||
if value not in bpy.data.materials:
|
||||
prop["material_data"] = None
|
||||
prop["material_id"] = -1
|
||||
else:
|
||||
mat = bpy.data.materials[value]
|
||||
fnMat = FnMaterial(mat)
|
||||
prop["material_data"] = mat
|
||||
prop["material_id"] = fnMat.material_id
|
||||
|
||||
|
||||
def _material_morph_data_set_related_mesh(prop: "MaterialMorphData", value: str):
|
||||
mesh = FnModel.find_mesh_object_by_name(prop.id_data, value)
|
||||
if mesh is not None:
|
||||
prop["related_mesh_data"] = mesh.data
|
||||
else:
|
||||
prop["related_mesh_data"] = None
|
||||
|
||||
|
||||
def _material_morph_data_get_related_mesh(prop):
|
||||
mesh_p = prop.get("related_mesh_data", None)
|
||||
if mesh_p is not None:
|
||||
return mesh_p.name
|
||||
return ""
|
||||
|
||||
|
||||
def _material_morph_data_update_modifiable_values(prop: "MaterialMorphData", _context):
|
||||
if not prop.name.startswith("mmd_bind"):
|
||||
return
|
||||
from ..core.shader import _MaterialMorph
|
||||
|
||||
mat = prop["material_data"]
|
||||
if mat is not None:
|
||||
_MaterialMorph.update_morph_inputs(mat, prop)
|
||||
else:
|
||||
for mat in FnModel(prop.id_data).materials():
|
||||
_MaterialMorph.update_morph_inputs(mat, prop)
|
||||
|
||||
|
||||
class MaterialMorphData(bpy.types.PropertyGroup):
|
||||
""" """
|
||||
|
||||
related_mesh: bpy.props.StringProperty(
|
||||
name="Related Mesh",
|
||||
description="Stores a reference to the mesh where this morph data belongs to",
|
||||
set=_material_morph_data_set_related_mesh,
|
||||
get=_material_morph_data_get_related_mesh,
|
||||
)
|
||||
|
||||
related_mesh_data: bpy.props.PointerProperty(
|
||||
name="Related Mesh Data",
|
||||
type=bpy.types.Mesh,
|
||||
)
|
||||
|
||||
offset_type: bpy.props.EnumProperty(name="Offset Type", description="Select offset type", items=[("MULT", "Multiply", "", 0), ("ADD", "Add", "", 1)], default="ADD")
|
||||
|
||||
material: bpy.props.StringProperty(
|
||||
name="Material",
|
||||
description="Target material",
|
||||
get=_material_morph_data_get_material,
|
||||
set=_material_morph_data_set_material,
|
||||
)
|
||||
|
||||
material_id: bpy.props.IntProperty(
|
||||
name="Material ID",
|
||||
default=-1,
|
||||
)
|
||||
|
||||
material_data: bpy.props.PointerProperty(
|
||||
name="Material Data",
|
||||
type=bpy.types.Material,
|
||||
)
|
||||
|
||||
diffuse_color: bpy.props.FloatVectorProperty(
|
||||
name="Diffuse Color",
|
||||
description="Diffuse color",
|
||||
subtype="COLOR",
|
||||
size=4,
|
||||
soft_min=0,
|
||||
soft_max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=[0, 0, 0, 1],
|
||||
update=_material_morph_data_update_modifiable_values,
|
||||
)
|
||||
|
||||
specular_color: bpy.props.FloatVectorProperty(
|
||||
name="Specular Color",
|
||||
description="Specular color",
|
||||
subtype="COLOR",
|
||||
size=3,
|
||||
soft_min=0,
|
||||
soft_max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=[0, 0, 0],
|
||||
update=_material_morph_data_update_modifiable_values,
|
||||
)
|
||||
|
||||
shininess: bpy.props.FloatProperty(
|
||||
name="Reflect",
|
||||
description="Reflect",
|
||||
soft_min=0,
|
||||
soft_max=500,
|
||||
step=100.0,
|
||||
default=0.0,
|
||||
update=_material_morph_data_update_modifiable_values,
|
||||
)
|
||||
|
||||
ambient_color: bpy.props.FloatVectorProperty(
|
||||
name="Ambient Color",
|
||||
description="Ambient color",
|
||||
subtype="COLOR",
|
||||
size=3,
|
||||
soft_min=0,
|
||||
soft_max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=[0, 0, 0],
|
||||
update=_material_morph_data_update_modifiable_values,
|
||||
)
|
||||
|
||||
edge_color: bpy.props.FloatVectorProperty(
|
||||
name="Edge Color",
|
||||
description="Edge color",
|
||||
subtype="COLOR",
|
||||
size=4,
|
||||
soft_min=0,
|
||||
soft_max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=[0, 0, 0, 1],
|
||||
update=_material_morph_data_update_modifiable_values,
|
||||
)
|
||||
|
||||
edge_weight: bpy.props.FloatProperty(
|
||||
name="Edge Weight",
|
||||
description="Edge weight",
|
||||
soft_min=0,
|
||||
soft_max=2,
|
||||
step=0.1,
|
||||
default=0,
|
||||
update=_material_morph_data_update_modifiable_values,
|
||||
)
|
||||
|
||||
texture_factor: bpy.props.FloatVectorProperty(
|
||||
name="Texture factor",
|
||||
description="Texture factor",
|
||||
subtype="COLOR",
|
||||
size=4,
|
||||
soft_min=0,
|
||||
soft_max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=[0, 0, 0, 1],
|
||||
update=_material_morph_data_update_modifiable_values,
|
||||
)
|
||||
|
||||
sphere_texture_factor: bpy.props.FloatVectorProperty(
|
||||
name="Sphere Texture factor",
|
||||
description="Sphere texture factor",
|
||||
subtype="COLOR",
|
||||
size=4,
|
||||
soft_min=0,
|
||||
soft_max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=[0, 0, 0, 1],
|
||||
update=_material_morph_data_update_modifiable_values,
|
||||
)
|
||||
|
||||
toon_texture_factor: bpy.props.FloatVectorProperty(
|
||||
name="Toon Texture factor",
|
||||
description="Toon texture factor",
|
||||
subtype="COLOR",
|
||||
size=4,
|
||||
soft_min=0,
|
||||
soft_max=1,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=[0, 0, 0, 1],
|
||||
update=_material_morph_data_update_modifiable_values,
|
||||
)
|
||||
|
||||
|
||||
class MaterialMorph(_MorphBase, bpy.types.PropertyGroup):
|
||||
"""Material Morph"""
|
||||
|
||||
data: bpy.props.CollectionProperty(
|
||||
name="Morph Data",
|
||||
type=MaterialMorphData,
|
||||
)
|
||||
active_data: bpy.props.IntProperty(
|
||||
name="Active Material Data",
|
||||
min=0,
|
||||
default=0,
|
||||
)
|
||||
|
||||
|
||||
class UVMorphOffset(bpy.types.PropertyGroup):
|
||||
"""UV Morph Offset"""
|
||||
|
||||
index: bpy.props.IntProperty(
|
||||
name="Vertex Index",
|
||||
description="Vertex index",
|
||||
min=0,
|
||||
default=0,
|
||||
)
|
||||
offset: bpy.props.FloatVectorProperty(
|
||||
name="UV Offset",
|
||||
description="UV offset",
|
||||
size=4,
|
||||
# min=-1,
|
||||
# max=1,
|
||||
# precision=3,
|
||||
step=0.1,
|
||||
default=[0, 0, 0, 0],
|
||||
)
|
||||
|
||||
|
||||
class UVMorph(_MorphBase, bpy.types.PropertyGroup):
|
||||
"""UV Morph"""
|
||||
|
||||
uv_index: bpy.props.IntProperty(
|
||||
name="UV Index",
|
||||
description="UV index (UV, UV1 ~ UV4)",
|
||||
min=0,
|
||||
max=4,
|
||||
default=0,
|
||||
)
|
||||
data_type: bpy.props.EnumProperty(
|
||||
name="Data Type",
|
||||
description="Select data type",
|
||||
items=[
|
||||
("DATA", "Data", "Store offset data in root object (deprecated)", 0),
|
||||
("VERTEX_GROUP", "Vertex Group", "Store offset data in vertex groups", 1),
|
||||
],
|
||||
default="DATA",
|
||||
)
|
||||
data: bpy.props.CollectionProperty(
|
||||
name="Morph Data",
|
||||
type=UVMorphOffset,
|
||||
)
|
||||
active_data: bpy.props.IntProperty(
|
||||
name="Active UV Data",
|
||||
min=0,
|
||||
default=0,
|
||||
)
|
||||
vertex_group_scale: bpy.props.FloatProperty(
|
||||
name="Vertex Group Scale",
|
||||
description='The value scale of "Vertex Group" data type',
|
||||
precision=3,
|
||||
step=0.1,
|
||||
default=1,
|
||||
)
|
||||
|
||||
|
||||
class GroupMorphOffset(bpy.types.PropertyGroup):
|
||||
"""Group Morph Offset"""
|
||||
|
||||
morph_type: bpy.props.EnumProperty(
|
||||
name="Morph Type",
|
||||
description="Select morph type",
|
||||
items=[
|
||||
("material_morphs", "Material", "Material Morphs", 0),
|
||||
("uv_morphs", "UV", "UV Morphs", 1),
|
||||
("bone_morphs", "Bone", "Bone Morphs", 2),
|
||||
("vertex_morphs", "Vertex", "Vertex Morphs", 3),
|
||||
("group_morphs", "Group", "Group Morphs", 4),
|
||||
],
|
||||
default="vertex_morphs",
|
||||
)
|
||||
factor: bpy.props.FloatProperty(name="Factor", description="Factor", soft_min=0, soft_max=1, precision=3, step=0.1, default=0)
|
||||
|
||||
|
||||
class GroupMorph(_MorphBase, bpy.types.PropertyGroup):
|
||||
"""Group Morph"""
|
||||
|
||||
data: bpy.props.CollectionProperty(
|
||||
name="Morph Data",
|
||||
type=GroupMorphOffset,
|
||||
)
|
||||
active_data: bpy.props.IntProperty(
|
||||
name="Active Group Data",
|
||||
min=0,
|
||||
default=0,
|
||||
)
|
||||
|
||||
|
||||
class VertexMorph(_MorphBase, bpy.types.PropertyGroup):
|
||||
"""Vertex Morph"""
|
||||
@@ -1,41 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 MMD Tools authors
|
||||
# This file was originally part of the MMD Tools project, However Neoneko has added it to Avatar Toolkit.
|
||||
# All credit goes to the original authors.
|
||||
# Please note that some code was modified to fit the needs of Avatar Toolkit and some code may of been removed.
|
||||
# MMD Tools is licensed under the terms of the GPL-3.0 license which Avatar Toolkit is also licensed under.
|
||||
# You can find MMD Tools at: https://github.com/MMD-Blender/blender_mmd_tools/
|
||||
# This file was originally part of the MMD Tools add-on for Blender
|
||||
# You can find MMD Tools here: https://github.com/MMD-Blender/blender_mmd_tools
|
||||
# Neoneko has modified this file to work with Avatar Toolkit and may of made changes or improvements.
|
||||
# MMD Tools is licensed under the terms of the GNU General Public License version 3 (GPLv3) same as Avatar Toolkit.
|
||||
|
||||
from typing import cast
|
||||
import bpy
|
||||
from bpy.types import PropertyGroup, Context, PoseBone
|
||||
from bpy.props import (
|
||||
StringProperty,
|
||||
IntProperty,
|
||||
BoolProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty
|
||||
)
|
||||
|
||||
from ..logging_setup import logger
|
||||
from ..bone import FnBone
|
||||
from ..core.bone import FnBone
|
||||
from . import patch_library_overridable
|
||||
|
||||
def _mmd_bone_update_additional_transform(prop, context: Context):
|
||||
"""Update handler for additional transform properties"""
|
||||
|
||||
def _mmd_bone_update_additional_transform(prop: "MMDBone", context: bpy.types.Context):
|
||||
prop["is_additional_transform_dirty"] = True
|
||||
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, context: Context):
|
||||
"""Update handler for additional transform influence"""
|
||||
|
||||
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):
|
||||
"""Getter for additional transform bone property"""
|
||||
|
||||
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:
|
||||
@@ -45,8 +37,8 @@ def _mmd_bone_get_additional_transform_bone(prop):
|
||||
return ""
|
||||
return pose_bone.name
|
||||
|
||||
def _mmd_bone_set_additional_transform_bone(prop, value: str):
|
||||
"""Setter for additional transform bone property"""
|
||||
|
||||
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():
|
||||
@@ -55,85 +47,70 @@ def _mmd_bone_set_additional_transform_bone(prop, value: str):
|
||||
pose_bone = arm.pose.bones[value]
|
||||
prop["additional_transform_bone_id"] = FnBone.get_or_assign_bone_id(pose_bone)
|
||||
|
||||
def _pose_bone_update_mmd_ik_toggle(prop: PoseBone, _context):
|
||||
"""Update handler for IK toggle property"""
|
||||
v = prop.mmd_ik_toggle
|
||||
armature_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:
|
||||
logger.debug('Updating IK constraint %s on bone %s', c.name, b.name)
|
||||
c.influence = v
|
||||
b_chain = b if c.use_tail else b.parent
|
||||
for chain_bone in ([b_chain] + b_chain.parent_recursive)[:c.chain_count]:
|
||||
limit_c = next((c for c in chain_bone.constraints if c.type == "LIMIT_ROTATION" and not c.mute), None)
|
||||
if limit_c:
|
||||
limit_c.influence = v
|
||||
|
||||
class MMDBone(PropertyGroup):
|
||||
"""Property group for MMD bone properties"""
|
||||
name_j: StringProperty(
|
||||
class MMDBone(bpy.types.PropertyGroup):
|
||||
name_j: bpy.props.StringProperty(
|
||||
name="Name",
|
||||
description="Japanese Name",
|
||||
default="",
|
||||
)
|
||||
|
||||
name_e: StringProperty(
|
||||
|
||||
name_e: bpy.props.StringProperty(
|
||||
name="Name(Eng)",
|
||||
description="English Name",
|
||||
default="",
|
||||
)
|
||||
|
||||
bone_id: IntProperty(
|
||||
|
||||
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: IntProperty(
|
||||
|
||||
transform_order: bpy.props.IntProperty(
|
||||
name="Transform Order",
|
||||
description="Deformation tier",
|
||||
min=0,
|
||||
max=100,
|
||||
soft_max=7,
|
||||
)
|
||||
|
||||
is_controllable: BoolProperty(
|
||||
|
||||
is_controllable: bpy.props.BoolProperty(
|
||||
name="Controllable",
|
||||
description="Is controllable",
|
||||
default=True,
|
||||
)
|
||||
|
||||
transform_after_dynamics: BoolProperty(
|
||||
|
||||
transform_after_dynamics: bpy.props.BoolProperty(
|
||||
name="After Dynamics",
|
||||
description="After physics",
|
||||
default=False,
|
||||
)
|
||||
|
||||
enabled_fixed_axis: BoolProperty(
|
||||
|
||||
enabled_fixed_axis: bpy.props.BoolProperty(
|
||||
name="Fixed Axis",
|
||||
description="Use fixed axis",
|
||||
default=False,
|
||||
)
|
||||
|
||||
fixed_axis: FloatVectorProperty(
|
||||
|
||||
fixed_axis: bpy.props.FloatVectorProperty(
|
||||
name="Fixed Axis",
|
||||
description="Fixed axis",
|
||||
subtype="XYZ",
|
||||
size=3,
|
||||
precision=3,
|
||||
step=0.1,
|
||||
step=0.1, # 0.1 / 100
|
||||
default=[0, 0, 0],
|
||||
)
|
||||
|
||||
enabled_local_axes: BoolProperty(
|
||||
|
||||
enabled_local_axes: bpy.props.BoolProperty(
|
||||
name="Local Axes",
|
||||
description="Use local axes",
|
||||
default=False,
|
||||
)
|
||||
|
||||
local_axis_x: FloatVectorProperty(
|
||||
|
||||
local_axis_x: bpy.props.FloatVectorProperty(
|
||||
name="Local X-Axis",
|
||||
description="Local x-axis",
|
||||
subtype="XYZ",
|
||||
@@ -142,8 +119,8 @@ class MMDBone(PropertyGroup):
|
||||
step=0.1,
|
||||
default=[1, 0, 0],
|
||||
)
|
||||
|
||||
local_axis_z: FloatVectorProperty(
|
||||
|
||||
local_axis_z: bpy.props.FloatVectorProperty(
|
||||
name="Local Z-Axis",
|
||||
description="Local z-axis",
|
||||
subtype="XYZ",
|
||||
@@ -152,14 +129,14 @@ class MMDBone(PropertyGroup):
|
||||
step=0.1,
|
||||
default=[0, 0, 1],
|
||||
)
|
||||
|
||||
is_tip: BoolProperty(
|
||||
|
||||
is_tip: bpy.props.BoolProperty(
|
||||
name="Tip Bone",
|
||||
description="Is zero length bone",
|
||||
default=False,
|
||||
)
|
||||
|
||||
ik_rotation_constraint: FloatProperty(
|
||||
|
||||
ik_rotation_constraint: bpy.props.FloatProperty(
|
||||
name="IK Rotation Constraint",
|
||||
description="The unit angle of IK",
|
||||
subtype="ANGLE",
|
||||
@@ -167,36 +144,36 @@ class MMDBone(PropertyGroup):
|
||||
soft_max=4,
|
||||
default=1,
|
||||
)
|
||||
|
||||
has_additional_rotation: BoolProperty(
|
||||
|
||||
has_additional_rotation: bpy.props.BoolProperty(
|
||||
name="Additional Rotation",
|
||||
description="Additional rotation",
|
||||
default=False,
|
||||
update=_mmd_bone_update_additional_transform,
|
||||
)
|
||||
|
||||
has_additional_location: BoolProperty(
|
||||
|
||||
has_additional_location: bpy.props.BoolProperty(
|
||||
name="Additional Location",
|
||||
description="Additional location",
|
||||
default=False,
|
||||
update=_mmd_bone_update_additional_transform,
|
||||
)
|
||||
|
||||
additional_transform_bone: StringProperty(
|
||||
|
||||
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: IntProperty(
|
||||
|
||||
additional_transform_bone_id: bpy.props.IntProperty(
|
||||
name="Additional Transform Bone ID",
|
||||
default=-1,
|
||||
update=_mmd_bone_update_additional_transform,
|
||||
)
|
||||
|
||||
additional_transform_influence: FloatProperty(
|
||||
|
||||
additional_transform_influence: bpy.props.FloatProperty(
|
||||
name="Additional Transform Influence",
|
||||
description="Additional transform influence",
|
||||
default=1,
|
||||
@@ -204,47 +181,44 @@ class MMDBone(PropertyGroup):
|
||||
soft_max=1,
|
||||
update=_mmd_bone_update_additional_transform_influence,
|
||||
)
|
||||
|
||||
is_additional_transform_dirty: BoolProperty(
|
||||
name="",
|
||||
default=True
|
||||
)
|
||||
|
||||
|
||||
is_additional_transform_dirty: bpy.props.BoolProperty(name="", default=True)
|
||||
|
||||
def is_id_unique(self):
|
||||
"""Check if the bone ID is unique"""
|
||||
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,
|
||||
)
|
||||
)
|
||||
|
||||
def register():
|
||||
"""Register MMD bone properties"""
|
||||
logger.info("Registering MMD bone properties")
|
||||
bpy.utils.register_class(MMDBone)
|
||||
|
||||
# Add properties to PoseBone
|
||||
bpy.types.PoseBone.mmd_bone = bpy.props.PointerProperty(type=MMDBone)
|
||||
bpy.types.PoseBone.is_mmd_shadow_bone = bpy.props.BoolProperty(
|
||||
name="is_mmd_shadow_bone",
|
||||
default=False
|
||||
)
|
||||
bpy.types.PoseBone.mmd_shadow_bone_type = bpy.props.StringProperty(
|
||||
name="mmd_shadow_bone_type"
|
||||
)
|
||||
bpy.types.PoseBone.mmd_ik_toggle = 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 unregister():
|
||||
"""Unregister MMD bone properties"""
|
||||
logger.info("Unregistering MMD bone properties")
|
||||
|
||||
# Remove properties from PoseBone
|
||||
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
|
||||
|
||||
bpy.utils.unregister_class(MMDBone)
|
||||
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
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 MMD Tools authors
|
||||
# This file was originally part of the MMD Tools add-on for Blender
|
||||
# You can find MMD Tools here: https://github.com/MMD-Blender/blender_mmd_tools
|
||||
# Neoneko has modified this file to work with Avatar Toolkit and may of made changes or improvements.
|
||||
# MMD Tools is licensed under the terms of the GNU General Public License version 3 (GPLv3) same as Avatar Toolkit.
|
||||
|
||||
"""Properties for rigid bodies and joints"""
|
||||
|
||||
import bpy
|
||||
|
||||
from .. import bpyutils
|
||||
from ..core import rigid_body
|
||||
from ..core.rigid_body import RigidBodyMaterial, FnRigidBody
|
||||
from ..core.model import FnModel
|
||||
from . import patch_library_overridable
|
||||
|
||||
|
||||
def _updateCollisionGroup(prop, _context):
|
||||
obj = prop.id_data
|
||||
materials = obj.data.materials
|
||||
if len(materials) == 0:
|
||||
materials.append(RigidBodyMaterial.getMaterial(prop.collision_group_number))
|
||||
else:
|
||||
obj.material_slots[0].material = RigidBodyMaterial.getMaterial(prop.collision_group_number)
|
||||
|
||||
|
||||
def _updateType(prop, _context):
|
||||
obj = prop.id_data
|
||||
rb = obj.rigid_body
|
||||
if rb:
|
||||
rb.kinematic = int(prop.type) == rigid_body.MODE_STATIC
|
||||
|
||||
|
||||
def _updateShape(prop, _context):
|
||||
obj = prop.id_data
|
||||
|
||||
if len(obj.data.vertices) > 0:
|
||||
size = prop.size
|
||||
prop.size = size # update mesh
|
||||
|
||||
rb = obj.rigid_body
|
||||
if rb:
|
||||
rb.collision_shape = prop.shape
|
||||
|
||||
|
||||
def _get_bone(prop):
|
||||
obj = prop.id_data
|
||||
relation = obj.constraints.get("mmd_tools_rigid_parent", None)
|
||||
if relation:
|
||||
arm = relation.target
|
||||
bone_name = relation.subtarget
|
||||
if arm is not None and bone_name in arm.data.bones:
|
||||
return bone_name
|
||||
return prop.get("bone", "")
|
||||
|
||||
|
||||
def _set_bone(prop, value):
|
||||
bone_name = value
|
||||
obj = prop.id_data
|
||||
relation = obj.constraints.get("mmd_tools_rigid_parent", None)
|
||||
if relation is None:
|
||||
relation = obj.constraints.new("CHILD_OF")
|
||||
relation.name = "mmd_tools_rigid_parent"
|
||||
relation.mute = True
|
||||
|
||||
arm = relation.target
|
||||
if arm is None:
|
||||
root = FnModel.find_root_object(obj)
|
||||
if root:
|
||||
arm = relation.target = FnModel.find_armature_object(root)
|
||||
|
||||
if arm is not None and bone_name in arm.data.bones:
|
||||
relation.subtarget = bone_name
|
||||
else:
|
||||
relation.subtarget = bone_name = ""
|
||||
|
||||
prop["bone"] = bone_name
|
||||
|
||||
|
||||
def _get_size(prop):
|
||||
if prop.id_data.mmd_type != "RIGID_BODY":
|
||||
return (0, 0, 0)
|
||||
return FnRigidBody.get_rigid_body_size(prop.id_data)
|
||||
|
||||
|
||||
def _set_size(prop, value):
|
||||
obj = prop.id_data
|
||||
assert obj.mode == "OBJECT" # not support other mode yet
|
||||
shape = prop.shape
|
||||
|
||||
mesh = obj.data
|
||||
rb = obj.rigid_body
|
||||
|
||||
if len(mesh.vertices) == 0 or rb is None or rb.collision_shape != shape:
|
||||
if shape == "SPHERE":
|
||||
bpyutils.makeSphere(
|
||||
radius=value[0],
|
||||
target_object=obj,
|
||||
)
|
||||
elif shape == "BOX":
|
||||
bpyutils.makeBox(
|
||||
size=value,
|
||||
target_object=obj,
|
||||
)
|
||||
elif shape == "CAPSULE":
|
||||
bpyutils.makeCapsule(
|
||||
radius=value[0],
|
||||
height=value[1],
|
||||
target_object=obj,
|
||||
)
|
||||
mesh.update()
|
||||
if rb:
|
||||
rb.collision_shape = shape
|
||||
else:
|
||||
if shape == "SPHERE":
|
||||
radius = max(value[0], 1e-3)
|
||||
for v in mesh.vertices:
|
||||
vec = v.co.normalized()
|
||||
v.co = vec * radius
|
||||
elif shape == "BOX":
|
||||
x = max(value[0], 1e-3)
|
||||
y = max(value[1], 1e-3)
|
||||
z = max(value[2], 1e-3)
|
||||
for v in mesh.vertices:
|
||||
x0, y0, z0 = v.co
|
||||
x0 = -x if x0 < 0 else x
|
||||
y0 = -y if y0 < 0 else y
|
||||
z0 = -z if z0 < 0 else z
|
||||
v.co = [x0, y0, z0]
|
||||
elif shape == "CAPSULE":
|
||||
r0, h0, xx = FnRigidBody.get_rigid_body_size(prop.id_data)
|
||||
h0 *= 0.5
|
||||
radius = max(value[0], 1e-3)
|
||||
height = max(value[1], 1e-3) * 0.5
|
||||
scale = radius / max(r0, 1e-3)
|
||||
for v in mesh.vertices:
|
||||
x0, y0, z0 = v.co
|
||||
x0 *= scale
|
||||
y0 *= scale
|
||||
if z0 < 0:
|
||||
z0 = (z0 + h0) * scale - height
|
||||
else:
|
||||
z0 = (z0 - h0) * scale + height
|
||||
v.co = [x0, y0, z0]
|
||||
mesh.update()
|
||||
|
||||
|
||||
def _get_rigid_name(prop):
|
||||
return prop.get("name", "")
|
||||
|
||||
|
||||
def _set_rigid_name(prop, value):
|
||||
prop["name"] = value
|
||||
|
||||
|
||||
class MMDRigidBody(bpy.types.PropertyGroup):
|
||||
name_j: bpy.props.StringProperty(
|
||||
name="Name",
|
||||
description="Japanese Name",
|
||||
default="",
|
||||
get=_get_rigid_name,
|
||||
set=_set_rigid_name,
|
||||
)
|
||||
|
||||
name_e: bpy.props.StringProperty(
|
||||
name="Name(Eng)",
|
||||
description="English Name",
|
||||
default="",
|
||||
)
|
||||
|
||||
collision_group_number: bpy.props.IntProperty(
|
||||
name="Collision Group",
|
||||
description="The collision group of the object",
|
||||
min=0,
|
||||
max=15,
|
||||
default=1,
|
||||
update=_updateCollisionGroup,
|
||||
)
|
||||
|
||||
collision_group_mask: bpy.props.BoolVectorProperty(
|
||||
name="Collision Group Mask",
|
||||
description="The groups the object can not collide with",
|
||||
size=16,
|
||||
subtype="LAYER",
|
||||
)
|
||||
|
||||
type: bpy.props.EnumProperty(
|
||||
name="Rigid Type",
|
||||
description="Select rigid type",
|
||||
items=[
|
||||
(str(rigid_body.MODE_STATIC), "Bone", "Rigid body's orientation completely determined by attached bone", 1),
|
||||
(str(rigid_body.MODE_DYNAMIC), "Physics", "Attached bone's orientation completely determined by rigid body", 2),
|
||||
(str(rigid_body.MODE_DYNAMIC_BONE), "Physics + Bone", "Bone determined by combination of parent and attached rigid body", 3),
|
||||
],
|
||||
update=_updateType,
|
||||
)
|
||||
|
||||
shape: bpy.props.EnumProperty(
|
||||
name="Shape",
|
||||
description="Select the collision shape",
|
||||
items=[
|
||||
("SPHERE", "Sphere", "", 1),
|
||||
("BOX", "Box", "", 2),
|
||||
("CAPSULE", "Capsule", "", 3),
|
||||
],
|
||||
update=_updateShape,
|
||||
)
|
||||
|
||||
bone: bpy.props.StringProperty(
|
||||
name="Bone",
|
||||
description="Target bone",
|
||||
default="",
|
||||
get=_get_bone,
|
||||
set=_set_bone,
|
||||
)
|
||||
|
||||
size: bpy.props.FloatVectorProperty(
|
||||
name="Size",
|
||||
description="Size of the object",
|
||||
subtype="XYZ",
|
||||
size=3,
|
||||
min=0,
|
||||
step=0.1,
|
||||
get=_get_size,
|
||||
set=_set_size,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def register():
|
||||
bpy.types.Object.mmd_rigid = patch_library_overridable(bpy.props.PointerProperty(type=MMDRigidBody))
|
||||
|
||||
@staticmethod
|
||||
def unregister():
|
||||
del bpy.types.Object.mmd_rigid
|
||||
|
||||
|
||||
def _updateSpringLinear(prop, context):
|
||||
obj = prop.id_data
|
||||
rbc = obj.rigid_body_constraint
|
||||
if rbc:
|
||||
rbc.spring_stiffness_x = prop.spring_linear[0]
|
||||
rbc.spring_stiffness_y = prop.spring_linear[1]
|
||||
rbc.spring_stiffness_z = prop.spring_linear[2]
|
||||
|
||||
|
||||
def _updateSpringAngular(prop, context):
|
||||
obj = prop.id_data
|
||||
rbc = obj.rigid_body_constraint
|
||||
if rbc and hasattr(rbc, "use_spring_ang_x"):
|
||||
rbc.spring_stiffness_ang_x = prop.spring_angular[0]
|
||||
rbc.spring_stiffness_ang_y = prop.spring_angular[1]
|
||||
rbc.spring_stiffness_ang_z = prop.spring_angular[2]
|
||||
|
||||
|
||||
class MMDJoint(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="",
|
||||
)
|
||||
|
||||
spring_linear: bpy.props.FloatVectorProperty(
|
||||
name="Spring(Linear)",
|
||||
description="Spring constant of movement",
|
||||
subtype="XYZ",
|
||||
size=3,
|
||||
min=0,
|
||||
step=0.1,
|
||||
update=_updateSpringLinear,
|
||||
)
|
||||
|
||||
spring_angular: bpy.props.FloatVectorProperty(
|
||||
name="Spring(Angular)",
|
||||
description="Spring constant of rotation",
|
||||
subtype="XYZ",
|
||||
size=3,
|
||||
min=0,
|
||||
step=0.1,
|
||||
update=_updateSpringAngular,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def register():
|
||||
bpy.types.Object.mmd_joint = patch_library_overridable(bpy.props.PointerProperty(type=MMDJoint))
|
||||
|
||||
@staticmethod
|
||||
def unregister():
|
||||
del bpy.types.Object.mmd_joint
|
||||
@@ -1,10 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 MMD Tools authors
|
||||
# This file was originally part of the MMD Tools project, However Neoneko has added it to Avatar Toolkit.
|
||||
# All credit goes to the original authors.
|
||||
# Please note that some code was modified to fit the needs of Avatar Toolkit and some code may of been removed.
|
||||
# MMD Tools is licensed under the terms of the GPL-3.0 license which Avatar Toolkit is also licensed under.
|
||||
# You can find MMD Tools at: https://github.com/MMD-Blender/blender_mmd_tools/
|
||||
# This file was originally part of the MMD Tools add-on for Blender
|
||||
# You can find MMD Tools here: https://github.com/MMD-Blender/blender_mmd_tools
|
||||
# Neoneko has modified this file to work with Avatar Toolkit and may of made changes or improvements.
|
||||
# MMD Tools is licensed under the terms of the GNU General Public License version 3 (GPLv3) same as Avatar Toolkit.
|
||||
|
||||
"""Properties for MMD model root object"""
|
||||
|
||||
@@ -500,26 +499,22 @@ class MMDRoot(bpy.types.PropertyGroup):
|
||||
|
||||
@staticmethod
|
||||
def __get_select(prop: bpy.types.Object) -> bool:
|
||||
# TODO: Object.select is deprecated since v4.0.0, use Object.select_get() method instead
|
||||
# utils.warn_deprecation("Object.select", "v4.0.0", "Use Object.select_get() method instead")
|
||||
utils.warn_deprecation("Object.select", "v4.0.0", "Use Object.select_get() method instead")
|
||||
return prop.select_get()
|
||||
|
||||
@staticmethod
|
||||
def __set_select(prop: bpy.types.Object, value: bool) -> None:
|
||||
# TODO: Object.select is deprecated since v4.0.0, use Object.select_set() method instead
|
||||
# utils.warn_deprecation("Object.select", "v4.0.0", "Use Object.select_set() method instead")
|
||||
utils.warn_deprecation("Object.select", "v4.0.0", "Use Object.select_set() method instead")
|
||||
prop.select_set(value)
|
||||
|
||||
@staticmethod
|
||||
def __get_hide(prop: bpy.types.Object) -> bool:
|
||||
# TODO: Object.hide is deprecated since v4.0.0, use Object.hide_get() method instead
|
||||
# utils.warn_deprecation("Object.hide", "v4.0.0", "Use Object.hide_get() method instead")
|
||||
utils.warn_deprecation("Object.hide", "v4.0.0", "Use Object.hide_get() method instead")
|
||||
return prop.hide_get()
|
||||
|
||||
@staticmethod
|
||||
def __set_hide(prop: bpy.types.Object, value: bool) -> None:
|
||||
# TODO: Object.hide is deprecated since v4.0.0, use Object.hide_set() method instead
|
||||
# utils.warn_deprecation("Object.hide", "v4.0.0", "Use Object.hide_set() method instead")
|
||||
utils.warn_deprecation("Object.hide", "v4.0.0", "Use Object.hide_set() method instead")
|
||||
prop.hide_set(value)
|
||||
if prop.hide_viewport != value:
|
||||
prop.hide_viewport = value
|
||||
@@ -579,4 +574,4 @@ class MMDRoot(bpy.types.PropertyGroup):
|
||||
del bpy.types.Object.hide
|
||||
del bpy.types.Object.select
|
||||
del bpy.types.Object.mmd_root
|
||||
del bpy.types.Object.mmd_type
|
||||
del bpy.types.Object.mmd_type
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 MMD Tools authors
|
||||
# This file was originally part of the MMD Tools add-on for Blender
|
||||
# You can find MMD Tools here: https://github.com/MMD-Blender/blender_mmd_tools
|
||||
# Neoneko has modified this file to work with Avatar Toolkit and may of made changes or improvements.
|
||||
# MMD Tools is licensed under the terms of the GNU General Public License version 3 (GPLv3) same as Avatar Toolkit.
|
||||
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
import bpy
|
||||
|
||||
from ..core.translations import FnTranslations, MMDTranslationElementType
|
||||
from ..translations import DictionaryEnum
|
||||
|
||||
MMD_TRANSLATION_ELEMENT_TYPE_ENUM_ITEMS = [
|
||||
(MMDTranslationElementType.BONE.name, MMDTranslationElementType.BONE.value, "Bones", 1),
|
||||
(MMDTranslationElementType.MORPH.name, MMDTranslationElementType.MORPH.value, "Morphs", 2),
|
||||
(MMDTranslationElementType.MATERIAL.name, MMDTranslationElementType.MATERIAL.value, "Materials", 4),
|
||||
(MMDTranslationElementType.DISPLAY.name, MMDTranslationElementType.DISPLAY.value, "Display frames", 8),
|
||||
(MMDTranslationElementType.PHYSICS.name, MMDTranslationElementType.PHYSICS.value, "Rigidbodies and joints", 16),
|
||||
(MMDTranslationElementType.INFO.name, MMDTranslationElementType.INFO.value, "Model name and comments", 32),
|
||||
]
|
||||
|
||||
|
||||
class MMDTranslationElement(bpy.types.PropertyGroup):
|
||||
type: bpy.props.EnumProperty(items=MMD_TRANSLATION_ELEMENT_TYPE_ENUM_ITEMS)
|
||||
object: bpy.props.PointerProperty(type=bpy.types.Object)
|
||||
data_path: bpy.props.StringProperty()
|
||||
name: bpy.props.StringProperty()
|
||||
name_j: bpy.props.StringProperty()
|
||||
name_e: bpy.props.StringProperty()
|
||||
|
||||
|
||||
class MMDTranslationElementIndex(bpy.types.PropertyGroup):
|
||||
value: bpy.props.IntProperty()
|
||||
|
||||
|
||||
BATCH_OPERATION_SCRIPT_PRESETS: Dict[str, Tuple[Optional[str], str, str, int]] = {
|
||||
"NOTHING": ("", "", "", 1),
|
||||
"CLEAR": (None, "Clear", '""', 10),
|
||||
"TO_ENGLISH": ("BLENDER", "Translate to English", "to_english(name)", 2),
|
||||
"TO_MMD_LR": ("JAPANESE", "Blender L/R to MMD L/R", "to_mmd_lr(name)", 3),
|
||||
"TO_BLENDER_LR": ("BLENDER", "MMD L/R to Blender L/R", "to_blender_lr(name_j)", 4),
|
||||
"RESTORE_BLENDER": ("BLENDER", "Restore Blender Names", "org_name", 5),
|
||||
"RESTORE_JAPANESE": ("JAPANESE", "Restore Japanese MMD Names", "org_name_j", 6),
|
||||
"RESTORE_ENGLISH": ("ENGLISH", "Restore English MMD Names", "org_name_e", 7),
|
||||
"ENGLISH_IF_EMPTY_JAPANESE": (None, "Copy English MMD Names, if empty copy Japanese MMD Name", "name_e if name_e else name_j", 8),
|
||||
"JAPANESE_IF_EMPTY_ENGLISH": (None, "Copy Japanese MMD Names, if empty copy English MMD Name", "name_j if name_j else name_e", 9),
|
||||
}
|
||||
|
||||
BATCH_OPERATION_SCRIPT_PRESET_ITEMS: List[Tuple[str, str, str, int]] = [(k, t[1], t[2], t[3]) for k, t in BATCH_OPERATION_SCRIPT_PRESETS.items()]
|
||||
|
||||
|
||||
class MMDTranslation(bpy.types.PropertyGroup):
|
||||
@staticmethod
|
||||
def _update_index(mmd_translation: "MMDTranslation", _context):
|
||||
FnTranslations.update_index(mmd_translation)
|
||||
|
||||
@staticmethod
|
||||
def _collect_data(mmd_translation: "MMDTranslation", _context):
|
||||
FnTranslations.collect_data(mmd_translation)
|
||||
|
||||
@staticmethod
|
||||
def _update_query(mmd_translation: "MMDTranslation", _context):
|
||||
FnTranslations.update_query(mmd_translation)
|
||||
|
||||
@staticmethod
|
||||
def _update_batch_operation_script_preset(mmd_translation: "MMDTranslation", _context):
|
||||
if mmd_translation.batch_operation_script_preset == "NOTHING":
|
||||
return
|
||||
|
||||
id2scripts: Dict[str, str] = {i[0]: i[2] for i in BATCH_OPERATION_SCRIPT_PRESET_ITEMS}
|
||||
|
||||
batch_operation_script = id2scripts.get(mmd_translation.batch_operation_script_preset)
|
||||
if batch_operation_script is None:
|
||||
return
|
||||
|
||||
mmd_translation.batch_operation_script = batch_operation_script
|
||||
batch_operation_target = BATCH_OPERATION_SCRIPT_PRESETS[mmd_translation.batch_operation_script_preset][0]
|
||||
if batch_operation_target:
|
||||
mmd_translation.batch_operation_target = batch_operation_target
|
||||
|
||||
translation_elements: bpy.props.CollectionProperty(type=MMDTranslationElement)
|
||||
filtered_translation_element_indices_active_index: bpy.props.IntProperty(update=_update_index.__func__)
|
||||
filtered_translation_element_indices: bpy.props.CollectionProperty(type=MMDTranslationElementIndex)
|
||||
|
||||
filter_japanese_blank: bpy.props.BoolProperty(name="Japanese Blank", default=False, update=_update_query.__func__)
|
||||
filter_english_blank: bpy.props.BoolProperty(name="English Blank", default=False, update=_update_query.__func__)
|
||||
filter_restorable: bpy.props.BoolProperty(name="Restorable", default=False, update=_update_query.__func__)
|
||||
filter_selected: bpy.props.BoolProperty(name="Selected", default=False, update=_update_query.__func__)
|
||||
filter_visible: bpy.props.BoolProperty(name="Visible", default=False, update=_update_query.__func__)
|
||||
filter_types: bpy.props.EnumProperty(
|
||||
items=MMD_TRANSLATION_ELEMENT_TYPE_ENUM_ITEMS,
|
||||
default={
|
||||
"BONE",
|
||||
"MORPH",
|
||||
"MATERIAL",
|
||||
"DISPLAY",
|
||||
"PHYSICS",
|
||||
},
|
||||
options={"ENUM_FLAG"},
|
||||
update=_update_query.__func__,
|
||||
)
|
||||
|
||||
dictionary: bpy.props.EnumProperty(
|
||||
items=DictionaryEnum.get_dictionary_items,
|
||||
name="Dictionary",
|
||||
)
|
||||
|
||||
batch_operation_target: bpy.props.EnumProperty(
|
||||
items=[
|
||||
("BLENDER", "Blender Name (name)", "", 1),
|
||||
("JAPANESE", "Japanese MMD Name (name_j)", "", 2),
|
||||
("ENGLISH", "English MMD Name (name_e)", "", 3),
|
||||
],
|
||||
name="Operation Target",
|
||||
default="JAPANESE",
|
||||
)
|
||||
|
||||
batch_operation_script_preset: bpy.props.EnumProperty(
|
||||
items=BATCH_OPERATION_SCRIPT_PRESET_ITEMS,
|
||||
name="Operation Script Preset",
|
||||
default="NOTHING",
|
||||
update=_update_batch_operation_script_preset.__func__,
|
||||
)
|
||||
|
||||
batch_operation_script: bpy.props.StringProperty()
|
||||
Reference in New Issue
Block a user