Compare commits

...

12 Commits

Author SHA1 Message Date
Yusarina 1b7f6632ea Merge pull request #218 from Yusarina/atk-next
Bring ATK Next up to date with Current
2025-11-29 22:50:29 +00:00
Yusarina 24b489f7a2 Fix swapped operator IDs for Apply Pose as Rest/Shapekey buttons 2025-11-29 22:49:18 +00:00
Yusarina 1e734a518e Fix garbled Japanese/Unicode text in armature and mesh dropdowns
- Add proper caching to EnumProperty callbacks to prevent encoding corruption
- Use ASCII-safe identifiers (ARM_/MESH_ + pointer) with Unicode display names
- Add get_mesh_from_identifier() helper for safe mesh retrieval
- Update visemes panel to use new mesh identifier system
- Ensure stable string objects prevent Blender RNA encoding issues
2025-11-29 22:48:25 +00:00
Yusarina 4b538cb8b2 Restart 2025-11-26 19:35:20 +00:00
Yusarina d85231b62b meh 2025-11-23 02:50:19 +00:00
Yusarina b13ca15ece Removal of IK bones and etc, zero weight bones and more 2025-11-23 02:21:30 +00:00
Yusarina 84bacca923 Armature Re-strutring and etc 2025-11-22 17:49:09 +00:00
Yusarina 53d2ac10b7 Add bone Translation
- Uses MMD Tools Dictionary to convert things into English then uses Translation service to do the rest

This i useful for the rest of our converter, it's better to have standard english names then trying to use a service first as each service translate things differnetly my orignal approach was bad due to this.
2025-11-22 16:57:26 +00:00
Yusarina 95cb726485 Start of the MMD Converter 2025-11-22 16:39:28 +00:00
Yusarina cb5b891d0d Merge pull request #215 from Yusarina/atk-next
Bring Translation Service Changes and UTF 8 decoding to ATK Next from Current
2025-11-22 16:23:15 +00:00
Yusarina aedd83e078 Version Bump 2025-11-22 16:21:49 +00:00
Yusarina 5719a55ae5 Merge pull request #9 from Yusarina/Current
Bring Updated UTF 8 decoding to ATK next Branch
2025-11-22 16:20:22 +00:00
11 changed files with 376 additions and 24 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
schema_version = "1.0.0" schema_version = "1.0.0"
id = "avatar_toolkit" id = "avatar_toolkit"
version = "0.5.2" version = "0.6.0"
name = "Avatar Toolkit" name = "Avatar Toolkit"
tagline = "A modern tool for importing and optimizing models for VRChat, Resonite, and other similar games." tagline = "A modern tool for importing and optimizing models for VRChat, Resonite, and other similar games."
maintainer = "Team NekoNeo" maintainer = "Team NekoNeo"
+60 -6
View File
@@ -142,6 +142,41 @@ def set_active_armature(context: Context, armature: Object) -> None:
else: else:
context.scene.avatar_toolkit.active_armature = 'NONE' context.scene.avatar_toolkit.active_armature = 'NONE'
def get_mesh_from_identifier(mesh_id: str) -> Optional[Object]:
"""Get mesh object from safe identifier
Args:
mesh_id: Safe identifier in format "MESH_{pointer}" or direct object name
Returns:
Mesh object or None if not found
"""
if not mesh_id or mesh_id == 'NONE':
return None
# Handle new-style identifiers (MESH_{pointer})
if mesh_id.startswith('MESH_'):
try:
pointer_str = mesh_id[5:] # Remove "MESH_" prefix
target_pointer = int(pointer_str)
# Search for object with matching pointer
for obj in bpy.data.objects:
if obj.type == 'MESH' and obj.as_pointer() == target_pointer:
return obj
except (ValueError, AttributeError):
pass
# Fallback for old-style identifiers (direct name)
return bpy.data.objects.get(mesh_id)
def clear_enum_caches() -> None:
"""Clear all enum property caches to force refresh of dropdown lists"""
if hasattr(get_armature_list, '_cache_key'):
delattr(get_armature_list, '_cache_key')
if hasattr(get_armature_list, '_cached_items'):
delattr(get_armature_list, '_cached_items')
def get_armature_list(self: Optional[Any] = None, context: Optional[Context] = None) -> List[Tuple[str, str, str]]: def get_armature_list(self: Optional[Any] = None, context: Optional[Context] = None) -> List[Tuple[str, str, str]]:
"""Get list of all armature objects in the scene """Get list of all armature objects in the scene
@@ -149,21 +184,40 @@ def get_armature_list(self: Optional[Any] = None, context: Optional[Context] = N
- identifier: ASCII-safe unique ID (uses object's memory address) - identifier: ASCII-safe unique ID (uses object's memory address)
- display_name: The actual object name (can contain Japanese characters) - display_name: The actual object name (can contain Japanese characters)
- description: Empty string - description: Empty string
Uses caching to prevent encoding issues with Blender's EnumProperty system
""" """
if context is None: if context is None:
context = bpy.context context = bpy.context
# Use object's as_pointer() value as a safe ASCII identifier # Create a cache key based on armature objects in scene
armature_objects = [obj for obj in context.scene.objects if obj.type == 'ARMATURE']
cache_key = tuple((obj.name, obj.as_pointer()) for obj in armature_objects)
# Check if we have a cached result
if hasattr(get_armature_list, '_cache_key') and get_armature_list._cache_key == cache_key:
if hasattr(get_armature_list, '_cached_items'):
return get_armature_list._cached_items
# Build the list
armatures = [] armatures = []
for obj in context.scene.objects: for obj in armature_objects:
if obj.type == 'ARMATURE':
# Create a safe ASCII identifier using the object pointer # Create a safe ASCII identifier using the object pointer
safe_id = f"ARM_{obj.as_pointer()}" safe_id = f"ARM_{obj.as_pointer()}"
armatures.append((safe_id, obj.name, "")) # Use the name directly - Blender should handle Unicode in display names
display_name = obj.name
armatures.append((safe_id, display_name, ""))
if not armatures: if not armatures:
return [('NONE', t("Armature.validation.no_armature"), '')] result = [('NONE', t("Armature.validation.no_armature"), '')]
return armatures else:
result = armatures
# Cache the result
get_armature_list._cache_key = cache_key
get_armature_list._cached_items = result
return result
def auto_select_single_armature(context: Context) -> None: def auto_select_single_armature(context: Context) -> None:
"""Automatically select armature if only one exists in scene""" """Automatically select armature if only one exists in scene"""
+124
View File
@@ -174,6 +174,130 @@ physics_names: Dict[str, List[str]] = {
"breast_tip": ["胸先", "むねさき", "ブレストティップ", "breasttip"], "breast_tip": ["胸先", "むねさき", "ブレストティップ", "breasttip"],
} }
# MMD bone name patterns (for detection)
mmd_bone_patterns: List[str] = [
# Japanese bone names
'全ての親', 'センター', '上半身', '下半身', '', '',
'右腕', '左腕', '右ひじ', '左ひじ', '右手首', '左手首',
'右足', '左足', '右ひざ', '左ひざ', '右足首', '左足首',
'両目', '左目', '右目', '右肩', '左肩',
# English bone names (common in MMD exports)
'center', 'groove', 'waist', 'upperbody', 'upperbody2', 'lowerbody',
'neck', 'head',
'shoulder_r', 'shoulder_l', 'arm_r', 'arm_l',
'elbow_r', 'elbow_l', 'wrist_r', 'wrist_l',
'leg_r', 'leg_l', 'knee_r', 'knee_l',
'ankle_r', 'ankle_l', 'toe_r', 'toe_l',
# Mixed/Romanized patterns
'센터', 'グルーブ', 'ウエスト',
# Common MMD suffixes
'_r', '_l', '.r', '.l'
]
# MMD to Unity bone mapping
# Maps MMD bone names (after English translation) to Unity humanoid bone names
mmd_to_unity_bone_map: Dict[str, Optional[str]] = {
# Root and core
"ParentNode": None, # Remove this
"Center": "Hips",
"センター": "Hips",
"Groove": None, # Remove this
"グルーブ": None,
"Waist": None, # Will be merged into Hips
# Spine chain
"LowerBody": "Hips",
"下半身": "Hips",
"UpperBody": "Spine",
"上半身": "Spine",
"UpperBody2": "Chest",
"上半身2": "Chest",
"Neck": "Neck",
"": "Neck",
"Head": "Head",
"": "Head",
# Right leg
"RightLeg": "Right leg",
"右足": "Right leg",
"RightLegD": None, # Remove D variant
"RightKnee": "Right knee",
"右ひざ": "Right knee",
"RightAnkle": "Right ankle",
"右足首": "Right ankle",
"RightToe": "Right toe",
"右つま先": "Right toe",
# Left leg
"LeftLeg": "Left leg",
"左足": "Left leg",
"LeftLegD": None, # Remove D variant
"LeftKnee": "Left knee",
"左ひざ": "Left knee",
"LeftAnkle": "Left ankle",
"左足首": "Left ankle",
"LeftToe": "Left toe",
"左つま先": "Left toe",
# Right arm
"RightShoulder": "Right shoulder",
"右肩": "Right shoulder",
"RightArm": "Right arm",
"右腕": "Right arm",
"RightElbow": "Right elbow",
"右ひじ": "Right elbow",
"RightWrist": "Right wrist",
"右手首": "Right wrist",
# Left arm
"LeftShoulder": "Left shoulder",
"左肩": "Left shoulder",
"LeftArm": "Left arm",
"左腕": "Left arm",
"LeftElbow": "Left elbow",
"左ひじ": "Left elbow",
"LeftWrist": "Left wrist",
"左手首": "Left wrist",
# Cancel/Helper bones (remove these)
"WaistCancelRight": None,
"WaistCancelLeft": None,
"LegIKParentRight": None,
"LegIKParentLeft": None,
}
# Unity humanoid bone hierarchy
# Defines parent-child relationships for Unity standard
unity_bone_hierarchy: Dict[str, Optional[str]] = {
"Hips": None, # Root bone
"Spine": "Hips",
"Chest": "Spine",
"Neck": "Chest",
"Head": "Neck",
# Arms
"Left shoulder": "Chest",
"Left arm": "Left shoulder",
"Left elbow": "Left arm",
"Left wrist": "Left elbow",
"Right shoulder": "Chest",
"Right arm": "Right shoulder",
"Right elbow": "Right arm",
"Right wrist": "Right elbow",
# Legs
"Left leg": "Hips",
"Left knee": "Left leg",
"Left ankle": "Left knee",
"Left toe": "Left ankle",
"Right leg": "Hips",
"Right knee": "Right leg",
"Right ankle": "Right knee",
"Right toe": "Right ankle",
}
# Create reverse lookup dictionaries # Create reverse lookup dictionaries
reverse_shapekey_lookup: Dict[str, str] = {} reverse_shapekey_lookup: Dict[str, str] = {}
reverse_material_lookup: Dict[str, str] = {} reverse_material_lookup: Dict[str, str] = {}
+96 -3
View File
@@ -67,10 +67,42 @@ def highlight_problem_bones(self: PropertyGroup, context: Context) -> None:
save_preference("highlight_problem_bones", self.highlight_problem_bones) save_preference("highlight_problem_bones", self.highlight_problem_bones)
def get_mesh_objects(self, context): def get_mesh_objects(self, context):
meshes = [(obj.name, obj.name, "") for obj in bpy.data.objects if obj.type == 'MESH'] """Get list of all mesh objects with ASCII-safe identifiers
Returns tuples of (identifier, display_name, description) where:
- identifier: ASCII-safe unique ID (uses object's memory address)
- display_name: The actual object name (can contain Japanese/non-ASCII characters)
- description: Empty string
Uses caching to prevent encoding issues with Blender's EnumProperty system
"""
# Create a cache key based on mesh objects
mesh_objects = [obj for obj in bpy.data.objects if obj.type == 'MESH']
cache_key = tuple((obj.name, obj.as_pointer()) for obj in mesh_objects)
# Check if we have a cached result
if hasattr(get_mesh_objects, '_cache_key') and get_mesh_objects._cache_key == cache_key:
if hasattr(get_mesh_objects, '_cached_items'):
return get_mesh_objects._cached_items
# Build the list
meshes = []
for obj in mesh_objects:
safe_id = f"MESH_{obj.as_pointer()}"
# Use the name directly - Blender should handle Unicode in display names
display_name = obj.name
meshes.append((safe_id, display_name, ""))
if not meshes: if not meshes:
return [('NONE', t("Visemes.no_meshes"), '')] result = [('NONE', t("Visemes.no_meshes"), '')]
return meshes else:
result = meshes
# Cache the result
get_mesh_objects._cache_key = cache_key
get_mesh_objects._cached_items = result
return result
def auto_populate_merge_armatures(context: Context) -> None: def auto_populate_merge_armatures(context: Context) -> None:
"""Auto-populate merge armature fields when there are 2+ armatures""" """Auto-populate merge armature fields when there are 2+ armatures"""
@@ -703,6 +735,67 @@ class AvatarToolkitSceneProperties(PropertyGroup):
default=True default=True
) )
# MMD Conversion Properties
mmd_make_parent: BoolProperty(
name=t("MMD.make_armature_parent"),
description="Remove parent Empty object and make armature the main parent",
default=True
)
mmd_rename_armature: BoolProperty(
name=t("MMD.rename_to_armature"),
description="Rename the armature object to 'Armature'",
default=True
)
mmd_translate_names: BoolProperty(
name=t("MMD.translate_names"),
description="Translate Japanese names to English using MMD dictionary and translation services",
default=True
)
mmd_translate_bones: BoolProperty(
name=t("MMD.translate_bones"),
description="Translate bone names",
default=True
)
mmd_translate_materials: BoolProperty(
name=t("MMD.translate_materials"),
description="Translate material names",
default=True
)
mmd_translate_shapekeys: BoolProperty(
name=t("MMD.translate_shapekeys"),
description="Translate shape key names",
default=True
)
mmd_translate_objects: BoolProperty(
name=t("MMD.translate_objects"),
description="Translate object names",
default=True
)
mmd_restructure_bones: BoolProperty(
name=t("MMD.restructure_bones"),
description="Restructure bone hierarchy to Unity humanoid format (Hips, Spine, Chest, etc.)",
default=True
)
mmd_remove_twist_bones: BoolProperty(
name=t("MMD.remove_twist_bones"),
description="Remove twist bones",
default=True
)
mmd_remove_zero_weight_bones: BoolProperty(
name=t("MMD.remove_zero_weight_bones"),
description="Remove bones with zero or near-zero vertex weights",
default=False
)
# Translation System Properties # Translation System Properties
translation_service: EnumProperty( translation_service: EnumProperty(
name=t("Translation.service"), name=t("Translation.service"),
+2 -2
View File
@@ -92,7 +92,7 @@ class AvatarToolkit_OT_StopPoseMode(Operator):
self.report({'ERROR'}, t("PoseMode.error.stop", error=traceback.format_exc())) self.report({'ERROR'}, t("PoseMode.error.stop", error=traceback.format_exc()))
return {'CANCELLED'} return {'CANCELLED'}
class AvatarToolkit_OT_ApplyPoseAsRest(Operator, BatchPoseOperationMixin): class AvatarToolkit_OT_ApplyPoseAsShapekey(Operator, BatchPoseOperationMixin):
bl_idname = 'avatar_toolkit.apply_pose_as_shapekey' bl_idname = 'avatar_toolkit.apply_pose_as_shapekey'
bl_label = t("QuickAccess.apply_pose_as_shapekey.label") bl_label = t("QuickAccess.apply_pose_as_shapekey.label")
bl_description = t("QuickAccess.apply_pose_as_shapekey.desc") bl_description = t("QuickAccess.apply_pose_as_shapekey.desc")
@@ -136,7 +136,7 @@ class AvatarToolkit_OT_ApplyPoseAsRest(Operator, BatchPoseOperationMixin):
self.report({'ERROR'}, t("PoseMode.error.shapekey", error=traceback.format_exc())) self.report({'ERROR'}, t("PoseMode.error.shapekey", error=traceback.format_exc()))
return {'CANCELLED'} return {'CANCELLED'}
class AvatarToolkit_OT_ApplyPoseAsShapekey(Operator, BatchPoseOperationMixin): class AvatarToolkit_OT_ApplyPoseAsRest(Operator, BatchPoseOperationMixin):
bl_idname = 'avatar_toolkit.apply_pose_as_rest' bl_idname = 'avatar_toolkit.apply_pose_as_rest'
bl_label = t("QuickAccess.apply_pose_as_rest.label") bl_label = t("QuickAccess.apply_pose_as_rest.label")
bl_description = t("QuickAccess.apply_pose_as_rest.desc") bl_description = t("QuickAccess.apply_pose_as_rest.desc")
+8 -4
View File
@@ -137,15 +137,17 @@ class AvatarToolkit_OT_PreviewVisemes(Operator):
return False return False
# Get mesh from UI selection # Get mesh from UI selection
from ..core.common import get_mesh_from_identifier
props = context.scene.avatar_toolkit props = context.scene.avatar_toolkit
mesh_obj = bpy.data.objects.get(props.viseme_mesh) mesh_obj = get_mesh_from_identifier(props.viseme_mesh)
# Validate mesh # Validate mesh
return mesh_obj and mesh_obj.type == 'MESH' return mesh_obj and mesh_obj.type == 'MESH'
def execute(self, context: Context) -> Set[str]: def execute(self, context: Context) -> Set[str]:
from ..core.common import get_mesh_from_identifier
props = context.scene.avatar_toolkit props = context.scene.avatar_toolkit
mesh = bpy.data.objects.get(props.viseme_mesh) mesh = get_mesh_from_identifier(props.viseme_mesh)
if props.viseme_preview_mode: if props.viseme_preview_mode:
VisemePreview.end_preview(mesh) VisemePreview.end_preview(mesh)
@@ -191,15 +193,17 @@ class AvatarToolkit_OT_CreateVisemes(Operator):
return False return False
# Get mesh from UI selection # Get mesh from UI selection
from ..core.common import get_mesh_from_identifier
props = context.scene.avatar_toolkit props = context.scene.avatar_toolkit
mesh_obj = bpy.data.objects.get(props.viseme_mesh) mesh_obj = get_mesh_from_identifier(props.viseme_mesh)
# Validate mesh # Validate mesh
return mesh_obj and mesh_obj.type == 'MESH' return mesh_obj and mesh_obj.type == 'MESH'
def execute(self, context: Context) -> Set[str]: def execute(self, context: Context) -> Set[str]:
from ..core.common import get_mesh_from_identifier
props = context.scene.avatar_toolkit props = context.scene.avatar_toolkit
mesh = bpy.data.objects.get(props.viseme_mesh) # Changed from context.active_object mesh = get_mesh_from_identifier(props.viseme_mesh)
if not mesh or not mesh.data.shape_keys: if not mesh or not mesh.data.shape_keys:
self.report({'ERROR'}, t("Visemes.error.no_shapekeys")) self.report({'ERROR'}, t("Visemes.error.no_shapekeys"))
+74 -1
View File
@@ -1,7 +1,7 @@
{ {
"authors": ["Avatar Toolkit Team"], "authors": ["Avatar Toolkit Team"],
"messages": { "messages": {
"AvatarToolkit.label": "Avatar Toolkit (Alpha 0.5.2)", "AvatarToolkit.label": "Avatar Toolkit (Alpha 0.6.0)",
"AvatarToolkit.desc1": "Avatar Toolkit is in Early Access there", "AvatarToolkit.desc1": "Avatar Toolkit is in Early Access there",
"AvatarToolkit.desc2": "will be issues, if you find any issues,", "AvatarToolkit.desc2": "will be issues, if you find any issues,",
"AvatarToolkit.desc3": "please report it on our Github.", "AvatarToolkit.desc3": "please report it on our Github.",
@@ -601,6 +601,79 @@
"VRM.remove_root": "Remove Root Bone", "VRM.remove_root": "Remove Root Bone",
"VRM.remove_root_desc": "Remove unnecessary VRM root bone and make Hips the root bone", "VRM.remove_root_desc": "Remove unnecessary VRM root bone and make Hips the root bone",
"MMD.panel.label": "MMD Converter",
"MMD.converter.title": "MMD Armature Converter",
"MMD.no_armature_selected": "No armature selected",
"MMD.select_armature_to_convert": "Select an armature to convert",
"MMD.armature_name": "Armature: {name}",
"MMD.armature_detected": "MMD armature detected",
"MMD.no_mmd_bones_detected": "No MMD bones detected",
"MMD.not_mmd_armature": "Selected armature does not appear to be MMD format",
"MMD.make_armature_parent": "Make Armature Main Parent",
"MMD.rename_to_armature": "Rename to 'Armature'",
"MMD.translate_names": "Translate Names to English",
"MMD.translate_bones": "Bones",
"MMD.translate_materials": "Materials",
"MMD.translate_shapekeys": "Shape Keys",
"MMD.translate_objects": "Objects",
"MMD.restructure_bones": "Restructure to Unity Format",
"MMD.bone_cleanup": "Bone Cleanup Options:",
"MMD.remove_ik_bones": "Remove IK Bones",
"MMD.remove_twist_bones": "Remove Twist Bones",
"MMD.remove_zero_weight_bones": "Remove Zero Weight Bones",
"MMD.translation_options": "Translation Options:",
"MMD.convert_armature_button": "Convert MMD Armature",
"MMD.convert_armature.label": "Convert MMD Armature",
"MMD.convert_armature.desc": "Convert MMD armature to standard Blender format",
"MMD.conversion_info.title": "Conversion Info:",
"MMD.conversion_info.removes_parent": "• Removes parent Empty object",
"MMD.conversion_info.renames_armature": "• Renames armature to 'Armature'",
"MMD.conversion_info.restructures_bones": "• Converts to Unity bone structure (Hips/Spine/Chest)",
"MMD.conversion_info.removes_ik_bones": "• Removes IK (Inverse Kinematics) bones",
"MMD.conversion_info.removes_twist_bones": "• Removes twist bones",
"MMD.conversion_info.removes_zero_weight_bones": "• Removes bones with zero vertex weights",
"MMD.conversion_info.maintains_hierarchy": "• Maintains object hierarchy",
"MMD.conversion_info.translates_names": "• Translates Japanese names to English",
"MMD.detection_failed.title": "MMD Detection Failed:",
"MMD.detection_failed.not_mmd_format": "• Selected armature is not MMD format",
"MMD.detection_failed.need_mmd_bones": "• Need at least 5 MMD bones detected",
"MMD.detection_failed.check_bone_names": "• Check armature bone names",
"MMD.error.invalid_armature": "Invalid armature object",
"MMD.error.not_mmd_armature": "Armature does not appear to be MMD format",
"MMD.error.rename_failed": "Failed to rename armature: {error}",
"MMD.armature_already_root": "Armature already has no parent",
"MMD.armature_already_named": "Armature is already named 'Armature'",
"MMD.parent_removed_and_reparented": "Removed parent '{parent_name}' and reparented {count} objects to armature",
"MMD.parent_unlinked_and_reparented": "Unlinked from parent '{parent_name}' and reparented {count} objects",
"MMD.parent_unlinked": "Unlinked armature from parent '{parent_name}'",
"MMD.armature_renamed": "Renamed armature from '{old_name}' to '{new_name}'",
"MMD.armature_renamed_with_suffix": "Renamed armature from '{old_name}' to '{new_name}' (name collision)",
"MMD.conversion_complete": "MMD armature conversion completed successfully",
"MMD.translation_starting": "Starting name translation...",
"MMD.bones_translated": "Translated {count} bones",
"MMD.bones_failed": "Failed to translate {count} bones",
"MMD.materials_translated": "Translated {count} materials",
"MMD.materials_failed": "Failed to translate {count} materials",
"MMD.shapekeys_translated": "Translated {count} shape keys",
"MMD.shapekeys_failed": "Failed to translate {count} shape keys",
"MMD.objects_translated": "Translated {count} objects",
"MMD.objects_failed": "Failed to translate {count} objects",
"MMD.translation_complete": "Translation complete: {total} items translated",
"MMD.restructure_starting": "Restructuring bones to Unity format...",
"MMD.bones_restructured": "Restructured {count} bones to Unity format",
"MMD.bones_removed": "Removed {count} unnecessary bones",
"MMD.bones_reparented": "Reparented {count} bones",
"MMD.restructure_failed": "Bone restructuring failed: {error}",
"MMD.ik_bones_removed": "Removed {count} IK bones",
"MMD.no_ik_bones_found": "No IK bones found to remove",
"MMD.ik_removal_failed": "IK bone removal failed: {error}",
"MMD.twist_bones_removed": "Removed {count} twist bones",
"MMD.no_twist_bones_found": "No twist bones found to remove",
"MMD.twist_removal_failed": "Twist bone removal failed: {error}",
"MMD.zero_weight_bones_removed": "Removed {count} zero weight bones",
"MMD.no_zero_weight_bones_found": "No zero weight bones found to remove",
"MMD.zero_weight_removal_failed": "Zero weight bone removal failed: {error}",
"Translation.label": "Translation", "Translation.label": "Translation",
"Translation.service": "Translation Service", "Translation.service": "Translation Service",
"Translation.service_desc": "Choose the translation service to use", "Translation.service_desc": "Choose the translation service to use",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"authors": ["Avatar Toolkit Team"], "authors": ["Avatar Toolkit Team"],
"messages": { "messages": {
"AvatarToolkit.label": "アバターツールキット (アルファ 0.5.2)", "AvatarToolkit.label": "アバターツールキット (アルファ 0.6.0)",
"AvatarToolkit.desc1": "アバターツールキットは早期アクセス中であり、", "AvatarToolkit.desc1": "アバターツールキットは早期アクセス中であり、",
"AvatarToolkit.desc2": "問題が発生する可能性があります。問題を見つけた場合は、", "AvatarToolkit.desc2": "問題が発生する可能性があります。問題を見つけた場合は、",
"AvatarToolkit.desc3": "GitHubで報告してください。", "AvatarToolkit.desc3": "GitHubで報告してください。",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"authors": ["Avatar Toolkit Team"], "authors": ["Avatar Toolkit Team"],
"messages": { "messages": {
"AvatarToolkit.label": "아바타 툴킷 (알파 0.5.2)", "AvatarToolkit.label": "아바타 툴킷 (알파 0.6.0)",
"AvatarToolkit.desc1": "아바타 툴킷은 초기 액세스 단계에 있으므로", "AvatarToolkit.desc1": "아바타 툴킷은 초기 액세스 단계에 있으므로",
"AvatarToolkit.desc2": "문제가 있을 수 있습니다. 문제를 발견하시면", "AvatarToolkit.desc2": "문제가 있을 수 있습니다. 문제를 발견하시면",
"AvatarToolkit.desc3": "Github에 보고해 주세요.", "AvatarToolkit.desc3": "Github에 보고해 주세요.",
+4 -1
View File
@@ -14,7 +14,8 @@ VISEMES_ORDER = 6
EYE_TRACKING_ORDER = 7 EYE_TRACKING_ORDER = 7
TEXTURE_ATLAS_ORDER = 8 TEXTURE_ATLAS_ORDER = 8
VRM_UNITY_ORDER = 9 VRM_UNITY_ORDER = 9
SETTINGS_ORDER = 10 MMD_ORDER = 10
SETTINGS_ORDER = 11
# Panel open/closed by default # Panel open/closed by default
PANELS_OPEN_BY_DEFAULT = { PANELS_OPEN_BY_DEFAULT = {
@@ -27,6 +28,7 @@ PANELS_OPEN_BY_DEFAULT = {
'EYE_TRACKING': True, 'EYE_TRACKING': True,
'TEXTURE_ATLAS': True, 'TEXTURE_ATLAS': True,
'VRM_UNITY': True, 'VRM_UNITY': True,
'MMD': True,
'SETTINGS': True, 'SETTINGS': True,
'TRANSLATION': True, 'TRANSLATION': True,
} }
@@ -44,6 +46,7 @@ def get_panel_order(panel_name: str) -> int:
'eye_tracking': EYE_TRACKING_ORDER, 'eye_tracking': EYE_TRACKING_ORDER,
'texture_atlas': TEXTURE_ATLAS_ORDER, 'texture_atlas': TEXTURE_ATLAS_ORDER,
'vrm_unity': VRM_UNITY_ORDER, 'vrm_unity': VRM_UNITY_ORDER,
'mmd': MMD_ORDER,
'settings': SETTINGS_ORDER, 'settings': SETTINGS_ORDER,
} }
return order_map.get(panel_name.lower(), 99) return order_map.get(panel_name.lower(), 99)
+3 -2
View File
@@ -34,8 +34,9 @@ class AvatarToolKit_PT_VisemesPanel(Panel):
else: else:
col.label(text=t("Visemes.no_armature"), icon='ERROR') col.label(text=t("Visemes.no_armature"), icon='ERROR')
# Get selected mesh # Get selected mesh using safe identifier
mesh_obj = bpy.data.objects.get(props.viseme_mesh) from ..core.common import get_mesh_from_identifier
mesh_obj = get_mesh_from_identifier(props.viseme_mesh)
if not mesh_obj or not mesh_obj.data or not mesh_obj.data.shape_keys: if not mesh_obj or not mesh_obj.data or not mesh_obj.data.shape_keys:
layout.label(text=t("Visemes.no_shapekeys")) layout.label(text=t("Visemes.no_shapekeys"))
return return