Merge branch 'main' into RemoveUnusedShapekeys

This commit is contained in:
Onan Chew
2024-09-10 20:36:38 -04:00
committed by GitHub
21 changed files with 281 additions and 93 deletions
+8 -8
View File
@@ -21,7 +21,7 @@ class SceneMatClass(PropertyGroup):
register_class(SceneMatClass) register_class(SceneMatClass)
class material_list_bool: class MaterialListBool:
#For the love that is holy do not ever touch these. If this was java I would make these private #For the love that is holy do not ever touch these. If this was java I would make these private
#They should only be accessed via context.scene.texture_atlas_Has_Mat_List_Shown #They should only be accessed via context.scene.texture_atlas_Has_Mat_List_Shown
#This is so we know if the materials are up to date. messing with these variables directly will make the thing blow up. #This is so we know if the materials are up to date. messing with these variables directly will make the thing blow up.
@@ -31,9 +31,9 @@ class material_list_bool:
bool_material_list_expand: dict[str,bool] = {} bool_material_list_expand: dict[str,bool] = {}
def set_bool(self, value: bool) -> None: def set_bool(self, value: bool) -> None:
material_list_bool.bool_material_list_expand[bpy.context.scene.name] = value MaterialListBool.bool_material_list_expand[bpy.context.scene.name] = value
if value == False: if value == False:
material_list_bool.old_list[bpy.context.scene.name] = [] MaterialListBool.old_list[bpy.context.scene.name] = []
def get_bool(self) -> bool: def get_bool(self) -> bool:
newlist: list[Material] = [] newlist: list[Material] = []
@@ -45,20 +45,20 @@ class material_list_bool:
newlist.append(mat_slot.material) newlist.append(mat_slot.material)
still_the_same: bool = True still_the_same: bool = True
if bpy.context.scene.name in material_list_bool.old_list: if bpy.context.scene.name in MaterialListBool.old_list:
for item in newlist: for item in newlist:
if item not in material_list_bool.old_list[bpy.context.scene.name]: if item not in MaterialListBool.old_list[bpy.context.scene.name]:
still_the_same = False still_the_same = False
break break
for item in material_list_bool.old_list[bpy.context.scene.name]: for item in MaterialListBool.old_list[bpy.context.scene.name]:
if item not in newlist: if item not in newlist:
still_the_same = False still_the_same = False
break break
else: else:
still_the_same = False still_the_same = False
material_list_bool.bool_material_list_expand[bpy.context.scene.name] = still_the_same MaterialListBool.bool_material_list_expand[bpy.context.scene.name] = still_the_same
return material_list_bool.bool_material_list_expand[bpy.context.scene.name] return MaterialListBool.bool_material_list_expand[bpy.context.scene.name]
### Clean up material names in the given mesh by removing the '.001' suffix. ### Clean up material names in the given mesh by removing the '.001' suffix.
+1 -1
View File
@@ -9,7 +9,7 @@ from ..functions.translations import t
@register_wrap @register_wrap
class ExportResonite(Operator): class AvatarToolKit_OT_ExportResonite(Operator):
bl_idname = 'avatar_toolkit.export_resonite' bl_idname = 'avatar_toolkit.export_resonite'
bl_label = t("Importer.export_resonite.label") bl_label = t("Importer.export_resonite.label")
bl_description = t("Importer.export_resonite.desc") bl_description = t("Importer.export_resonite.desc")
+3 -3
View File
@@ -4,7 +4,7 @@ from ..core.register import register_property
from bpy.types import Scene, Object, Material, Context from bpy.types import Scene, Object, Material, Context
from bpy.props import BoolProperty, EnumProperty, IntProperty, CollectionProperty, StringProperty, FloatVectorProperty, PointerProperty from bpy.props import BoolProperty, EnumProperty, IntProperty, CollectionProperty, StringProperty, FloatVectorProperty, PointerProperty
from ..core.addon_preferences import get_preference from ..core.addon_preferences import get_preference
from ..core.common import SceneMatClass, material_list_bool, get_armatures, get_mesh_items from ..core.common import SceneMatClass, MaterialListBool, get_armatures, get_mesh_items
def register() -> None: def register() -> None:
default_language = get_preference("language", 0) default_language = get_preference("language", 0)
@@ -106,8 +106,8 @@ def register() -> None:
register_property((Scene, "texture_atlas_Has_Mat_List_Shown", BoolProperty( register_property((Scene, "texture_atlas_Has_Mat_List_Shown", BoolProperty(
default=False, default=False,
get=material_list_bool.get_bool, get=MaterialListBool.get_bool,
set=material_list_bool.set_bool))) set=MaterialListBool.set_bool)))
def unregister() -> None: def unregister() -> None:
+1 -1
View File
@@ -5,7 +5,7 @@ from ..core.common import get_selected_armature, is_valid_armature, get_all_mesh
from ..functions.translations import t from ..functions.translations import t
@register_wrap @register_wrap
class ApplyTransforms(Operator): class AvatarToolKit_OT_ApplyTransforms(Operator):
bl_idname = "avatar_toolkit.apply_transforms" bl_idname = "avatar_toolkit.apply_transforms"
bl_label = t("Tools.apply_transforms.label") bl_label = t("Tools.apply_transforms.label")
bl_description = t("Tools.apply_transforms.desc") bl_description = t("Tools.apply_transforms.desc")
+2 -4
View File
@@ -2,13 +2,11 @@ from pathlib import Path
import numpy import numpy
import bpy import bpy
import re
import os import os
from typing import List, Tuple, Optional from typing import List, Tuple, Optional
from mathutils import Vector
from bpy.types import Material, Operator, Context, Object, Image, Mesh, MeshUVLoopLayer, Float2AttributeValue, ShaderNodeTexImage, ShaderNodeBsdfPrincipled, ShaderNodeNormalMap from bpy.types import Material, Operator, Context, Object, Image, Mesh, MeshUVLoopLayer, Float2AttributeValue, ShaderNodeTexImage, ShaderNodeBsdfPrincipled, ShaderNodeNormalMap
from ..core.register import register_wrap from ..core.register import register_wrap
from ..core.common import SceneMatClass, material_list_bool from ..core.common import SceneMatClass, MaterialListBool
from ..core.packer.rectangle_packer import MaterialImageList, BinPacker from ..core.packer.rectangle_packer import MaterialImageList, BinPacker
from ..functions.translations import t from ..functions.translations import t
@@ -113,7 +111,7 @@ def prep_images_in_scene(context: Context) -> list[MaterialImageList]:
@register_wrap @register_wrap
class Atlas_Materials(Operator): class AvatarToolKit_OT_AtlasMaterials(Operator):
bl_idname = "avatar_toolkit.atlas_materials" bl_idname = "avatar_toolkit.atlas_materials"
bl_label = t("TextureAtlas.atlas_materials") bl_label = t("TextureAtlas.atlas_materials")
+1 -1
View File
@@ -53,7 +53,7 @@ def get_base_name(name: str) -> str:
return mat_match.group(1) if mat_match else name return mat_match.group(1) if mat_match else name
@register_wrap @register_wrap
class CombineMaterials(Operator): class AvatarToolKit_OT_CombineMaterials(Operator):
bl_idname = "avatar_toolkit.combine_materials" bl_idname = "avatar_toolkit.combine_materials"
bl_label = t("Optimization.combine_materials.label") bl_label = t("Optimization.combine_materials.label")
bl_description = t("Optimization.combine_materials.desc") bl_description = t("Optimization.combine_materials.desc")
+2 -2
View File
@@ -6,8 +6,8 @@ import re
@register_wrap @register_wrap
class CreateDigitigradeLegs(bpy.types.Operator): class AvatarToolKit_OT_CreateDigitigradeLegs(bpy.types.Operator):
bl_idname = "avatar_toolkit.createdigitigradelegs" bl_idname = "avatar_toolkit.create_digitigrade_legs"
bl_label = t('Tools.create_digitigrade_legs.label') bl_label = t('Tools.create_digitigrade_legs.label')
bl_description = t('Tools.create_digitigrade_legs.desc') bl_description = t('Tools.create_digitigrade_legs.desc')
+5 -6
View File
@@ -3,14 +3,13 @@ from bpy.types import Operator
from bpy_extras.io_utils import ImportHelper from bpy_extras.io_utils import ImportHelper
from ..core.register import register_wrap from ..core.register import register_wrap
from ..core.importer import imports, import_types from ..core.importer import imports, import_types
from ..core.common import remove_default_objects from ..core.common import remove_default_objects, open_web_after_delay_multi_threaded
from ..functions.translations import t from ..functions.translations import t
import pathlib import pathlib
import os import os
from ..core import common
@register_wrap @register_wrap
class ImportAnyModel(Operator, ImportHelper): class AvatarToolKit_OT_ImportAnyModel(Operator, ImportHelper):
bl_idname = 'avatar_toolkit.import_any_model' bl_idname = 'avatar_toolkit.import_any_model'
bl_label = t('Tools.import_any_model.label') bl_label = t('Tools.import_any_model.label')
bl_description = t('Tools.import_any_model.desc') bl_description = t('Tools.import_any_model.desc')
@@ -24,7 +23,7 @@ class ImportAnyModel(Operator, ImportHelper):
#since I wrote this myself, a bit more efficent than cats. mostly - @989onan #since I wrote this myself, a bit more efficent than cats. mostly - @989onan
def execute(self, context: bpy.types.Context): def execute(self, context: bpy.types.Context):
file_grouping_dict: dict[str, list[dict[str,str]]] = dict()#group our files so our importers can import them together. in the case of OBJ+MTL and others that need grouped files, this is extremely important. file_grouping_dict: dict[str, list[dict[str,str]]] = dict()#group our files so our importers can import them together. in the case of OBJ+MTL and others that need grouped files, this is extremely important.
common.remove_default_objects() remove_default_objects()
#check if we are importing multiple files #check if we are importing multiple files
is_multi = False is_multi = False
try: try:
@@ -69,9 +68,9 @@ class ImportAnyModel(Operator, ImportHelper):
else: else:
import_types[file_group_name]("",files,self.filepath) #give an empty directory, works just fine for 90% import_types[file_group_name]("",files,self.filepath) #give an empty directory, works just fine for 90%
except AttributeError as e: except AttributeError as e:
print("Warning, you may not have the required importer!") print("Warning, you may not have the required importer for extension type \"{extension}\"!".format(extension = file_group_name))
common.open_web_after_delay_multi_threaded(delay=12, url=t('Importing.importer_search_term').format(extension = file_group_name)) open_web_after_delay_multi_threaded(delay=12, url=t('Importing.importer_search_term').format(extension = file_group_name))
self.report({'ERROR'},t('Importing.need_importer').format(extension = file_group_name)) self.report({'ERROR'},t('Importing.need_importer').format(extension = file_group_name))
+2 -2
View File
@@ -6,7 +6,7 @@ from ..core.common import fix_uv_coordinates, get_selected_armature, is_valid_ar
from ..functions.translations import t from ..functions.translations import t
@register_wrap @register_wrap
class JoinAllMeshes(Operator): class AvatarToolKit_OT_JoinAllMeshes(Operator):
bl_idname = "avatar_toolkit.join_all_meshes" bl_idname = "avatar_toolkit.join_all_meshes"
bl_label = t("Optimization.join_all_meshes.label") bl_label = t("Optimization.join_all_meshes.label")
bl_description = t("Optimization.join_all_meshes.desc") bl_description = t("Optimization.join_all_meshes.desc")
@@ -72,7 +72,7 @@ class JoinAllMeshes(Operator):
finish_progress(context) finish_progress(context)
@register_wrap @register_wrap
class JoinSelectedMeshes(Operator): class AvatarToolKit_OT_JoinSelectedMeshes(Operator):
bl_idname = "avatar_toolkit.join_selected_meshes" bl_idname = "avatar_toolkit.join_selected_meshes"
bl_label = t("Optimization.join_selected_meshes.label") bl_label = t("Optimization.join_selected_meshes.label")
bl_description = t("Optimization.join_selected_meshes.desc") bl_description = t("Optimization.join_selected_meshes.desc")
+2 -2
View File
@@ -12,7 +12,7 @@ class meshEntry(TypedDict):
cur_vertex_pass: int cur_vertex_pass: int
@register_wrap @register_wrap
class RemoveDoublesSafelyAdvanced(Operator): class AvatarToolKit_OT_RemoveDoublesSafelyAdvanced(Operator):
bl_idname = "avatar_toolkit.remove_doubles_safely_advanced" bl_idname = "avatar_toolkit.remove_doubles_safely_advanced"
bl_label = t("Optimization.remove_doubles_safely_advanced.label") bl_label = t("Optimization.remove_doubles_safely_advanced.label")
bl_description = t("Optimization.remove_doubles_safely_advanced.desc") bl_description = t("Optimization.remove_doubles_safely_advanced.desc")
@@ -30,7 +30,7 @@ class RemoveDoublesSafelyAdvanced(Operator):
bpy.ops.avatar_toolkit.remove_doubles_safely('INVOKE_DEFAULT',advanced=True,merge_distance=self.merge_distance) bpy.ops.avatar_toolkit.remove_doubles_safely('INVOKE_DEFAULT',advanced=True,merge_distance=self.merge_distance)
return {'FINISHED'} return {'FINISHED'}
@register_wrap @register_wrap
class RemoveDoublesSafely(Operator): class AvatarToolKit_OT_RemoveDoublesSafely(Operator):
bl_idname = "avatar_toolkit.remove_doubles_safely" bl_idname = "avatar_toolkit.remove_doubles_safely"
bl_label = t("Optimization.remove_doubles_safely.label") bl_label = t("Optimization.remove_doubles_safely.label")
bl_description = t("Optimization.remove_doubles_safely.desc") bl_description = t("Optimization.remove_doubles_safely.desc")
+1 -1
View File
@@ -8,7 +8,7 @@ from ..core.common import get_selected_armature, simplify_bonename, is_valid_arm
from ..functions.translations import t from ..functions.translations import t
@register_wrap @register_wrap
class ConvertToResonite(Operator): class AvatarToolKit_OT_ConvertToResonite(Operator):
bl_idname = 'avatar_toolkit.convert_to_resonite' bl_idname = 'avatar_toolkit.convert_to_resonite'
bl_label = t('Tools.convert_to_resonite.label') bl_label = t('Tools.convert_to_resonite.label')
bl_description = t('Tools.convert_to_resonite.desc') bl_description = t('Tools.convert_to_resonite.desc')
+2 -3
View File
@@ -1,11 +1,10 @@
import bpy import bpy
from bpy.types import Context, Operator from bpy.types import Context, Operator
from ..core.register import register_wrap from ..core.register import register_wrap
from ..core.common import get_selected_armature, is_valid_armature, select_current_armature
from ..functions.translations import t from ..functions.translations import t
@register_wrap @register_wrap
class SeparateByMaterials(Operator): class AvatarToolKit_OT_SeparateByMaterials(Operator):
bl_idname = "avatar_toolkit.separate_by_materials" bl_idname = "avatar_toolkit.separate_by_materials"
bl_label = t("Tools.separate_by_materials.label") bl_label = t("Tools.separate_by_materials.label")
bl_description = t("Tools.separate_by_materials.desc") bl_description = t("Tools.separate_by_materials.desc")
@@ -25,7 +24,7 @@ class SeparateByMaterials(Operator):
return {'FINISHED'} return {'FINISHED'}
@register_wrap @register_wrap
class SeparateByLooseParts(Operator): class AvatarToolKit_OT_SeparateByLooseParts(Operator):
bl_idname = "avatar_toolkit.separate_by_loose_parts" bl_idname = "avatar_toolkit.separate_by_loose_parts"
bl_label = t("Tools.separate_by_loose_parts.label") bl_label = t("Tools.separate_by_loose_parts.label")
bl_description = t("Tools.separate_by_loose_parts.desc") bl_description = t("Tools.separate_by_loose_parts.desc")
+1 -1
View File
@@ -6,7 +6,7 @@ from typing import List, Tuple
from ..core.common import get_selected_armature, is_valid_armature, get_all_meshes, init_progress, update_progress, finish_progress from ..core.common import get_selected_armature, is_valid_armature, get_all_meshes, init_progress, update_progress, finish_progress
@register_wrap @register_wrap
class AutoVisemeButton(bpy.types.Operator): class AvatarToolKit_OT_AutoVisemeButton(bpy.types.Operator):
bl_idname = 'avatar_toolkit.create_visemes' bl_idname = 'avatar_toolkit.create_visemes'
bl_label = t('AutoVisemeButton.label') bl_label = t('AutoVisemeButton.label')
bl_description = t('AutoVisemeButton.desc') bl_description = t('AutoVisemeButton.desc')
+9
View File
@@ -79,6 +79,15 @@
"Quick_Access.label": "Quick Access", "Quick_Access.label": "Quick Access",
"Quick_Access.options": "Quick Access:", "Quick_Access.options": "Quick Access:",
"Quick_Access.select_armature": "Select Armature:", "Quick_Access.select_armature": "Select Armature:",
"Quick_Access.apply_armature_failed": "Applying armature as pose failed at the joining shapekeys back together stage!",
"Quick_Access.apply_pose_as_rest.desc": "Makes current pose the default rest pose.",
"Quick_Access.stop_pose_mode.desc": "Exits pose mode and clears all posing on all visible bones in pose mode.",
"Quick_Access.apply_pose_as_rest.label": "Apply Pose as Rest Pose",
"Quick_Access.apply_pose_as_shapekey.desc": "Makes the current pose a shapekey that can be activated later.\nThis is good for applying a jaw open position as a shapekey for facial movements.",
"Quick_Access.apply_pose_as_shapekey.label": "Apply Pose as Shapekey",
"Quick_Access.stop_pose_mode.label": "Exit Pose Mode",
"Quick_Access.start_pose_mode.desc": "Starts pose mode for the armature targeted by Avatar Toolkit.",
"Quick_Access.start_pose_mode.label": "Start Pose Mode",
"Quick_Access.select_export.label": "Select Export Method", "Quick_Access.select_export.label": "Select Export Method",
"Quick_Access.select_export_resonite.label": "Resonite", "Quick_Access.select_export_resonite.label": "Resonite",
"Settings.label": "Settings", "Settings.label": "Settings",
+12 -12
View File
@@ -1,13 +1,13 @@
from bpy.types import UIList, Panel, UILayout, Object, Context,Material, Operator from bpy.types import UIList, Panel, UILayout, Object, Context,Material, Operator
import bpy import bpy
from ..core.register import register_wrap from ..core.register import register_wrap
from .panel import AvatarToolkitPanel from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME
from ..core.common import SceneMatClass, material_list_bool, get_selected_armature from ..core.common import SceneMatClass, MaterialListBool, get_selected_armature
from ..functions.atlas_materials import Atlas_Materials from ..functions.atlas_materials import AvatarToolKit_OT_AtlasMaterials
from ..functions.translations import t from ..functions.translations import t
@register_wrap @register_wrap
class ExpandSection_Materials(Operator): class AvatarToolKit_OT_ExpandSectionMaterials(Operator):
bl_idname = 'avatar_toolkit.expand_section_materials' bl_idname = 'avatar_toolkit.expand_section_materials'
bl_label = "" bl_label = ""
bl_description = "" bl_description = ""
@@ -28,13 +28,13 @@ class ExpandSection_Materials(Operator):
newlist.append(mat_slot.material) newlist.append(mat_slot.material)
newitem: SceneMatClass = context.scene.materials.add() newitem: SceneMatClass = context.scene.materials.add()
newitem.mat = mat_slot.material newitem.mat = mat_slot.material
material_list_bool.old_list[context.scene.name] = newlist MaterialListBool.old_list[context.scene.name] = newlist
else: else:
context.scene.texture_atlas_Has_Mat_List_Shown = False context.scene.texture_atlas_Has_Mat_List_Shown = False
return {'FINISHED'} return {'FINISHED'}
@register_wrap @register_wrap
class MaterialTextureAtlasProperties(UIList): class AvatarToolKit_UL_MaterialTextureAtlasProperties(UIList):
bl_label = t("TextureAtlas.material_list_label") bl_label = t("TextureAtlas.material_list_label")
bl_idname = "Material_UL_avatar_toolkit_texture_atlas_mat_list_mat" bl_idname = "Material_UL_avatar_toolkit_texture_atlas_mat_list_mat"
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
@@ -59,13 +59,13 @@ class MaterialTextureAtlasProperties(UIList):
col.prop(item.mat, "texture_atlas_roughness") col.prop(item.mat, "texture_atlas_roughness")
@register_wrap @register_wrap
class TextureAtlasPanel(Panel): class AvatarToolKit_PT_TextureAtlasPanel(Panel):
bl_label = t("TextureAtlas.label") bl_label = t("TextureAtlas.label")
bl_idname = "OBJECT_PT_avatar_toolkit_texture_atlas" bl_idname = "OBJECT_PT_avatar_toolkit_texture_atlas"
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
bl_region_type = 'UI' bl_region_type = 'UI'
bl_category = "Avatar Toolkit" bl_category = CATEGORY_NAME
bl_parent_id = "OBJECT_PT_avatar_toolkit" bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order = 4 bl_order = 4
def draw(self, context: Context): def draw(self, context: Context):
@@ -77,12 +77,12 @@ class TextureAtlasPanel(Panel):
boxoutter = row.box() boxoutter = row.box()
direction_icon = 'RIGHTARROW' if not context.scene.texture_atlas_Has_Mat_List_Shown else 'DOWNARROW_HLT' direction_icon = 'RIGHTARROW' if not context.scene.texture_atlas_Has_Mat_List_Shown else 'DOWNARROW_HLT'
row = boxoutter.row() row = boxoutter.row()
row.operator(ExpandSection_Materials.bl_idname, text=(t("TextureAtlas.reload_list") if not context.scene.texture_atlas_Has_Mat_List_Shown else t("TextureAtlas.loaded_list")), icon=direction_icon) row.operator(AvatarToolKit_OT_ExpandSectionMaterials.bl_idname, text=(t("TextureAtlas.reload_list") if not context.scene.texture_atlas_Has_Mat_List_Shown else t("TextureAtlas.loaded_list")), icon=direction_icon)
if context.scene.texture_atlas_Has_Mat_List_Shown: if context.scene.texture_atlas_Has_Mat_List_Shown:
row = boxoutter.row() row = boxoutter.row()
row.template_list(MaterialTextureAtlasProperties.bl_idname, 'material_list', context.scene, 'materials', row.template_list(AvatarToolKit_UL_MaterialTextureAtlasProperties.bl_idname, 'material_list', context.scene, 'materials',
context.scene, 'texture_atlas_material_index', rows=12, type='DEFAULT') context.scene, 'texture_atlas_material_index', rows=12, type='DEFAULT')
row = layout.row() row = layout.row()
row.operator(Atlas_Materials.bl_idname, text=t("TextureAtlas.atlas_materials")) row.operator(AvatarToolKit_OT_AtlasMaterials.bl_idname, text=t("TextureAtlas.atlas_materials"))
else: else:
layout.label(text=t("Tools.select_armature"), icon='ERROR') layout.label(text=t("Tools.select_armature"), icon='ERROR')
+12 -10
View File
@@ -1,18 +1,20 @@
import bpy import bpy
from ..core.register import register_wrap from ..core.register import register_wrap
from .panel import AvatarToolkitPanel from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME
from ..functions.translations import t from ..functions.translations import t
from ..functions.remove_doubles_safely import RemoveDoublesSafely, RemoveDoublesSafelyAdvanced from ..functions.remove_doubles_safely import AvatarToolKit_OT_RemoveDoublesSafely, AvatarToolKit_OT_RemoveDoublesSafelyAdvanced
from ..core.common import get_selected_armature from ..core.common import get_selected_armature
from ..functions.join_meshes import AvatarToolKit_OT_JoinAllMeshes, AvatarToolKit_OT_JoinSelectedMeshes
from ..functions.combine_materials import AvatarToolKit_OT_CombineMaterials
@register_wrap @register_wrap
class AvatarToolkitOptimizationPanel(bpy.types.Panel): class AvatarToolkit_PT_OptimizationPanel(bpy.types.Panel):
bl_label = t("Optimization.label") bl_label = t("Optimization.label")
bl_idname = "OBJECT_PT_avatar_toolkit_optimization" bl_idname = "OBJECT_PT_avatar_toolkit_optimization"
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
bl_region_type = 'UI' bl_region_type = 'UI'
bl_category = "Avatar Toolkit" bl_category = CATEGORY_NAME
bl_parent_id = "OBJECT_PT_avatar_toolkit" bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order = 2 bl_order = 2
def draw(self, context): def draw(self, context):
@@ -24,18 +26,18 @@ class AvatarToolkitOptimizationPanel(bpy.types.Panel):
row = layout.row() row = layout.row()
row.scale_y = 1.2 row.scale_y = 1.2
row.operator("avatar_toolkit.combine_materials", text=t("Optimization.combine_materials.label"), icon='MATERIAL') row.operator(AvatarToolKit_OT_CombineMaterials.bl_idname, text=t("Optimization.combine_materials.label"), icon='MATERIAL')
row = layout.row(align=True) row = layout.row(align=True)
row.scale_y = 1.2 row.scale_y = 1.2
row.operator(RemoveDoublesSafely.bl_idname, text=t("Optimization.remove_doubles_safely.label"), icon='SNAP_VERTEX') row.operator(AvatarToolKit_OT_RemoveDoublesSafely.bl_idname, text=t("Optimization.remove_doubles_safely.label"), icon='SNAP_VERTEX')
row.operator(RemoveDoublesSafelyAdvanced.bl_idname, text=t("Optimization.remove_doubles_safely_advanced.label"), icon = "ACTION") row.operator(AvatarToolKit_OT_RemoveDoublesSafelyAdvanced.bl_idname, text=t("Optimization.remove_doubles_safely_advanced.label"), icon = "ACTION")
layout.separator(factor=0.5) layout.separator(factor=0.5)
layout.label(text=t("Optimization.joinmeshes.label"), icon='SETTINGS') layout.label(text=t("Optimization.joinmeshes.label"), icon='SETTINGS')
row = layout.row(align=True) row = layout.row(align=True)
row.scale_y = 1.2 row.scale_y = 1.2
row.operator("avatar_toolkit.join_all_meshes", text=t("Optimization.join_all_meshes.label"), icon='OUTLINER_OB_MESH') row.operator(AvatarToolKit_OT_JoinAllMeshes.bl_idname, text=t("Optimization.join_all_meshes.label"), icon='OUTLINER_OB_MESH')
row.operator("avatar_toolkit.join_selected_meshes", text=t("Optimization.join_selected_meshes.label"), icon='STICKY_UVS_LOC') row.operator(AvatarToolKit_OT_JoinSelectedMeshes.bl_idname, text=t("Optimization.join_selected_meshes.label"), icon='STICKY_UVS_LOC')
else: else:
layout.label(text=t("Optimization.select_armature"), icon='ERROR') layout.label(text=t("Optimization.select_armature"), icon='ERROR')
+4 -2
View File
@@ -2,13 +2,15 @@ import bpy
from ..core.register import register_wrap from ..core.register import register_wrap
from ..functions.translations import t from ..functions.translations import t
CATEGORY_NAME = "Avatar Toolkit"
@register_wrap @register_wrap
class AvatarToolkitPanel(bpy.types.Panel): class AvatarToolKit_PT_AvatarToolkitPanel(bpy.types.Panel):
bl_label = t("AvatarToolkit.label") bl_label = t("AvatarToolkit.label")
bl_idname = "OBJECT_PT_avatar_toolkit" bl_idname = "OBJECT_PT_avatar_toolkit"
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
bl_region_type = 'UI' bl_region_type = 'UI'
bl_category = "Avatar Toolkit" bl_category = CATEGORY_NAME
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
+192 -16
View File
@@ -1,23 +1,23 @@
import bpy import bpy
from ..core.register import register_wrap from ..core.register import register_wrap
from .panel import AvatarToolkitPanel from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME
from bpy.types import Context from ..core.export_resonite import AvatarToolKit_OT_ExportResonite
from bpy.types import Context, Mesh, Panel, Operator
from ..functions.translations import t from ..functions.translations import t
from ..core.import_pmx import import_pmx from ..core.import_pmx import import_pmx
from ..core.import_pmd import import_pmd from ..core.import_pmd import import_pmd
from ..functions.import_anything import ImportAnyModel from ..functions.import_anything import AvatarToolKit_OT_ImportAnyModel
from ..core.common import get_selected_armature, set_selected_armature from ..core.common import get_selected_armature, set_selected_armature, get_all_meshes
@register_wrap @register_wrap
@register_wrap class AvatarToolkitQuickAccessPanel(Panel):
class AvatarToolkitQuickAccessPanel(bpy.types.Panel):
bl_label = t("Quick_Access.label") bl_label = t("Quick_Access.label")
bl_idname = "OBJECT_PT_avatar_toolkit_quick_access" bl_idname = "OBJECT_PT_avatar_toolkit_quick_access"
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
bl_region_type = 'UI' bl_region_type = 'UI'
bl_category = "Avatar Toolkit" bl_category = CATEGORY_NAME
bl_parent_id = "OBJECT_PT_avatar_toolkit" bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order = 1 bl_order = 1
def draw(self, context: Context): def draw(self, context: Context):
@@ -35,11 +35,23 @@ class AvatarToolkitQuickAccessPanel(bpy.types.Panel):
row = layout.row(align=True) row = layout.row(align=True)
row.scale_y = 1.5 row.scale_y = 1.5
row.operator(ImportAnyModel.bl_idname, text=t("Quick_Access.import"), icon='IMPORT') row.operator(AvatarToolKit_OT_ImportAnyModel.bl_idname, text=t("Quick_Access.import"), icon='IMPORT')
row.operator("avatar_toolkit.export_menu", text=t("Quick_Access.export"), icon='EXPORT') row.operator(AVATAR_TOOLKIT_OT_ExportMenu.bl_idname, text=t("Quick_Access.export"), icon='EXPORT')
if get_selected_armature(context) != None:
if(context.mode == "POSE"):
row = layout.row(align=True)
row.operator(AvatarToolkit_OT_StopPoseMode.bl_idname, text=t("Quick_Access.stop_pose_mode.label"), icon='POSE_HLT')
row = layout.row(align=True)
row.operator(AvatarToolkit_OT_ApplyPoseAsRest.bl_idname, text=t("Quick_Access.apply_pose_as_rest.label"), icon='MOD_ARMATURE')
row = layout.row(align=True)
row.operator(AvatarToolkit_OT_ApplyPoseAsShapekey.bl_idname, text=t("Quick_Access.apply_pose_as_shapekey.label"), icon='MOD_ARMATURE')
else:
row = layout.row(align=True)
row.operator(AvatarToolkit_OT_StartPoseMode.bl_idname, text=t("Quick_Access.start_pose_mode.label"), icon='POSE_HLT')
@register_wrap @register_wrap
class AVATAR_TOOLKIT_OT_export_menu(bpy.types.Operator): class AVATAR_TOOLKIT_OT_ExportMenu(bpy.types.Operator):
bl_idname = "avatar_toolkit.export_menu" bl_idname = "avatar_toolkit.export_menu"
bl_label = t("Quick_Access.export_menu.label") bl_label = t("Quick_Access.export_menu.label")
bl_description = t("Quick_Access.export_menu.desc") bl_description = t("Quick_Access.export_menu.desc")
@@ -48,7 +60,7 @@ class AVATAR_TOOLKIT_OT_export_menu(bpy.types.Operator):
def poll(cls, context): def poll(cls, context):
return any(obj.type == 'MESH' for obj in context.scene.objects) return any(obj.type == 'MESH' for obj in context.scene.objects)
def execute(self, context: Context): def execute(self, context: Context) -> set[str]:
return {'FINISHED'} return {'FINISHED'}
def invoke(self, context: Context, event): def invoke(self, context: Context, event):
@@ -58,16 +70,180 @@ class AVATAR_TOOLKIT_OT_export_menu(bpy.types.Operator):
def draw(self, context: Context): def draw(self, context: Context):
layout = self.layout layout = self.layout
layout.label(text=t("Quick_Access.select_export.label"), icon='EXPORT') layout.label(text=t("Quick_Access.select_export.label"), icon='EXPORT')
layout.operator("avatar_toolkit.export_resonite", text=t("Quick_Access.select_export_resonite.label"), icon='SCENE_DATA') layout.operator(AvatarToolKit_OT_ExportResonite.bl_idname, text=t("Quick_Access.select_export_resonite.label"), icon='SCENE_DATA')
layout.operator("avatar_toolkit.export_fbx", text=t("Quick_Access.export_fbx.label"), icon='OBJECT_DATA') layout.operator(AVATAR_TOOLKIT_OT_ExportFbx.bl_idname, text=t("Quick_Access.export_fbx.label"), icon='OBJECT_DATA')
@register_wrap @register_wrap
class AVATAR_TOOLKIT_OT_export_fbx(bpy.types.Operator): class AVATAR_TOOLKIT_OT_ExportFbx(bpy.types.Operator):
bl_idname = 'avatar_toolkit.export_fbx' bl_idname = 'avatar_toolkit.export_fbx'
bl_label = t("Quick_Access.export_fbx.label") bl_label = t("Quick_Access.export_fbx.label")
bl_description = t("Quick_Access.export_fbx.desc") bl_description = t("Quick_Access.export_fbx.desc")
bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} bl_options = {'REGISTER', 'UNDO', 'INTERNAL'}
def execute(self, context): def execute(self, context) -> set[str]:
bpy.ops.export_scene.fbx('INVOKE_DEFAULT') bpy.ops.export_scene.fbx('INVOKE_DEFAULT')
return {'FINISHED'} return {'FINISHED'}
@register_wrap
class AvatarToolkit_OT_StartPoseMode(Operator):
bl_idname = 'avatar_toolkit.start_pose_mode'
bl_label = t("Quick_Access.start_pose_mode.label")
bl_description = t("Quick_Access.start_pose_mode.desc")
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return get_selected_armature(context) != None and context.mode != "POSE"
def execute(self, context: Context) -> set[str]:
context.view_layer.objects.active = get_selected_armature(context)
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='DESELECT')
context.view_layer.objects.active = get_selected_armature(context)
context.view_layer.objects.active.select_set(True)
bpy.ops.object.mode_set(mode='POSE')
return {'FINISHED'}
@register_wrap
class AvatarToolkit_OT_StopPoseMode(Operator):
bl_idname = 'avatar_toolkit.stop_pose_mode'
bl_label = t("Quick_Access.stop_pose_mode.label")
bl_description = t("Quick_Access.stop_pose_mode.desc")
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return get_selected_armature(context) != None and context.mode == "POSE"
def execute(self, context: Context) -> set[str]:
bpy.ops.pose.transforms_clear()
bpy.ops.pose.select_all(action="INVERT")
bpy.ops.pose.transforms_clear()
bpy.ops.pose.select_all(action="INVERT")
bpy.ops.object.mode_set(mode='OBJECT')
return {'FINISHED'}
@register_wrap
class AvatarToolkit_OT_ApplyPoseAsShapekey(Operator):
bl_idname = 'avatar_toolkit.apply_pose_as_shapekey'
bl_label = t("Quick_Access.apply_pose_as_shapekey.label")
bl_description = t("Quick_Access.apply_pose_as_shapekey.desc")
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return get_selected_armature(context) != None and context.mode == "POSE"
def execute(self, context: Context):
bpy.ops.object.mode_set(mode="OBJECT")
for obj in get_all_meshes(context):
modifier_armature_name: str = ""
context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.select_all(action="DESELECT")
context.view_layer.objects.active = obj
obj.select_set(True)
for modifier in obj.modifiers:
if modifier.type == "ARMATURE":
arm_modifier: bpy.types.ArmatureModifier = modifier
modifier_armature_name = arm_modifier.object.name
bpy.ops.object.modifier_apply_as_shapekey(modifier=modifier_armature_name,keep_modifier=True,report=True)
return {'FINISHED'}
@register_wrap
class AvatarToolkit_OT_ApplyPoseAsRest(Operator):
bl_idname = 'avatar_toolkit.apply_pose_as_rest'
bl_label = t("Quick_Access.apply_pose_as_rest.label")
bl_description = t("Quick_Access.apply_pose_as_rest.desc")
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return get_selected_armature(context) != None and context.mode == "POSE"
def execute(self, context: Context):
for obj in get_all_meshes(context):
mesh_data: Mesh = obj.data
if mesh_data.shape_keys:
shape_key_obj_list: list[bpy.types.Object] = []
modifier_armature_name: str = ""
for modifier in obj.modifiers:
if modifier.type == "ARMATURE":
arm_modifier: bpy.types.ArmatureModifier = modifier
modifier_armature_name = arm_modifier.object.name
for idx,shape in enumerate(mesh_data.shape_keys.key_blocks):
if idx == 0:
continue
context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.select_all(action="DESELECT")
context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.duplicate()
shape_obj = context.view_layer.objects.active
shape_obj.active_shape_key_index = idx
shape_obj.name = shape.name
bpy.ops.object.shape_key_move(type="TOP")
bpy.ops.object.mode_set(mode="EDIT")
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.shape_key_remove(all=True)
bpy.ops.object.modifier_apply(modifier=modifier_armature_name)
shape_key_obj_list.append(shape_obj)
context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode="OBJECT")
context.view_layer.objects.active.select_set(True)
bpy.ops.object.shape_key_remove(all=True)
bpy.ops.object.modifier_apply(modifier=modifier_armature_name)
bpy.ops.object.select_all(action="DESELECT")
for shapekey_obj in shape_key_obj_list:
shapekey_obj.select_set(True)
context.view_layer.objects.active = obj
context.view_layer.objects.active.select_set(True)
try:
bpy.ops.object.join_shapes()
except:
self.report({'ERROR'}, t("Quick_Access.apply_armature_failed"))
context.view_layer.objects.active = shape_key_obj_list[0]
obj.select_set(False)
bpy.ops.object.delete(confirm=False)
return {'CANCELLED'}
context.view_layer.objects.active = shape_key_obj_list[0]
obj.select_set(False)
bpy.ops.object.delete(confirm=False)
else:
modifier_armature_name: str = ""
for modifier in obj.modifiers:
if modifier.type == "ARMATURE":
arm_modifier: bpy.types.ArmatureModifier = modifier
modifier_armature_name = arm_modifier.object.name
context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.select_all(action="DESELECT")
context.view_layer.objects.active.select_set(True)
bpy.ops.object.modifier_apply(modifier=modifier_armature_name)
armature_obj: bpy.types.Object = get_selected_armature(context)
context.view_layer.objects.active = armature_obj
armature_obj.select_set(True)
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.mode_set(mode="POSE")
bpy.ops.pose.armature_apply(selected=False)
return {'FINISHED'}
+3 -3
View File
@@ -1,6 +1,6 @@
import bpy import bpy
from ..core.register import register_wrap from ..core.register import register_wrap
from .panel import AvatarToolkitPanel from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME
from ..functions.translations import t from ..functions.translations import t
@register_wrap @register_wrap
@@ -9,8 +9,8 @@ class AvatarToolkitSettingsPanel(bpy.types.Panel):
bl_idname = "OBJECT_PT_avatar_toolkit_settings" bl_idname = "OBJECT_PT_avatar_toolkit_settings"
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
bl_region_type = 'UI' bl_region_type = 'UI'
bl_category = "Avatar Toolkit" bl_category = CATEGORY_NAME
bl_parent_id = "OBJECT_PT_avatar_toolkit" bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order = 6 bl_order = 6
def draw(self, context): def draw(self, context):
+13 -12
View File
@@ -1,22 +1,23 @@
import bpy import bpy
from ..core.register import register_wrap from ..core.register import register_wrap
from .panel import AvatarToolkitPanel from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME
from bpy.types import Context from bpy.types import Context
from ..functions.digitigrade_legs import CreateDigitigradeLegs from ..functions.digitigrade_legs import AvatarToolKit_OT_CreateDigitigradeLegs
from ..functions.resonite_functions import AvatarToolKit_OT_ConvertToResonite
from ..functions.translations import t from ..functions.translations import t
from ..core.common import get_selected_armature from ..core.common import get_selected_armature
from ..functions.seperate_by import SeparateByMaterials, SeparateByLooseParts
from ..functions.additional_tools import ApplyTransforms
from ..functions.mesh_tools import AvatarToolkit_OT_RemoveUnusedShapekeys from ..functions.mesh_tools import AvatarToolkit_OT_RemoveUnusedShapekeys
from ..functions.seperate_by import AvatarToolKit_OT_SeparateByMaterials, AvatarToolKit_OT_SeparateByLooseParts
from ..functions.additional_tools import AvatarToolKit_OT_ApplyTransform
@register_wrap @register_wrap
class AvatarToolkitToolsPanel(bpy.types.Panel): class AvatarToolkit_PT_ToolsPanel(bpy.types.Panel):
bl_label = t("Tools.label") bl_label = t("Tools.label")
bl_idname = "OBJECT_PT_avatar_toolkit_tools" bl_idname = "OBJECT_PT_avatar_toolkit_tools"
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
bl_region_type = 'UI' bl_region_type = 'UI'
bl_category = "Avatar Toolkit" bl_category = CATEGORY_NAME
bl_parent_id = "OBJECT_PT_avatar_toolkit" bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order = 3 bl_order = 3
def draw(self, context: Context): def draw(self, context: Context):
@@ -29,16 +30,16 @@ class AvatarToolkitToolsPanel(bpy.types.Panel):
row = layout.row(align=True) row = layout.row(align=True)
row.scale_y = 1.5 row.scale_y = 1.5
row.operator("avatar_toolkit.convert_to_resonite", text=t("Tools.convert_to_resonite.label"), icon='SCENE_DATA') row.operator(AvatarToolKit_OT_ConvertToResonite.bl_idname, text=t("Tools.convert_to_resonite.label"), icon='SCENE_DATA')
row = layout.row(align=True) row = layout.row(align=True)
row.operator(CreateDigitigradeLegs.bl_idname, text=t("Tools.create_digitigrade_legs.label"), icon='BONE_DATA') row.operator(AvatarToolKit_OT_CreateDigitigradeLegs.bl_idname, text=t("Tools.create_digitigrade_legs.label"), icon='BONE_DATA')
layout.separator() layout.separator()
row = layout.row(align=True) row = layout.row(align=True)
layout.label(text=t("Tools.separate_by.label"), icon='MESH_DATA') layout.label(text=t("Tools.separate_by.label"), icon='MESH_DATA')
row.operator(SeparateByMaterials.bl_idname, text=t("Tools.separate_by_materials.label"), icon='MATERIAL') row.operator(AvatarToolKit_OT_SeparateByMaterials.bl_idname, text=t("Tools.separate_by_materials.label"), icon='MATERIAL')
row.operator(SeparateByLooseParts.bl_idname, text=t("Tools.separate_by_loose_parts.label"), icon='OUTLINER_OB_MESH') row.operator(AvatarToolKit_OT_SeparateByLooseParts.bl_idname, text=t("Tools.separate_by_loose_parts.label"), icon='OUTLINER_OB_MESH')
row = layout.row(align=True) row = layout.row(align=True)
row.operator(ApplyTransforms.bl_idname, text=t("Tools.apply_transforms.label"), icon='OBJECT_ORIGIN') row.operator(AvatarToolKit_OT_ApplyTransforms.bl_idname, text=t("Tools.apply_transforms.label"), icon='OBJECT_ORIGIN')
row.operator(AvatarToolkit_OT_RemoveUnusedShapekeys.bl_idname, text=t("Tools.remove_unused_shapekeys.label"), icon='SHAPEKEY_DATA') row.operator(AvatarToolkit_OT_RemoveUnusedShapekeys.bl_idname, text=t("Tools.remove_unused_shapekeys.label"), icon='SHAPEKEY_DATA')
else: else:
layout.label(text=t("Tools.select_armature"), icon='ERROR') layout.label(text=t("Tools.select_armature"), icon='ERROR')
+5 -3
View File
@@ -1,5 +1,7 @@
import bpy import bpy
from ..core.register import register_wrap from ..core.register import register_wrap
from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME
from ..functions.viseme import AvatarToolKit_OT_AutoVisemeButton
from ..functions.translations import t from ..functions.translations import t
from ..core.common import get_selected_armature from ..core.common import get_selected_armature
@@ -9,8 +11,8 @@ class AvatarToolkitVisemePanel(bpy.types.Panel):
bl_idname = "OBJECT_PT_avatar_toolkit_viseme" bl_idname = "OBJECT_PT_avatar_toolkit_viseme"
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
bl_region_type = 'UI' bl_region_type = 'UI'
bl_category = "Avatar Toolkit" bl_category = CATEGORY_NAME
bl_parent_id = "OBJECT_PT_avatar_toolkit" bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order = 5 bl_order = 5
def draw(self, context: bpy.types.Context) -> None: def draw(self, context: bpy.types.Context) -> None:
@@ -32,7 +34,7 @@ class AvatarToolkitVisemePanel(bpy.types.Panel):
row = layout.row() row = layout.row()
row.scale_y = 1.2 row.scale_y = 1.2
row.operator("avatar_toolkit.create_visemes", text=t('VisemePanel.create_visemes'), icon='TRIA_RIGHT') row.operator(AvatarToolKit_OT_AutoVisemeButton.bl_idname, text=t('VisemePanel.create_visemes'), icon='TRIA_RIGHT')
else: else:
layout.label(text=t('VisemePanel.error.noShapekeys'), icon='ERROR') layout.label(text=t('VisemePanel.error.noShapekeys'), icon='ERROR')
else: else: