From ca3af697765e83214ca080d4e0251f4c56eda8f4 Mon Sep 17 00:00:00 2001 From: Isamu Mogi Date: Tue, 18 Jun 2024 20:58:57 +0900 Subject: [PATCH] wip --- src/io_scene_vrm/common/shader.py | 6 +- src/io_scene_vrm/editor/extension.py | 61 +++++- src/io_scene_vrm/editor/make_armature.py | 23 ++- src/io_scene_vrm/editor/migration.py | 5 +- src/io_scene_vrm/editor/mtoon1/handler.py | 5 +- src/io_scene_vrm/editor/mtoon1/migration.py | 3 +- src/io_scene_vrm/editor/mtoon1/ops.py | 49 ++--- src/io_scene_vrm/editor/mtoon1/panel.py | 5 +- .../editor/mtoon1/property_group.py | 62 +++--- .../editor/node_constraint1/panel.py | 5 +- src/io_scene_vrm/editor/ops.py | 18 +- src/io_scene_vrm/editor/panel.py | 3 +- src/io_scene_vrm/editor/property_group.py | 22 +- src/io_scene_vrm/editor/search.py | 13 +- .../editor/spring_bone1/handler.py | 3 +- .../editor/spring_bone1/migration.py | 10 +- src/io_scene_vrm/editor/spring_bone1/ops.py | 55 ++--- src/io_scene_vrm/editor/spring_bone1/panel.py | 11 +- .../editor/spring_bone1/property_group.py | 27 ++- .../editor/spring_bone1/ui_list.py | 5 +- src/io_scene_vrm/editor/validation.py | 43 ++-- src/io_scene_vrm/editor/vrm0/gizmo_group.py | 6 +- src/io_scene_vrm/editor/vrm0/migration.py | 24 ++- src/io_scene_vrm/editor/vrm0/ops.py | 195 ++++++++++-------- src/io_scene_vrm/editor/vrm0/panel.py | 39 ++-- .../editor/vrm0/property_group.py | 24 ++- src/io_scene_vrm/editor/vrm0/ui_list.py | 3 +- src/io_scene_vrm/editor/vrm1/handler.py | 4 +- src/io_scene_vrm/editor/vrm1/migration.py | 23 ++- src/io_scene_vrm/editor/vrm1/ops.py | 63 +++--- src/io_scene_vrm/editor/vrm1/panel.py | 23 ++- .../editor/vrm1/property_group.py | 25 ++- .../exporter/abstract_base_vrm_exporter.py | 7 +- src/io_scene_vrm/exporter/export_scene.py | 41 ++-- src/io_scene_vrm/exporter/vrm0_exporter.py | 41 ++-- src/io_scene_vrm/exporter/vrm1_exporter.py | 23 ++- .../exporter/vrm_animation_exporter.py | 7 +- .../importer/abstract_base_vrm_importer.py | 5 +- src/io_scene_vrm/importer/import_scene.py | 5 +- src/io_scene_vrm/importer/vrm0_importer.py | 9 +- src/io_scene_vrm/importer/vrm1_importer.py | 46 +++-- .../importer/vrm_animation_importer.py | 13 +- src/io_scene_vrm/registration.py | 12 +- tests/blender_test_bone_order_validation.py | 4 +- tests/blender_test_fixup_human_bones.py | 3 +- .../blender_test_load_human_bone_mappings.py | 4 +- tests/blender_test_spring_bone.py | 117 ++++++----- 47 files changed, 699 insertions(+), 501 deletions(-) diff --git a/src/io_scene_vrm/common/shader.py b/src/io_scene_vrm/common/shader.py index 4e17fa10d..1a4474db9 100644 --- a/src/io_scene_vrm/common/shader.py +++ b/src/io_scene_vrm/common/shader.py @@ -236,6 +236,8 @@ def load_mtoon1_node_group( *, reset_node_groups: bool, ) -> None: + from ..editor.extension import get_node_tree_extension + start_time = time.perf_counter() if not blend_file_path.exists(): @@ -246,7 +248,7 @@ def load_mtoon1_node_group( checking_node_group = context.blend_data.node_groups.get(node_group_name) if checking_node_group: if ( - tuple(checking_node_group.vrm_addon_extension.addon_version) + tuple(get_node_tree_extension(checking_node_group).addon_version) >= LAST_MODIFIED_VERSION ): return @@ -299,7 +301,7 @@ def load_mtoon1_node_group( ) clear_node_tree(node_group, clear_inputs_outputs=True) copy_node_tree(context, template_node_group, node_group) - node_group.vrm_addon_extension.addon_version = addon_version() + get_node_tree_extension(node_group).addon_version = addon_version() finally: if template_node_group and template_node_group.users <= 1: context.blend_data.node_groups.remove(template_node_group) diff --git a/src/io_scene_vrm/editor/extension.py b/src/io_scene_vrm/editor/extension.py index c59963f0c..b86f828d6 100644 --- a/src/io_scene_vrm/editor/extension.py +++ b/src/io_scene_vrm/editor/extension.py @@ -9,7 +9,16 @@ PointerProperty, StringProperty, ) -from bpy.types import Context, PropertyGroup +from bpy.types import ( + Armature, + Bone, + Context, + Material, + NodeTree, + Object, + PropertyGroup, + Scene, +) from mathutils import Matrix, Quaternion from ..common.logging import get_logger @@ -42,7 +51,7 @@ def update_vrm0_material_property_names(context: Context, scene_name: str) -> No if not scene: logger.error(f'No scene "{scene_name}"') return - ext = scene.vrm_addon_extension + ext = get_scene_extension(scene) # Unity 2022.3.4 + UniVRM 0.112.0 gltf_property_names = [ @@ -428,3 +437,51 @@ class VrmAddonNodeTreeExtensionPropertyGroup(PropertyGroup): # This code is auto generated. # `poetry run python tools/property_typing.py` addon_version: Sequence[int] # type: ignore[no-redef] + + +def get_material_extension( + material: Material, +) -> VrmAddonMaterialExtensionPropertyGroup: + extension = getattr(material, "vrm_addon_extension", None) + if not isinstance(extension, VrmAddonMaterialExtensionPropertyGroup): + raise TypeError + return extension + + +def get_armature_extension( + armature: Armature, +) -> VrmAddonArmatureExtensionPropertyGroup: + extension = getattr(armature, "vrm_addon_extension", None) + if not isinstance(extension, VrmAddonArmatureExtensionPropertyGroup): + raise TypeError + return extension + + +def get_node_tree_extension( + node_tree: NodeTree, +) -> VrmAddonNodeTreeExtensionPropertyGroup: + extension = getattr(node_tree, "vrm_addon_extension", None) + if not isinstance(extension, VrmAddonNodeTreeExtensionPropertyGroup): + raise TypeError + return extension + + +def get_scene_extension(scene: Scene) -> VrmAddonSceneExtensionPropertyGroup: + extension = getattr(scene, "vrm_addon_extension", None) + if not isinstance(extension, VrmAddonSceneExtensionPropertyGroup): + raise TypeError + return extension + + +def get_bone_extension(bone: Bone) -> VrmAddonBoneExtensionPropertyGroup: + extension = getattr(bone, "vrm_addon_extension", None) + if not isinstance(extension, VrmAddonBoneExtensionPropertyGroup): + raise TypeError + return extension + + +def get_object_extension(obj: Object) -> VrmAddonObjectExtensionPropertyGroup: + extension = getattr(obj, "vrm_addon_extension", None) + if not isinstance(extension, VrmAddonObjectExtensionPropertyGroup): + raise TypeError + return extension diff --git a/src/io_scene_vrm/editor/make_armature.py b/src/io_scene_vrm/editor/make_armature.py index 6c80cdae6..dfc04028e 100644 --- a/src/io_scene_vrm/editor/make_armature.py +++ b/src/io_scene_vrm/editor/make_armature.py @@ -15,6 +15,7 @@ from ..common.vrm0.human_bone import HumanBoneSpecifications from ..common.workspace import save_workspace from . import migration +from .extension import get_armature_extension from .vrm0.property_group import ( Vrm0BlendShapeGroupPropertyGroup, Vrm0HumanoidPropertyGroup, @@ -177,7 +178,7 @@ def make_armature(self, context: Context) -> tuple[Object, dict[str, str]]: if not isinstance(armature_data, Armature): message = "armature data is not an Armature" raise TypeError(message) - armature_data.vrm_addon_extension.addon_version = addon_version() + get_armature_extension(armature_data).addon_version = addon_version() bone_dict: dict[str, EditBone] = {} @@ -577,9 +578,9 @@ def setup_as_vrm( armature_data = armature.data if isinstance(armature_data, Armature) and not self.skip_heavy_armature_setup: for vrm_bone_name, bpy_bone_name in compare_dict.items(): - for ( - human_bone - ) in armature_data.vrm_addon_extension.vrm0.humanoid.human_bones: + for human_bone in get_armature_extension( + armature_data + ).vrm0.humanoid.human_bones: if human_bone.bone == vrm_bone_name: human_bone.node.set_bone_name(bpy_bone_name) break @@ -599,8 +600,8 @@ def make_extension_setting_and_metas( armature_data = armature.data if not isinstance(armature_data, Armature): return - vrm0 = armature_data.vrm_addon_extension.vrm0 - vrm1 = armature_data.vrm_addon_extension.vrm1 + vrm0 = get_armature_extension(armature_data).vrm0 + vrm1 = get_armature_extension(armature_data).vrm1 vrm0.first_person.first_person_bone.set_bone_name("head") vrm0.first_person.first_person_bone_offset = (0, 0, 0.06) vrm1.look_at.offset_from_head_bone = offset_from_head_bone @@ -706,13 +707,15 @@ def get_humanoid_bone(self, bone: str) -> Bone: tmp_dict = { v.bone: i for i, v in enumerate( - armature_data.vrm_addon_extension.vrm0.humanoid.human_bones + get_armature_extension(armature_data).vrm0.humanoid.human_bones ) } - bone_name: str = armature_data.vrm_addon_extension.vrm0.humanoid.human_bones[ - tmp_dict[bone] - ].node.bone_name + bone_name: str = ( + get_armature_extension(armature_data) + .vrm0.humanoid.human_bones[tmp_dict[bone]] + .node.bone_name + ) humanoid_bone = armature_data.bones[bone_name] return humanoid_bone diff --git a/src/io_scene_vrm/editor/migration.py b/src/io_scene_vrm/editor/migration.py index b4f434a6b..7fea40b96 100644 --- a/src/io_scene_vrm/editor/migration.py +++ b/src/io_scene_vrm/editor/migration.py @@ -11,6 +11,7 @@ from .extension import ( VrmAddonArmatureExtensionPropertyGroup, VrmAddonSceneExtensionPropertyGroup, + get_armature_extension, ) from .mtoon1 import migration as mtoon1_migration from .mtoon1 import ops as mtoon1_ops @@ -25,7 +26,7 @@ def is_unnecessary(armature_data: Armature) -> bool: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) return ( tuple(ext.addon_version) >= addon_version() and armature_data.name == ext.armature_data_name @@ -73,7 +74,7 @@ def migrate(context: Optional[Context], armature_object_name: str) -> bool: if is_unnecessary(armature_data): return True - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) ext.armature_data_name = armature_data.name for bone_property_group in BonePropertyGroup.get_all_bone_property_groups(armature): diff --git a/src/io_scene_vrm/editor/mtoon1/handler.py b/src/io_scene_vrm/editor/mtoon1/handler.py index 9e3e37665..f6ca018c0 100644 --- a/src/io_scene_vrm/editor/mtoon1/handler.py +++ b/src/io_scene_vrm/editor/mtoon1/handler.py @@ -6,6 +6,7 @@ from bpy.types import Mesh from ...common.logging import get_logger +from ..extension import get_material_extension from .ops import VRM_OT_refresh_mtoon1_outline logger = get_logger(__name__) @@ -25,9 +26,9 @@ def update_mtoon1_outline() -> Optional[float]: [ ( material_slot.material.name, - material_slot.material.vrm_addon_extension.mtoon1.get_enabled_in_material( + get_material_extension( material_slot.material - ), + ).mtoon1.get_enabled_in_material(material_slot.material), has_auto_smooth and obj.data.use_auto_smooth, ) if material_slot.material diff --git a/src/io_scene_vrm/editor/mtoon1/migration.py b/src/io_scene_vrm/editor/mtoon1/migration.py index 72c244491..1d02091cf 100644 --- a/src/io_scene_vrm/editor/mtoon1/migration.py +++ b/src/io_scene_vrm/editor/mtoon1/migration.py @@ -13,6 +13,7 @@ from ...common import convert, native, shader from ...common.gl import GL_LINEAR, GL_NEAREST from ...common.logging import get_logger +from ..extension import get_material_extension from .property_group import ( GL_LINEAR_IMAGE_INTERPOLATIONS, IMAGE_INTERPOLATION_CLOSEST, @@ -113,7 +114,7 @@ def migrate_material(context: Context, material: Material) -> None: ) # ここから先は、シェーダーノードが最新の状態になっている想定のコードを書ける - typed_mtoon1 = material.vrm_addon_extension.mtoon1 + typed_mtoon1 = get_material_extension(material).mtoon1 if alpha_mode is not None: typed_mtoon1.alpha_mode = alpha_mode if alpha_cutoff is not None: diff --git a/src/io_scene_vrm/editor/mtoon1/ops.py b/src/io_scene_vrm/editor/mtoon1/ops.py index 338845423..15a4aafb4 100644 --- a/src/io_scene_vrm/editor/mtoon1/ops.py +++ b/src/io_scene_vrm/editor/mtoon1/ops.py @@ -24,6 +24,7 @@ from ...common import convert, shader from ...common.logging import get_logger from .. import search +from ..extension import get_material_extension from .property_group import ( Mtoon0ReceiveShadowTexturePropertyGroup, Mtoon0ShadingGradeTexturePropertyGroup, @@ -152,7 +153,7 @@ def convert_material_to_mtoon1(self, context: Context, material: Material) -> No reset_node_groups=False, ) - gltf = material.vrm_addon_extension.mtoon1 + gltf = get_material_extension(material).mtoon1 gltf.pbr_metallic_roughness.base_color_factor = base_color_factor if base_color_texture_image: gltf.pbr_metallic_roughness.base_color_texture.index.source = ( @@ -356,7 +357,7 @@ def convert_mtoon_unversioned_to_mtoon1( shader.load_mtoon1_shader(context, material, reset_node_groups=True) - gltf = material.vrm_addon_extension.mtoon1 + gltf = get_material_extension(material).mtoon1 mtoon = gltf.extensions.vrmc_materials_mtoon gltf.alpha_mode = alpha_mode @@ -513,7 +514,7 @@ def convert_mtoon1_to_bsdf_principled(self, material: Material) -> None: return principled_bsdf = PrincipledBSDFWrapper(material, is_readonly=False) - gltf = material.vrm_addon_extension.mtoon1 + gltf = get_material_extension(material).mtoon1 principled_bsdf.base_color = gltf.pbr_metallic_roughness.base_color_factor[:3] base_color_texture_image = ( @@ -653,7 +654,7 @@ def execute(self, context: Context) -> set[str]: if not isinstance(material, Material): return {"FINISHED"} - gltf = material.vrm_addon_extension.mtoon1 + gltf = get_material_extension(material).mtoon1 mtoon = gltf.extensions.vrmc_materials_mtoon for texture in [ @@ -771,7 +772,7 @@ def assign( ) if not node_group: return - mtoon = material.vrm_addon_extension.mtoon1.extensions.vrmc_materials_mtoon + mtoon = get_material_extension(material).mtoon1.extensions.vrmc_materials_mtoon outline_width_mode_value = next( ( value @@ -831,7 +832,7 @@ def assign( outline_material_name = f"MToon Outline ({material.name})" modifier_name = f"MToon Outline ({material.name})" - outline_material = material.vrm_addon_extension.mtoon1.outline_material + outline_material = get_material_extension(material).mtoon1.outline_material reset_outline_material = not outline_material if reset_outline_material: outline_material = context.blend_data.materials.new( @@ -846,28 +847,28 @@ def assign( shader.load_mtoon1_shader( context, outline_material, reset_node_groups=False ) - outline_material.vrm_addon_extension.mtoon1.is_outline_material = True - material.vrm_addon_extension.mtoon1.outline_material = outline_material + get_material_extension(outline_material).mtoon1.is_outline_material = True + get_material_extension(material).mtoon1.outline_material = outline_material if outline_material.name != outline_material_name: outline_material.name = outline_material_name if not outline_material.use_nodes: outline_material.use_nodes = True - if not outline_material.vrm_addon_extension.mtoon1.is_outline_material: - outline_material.vrm_addon_extension.mtoon1.is_outline_material = True + if not get_material_extension(outline_material).mtoon1.is_outline_material: + get_material_extension(outline_material).mtoon1.is_outline_material = True if ( - outline_material.vrm_addon_extension.mtoon1.alpha_cutoff - != material.vrm_addon_extension.mtoon1.alpha_cutoff + get_material_extension(outline_material).mtoon1.alpha_cutoff + != get_material_extension(material).mtoon1.alpha_cutoff ): - outline_material.vrm_addon_extension.mtoon1.alpha_cutoff = ( - material.vrm_addon_extension.mtoon1.alpha_cutoff - ) + get_material_extension( + outline_material + ).mtoon1.alpha_cutoff = get_material_extension(material).mtoon1.alpha_cutoff if ( - outline_material.vrm_addon_extension.mtoon1.alpha_mode - != material.vrm_addon_extension.mtoon1.alpha_mode + get_material_extension(outline_material).mtoon1.alpha_mode + != get_material_extension(material).mtoon1.alpha_mode ): - outline_material.vrm_addon_extension.mtoon1.alpha_mode = ( - material.vrm_addon_extension.mtoon1.alpha_mode - ) + get_material_extension( + outline_material + ).mtoon1.alpha_mode = get_material_extension(material).mtoon1.alpha_mode if outline_material.shadow_method != "NONE": outline_material.shadow_method = "NONE" if not outline_material.use_backface_culling: @@ -995,9 +996,9 @@ def refresh_object(context: Context, obj: Object) -> None: material = context.blend_data.materials.get(material_slot.material.name) if not material: continue - if not material.vrm_addon_extension.mtoon1.enabled: + if not get_material_extension(material).mtoon1.enabled: continue - if material.vrm_addon_extension.mtoon1.is_outline_material: + if get_material_extension(material).mtoon1.is_outline_material: continue VRM_OT_refresh_mtoon1_outline.assign( @@ -1028,9 +1029,9 @@ def refresh( material = context.blend_data.materials.get(material_slot.material.name) if not material: continue - if not material.vrm_addon_extension.mtoon1.enabled: + if not get_material_extension(material).mtoon1.enabled: continue - if material.vrm_addon_extension.mtoon1.is_outline_material: + if get_material_extension(material).mtoon1.is_outline_material: continue VRM_OT_refresh_mtoon1_outline.assign( diff --git a/src/io_scene_vrm/editor/mtoon1/panel.py b/src/io_scene_vrm/editor/mtoon1/panel.py index 5d721824a..958e068a5 100644 --- a/src/io_scene_vrm/editor/mtoon1/panel.py +++ b/src/io_scene_vrm/editor/mtoon1/panel.py @@ -6,6 +6,7 @@ from ...common.logging import get_logger from .. import search +from ..extension import get_material_extension from ..ops import VRM_OT_open_url_in_web_browser, layout_operator from .ops import ( VRM_OT_import_mtoon1_texture_image_file, @@ -162,7 +163,7 @@ def draw_mtoon1_material(context: Context, layout: UILayout) -> None: material = context.material if not material: return - ext = material.vrm_addon_extension + ext = get_material_extension(material) layout = layout.column() layout.prop(ext.mtoon1, "enabled") @@ -368,7 +369,7 @@ def draw_material(context: Context, layout: UILayout) -> None: material = context.material if not material: return - ext = material.vrm_addon_extension + ext = get_material_extension(material) if ext.mtoon1.is_outline_material: layout.box().label(icon="INFO", text="This is a MToon Outline material") return diff --git a/src/io_scene_vrm/editor/mtoon1/property_group.py b/src/io_scene_vrm/editor/mtoon1/property_group.py index f18504c36..8461e0170 100644 --- a/src/io_scene_vrm/editor/mtoon1/property_group.py +++ b/src/io_scene_vrm/editor/mtoon1/property_group.py @@ -189,7 +189,7 @@ def find_material(self) -> Material: for material in context.blend_data.materials: if not material: continue - ext = material.vrm_addon_extension.mtoon1 + ext = get_material_mtoon1_extension(material) if functools.reduce(getattr, chain, ext) == self: return material @@ -215,9 +215,9 @@ def get_material_property_chain(cls) -> list[str]: def find_outline_property_group( cls, material: Material ) -> Optional["MaterialTraceablePropertyGroup"]: - if material.vrm_addon_extension.mtoon1.is_outline_material: + if get_material_mtoon1_extension(material).is_outline_material: return None - outline_material = material.vrm_addon_extension.mtoon1.outline_material + outline_material = get_material_mtoon1_extension(material).outline_material if not outline_material: return None if material.name == outline_material.name: @@ -226,7 +226,7 @@ def find_outline_property_group( ) return None chain = cls.get_material_property_chain() - attr = outline_material.vrm_addon_extension.mtoon1 + attr: object = get_material_mtoon1_extension(outline_material) for name in chain: attr = getattr(attr, name, None) if isinstance(attr, MaterialTraceablePropertyGroup): @@ -451,7 +451,7 @@ def get_texture_info_property_group(self) -> "Mtoon1TextureInfoPropertyGroup": if chain[-1:] == ["extensions"]: chain = chain[:-1] material = self.find_material() - ext = material.vrm_addon_extension.mtoon1 + ext = get_material_mtoon1_extension(material) property_group = functools.reduce(getattr, chain, ext) if not isinstance(property_group, Mtoon1TextureInfoPropertyGroup): message = f"{property_group} is not a Mtoon1TextureInfoPropertyGroup" @@ -812,14 +812,14 @@ class Mtoon1OutlineWidthMultiplyKhrTextureTransformPropertyGroup( def update_texture_offset_and_outline(self, context: Context) -> None: material = self.find_material() - if material.vrm_addon_extension.mtoon1.is_outline_material: + if get_material_mtoon1_extension(material).is_outline_material: return self.update_texture_offset(context) bpy.ops.vrm.refresh_mtoon1_outline(material_name=material.name) def update_texture_scale_and_outline(self, context: Context) -> None: material = self.find_material() - if material.vrm_addon_extension.mtoon1.is_outline_material: + if get_material_mtoon1_extension(material).is_outline_material: return self.update_texture_scale(context) bpy.ops.vrm.refresh_mtoon1_outline(material_name=material.name) @@ -1487,9 +1487,8 @@ class Mtoon1OutlineWidthMultiplyTexturePropertyGroup(Mtoon1TexturePropertyGroup) colorspace = "Non-Color" def update_source(self, context: Context) -> None: - ext = self.find_material().vrm_addon_extension - mtoon = ext.mtoon1.extensions.vrmc_materials_mtoon - mtoon.update_outline_geometry(context) + mtoon1 = get_material_mtoon1_extension(self.find_material()) + mtoon1.extensions.vrmc_materials_mtoon.update_outline_geometry(context) super().update_source(context) sampler: PointerProperty( # type: ignore[valid-type] @@ -1676,7 +1675,7 @@ def update_scale(self, _context: Context) -> None: principled_bsdf = PrincipledBSDFWrapper(material, is_readonly=False) principled_bsdf.normalmap_strength = self.scale - mtoon1 = material.vrm_addon_extension.mtoon1 + mtoon1 = get_material_mtoon1_extension(material) if mtoon1.is_outline_material: return outline_material = mtoon1.outline_material @@ -1981,7 +1980,7 @@ def update_base_color_factor(self, _context: Context) -> None: ) principled_bsdf.alpha = self.base_color_factor[3] - mtoon1 = material.vrm_addon_extension.mtoon1 + mtoon1 = get_material_mtoon1_extension(material) if mtoon1.is_outline_material: return outline_material = mtoon1.outline_material @@ -2024,7 +2023,7 @@ def update_transparent_with_z_write(self, _context: Context) -> None: self.transparent_with_z_write, ) - mtoon1 = self.find_material().vrm_addon_extension.mtoon1 + mtoon1 = get_material_mtoon1_extension(self.find_material()) mtoon1.set_mtoon0_render_queue_and_clamp(mtoon1.mtoon0_render_queue) transparent_with_z_write: BoolProperty( # type: ignore[valid-type] @@ -2229,7 +2228,7 @@ def update_parametric_rim_lift_factor(self, _context: Context) -> None: def update_outline_geometry(self, _context: Context) -> None: material = self.find_material() - if material.vrm_addon_extension.mtoon1.is_outline_material: + if get_material_mtoon1_extension(material).is_outline_material: return bpy.ops.vrm.refresh_mtoon1_outline( material_name=material.name, create_modifier=True @@ -2270,7 +2269,7 @@ def update_outline_color_factor(self, context: Context) -> None: self.update_outline_geometry(context) material = self.find_material() - mtoon1 = material.vrm_addon_extension.mtoon1 + mtoon1 = get_material_mtoon1_extension(material) if mtoon1.is_outline_material: return outline_material = mtoon1.outline_material @@ -2417,7 +2416,7 @@ def update_emissive_strength(self, _context: Context) -> None: if isinstance(socket, NodeSocketFloat): socket.default_value = self.emissive_strength - mtoon1 = material.vrm_addon_extension.mtoon1 + mtoon1 = get_material_mtoon1_extension(material) if mtoon1.is_outline_material: return outline_material = mtoon1.outline_material @@ -2545,17 +2544,17 @@ def set_alpha_mode(self, value: int) -> None: if changed: self.set_mtoon0_render_queue_and_clamp(self.mtoon0_render_queue) - if material.vrm_addon_extension.mtoon1.is_outline_material: + if get_material_mtoon1_extension(material).is_outline_material: material.shadow_method = "NONE" return if shadow_method is not None: material.shadow_method = shadow_method - outline_material = material.vrm_addon_extension.mtoon1.outline_material + outline_material = get_material_mtoon1_extension(material).outline_material if not outline_material: return - outline_material.vrm_addon_extension.mtoon1.set_alpha_mode(value) + get_material_mtoon1_extension(outline_material).set_alpha_mode(value) alpha_mode: EnumProperty( # type: ignore[valid-type] items=alpha_mode_items, @@ -2573,12 +2572,12 @@ def set_double_sided(self, value: object) -> None: self.set_bool( shader.OUTPUT_GROUP_NAME, shader.OUTPUT_GROUP_DOUBLE_SIDED_LABEL, value ) - if material.vrm_addon_extension.mtoon1.is_outline_material: + if get_material_mtoon1_extension(material).is_outline_material: return - outline_material = material.vrm_addon_extension.mtoon1.outline_material + outline_material = get_material_mtoon1_extension(material).outline_material if not outline_material: return - outline_material.vrm_addon_extension.mtoon1.double_sided = False + get_material_mtoon1_extension(outline_material).double_sided = False double_sided: BoolProperty( # type: ignore[valid-type] name=shader.OUTPUT_GROUP_DOUBLE_SIDED_LABEL, @@ -2603,12 +2602,12 @@ def set_alpha_cutoff(self, value: float) -> None: max(0, value), ) - if material.vrm_addon_extension.mtoon1.is_outline_material: + if get_material_mtoon1_extension(material).is_outline_material: return - outline_material = material.vrm_addon_extension.mtoon1.outline_material + outline_material = get_material_mtoon1_extension(material).outline_material if not outline_material: return - outline_material.vrm_addon_extension.mtoon1.set_alpha_cutoff(value) + get_material_mtoon1_extension(outline_material).set_alpha_cutoff(value) alpha_cutoff: FloatProperty( # type: ignore[valid-type] name="Cutoff", @@ -2653,7 +2652,7 @@ def update_emissive_factor(self, _context: Context) -> None: 1, ) - mtoon1 = material.vrm_addon_extension.mtoon1 + mtoon1 = get_material_mtoon1_extension(material) if mtoon1.is_outline_material: return outline_material = mtoon1.outline_material @@ -2942,7 +2941,7 @@ def reset_shader_node_group( reset_material_node_tree: bool, reset_node_groups: bool, ) -> None: - gltf = material.vrm_addon_extension.mtoon1 + gltf = get_material_mtoon1_extension(material) mtoon = gltf.extensions.vrmc_materials_mtoon base_color_factor = list(gltf.pbr_metallic_roughness.base_color_factor) @@ -3001,7 +3000,7 @@ def reset_shader_node_group( gltf.is_outline_material = False if gltf.outline_material: - gltf.outline_material.vrm_addon_extension.mtoon1.is_outline_material = True + get_material_mtoon1_extension(gltf.outline_material).is_outline_material = True gltf.pbr_metallic_roughness.base_color_factor = base_color_factor gltf.pbr_metallic_roughness.base_color_texture.restore(base_color_texture) @@ -3045,3 +3044,10 @@ def reset_shader_node_group( mtoon.uv_animation_rotation_speed_factor = uv_animation_rotation_speed_factor gltf.addon_version = addon_version() + + +def get_material_mtoon1_extension(material: Material) -> Mtoon1MaterialPropertyGroup: + from ..extension import get_material_extension + + mtoon1: Mtoon1MaterialPropertyGroup = get_material_extension(material).mtoon1 + return mtoon1 diff --git a/src/io_scene_vrm/editor/node_constraint1/panel.py b/src/io_scene_vrm/editor/node_constraint1/panel.py index 088983be2..f28585007 100644 --- a/src/io_scene_vrm/editor/node_constraint1/panel.py +++ b/src/io_scene_vrm/editor/node_constraint1/panel.py @@ -13,6 +13,7 @@ from ...common.preferences import get_preferences from .. import search +from ..extension import get_armature_extension from ..panel import VRM_PT_vrm_armature_object_property from ..search import active_object_is_vrm1_armature from .property_group import NodeConstraint1NodeConstraintPropertyGroup @@ -260,7 +261,7 @@ def draw(self, context: Context) -> None: context, active_object, self.layout, - armature_data.vrm_addon_extension.node_constraint1, + get_armature_extension(armature_data).node_constraint1, ) @@ -291,5 +292,5 @@ def draw(self, context: Context) -> None: context, armature, self.layout, - armature_data.vrm_addon_extension.node_constraint1, + get_armature_extension(armature_data).node_constraint1, ) diff --git a/src/io_scene_vrm/editor/ops.py b/src/io_scene_vrm/editor/ops.py index 4587d54d4..82747ea49 100644 --- a/src/io_scene_vrm/editor/ops.py +++ b/src/io_scene_vrm/editor/ops.py @@ -18,6 +18,7 @@ from ..common.vrm0.human_bone import HumanBoneSpecifications from ..common.workspace import save_workspace from . import search +from .extension import get_armature_extension from .make_armature import ICYP_OT_make_armature @@ -178,7 +179,9 @@ def execute(self, context: Context) -> set[str]: return {"CANCELLED"} mappings = {} - for human_bone in armature_data.vrm_addon_extension.vrm0.humanoid.human_bones: + for human_bone in get_armature_extension( + armature_data + ).vrm0.humanoid.human_bones: if human_bone.bone not in HumanBoneSpecifications.all_names: continue if not human_bone.node.bone_name: @@ -234,10 +237,11 @@ def execute(self, context: Context) -> set[str]: continue if not isinstance(bpy_bone_name, str): continue + # INFO@MICROSOFT.COM found = False - for ( - human_bone - ) in armature_data.vrm_addon_extension.vrm0.humanoid.human_bones: + for human_bone in get_armature_extension( + armature_data + ).vrm0.humanoid.human_bones: if human_bone.bone == human_bone_name: human_bone.node.set_bone_name(bpy_bone_name) found = True @@ -245,9 +249,9 @@ def execute(self, context: Context) -> set[str]: if found: continue - human_bone = ( - armature_data.vrm_addon_extension.vrm0.humanoid.human_bones.add() - ) + human_bone = get_armature_extension( + armature_data + ).vrm0.humanoid.human_bones.add() human_bone.bone = human_bone_name human_bone.node.set_bone_name(bpy_bone_name) diff --git a/src/io_scene_vrm/editor/panel.py b/src/io_scene_vrm/editor/panel.py index fa0557b06..4ac6e196c 100644 --- a/src/io_scene_vrm/editor/panel.py +++ b/src/io_scene_vrm/editor/panel.py @@ -20,6 +20,7 @@ search, validation, ) +from .extension import get_armature_extension from .ops import layout_operator __AddOperator = TypeVar("__AddOperator", bound=Operator) @@ -266,7 +267,7 @@ def draw(self, context: Context) -> None: armature_data = armature.data if isinstance(armature_data, Armature): layout.prop( - armature_data.vrm_addon_extension, + get_armature_extension(armature_data), "spec_version", text="", translate=False, diff --git a/src/io_scene_vrm/editor/property_group.py b/src/io_scene_vrm/editor/property_group.py index 29e1e0383..9430f9605 100644 --- a/src/io_scene_vrm/editor/property_group.py +++ b/src/io_scene_vrm/editor/property_group.py @@ -132,10 +132,12 @@ class BonePropertyGroup(PropertyGroup): def get_all_bone_property_groups( armature: Object, ) -> Iterator["BonePropertyGroup"]: + from .extension import get_armature_extension + armature_data = armature.data if not isinstance(armature_data, Armature): return - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) yield ext.vrm0.first_person.first_person_bone for human_bone in ext.vrm0.humanoid.human_bones: yield human_bone.node @@ -216,6 +218,8 @@ def find_bone_candidates( return result def get_bone_name(self) -> str: + from .extension import get_bone_extension + context = bpy.context if not self.bone_uuid: @@ -228,7 +232,7 @@ def get_bone_name(self) -> str: # TODO: Optimization for bone in armature_data.bones: - if bone.vrm_addon_extension.uuid == self.bone_uuid: + if get_bone_extension(bone).uuid == self.bone_uuid: return bone.name return "" @@ -241,6 +245,8 @@ def set_bone_name_and_refresh_node_candidates(self, value: object) -> None: def set_bone_name( self, value: Optional[str], *, refresh_node_candidates: bool = False ) -> None: + from .extension import get_armature_extension, get_bone_extension + context = bpy.context armature: Optional[Object] = None @@ -275,10 +281,10 @@ def set_bone_name( # Reassign UUIDs if duplicate UUIDs exist in case of bone duplication. found_uuids: set[str] = set() for bone in armature_data.bones: - found_uuid = bone.vrm_addon_extension.uuid + found_uuid = get_bone_extension(bone).uuid if not found_uuid or found_uuid in found_uuids: - bone.vrm_addon_extension.uuid = uuid.uuid4().hex - found_uuids.add(bone.vrm_addon_extension.uuid) + get_bone_extension(bone).uuid = uuid.uuid4().hex + found_uuids.add(get_bone_extension(bone).uuid) if not value or value not in armature_data.bones: if not self.bone_uuid: @@ -286,14 +292,14 @@ def set_bone_name( self.bone_uuid = "" elif ( self.bone_uuid - and self.bone_uuid == armature_data.bones[value].vrm_addon_extension.uuid + and self.bone_uuid == get_bone_extension(armature_data.bones[value]).uuid ): return else: bone = armature_data.bones[value] - self.bone_uuid = bone.vrm_addon_extension.uuid + self.bone_uuid = get_bone_extension(bone).uuid - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) for collider_group in ext.vrm0.secondary_animation.collider_groups: collider_group.refresh(armature) diff --git a/src/io_scene_vrm/editor/search.py b/src/io_scene_vrm/editor/search.py index 29c7c86b3..c313d8849 100644 --- a/src/io_scene_vrm/editor/search.py +++ b/src/io_scene_vrm/editor/search.py @@ -20,6 +20,7 @@ ) from ..common.logging import get_logger +from .extension import get_armature_extension logger = get_logger(__name__) @@ -188,7 +189,7 @@ def current_armature_is_vrm0(context: Context) -> bool: return False if all( hasattr(armature_data, "vrm_addon_extension") - and armature_data.vrm_addon_extension.is_vrm0() + and get_armature_extension(armature_data).is_vrm0() for armature_data in live_armature_datum ) and any(obj.type == "ARMATURE" for obj in context.blend_data.objects): return True @@ -198,7 +199,7 @@ def current_armature_is_vrm0(context: Context) -> bool: armature_data = armature.data if not isinstance(armature_data, Armature): return False - return armature_data.vrm_addon_extension.is_vrm0() + return get_armature_extension(armature_data).is_vrm0() def current_armature_is_vrm1(context: Context) -> bool: @@ -211,7 +212,7 @@ def current_armature_is_vrm1(context: Context) -> bool: return False if all( hasattr(armature_data, "vrm_addon_extension") - and armature_data.vrm_addon_extension.is_vrm1() + and get_armature_extension(armature_data).is_vrm1() for armature_data in live_armature_datum ) and any(obj.type == "ARMATURE" for obj in context.blend_data.objects): return True @@ -221,7 +222,7 @@ def current_armature_is_vrm1(context: Context) -> bool: armature_data = armature.data if not isinstance(armature_data, Armature): return False - return armature_data.vrm_addon_extension.is_vrm1() + return get_armature_extension(armature_data).is_vrm1() def multiple_armatures_exist(context: Context) -> bool: @@ -651,7 +652,7 @@ def active_object_is_vrm1_armature(context: Context) -> bool: armature_data = active_object.data if not isinstance(armature_data, Armature): return False - return armature_data.vrm_addon_extension.is_vrm1() + return get_armature_extension(armature_data).is_vrm1() def active_object_is_vrm0_armature(context: Context) -> bool: @@ -663,4 +664,4 @@ def active_object_is_vrm0_armature(context: Context) -> bool: armature_data = active_object.data if not isinstance(armature_data, Armature): return False - return armature_data.vrm_addon_extension.is_vrm0() + return get_armature_extension(armature_data).is_vrm0() diff --git a/src/io_scene_vrm/editor/spring_bone1/handler.py b/src/io_scene_vrm/editor/spring_bone1/handler.py index 0047c6043..464ed5dc9 100644 --- a/src/io_scene_vrm/editor/spring_bone1/handler.py +++ b/src/io_scene_vrm/editor/spring_bone1/handler.py @@ -8,6 +8,7 @@ from bpy.types import Armature, Context, Object, PoseBone from mathutils import Matrix, Quaternion, Vector +from ..extension import get_armature_extension from .property_group import ( SpringBone1ColliderPropertyGroup, SpringBone1JointPropertyGroup, @@ -126,7 +127,7 @@ def calculate_object_pose_bone_rotations( armature_data = obj.data if not isinstance(armature_data, Armature): return - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) if not ext.is_vrm1(): return spring_bone1 = ext.spring_bone1 diff --git a/src/io_scene_vrm/editor/spring_bone1/migration.py b/src/io_scene_vrm/editor/spring_bone1/migration.py index 46bc34f4c..cb4349951 100644 --- a/src/io_scene_vrm/editor/spring_bone1/migration.py +++ b/src/io_scene_vrm/editor/spring_bone1/migration.py @@ -1,8 +1,10 @@ from bpy.types import Armature, Context, Object +from ..extension import get_armature_extension + def migrate_blender_object(armature: Armature) -> None: - ext = armature.vrm_addon_extension + ext = get_armature_extension(armature) if tuple(ext.addon_version) >= (2, 3, 27): return @@ -13,7 +15,7 @@ def migrate_blender_object(armature: Armature) -> None: def fixup_gravity_dir(armature: Armature) -> None: - ext = armature.vrm_addon_extension + ext = get_armature_extension(armature) if tuple(ext.addon_version) <= (2, 14, 3): for spring in ext.spring_bone1.springs: @@ -42,9 +44,9 @@ def fixup_gravity_dir(armature: Armature) -> None: def fixup_collider_group_name(context: Context, armature: Armature) -> None: - ext = armature.vrm_addon_extension + ext = get_armature_extension(armature) if tuple(ext.addon_version) <= (2, 20, 38): - spring_bone = armature.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_extension(armature).spring_bone1 for collider_group in spring_bone.collider_groups: collider_group.fix_index(context) diff --git a/src/io_scene_vrm/editor/spring_bone1/ops.py b/src/io_scene_vrm/editor/spring_bone1/ops.py index 966c3a10d..c14f4362b 100644 --- a/src/io_scene_vrm/editor/spring_bone1/ops.py +++ b/src/io_scene_vrm/editor/spring_bone1/ops.py @@ -6,6 +6,7 @@ from bpy.props import BoolProperty, FloatProperty, IntProperty, StringProperty from bpy.types import Armature, Context, Operator +from ..extension import get_armature_extension from .handler import reset_state, update_pose_bone_rotations @@ -26,7 +27,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone = armature_data.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_extension(armature_data).spring_bone1 collider = spring_bone.colliders.add() collider.uuid = uuid.uuid4().hex collider.shape.sphere.radius = 0.125 @@ -61,7 +62,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone = armature_data.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_extension(armature_data).spring_bone1 if len(spring_bone.colliders) <= self.collider_index: return {"CANCELLED"} @@ -126,7 +127,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone = armature_data.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_extension(armature_data).spring_bone1 if len(spring_bone.collider_groups) <= self.collider_group_index: return {"CANCELLED"} new_index = (self.collider_group_index - 1) % len(spring_bone.collider_groups) @@ -164,7 +165,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone = armature_data.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_extension(armature_data).spring_bone1 if len(spring_bone.collider_groups) <= self.collider_group_index: return {"CANCELLED"} new_index = (self.collider_group_index + 1) % len(spring_bone.collider_groups) @@ -198,7 +199,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 spring = spring_bone1.springs.add() spring.vrm_name = "Spring" spring_bone1.active_spring_index = len(spring_bone1.springs) - 1 @@ -231,7 +232,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 if len(spring_bone1.springs) <= self.spring_index: return {"CANCELLED"} spring_bone1.springs.remove(self.spring_index) @@ -269,7 +270,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 springs = spring_bone1.springs if len(springs) <= self.spring_index: return {"CANCELLED"} @@ -306,7 +307,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 springs = spring_bone1.springs if len(springs) <= self.spring_index: return {"CANCELLED"} @@ -339,7 +340,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone = armature_data.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_extension(armature_data).spring_bone1 collider_group = spring_bone.collider_groups.add() collider_group.uuid = uuid.uuid4().hex collider_group.vrm_name = "Collider Group" @@ -373,7 +374,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone = armature_data.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_extension(armature_data).spring_bone1 collider_groups = spring_bone.collider_groups if len(collider_groups) <= self.collider_group_index: return {"CANCELLED"} @@ -428,7 +429,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 colliders = spring_bone1.colliders if len(colliders) <= self.collider_index: return {"CANCELLED"} @@ -465,7 +466,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 colliders = spring_bone1.colliders if len(colliders) <= self.collider_index: return {"CANCELLED"} @@ -502,7 +503,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - collider_groups = armature_data.vrm_addon_extension.spring_bone1.collider_groups + collider_groups = get_armature_extension( + armature_data + ).spring_bone1.collider_groups if len(collider_groups) <= self.collider_group_index: return {"CANCELLED"} collider_group = collider_groups[self.collider_group_index] @@ -542,7 +545,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - collider_groups = armature_data.vrm_addon_extension.spring_bone1.collider_groups + collider_groups = get_armature_extension( + armature_data + ).spring_bone1.collider_groups if len(collider_groups) <= self.collider_group_index: return {"CANCELLED"} collider_group = collider_groups[self.collider_group_index] @@ -588,7 +593,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 if len(spring_bone1.collider_groups) <= self.collider_group_index: return {"CANCELLED"} collider_group = spring_bone1.collider_groups[self.collider_group_index] @@ -632,7 +637,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 if len(spring_bone1.collider_groups) <= self.collider_group_index: return {"CANCELLED"} collider_group = spring_bone1.collider_groups[self.collider_group_index] @@ -672,7 +677,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - springs = armature_data.vrm_addon_extension.spring_bone1.springs + springs = get_armature_extension(armature_data).spring_bone1.springs if len(springs) <= self.spring_index: return {"CANCELLED"} spring = springs[self.spring_index] @@ -712,7 +717,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - springs = armature_data.vrm_addon_extension.spring_bone1.springs + springs = get_armature_extension(armature_data).spring_bone1.springs if len(springs) <= self.spring_index: return {"CANCELLED"} spring = springs[self.spring_index] @@ -757,7 +762,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 springs = spring_bone1.springs if len(springs) <= self.spring_index: return {"CANCELLED"} @@ -804,7 +809,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 springs = spring_bone1.springs if len(springs) <= self.spring_index: return {"CANCELLED"} @@ -850,7 +855,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - springs = armature_data.vrm_addon_extension.spring_bone1.springs + springs = get_armature_extension(armature_data).spring_bone1.springs if len(springs) <= self.spring_index: return {"CANCELLED"} spring = springs[self.spring_index] @@ -905,7 +910,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - springs = armature_data.vrm_addon_extension.spring_bone1.springs + springs = get_armature_extension(armature_data).spring_bone1.springs if len(springs) <= self.spring_index: return {"CANCELLED"} spring = springs[self.spring_index] @@ -950,7 +955,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 springs = spring_bone1.springs if len(springs) <= self.spring_index: return {"CANCELLED"} @@ -995,7 +1000,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - spring_bone1 = armature_data.vrm_addon_extension.spring_bone1 + spring_bone1 = get_armature_extension(armature_data).spring_bone1 springs = spring_bone1.springs if len(springs) <= self.spring_index: return {"CANCELLED"} @@ -1032,7 +1037,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - for spring in armature_data.vrm_addon_extension.spring_bone1.springs: + for spring in get_armature_extension(armature_data).spring_bone1.springs: for joint in spring.joints: joint.animation_state.initialized_as_tail = False reset_state(context) diff --git a/src/io_scene_vrm/editor/spring_bone1/panel.py b/src/io_scene_vrm/editor/spring_bone1/panel.py index 62a19c290..0d599001f 100644 --- a/src/io_scene_vrm/editor/spring_bone1/panel.py +++ b/src/io_scene_vrm/editor/spring_bone1/panel.py @@ -4,6 +4,7 @@ from bpy.types import Armature, Context, Object, Panel, UILayout from .. import search +from ..extension import get_armature_extension from ..migration import defer_migrate from ..panel import VRM_PT_vrm_armature_object_property, draw_template_list from ..search import active_object_is_vrm1_armature @@ -365,7 +366,7 @@ def draw(self, context: Context) -> None: draw_spring_bone1_spring_bone_layout( active_object, self.layout, - armature_data.vrm_addon_extension.spring_bone1, + get_armature_extension(armature_data).spring_bone1, ) @@ -395,7 +396,7 @@ def draw(self, context: Context) -> None: draw_spring_bone1_spring_bone_layout( armature, self.layout, - armature_data.vrm_addon_extension.spring_bone1, + get_armature_extension(armature_data).spring_bone1, ) @@ -440,7 +441,9 @@ def active_armature_and_collider( armature_data = obj.data if not isinstance(armature_data, Armature): continue - for collider in armature_data.vrm_addon_extension.spring_bone1.colliders: + for collider in get_armature_extension( + armature_data + ).spring_bone1.colliders: if collider.bpy_object == collider_object: return (obj, collider) return None @@ -457,7 +460,7 @@ def draw(self, context: Context) -> None: armature_data = armature.data if not isinstance(armature_data, Armature): return - if armature_data.vrm_addon_extension.is_vrm1(): + if get_armature_extension(armature_data).is_vrm1(): draw_spring_bone1_collider_layout(armature, self.layout.column(), collider) return diff --git a/src/io_scene_vrm/editor/spring_bone1/property_group.py b/src/io_scene_vrm/editor/spring_bone1/property_group.py index 73d96886e..ea0b31ca3 100644 --- a/src/io_scene_vrm/editor/spring_bone1/property_group.py +++ b/src/io_scene_vrm/editor/spring_bone1/property_group.py @@ -40,7 +40,9 @@ def find_armature_and_collider( armature_data = obj.data if not isinstance(armature_data, Armature): continue - for collider in armature_data.vrm_addon_extension.spring_bone1.colliders: + for collider in get_armature_spring_bone1_extension( + armature_data + ).colliders: if collider.shape.sphere == self: return (obj, collider) message = "No armature" @@ -149,7 +151,9 @@ def find_armature_and_collider( armature_data = obj.data if not isinstance(armature_data, Armature): continue - for collider in armature_data.vrm_addon_extension.spring_bone1.colliders: + for collider in get_armature_spring_bone1_extension( + armature_data + ).colliders: if collider.shape.capsule == self: return (obj, collider) message = "No armature" @@ -329,7 +333,7 @@ def broadcast_bpy_object_name(self, context: Context) -> None: if not hasattr(armature, "vrm_addon_extension"): continue - spring_bone = armature.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_spring_bone1_extension(armature) for collider in spring_bone.colliders: if collider.search_one_time_uuid != self.search_one_time_uuid: @@ -466,7 +470,7 @@ def set_collider_name(self, value: object) -> None: self.search_one_time_uuid = uuid.uuid4().hex for armature in context.blend_data.armatures: - spring_bone = armature.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_spring_bone1_extension(armature) for collider_group in spring_bone.collider_groups: for collider_reference in collider_group.colliders: if ( @@ -511,7 +515,7 @@ def set_vrm_name(self, vrm_name: object) -> None: def fix_index(self, context: Context) -> None: self.search_one_time_uuid = uuid.uuid4().hex for armature in context.blend_data.armatures: - spring_bone = armature.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_spring_bone1_extension(armature) for index, collider_group in enumerate(spring_bone.collider_groups): if collider_group.search_one_time_uuid != self.search_one_time_uuid: @@ -665,7 +669,7 @@ def set_collider_group_name(self, value: object) -> None: self.search_one_time_uuid = uuid.uuid4().hex for armature in context.blend_data.armatures: - spring_bone = armature.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_spring_bone1_extension(armature) for spring in spring_bone.springs: for collider_group_reference in spring.collider_groups: if ( @@ -814,3 +818,14 @@ def update_enable_animation(self, _context: Context) -> None: active_collider_index: int # type: ignore[no-redef] active_collider_group_index: int # type: ignore[no-redef] active_spring_index: int # type: ignore[no-redef] + + +def get_armature_spring_bone1_extension( + armature: Armature, +) -> SpringBone1SpringBonePropertyGroup: + spring_bone1 = getattr( + getattr(armature, "vrm_addon_extension", None), "spring_bone1", None + ) + if not isinstance(spring_bone1, SpringBone1SpringBonePropertyGroup): + raise TypeError + return spring_bone1 diff --git a/src/io_scene_vrm/editor/spring_bone1/ui_list.py b/src/io_scene_vrm/editor/spring_bone1/ui_list.py index fada25386..a2615f3fa 100644 --- a/src/io_scene_vrm/editor/spring_bone1/ui_list.py +++ b/src/io_scene_vrm/editor/spring_bone1/ui_list.py @@ -1,6 +1,7 @@ from bpy.types import Context, UILayout, UIList from ...common.logging import get_logger +from ..extension import get_armature_extension from .property_group import ( SpringBone1ColliderGroupPropertyGroup, SpringBone1ColliderGroupReferencePropertyGroup, @@ -110,7 +111,7 @@ def draw_item( # Search for armature spring_bone = None for armature in context.blend_data.armatures: - ext = armature.vrm_addon_extension + ext = get_armature_extension(armature) if any(collider_group == c for c in ext.spring_bone1.collider_groups): spring_bone = ext.spring_bone1 break @@ -229,7 +230,7 @@ def draw_item( # Search for armature spring_bone = None for armature in context.blend_data.armatures: - ext = armature.vrm_addon_extension + ext = get_armature_extension(armature) if any(spring == s for s in ext.spring_bone1.springs): spring_bone = ext.spring_bone1 break diff --git a/src/io_scene_vrm/editor/validation.py b/src/io_scene_vrm/editor/validation.py index 9573b4362..eb5db5830 100644 --- a/src/io_scene_vrm/editor/validation.py +++ b/src/io_scene_vrm/editor/validation.py @@ -29,8 +29,9 @@ from ..common.preferences import get_preferences from ..common.vrm0 import human_bone as vrm0_human_bone from ..common.vrm1 import human_bone as vrm1_human_bone -from ..editor.property_group import CollectionPropertyProtocol from . import migration, search +from .extension import get_armature_extension, get_material_extension +from .property_group import CollectionPropertyProtocol logger = get_logger(__name__) @@ -111,7 +112,7 @@ def validate_bone_order_vrm0( if not isinstance(armature_data, Armature): message = f"{type(armature_data)} is not an Armature" raise TypeError(message) - humanoid = armature_data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(armature_data).vrm0.humanoid if readonly: humanoid.defer_update_all_node_candidates(armature_data.name) else: @@ -148,7 +149,7 @@ def validate_bone_order_vrm1( if not isinstance(armature_data, Armature): message = f"{type(armature_data)} is not an Armature" raise TypeError(message) - human_bones = armature_data.vrm_addon_extension.vrm1.humanoid.human_bones + human_bones = get_armature_extension(armature_data).vrm1.humanoid.human_bones if readonly: human_bones.defer_update_all_node_candidates(armature_data.name) else: @@ -190,7 +191,7 @@ def validate_bone_order( if not isinstance(armature_data, Armature): message = f"{type(armature_data)} is not an Armature" raise TypeError(message) - if armature_data.vrm_addon_extension.is_vrm0(): + if get_armature_extension(armature_data).is_vrm0(): WM_OT_vrm_validator.validate_bone_order_vrm0( context, messages, armature, readonly=readonly ) @@ -329,15 +330,15 @@ def detect_errors( # TODO: T_POSE, all_required_bones_exist = True - if armature_data.vrm_addon_extension.is_vrm1(): + if get_armature_extension(armature_data).is_vrm1(): _, _, constraint_warning_messages = search.export_constraints( export_objects, armature ) skippable_warning_messages.extend(constraint_warning_messages) - human_bones = ( - armature_data.vrm_addon_extension.vrm1.humanoid.human_bones - ) + human_bones = get_armature_extension( + armature_data + ).vrm1.humanoid.human_bones human_bone_name_to_human_bone = ( human_bones.human_bone_name_to_human_bone() @@ -418,7 +419,7 @@ def detect_errors( ) else: - humanoid = armature_data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(armature_data).vrm0.humanoid human_bones = humanoid.human_bones all_required_bones_exist = True for ( @@ -469,7 +470,7 @@ def detect_errors( if ( armature is not None and isinstance(armature.data, Armature) - and armature.data.vrm_addon_extension.is_vrm1() + and get_armature_extension(armature.data).is_vrm1() ): error_messages.extend( pgettext( @@ -482,7 +483,7 @@ def detect_errors( ) joint_chain_bone_names_to_spring_vrm_name: dict[str, str] = {} - for spring in armature.data.vrm_addon_extension.spring_bone1.springs: + for spring in get_armature_extension(armature.data).spring_bone1.springs: joint_bone_names: list[str] = [] for joint in spring.joints: bone_name = joint.node.bone_name @@ -546,7 +547,7 @@ def detect_errors( if ( armature is not None and isinstance(armature.data, Armature) - and armature.data.vrm_addon_extension.is_vrm1() + and get_armature_extension(armature.data).is_vrm1() ): continue info_messages.append( @@ -578,7 +579,7 @@ def detect_errors( vertex_error_count = vertex_error_count + 1 for mat in used_materials: - if not mat.node_tree or mat.vrm_addon_extension.mtoon1.enabled: + if not mat.node_tree or get_material_extension(mat).mtoon1.enabled: continue for node in mat.node_tree.nodes: if node.type != "OUTPUT_MATERIAL": @@ -668,7 +669,7 @@ def detect_errors( ) for mat in used_materials: - gltf = mat.vrm_addon_extension.mtoon1 + gltf = get_material_extension(mat).mtoon1 if not gltf.enabled: continue @@ -676,7 +677,7 @@ def detect_errors( downgrade_to_mtoon0=( armature is None or not isinstance(armature.data, Armature) - or armature.data.vrm_addon_extension.is_vrm0() + or get_armature_extension(armature.data).is_vrm0() ) ): source = texture.source @@ -707,7 +708,7 @@ def detect_errors( if ( armature is None or not isinstance(armature.data, Armature) - or not armature.data.vrm_addon_extension.is_vrm0() + or not get_armature_extension(armature.data).is_vrm0() or not source ): continue @@ -754,7 +755,7 @@ def detect_errors( if ( armature is not None and isinstance(armature.data, Armature) - and armature.data.vrm_addon_extension.is_vrm0() + and get_armature_extension(armature.data).is_vrm0() ): if export_fb_ngon_encoding: warning_messages.append( @@ -765,7 +766,7 @@ def detect_errors( ) # first_person - first_person = armature.data.vrm_addon_extension.vrm0.first_person + first_person = get_armature_extension(armature.data).vrm0.first_person if not first_person.first_person_bone.bone_name: info_messages.append( pgettext( @@ -776,9 +777,9 @@ def detect_errors( # blend_shape_master # TODO: material value and material existence - blend_shape_master = ( - armature.data.vrm_addon_extension.vrm0.blend_shape_master - ) + blend_shape_master = get_armature_extension( + armature.data + ).vrm0.blend_shape_master for blend_shape_group in blend_shape_master.blend_shape_groups: for bind in blend_shape_group.binds: mesh_object = context.blend_data.objects.get( diff --git a/src/io_scene_vrm/editor/vrm0/gizmo_group.py b/src/io_scene_vrm/editor/vrm0/gizmo_group.py index 769d42588..8f8f17898 100644 --- a/src/io_scene_vrm/editor/vrm0/gizmo_group.py +++ b/src/io_scene_vrm/editor/vrm0/gizmo_group.py @@ -2,6 +2,8 @@ from bpy.types import Armature, Context, GizmoGroup +from ..extension import get_armature_extension + # https://gist.github.com/FujiSunflower/09fdabc7ca991f8292657abc4ef001b0 class Vrm0FirstPersonBoneOffsetGizmoGroup(GizmoGroup): @@ -25,7 +27,7 @@ def setup(self, context: Context) -> None: armature_data = active_object.data if not isinstance(armature_data, Armature): return - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) first_person = ext.vrm0.first_person first_person_bone = armature_data.bones[ first_person.first_person_bone.bone_name @@ -50,7 +52,7 @@ def refresh(self, context: Context) -> None: armature_data = active_object.data if not isinstance(armature_data, Armature): return - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) gizmo = self.first_person_gizmo first_person = ext.vrm0.first_person first_person_bone = armature_data.bones[ diff --git a/src/io_scene_vrm/editor/vrm0/migration.py b/src/io_scene_vrm/editor/vrm0/migration.py index 3cc87e7db..03c4761e2 100644 --- a/src/io_scene_vrm/editor/vrm0/migration.py +++ b/src/io_scene_vrm/editor/vrm0/migration.py @@ -10,6 +10,7 @@ from ...common.convert import Json from ...common.deep import make_json from ...common.vrm0.human_bone import HumanBoneSpecifications +from ..extension import get_armature_extension, get_bone_extension from ..property_group import BonePropertyGroup from .property_group import ( Vrm0BlendShapeGroupPropertyGroup, @@ -443,7 +444,7 @@ def migrate_vrm0_secondary_animation( def migrate_legacy_custom_properties( context: Context, armature: Object, armature_data: Armature ) -> None: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) if tuple(ext.addon_version) >= (2, 0, 1): return @@ -486,7 +487,7 @@ def migrate_legacy_custom_properties( def migrate_blender_object(armature_data: Armature) -> None: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) if tuple(ext.addon_version) >= (2, 3, 27): return @@ -500,7 +501,7 @@ def migrate_blender_object(armature_data: Armature) -> None: def migrate_link_to_bone_object( context: Context, armature: Object, armature_data: Armature ) -> None: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) if tuple(ext.addon_version) >= (2, 3, 27): return @@ -519,9 +520,10 @@ def migrate_link_to_bone_object( bone = parent_data.bones.get(link_to_bone.parent_bone) if not bone: continue - if not bone.vrm_addon_extension.uuid: - bone.vrm_addon_extension.uuid = uuid.uuid4().hex - bone_property_group.bone_uuid = bone.vrm_addon_extension.uuid + bone_extension = get_bone_extension(bone) + if not bone_extension.uuid: + bone_extension.uuid = uuid.uuid4().hex + bone_property_group.bone_uuid = bone_extension.uuid for bone_property_group in BonePropertyGroup.get_all_bone_property_groups(armature): link_to_bone = bone_property_group.pop("link_to_bone", None) @@ -542,7 +544,7 @@ def migrate_link_to_bone_object( def migrate_link_to_mesh_object(armature_data: Armature) -> None: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) if tuple(ext.addon_version) >= (2, 3, 23): return @@ -570,7 +572,7 @@ def migrate_link_to_mesh_object(armature_data: Armature) -> None: def remove_link_to_mesh_object(armature_data: Armature) -> None: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) if tuple(ext.addon_version) >= (2, 3, 27): return @@ -598,7 +600,7 @@ def remove_link_to_mesh_object(armature_data: Armature) -> None: def fixup_gravity_dir(armature_data: Armature) -> None: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) if tuple(ext.addon_version) >= (2, 15, 4): return @@ -609,7 +611,7 @@ def fixup_gravity_dir(armature_data: Armature) -> None: def fixup_humanoid_feet_spacing(armature_data: Armature) -> None: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) if tuple(ext.addon_version) >= (2, 18, 2): return humanoid = ext.vrm0.humanoid @@ -619,7 +621,7 @@ def fixup_humanoid_feet_spacing(armature_data: Armature) -> None: def migrate_pose(context: Context, armature_data: bpy.types.Armature) -> None: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) if tuple(ext.addon_version) >= (2, 20, 34): return diff --git a/src/io_scene_vrm/editor/vrm0/ops.py b/src/io_scene_vrm/editor/vrm0/ops.py index deecf7bf5..c2fa9a2da 100644 --- a/src/io_scene_vrm/editor/vrm0/ops.py +++ b/src/io_scene_vrm/editor/vrm0/ops.py @@ -6,6 +6,7 @@ from bpy.types import Armature, Context, Operator from ...common.human_bone_mapper.human_bone_mapper import create_human_bone_mapping +from ..extension import get_armature_extension from .property_group import Vrm0HumanoidPropertyGroup @@ -26,7 +27,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - first_person = armature_data.vrm_addon_extension.vrm0.first_person + first_person = get_armature_extension(armature_data).vrm0.first_person first_person.mesh_annotations.add() first_person.active_mesh_annotation_index = ( len(first_person.mesh_annotations) - 1 @@ -60,7 +61,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - first_person = armature_data.vrm_addon_extension.vrm0.first_person + first_person = get_armature_extension(armature_data).vrm0.first_person if len(first_person.mesh_annotations) <= self.mesh_annotation_index: return {"CANCELLED"} first_person.mesh_annotations.remove(self.mesh_annotation_index) @@ -98,7 +99,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - first_person = armature_data.vrm_addon_extension.vrm0.first_person + first_person = get_armature_extension(armature_data).vrm0.first_person if len(first_person.mesh_annotations) <= self.mesh_annotation_index: return {"CANCELLED"} if len(first_person.mesh_annotations) <= self.mesh_annotation_index: @@ -138,7 +139,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - first_person = armature_data.vrm_addon_extension.vrm0.first_person + first_person = get_armature_extension(armature_data).vrm0.first_person if len(first_person.mesh_annotations) <= self.mesh_annotation_index: return {"CANCELLED"} new_index = (first_person.active_mesh_annotation_index + 1) % len( @@ -176,9 +177,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_groups = ( - armature_data.vrm_addon_extension.vrm0.blend_shape_master.blend_shape_groups - ) + blend_shape_groups = get_armature_extension( + armature_data + ).vrm0.blend_shape_master.blend_shape_groups if len(blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} blend_shape_group = blend_shape_groups[self.blend_shape_group_index] @@ -220,9 +221,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_groups = ( - armature_data.vrm_addon_extension.vrm0.blend_shape_master.blend_shape_groups - ) + blend_shape_groups = get_armature_extension( + armature_data + ).vrm0.blend_shape_master.blend_shape_groups if len(blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} blend_shape_group = blend_shape_groups[self.blend_shape_group_index] @@ -268,9 +269,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_groups = ( - armature_data.vrm_addon_extension.vrm0.blend_shape_master.blend_shape_groups - ) + blend_shape_groups = get_armature_extension( + armature_data + ).vrm0.blend_shape_master.blend_shape_groups if len(blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} blend_shape_group = blend_shape_groups[self.blend_shape_group_index] @@ -316,9 +317,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_groups = ( - armature_data.vrm_addon_extension.vrm0.blend_shape_master.blend_shape_groups - ) + blend_shape_groups = get_armature_extension( + armature_data + ).vrm0.blend_shape_master.blend_shape_groups if len(blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} blend_shape_group = blend_shape_groups[self.blend_shape_group_index] @@ -364,9 +365,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_groups = ( - armature_data.vrm_addon_extension.vrm0.blend_shape_master.blend_shape_groups - ) + blend_shape_groups = get_armature_extension( + armature_data + ).vrm0.blend_shape_master.blend_shape_groups if len(blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} material_values = blend_shape_groups[ @@ -414,9 +415,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_groups = ( - armature_data.vrm_addon_extension.vrm0.blend_shape_master.blend_shape_groups - ) + blend_shape_groups = get_armature_extension( + armature_data + ).vrm0.blend_shape_master.blend_shape_groups if len(blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} material_values = blend_shape_groups[ @@ -460,9 +461,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_groups = ( - armature_data.vrm_addon_extension.vrm0.blend_shape_master.blend_shape_groups - ) + blend_shape_groups = get_armature_extension( + armature_data + ).vrm0.blend_shape_master.blend_shape_groups if len(blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} blend_shape_group = blend_shape_groups[self.blend_shape_group_index] @@ -502,9 +503,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_groups = ( - armature_data.vrm_addon_extension.vrm0.blend_shape_master.blend_shape_groups - ) + blend_shape_groups = get_armature_extension( + armature_data + ).vrm0.blend_shape_master.blend_shape_groups if len(blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} blend_shape_group = blend_shape_groups[self.blend_shape_group_index] @@ -550,9 +551,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_groups = ( - armature_data.vrm_addon_extension.vrm0.blend_shape_master.blend_shape_groups - ) + blend_shape_groups = get_armature_extension( + armature_data + ).vrm0.blend_shape_master.blend_shape_groups if len(blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} blend_shape_group = blend_shape_groups[self.blend_shape_group_index] @@ -596,9 +597,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_groups = ( - armature_data.vrm_addon_extension.vrm0.blend_shape_master.blend_shape_groups - ) + blend_shape_groups = get_armature_extension( + armature_data + ).vrm0.blend_shape_master.blend_shape_groups if len(blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} blend_shape_group = blend_shape_groups[self.blend_shape_group_index] @@ -641,9 +642,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - collider_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.collider_groups - ) + collider_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.collider_groups if len(collider_groups) <= self.collider_group_index: return {"CANCELLED"} collider_group = collider_groups[self.collider_group_index] @@ -697,9 +698,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - collider_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.collider_groups - ) + collider_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.collider_groups if len(collider_groups) <= self.collider_group_index: return {"CANCELLED"} collider_group = collider_groups[self.collider_group_index] @@ -749,9 +750,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - collider_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.collider_groups - ) + collider_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.collider_groups if len(collider_groups) <= self.collider_group_index: return {"CANCELLED"} collider_group = collider_groups[self.collider_group_index] @@ -795,9 +796,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - collider_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.collider_groups - ) + collider_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.collider_groups if len(collider_groups) <= self.collider_group_index: return {"CANCELLED"} collider_group = collider_groups[self.collider_group_index] @@ -837,9 +838,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - bone_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.bone_groups - ) + bone_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.bone_groups if len(bone_groups) <= self.bone_group_index: return {"CANCELLED"} bone_group = bone_groups[self.bone_group_index] @@ -880,9 +881,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - bone_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.bone_groups - ) + bone_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.bone_groups if len(bone_groups) <= self.bone_group_index: return {"CANCELLED"} bone_group = bone_groups[self.bone_group_index] @@ -927,9 +928,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - bone_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.bone_groups - ) + bone_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.bone_groups if len(bone_groups) <= self.bone_group_index: return {"CANCELLED"} bone_group = bone_groups[self.bone_group_index] @@ -973,9 +974,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - bone_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.bone_groups - ) + bone_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.bone_groups if len(bone_groups) <= self.bone_group_index: return {"CANCELLED"} bone_group = bone_groups[self.bone_group_index] @@ -1015,9 +1016,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - bone_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.bone_groups - ) + bone_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.bone_groups if len(bone_groups) <= self.bone_group_index: return {"CANCELLED"} bone_group = bone_groups[self.bone_group_index] @@ -1058,9 +1059,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - bone_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.bone_groups - ) + bone_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.bone_groups if len(bone_groups) <= self.bone_group_index: return {"CANCELLED"} bone_group = bone_groups[self.bone_group_index] @@ -1106,9 +1107,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - bone_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.bone_groups - ) + bone_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.bone_groups if len(bone_groups) <= self.bone_group_index: return {"CANCELLED"} bone_group = bone_groups[self.bone_group_index] @@ -1152,9 +1153,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - bone_groups = ( - armature_data.vrm_addon_extension.vrm0.secondary_animation.bone_groups - ) + bone_groups = get_armature_extension( + armature_data + ).vrm0.secondary_animation.bone_groups if len(bone_groups) <= self.bone_group_index: return {"CANCELLED"} bone_group = bone_groups[self.bone_group_index] @@ -1193,7 +1194,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_master = armature_data.vrm_addon_extension.vrm0.blend_shape_master + blend_shape_master = get_armature_extension( + armature_data + ).vrm0.blend_shape_master blend_shape_group = blend_shape_master.blend_shape_groups.add() blend_shape_group.name = self.name blend_shape_master.active_blend_shape_group_index = ( @@ -1229,7 +1232,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_master = armature_data.vrm_addon_extension.vrm0.blend_shape_master + blend_shape_master = get_armature_extension( + armature_data + ).vrm0.blend_shape_master if len(blend_shape_master.blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} blend_shape_master.blend_shape_groups.remove(self.blend_shape_group_index) @@ -1267,7 +1272,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_master = armature_data.vrm_addon_extension.vrm0.blend_shape_master + blend_shape_master = get_armature_extension( + armature_data + ).vrm0.blend_shape_master if len(blend_shape_master.blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} new_index = (self.blend_shape_group_index - 1) % len( @@ -1307,7 +1314,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - blend_shape_master = armature_data.vrm_addon_extension.vrm0.blend_shape_master + blend_shape_master = get_armature_extension( + armature_data + ).vrm0.blend_shape_master if len(blend_shape_master.blend_shape_groups) <= self.blend_shape_group_index: return {"CANCELLED"} new_index = (self.blend_shape_group_index + 1) % len( @@ -1349,7 +1358,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - secondary_animation = armature_data.vrm_addon_extension.vrm0.secondary_animation + secondary_animation = get_armature_extension( + armature_data + ).vrm0.secondary_animation secondary_animation.bone_groups.add() secondary_animation.active_bone_group_index = ( len(secondary_animation.bone_groups) - 1 @@ -1384,7 +1395,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - secondary_animation = armature_data.vrm_addon_extension.vrm0.secondary_animation + secondary_animation = get_armature_extension( + armature_data + ).vrm0.secondary_animation if len(secondary_animation.bone_groups) <= self.bone_group_index: return {"CANCELLED"} secondary_animation.bone_groups.remove(self.bone_group_index) @@ -1422,7 +1435,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - secondary_animation = armature_data.vrm_addon_extension.vrm0.secondary_animation + secondary_animation = get_armature_extension( + armature_data + ).vrm0.secondary_animation if len(secondary_animation.bone_groups) <= self.bone_group_index: return {"CANCELLED"} new_index = (self.bone_group_index - 1) % len(secondary_animation.bone_groups) @@ -1458,7 +1473,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - secondary_animation = armature_data.vrm_addon_extension.vrm0.secondary_animation + secondary_animation = get_armature_extension( + armature_data + ).vrm0.secondary_animation if len(secondary_animation.bone_groups) <= self.bone_group_index: return {"CANCELLED"} new_index = (self.bone_group_index + 1) % len(secondary_animation.bone_groups) @@ -1490,7 +1507,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) secondary_animation = ext.vrm0.secondary_animation collider_group = secondary_animation.collider_groups.add() collider_group.uuid = uuid.uuid4().hex @@ -1527,14 +1544,16 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - secondary_animation = armature_data.vrm_addon_extension.vrm0.secondary_animation + secondary_animation = get_armature_extension( + armature_data + ).vrm0.secondary_animation if len(secondary_animation.collider_groups) <= self.collider_group_index: return {"CANCELLED"} secondary_animation.collider_groups.remove(self.collider_group_index) - for ( - bone_group - ) in armature_data.vrm_addon_extension.vrm0.secondary_animation.bone_groups: + for bone_group in get_armature_extension( + armature_data + ).vrm0.secondary_animation.bone_groups: bone_group.refresh(armature) secondary_animation.active_collider_group_index = min( @@ -1571,7 +1590,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - secondary_animation = armature_data.vrm_addon_extension.vrm0.secondary_animation + secondary_animation = get_armature_extension( + armature_data + ).vrm0.secondary_animation if len(secondary_animation.collider_groups) <= self.collider_group_index: return {"CANCELLED"} new_index = (self.collider_group_index - 1) % len( @@ -1609,7 +1630,9 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - secondary_animation = armature_data.vrm_addon_extension.vrm0.secondary_animation + secondary_animation = get_armature_extension( + armature_data + ).vrm0.secondary_animation if len(secondary_animation.collider_groups) <= self.collider_group_index: return {"CANCELLED"} new_index = (self.collider_group_index + 1) % len( @@ -1645,7 +1668,7 @@ def execute(self, context: Context) -> set[str]: return {"CANCELLED"} Vrm0HumanoidPropertyGroup.fixup_human_bones(armature) - humanoid = armature_data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(armature_data).vrm0.humanoid bones = armature_data.bones for ( bone_name, diff --git a/src/io_scene_vrm/editor/vrm0/panel.py b/src/io_scene_vrm/editor/vrm0/panel.py index d649fb305..d940e9241 100644 --- a/src/io_scene_vrm/editor/vrm0/panel.py +++ b/src/io_scene_vrm/editor/vrm0/panel.py @@ -13,6 +13,11 @@ from ...common.vrm0.human_bone import HumanBoneSpecification, HumanBoneSpecifications from .. import ops, search +from ..extension import ( + get_armature_extension, + get_material_extension, + get_scene_extension, +) from ..migration import defer_migrate from ..ops import layout_operator from ..panel import VRM_PT_vrm_armature_object_property, draw_template_list @@ -98,7 +103,7 @@ def draw_vrm0_humanoid_required_bones_layout( if not isinstance(armature_data, Armature): return - humanoid = armature_data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(armature_data).vrm0.humanoid layout.label(text="VRM Required Bones", icon="ARMATURE_DATA") row = layout.row(align=True).split(factor=split_factor, align=True) column = row.column(align=True) @@ -160,7 +165,7 @@ def draw_vrm0_humanoid_optional_bones_layout( if not isinstance(armature_data, Armature): return - humanoid = armature_data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(armature_data).vrm0.humanoid split_factor = 0.2 layout.label(text="VRM Optional Bones", icon="BONE_DATA") @@ -407,7 +412,7 @@ def draw(self, context: Context) -> None: context, active_object, self.layout, - armature_data.vrm_addon_extension.vrm0.humanoid, + get_armature_extension(armature_data).vrm0.humanoid, ) @@ -437,7 +442,7 @@ def draw(self, context: Context) -> None: context, armature, self.layout, - armature_data.vrm_addon_extension.vrm0.humanoid, + get_armature_extension(armature_data).vrm0.humanoid, ) @@ -528,7 +533,7 @@ def draw(self, context: Context) -> None: armature_data = active_object.data if not isinstance(armature_data, Armature): return - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) draw_vrm0_first_person_layout( active_object, context, @@ -563,7 +568,7 @@ def draw(self, context: Context) -> None: armature, context, self.layout, - armature_data.vrm_addon_extension.vrm0.first_person, + get_armature_extension(armature_data).vrm0.first_person, ) @@ -711,7 +716,7 @@ def draw_vrm0_blend_shape_master_layout( ) else: material = material_value.material - ext = material.vrm_addon_extension + ext = get_material_extension(material) node, vrm_shader_name = search.vrm_shader_node(material) if ext.mtoon1.enabled or ( node and vrm_shader_name == "MToon_unversioned" @@ -720,7 +725,7 @@ def draw_vrm0_blend_shape_master_layout( material_value_column.prop_search( material_value, "property_name", - context.scene.vrm_addon_extension, + get_scene_extension(context.scene), "vrm0_material_mtoon0_property_names", icon="PROPERTIES", results_are_suggestions=True, @@ -729,7 +734,7 @@ def draw_vrm0_blend_shape_master_layout( material_value_column.prop_search( material_value, "property_name", - context.scene.vrm_addon_extension, + get_scene_extension(context.scene), "vrm0_material_mtoon0_property_names", icon="PROPERTIES", ) @@ -737,7 +742,7 @@ def draw_vrm0_blend_shape_master_layout( material_value_column.prop_search( material_value, "property_name", - context.scene.vrm_addon_extension, + get_scene_extension(context.scene), "vrm0_material_gltf_property_names", icon="PROPERTIES", results_are_suggestions=True, @@ -746,7 +751,7 @@ def draw_vrm0_blend_shape_master_layout( material_value_column.prop_search( material_value, "property_name", - context.scene.vrm_addon_extension, + get_scene_extension(context.scene), "vrm0_material_gltf_property_names", icon="PROPERTIES", ) @@ -802,7 +807,7 @@ def draw(self, context: Context) -> None: armature_data = active_object.data if not isinstance(armature_data, Armature): return - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) draw_vrm0_blend_shape_master_layout( active_object, context, self.layout, ext.vrm0.blend_shape_master ) @@ -834,7 +839,7 @@ def draw(self, context: Context) -> None: armature, context, self.layout, - armature_data.vrm_addon_extension.vrm0.blend_shape_master, + get_armature_extension(armature_data).vrm0.blend_shape_master, ) @@ -1089,7 +1094,7 @@ def draw(self, context: Context) -> None: armature_data = active_object.data if not isinstance(armature_data, Armature): return - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) draw_vrm0_secondary_animation_layout( active_object, self.layout, ext.vrm0.secondary_animation ) @@ -1120,7 +1125,7 @@ def draw(self, context: Context) -> None: draw_vrm0_secondary_animation_layout( armature, self.layout, - armature_data.vrm_addon_extension.vrm0.secondary_animation, + get_armature_extension(armature_data).vrm0.secondary_animation, ) @@ -1182,7 +1187,7 @@ def draw(self, context: Context) -> None: armature_data = active_object.data if not isinstance(armature_data, Armature): return - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) draw_vrm0_meta_layout(active_object, context, self.layout, ext.vrm0.meta) @@ -1212,5 +1217,5 @@ def draw(self, context: Context) -> None: armature, context, self.layout, - armature_data.vrm_addon_extension.vrm0.meta, + get_armature_extension(armature_data).vrm0.meta, ) diff --git a/src/io_scene_vrm/editor/vrm0/property_group.py b/src/io_scene_vrm/editor/vrm0/property_group.py index 2dfb44a79..a97c84fe7 100644 --- a/src/io_scene_vrm/editor/vrm0/property_group.py +++ b/src/io_scene_vrm/editor/vrm0/property_group.py @@ -244,6 +244,8 @@ def update_all_node_candidates( *, force: bool = False, ) -> None: + from ..extension import get_armature_extension + if context is None: context = bpy.context @@ -251,7 +253,7 @@ def update_all_node_candidates( if not armature_data: return bones = armature_data.bones.values() - humanoid = armature_data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(armature_data).vrm0.humanoid bone_names: list[str] = [] for bone in sorted(bones, key=lambda b: str(b.name)): bone_names.append(bone.name) @@ -284,11 +286,13 @@ def update_all_node_candidates( @staticmethod def fixup_human_bones(obj: Object) -> None: + from ..extension import get_armature_extension + armature_data = obj.data if not isinstance(armature_data, Armature): return - humanoid = armature_data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(armature_data).vrm0.humanoid # 存在していないボーンマップを追加 refresh = False @@ -338,7 +342,9 @@ def fixup_human_bones(obj: Object) -> None: if not refresh: return - secondary_animation = armature_data.vrm_addon_extension.vrm0.secondary_animation + secondary_animation = get_armature_extension( + armature_data + ).vrm0.secondary_animation for collider_group in secondary_animation.collider_groups: collider_group.refresh(obj) for bone_group in secondary_animation.bone_groups: @@ -742,6 +748,8 @@ class Vrm0SecondaryAnimationColliderGroupPropertyGroup(PropertyGroup): ) def refresh(self, armature: Object) -> None: + from ..extension import get_armature_extension + self.name = ( str(self.node.bone_name) if self.node and self.node.bone_name else "" ) + f"#{self.uuid}" @@ -755,9 +763,9 @@ def refresh(self, armature: Object) -> None: armature_data = armature.data if not isinstance(armature_data, Armature): return - for ( - bone_group - ) in armature_data.vrm_addon_extension.vrm0.secondary_animation.bone_groups: + for bone_group in get_armature_extension( + armature_data + ).vrm0.secondary_animation.bone_groups: bone_group.refresh(armature) # for UI @@ -865,10 +873,12 @@ def update_gravity_dir(self, _context: Context) -> None: active_collider_group_index: IntProperty(min=0) # type: ignore[valid-type] def refresh(self, armature: Object) -> None: + from ..extension import get_armature_extension + armature_data = armature.data if not isinstance(armature_data, Armature): return - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) collider_group_uuid_to_name = { collider_group.uuid: collider_group.name for collider_group in ext.vrm0.secondary_animation.collider_groups diff --git a/src/io_scene_vrm/editor/vrm0/ui_list.py b/src/io_scene_vrm/editor/vrm0/ui_list.py index 884057c4e..f55c8cc96 100644 --- a/src/io_scene_vrm/editor/vrm0/ui_list.py +++ b/src/io_scene_vrm/editor/vrm0/ui_list.py @@ -1,5 +1,6 @@ from bpy.types import Context, Mesh, UILayout, UIList +from ..extension import get_armature_extension from ..property_group import BonePropertyGroup, StringPropertyGroup from .property_group import ( Vrm0BlendShapeBindPropertyGroup, @@ -180,7 +181,7 @@ def draw_item( secondary_animation = None for armature in context.blend_data.armatures: - ext = armature.vrm_addon_extension.vrm0 + ext = get_armature_extension(armature).vrm0 if any(bone_group == bg for bg in ext.secondary_animation.bone_groups): secondary_animation = ext.secondary_animation break diff --git a/src/io_scene_vrm/editor/vrm1/handler.py b/src/io_scene_vrm/editor/vrm1/handler.py index 775067f29..f6c72fd60 100644 --- a/src/io_scene_vrm/editor/vrm1/handler.py +++ b/src/io_scene_vrm/editor/vrm1/handler.py @@ -6,6 +6,7 @@ from mathutils import Vector from ...common.logging import get_logger +from ..extension import get_armature_extension from .property_group import Vrm1ExpressionPropertyGroup, Vrm1LookAtPropertyGroup logger = get_logger(__name__) @@ -46,7 +47,8 @@ def update_look_at_preview() -> Optional[float]: changed = any( True for ext in [ - armature.vrm_addon_extension for armature in context.blend_data.armatures + get_armature_extension(armature) + for armature in context.blend_data.armatures ] if ext.is_vrm1() and ext.vrm1.look_at.enable_preview diff --git a/src/io_scene_vrm/editor/vrm1/migration.py b/src/io_scene_vrm/editor/vrm1/migration.py index 81aea4007..0bcfda04c 100644 --- a/src/io_scene_vrm/editor/vrm1/migration.py +++ b/src/io_scene_vrm/editor/vrm1/migration.py @@ -4,6 +4,7 @@ from mathutils import Vector from ...common import convert, shader +from ..extension import get_armature_extension from .property_group import ( Vrm1ExpressionPropertyGroup, Vrm1ExpressionsPropertyGroup, @@ -181,7 +182,7 @@ def migrate_old_expressions_layout(expressions: Vrm1ExpressionsPropertyGroup) -> def migrate_pose(context: Context, armature_data: Armature) -> None: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) if tuple(ext.addon_version) >= (2, 20, 34): return @@ -213,20 +214,20 @@ def migrate(context: Context, vrm1: Vrm1PropertyGroup, armature: Object) -> None armature_name=armature.name ) - if tuple(armature_data.vrm_addon_extension.addon_version) <= (2, 14, 10): - ext = armature_data.vrm_addon_extension + if tuple(get_armature_extension(armature_data).addon_version) <= (2, 14, 10): + ext = get_armature_extension(armature_data) head_bone_name = ext.vrm1.humanoid.human_bones.head.node.bone_name head_bone = armature_data.bones.get(head_bone_name) if head_bone: - look_at = armature_data.vrm_addon_extension.vrm1.look_at + look_at = get_armature_extension(armature_data).vrm1.look_at world_translation = ( armature.matrix_world @ head_bone.matrix_local ).to_quaternion() @ Vector(look_at.offset_from_head_bone) look_at.offset_from_head_bone = list(world_translation) - if tuple(armature_data.vrm_addon_extension.addon_version) <= (2, 15, 5): + if tuple(get_armature_extension(armature_data).addon_version) <= (2, 15, 5): # Apply lower limit value - look_at = armature_data.vrm_addon_extension.vrm1.look_at + look_at = get_armature_extension(armature_data).vrm1.look_at look_at.range_map_horizontal_inner.input_max_value = ( look_at.range_map_horizontal_inner.input_max_value ) @@ -240,13 +241,13 @@ def migrate(context: Context, vrm1: Vrm1PropertyGroup, armature: Object) -> None look_at.range_map_vertical_up.input_max_value ) - if tuple(armature_data.vrm_addon_extension.addon_version) < (2, 18, 0): + if tuple(get_armature_extension(armature_data).addon_version) < (2, 18, 0): migrate_old_expressions_layout( - armature_data.vrm_addon_extension.vrm1.expressions + get_armature_extension(armature_data).vrm1.expressions ) - if tuple(armature_data.vrm_addon_extension.addon_version) < (2, 20, 0): - look_at = armature_data.vrm_addon_extension.vrm1.look_at + if tuple(get_armature_extension(armature_data).addon_version) < (2, 20, 0): + look_at = get_armature_extension(armature_data).vrm1.look_at look_at.offset_from_head_bone = ( look_at.offset_from_head_bone[0], look_at.offset_from_head_bone[2], @@ -257,7 +258,7 @@ def migrate(context: Context, vrm1: Vrm1PropertyGroup, armature: Object) -> None # Expressionのプリセットに名前を設定する # 管理上は無くてもよいが、アニメーションキーフレームに表示されるので設定しておきたい - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions preset_name_to_expression_dict = expressions.preset.name_to_expression_dict() for preset_name, preset_expression in preset_name_to_expression_dict.items(): if preset_expression.name != preset_name: diff --git a/src/io_scene_vrm/editor/vrm1/ops.py b/src/io_scene_vrm/editor/vrm1/ops.py index 148905685..8561b6e90 100644 --- a/src/io_scene_vrm/editor/vrm1/ops.py +++ b/src/io_scene_vrm/editor/vrm1/ops.py @@ -9,6 +9,7 @@ from ...common.logging import get_logger from ...common.vrm0.human_bone import HumanBoneName as Vrm0HumanBoneName from ...common.vrm1.human_bone import HumanBoneName, HumanBoneSpecifications +from ..extension import get_armature_extension from ..vrm0.property_group import Vrm0HumanoidPropertyGroup from .property_group import Vrm1HumanBonesPropertyGroup @@ -32,7 +33,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - meta = armature_data.vrm_addon_extension.vrm1.meta + meta = get_armature_extension(armature_data).vrm1.meta author = meta.authors.add() author.value = "" meta.active_author_index = len(meta.authors) - 1 @@ -65,7 +66,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - meta = armature_data.vrm_addon_extension.vrm1.meta + meta = get_armature_extension(armature_data).vrm1.meta if len(meta.authors) <= self.author_index: return {"CANCELLED"} meta.authors.remove(self.author_index) @@ -103,7 +104,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - meta = armature_data.vrm_addon_extension.vrm1.meta + meta = get_armature_extension(armature_data).vrm1.meta if len(meta.authors) <= self.author_index: return {"CANCELLED"} new_index = (self.author_index - 1) % len(meta.authors) @@ -139,7 +140,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - meta = armature_data.vrm_addon_extension.vrm1.meta + meta = get_armature_extension(armature_data).vrm1.meta if len(meta.authors) <= self.author_index: return {"CANCELLED"} new_index = (self.author_index + 1) % len(meta.authors) @@ -171,7 +172,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - meta = armature_data.vrm_addon_extension.vrm1.meta + meta = get_armature_extension(armature_data).vrm1.meta reference = meta.references.add() reference.value = "" meta.active_reference_index = len(meta.references) - 1 @@ -204,7 +205,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - meta = armature_data.vrm_addon_extension.vrm1.meta + meta = get_armature_extension(armature_data).vrm1.meta if len(meta.references) <= self.reference_index: return {"CANCELLED"} meta.references.remove(self.reference_index) @@ -242,7 +243,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - meta = armature_data.vrm_addon_extension.vrm1.meta + meta = get_armature_extension(armature_data).vrm1.meta if len(meta.references) <= self.reference_index: return {"CANCELLED"} new_index = (self.reference_index - 1) % len(meta.references) @@ -278,7 +279,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - meta = armature_data.vrm_addon_extension.vrm1.meta + meta = get_armature_extension(armature_data).vrm1.meta if len(meta.references) <= self.reference_index: return {"CANCELLED"} new_index = (self.reference_index + 1) % len(meta.references) @@ -313,7 +314,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions new_last_custom_index = len(expressions.custom) custom_expression = expressions.custom.add() custom_expression.custom_name = self.custom_expression_name @@ -349,7 +350,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions for custom_index, custom_expression in enumerate( list(expressions.custom.values()) ): @@ -389,7 +390,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression_index = next( ( i @@ -434,7 +435,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression_index = next( ( i @@ -476,7 +477,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - first_person = armature_data.vrm_addon_extension.vrm1.first_person + first_person = get_armature_extension(armature_data).vrm1.first_person first_person.mesh_annotations.add() first_person.active_mesh_annotation_index = ( len(first_person.mesh_annotations) - 1 @@ -510,7 +511,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - first_person = armature_data.vrm_addon_extension.vrm1.first_person + first_person = get_armature_extension(armature_data).vrm1.first_person if len(first_person.mesh_annotations) <= self.mesh_annotation_index: return {"CANCELLED"} first_person.mesh_annotations.remove(self.mesh_annotation_index) @@ -548,7 +549,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - first_person = armature_data.vrm_addon_extension.vrm1.first_person + first_person = get_armature_extension(armature_data).vrm1.first_person if len(first_person.mesh_annotations) <= self.mesh_annotation_index: return {"CANCELLED"} new_index = (self.mesh_annotation_index - 1) % len( @@ -586,7 +587,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - first_person = armature_data.vrm_addon_extension.vrm1.first_person + first_person = get_armature_extension(armature_data).vrm1.first_person if len(first_person.mesh_annotations) <= self.mesh_annotation_index: return {"CANCELLED"} new_index = (self.mesh_annotation_index + 1) % len( @@ -623,7 +624,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression = expressions.all_name_to_expression_dict().get(self.expression_name) if expression is None: return {"CANCELLED"} @@ -664,7 +665,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression = expressions.all_name_to_expression_dict().get(self.expression_name) if expression is None: return {"CANCELLED"} @@ -709,7 +710,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression = expressions.all_name_to_expression_dict().get(self.expression_name) if expression is None: return {"CANCELLED"} @@ -752,7 +753,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression = expressions.all_name_to_expression_dict().get(self.expression_name) if expression is None: return {"CANCELLED"} @@ -791,7 +792,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) expression = ext.vrm1.expressions.all_name_to_expression_dict().get( self.expression_name ) @@ -834,7 +835,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression = expressions.all_name_to_expression_dict().get(self.expression_name) if expression is None: return {"CANCELLED"} @@ -879,7 +880,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression = expressions.all_name_to_expression_dict().get(self.expression_name) if expression is None: return {"CANCELLED"} @@ -922,7 +923,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression = expressions.all_name_to_expression_dict().get(self.expression_name) if expression is None: return {"CANCELLED"} @@ -961,7 +962,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression = expressions.all_name_to_expression_dict().get(self.expression_name) if expression is None: return {"CANCELLED"} @@ -1002,7 +1003,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression = expressions.all_name_to_expression_dict().get(self.expression_name) if expression is None: return {"CANCELLED"} @@ -1047,7 +1048,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression = expressions.all_name_to_expression_dict().get(self.expression_name) if expression is None: return {"CANCELLED"} @@ -1090,7 +1091,7 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression = expressions.all_name_to_expression_dict().get(self.expression_name) if expression is None: return {"CANCELLED"} @@ -1136,7 +1137,7 @@ def execute(self, context: Context) -> set[str]: Vrm1HumanBonesPropertyGroup.update_all_node_candidates( context, armature_data.name ) - human_bones = armature_data.vrm_addon_extension.vrm1.humanoid.human_bones + human_bones = get_armature_extension(armature_data).vrm1.humanoid.human_bones human_bone_name_to_human_bone = human_bones.human_bone_name_to_human_bone() bones = armature_data.bones @@ -1144,7 +1145,7 @@ def execute(self, context: Context) -> set[str]: Vrm0HumanoidPropertyGroup.update_all_node_candidates( context, armature_data.name ) - vrm0_humanoid = armature_data.vrm_addon_extension.vrm0.humanoid + vrm0_humanoid = get_armature_extension(armature_data).vrm0.humanoid if vrm0_humanoid.all_required_bones_are_assigned(): for vrm0_human_bone in vrm0_humanoid.human_bones: if ( @@ -1203,7 +1204,7 @@ class VRM_OT_update_vrm1_expression_ui_list_elements(Operator): def execute(self, context: Context) -> set[str]: for armature in context.blend_data.armatures: - expressions = armature.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature).vrm1.expressions # Set the number of elements equal to the number of elements wanted to show # in the UIList. diff --git a/src/io_scene_vrm/editor/vrm1/panel.py b/src/io_scene_vrm/editor/vrm1/panel.py index b8a2556bc..f4a1cec0d 100644 --- a/src/io_scene_vrm/editor/vrm1/panel.py +++ b/src/io_scene_vrm/editor/vrm1/panel.py @@ -7,6 +7,7 @@ from ...common.logging import get_logger from ...common.vrm1.human_bone import HumanBoneSpecifications from .. import ops, search +from ..extension import get_armature_extension, get_bone_extension from ..migration import defer_migrate from ..ops import layout_operator from ..panel import VRM_PT_vrm_armature_object_property, draw_template_list @@ -326,7 +327,7 @@ def draw(self, context: Context) -> None: context, active_object, self.layout, - armature_data.vrm_addon_extension.vrm1.humanoid, + get_armature_extension(armature_data).vrm1.humanoid, ) @@ -357,7 +358,7 @@ def draw(self, context: Context) -> None: context, armature, self.layout, - armature_data.vrm_addon_extension.vrm1.humanoid, + get_armature_extension(armature_data).vrm1.humanoid, ) @@ -426,7 +427,7 @@ def draw(self, context: Context) -> None: active_object, context, self.layout, - armature_data.vrm_addon_extension.vrm1.first_person, + get_armature_extension(armature_data).vrm1.first_person, ) @@ -457,7 +458,7 @@ def draw(self, context: Context) -> None: armature, context, self.layout, - armature_data.vrm_addon_extension.vrm1.first_person, + get_armature_extension(armature_data).vrm1.first_person, ) @@ -533,7 +534,7 @@ def draw(self, context: Context) -> None: active_object, context, self.layout, - armature_data.vrm_addon_extension.vrm1.look_at, + get_armature_extension(armature_data).vrm1.look_at, ) @@ -564,7 +565,7 @@ def draw(self, context: Context) -> None: armature, context, self.layout, - armature_data.vrm_addon_extension.vrm1.look_at, + get_armature_extension(armature_data).vrm1.look_at, ) @@ -851,7 +852,7 @@ def draw(self, context: Context) -> None: active_object, context, self.layout, - armature_data.vrm_addon_extension.vrm1.expressions, + get_armature_extension(armature_data).vrm1.expressions, ) @@ -882,7 +883,7 @@ def draw(self, context: Context) -> None: armature, context, self.layout, - armature_data.vrm_addon_extension.vrm1.expressions, + get_armature_extension(armature_data).vrm1.expressions, ) @@ -1001,7 +1002,7 @@ def draw(self, context: Context) -> None: armature_data = active_object.data if not isinstance(armature_data, Armature): return - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) draw_vrm1_meta_layout(active_object, context, self.layout, ext.vrm1.meta) @@ -1032,7 +1033,7 @@ def draw(self, context: Context) -> None: armature, context, self.layout, - armature_data.vrm_addon_extension.vrm1.meta, + get_armature_extension(armature_data).vrm1.meta, ) @@ -1070,6 +1071,6 @@ def draw(self, context: Context) -> None: bone = armature_data.bones.active if not bone: return - ext = bone.vrm_addon_extension + ext = get_bone_extension(bone) layout = self.layout layout.prop(ext, "axis_translation") diff --git a/src/io_scene_vrm/editor/vrm1/property_group.py b/src/io_scene_vrm/editor/vrm1/property_group.py index 50ad22cd5..7aaba6e5f 100644 --- a/src/io_scene_vrm/editor/vrm1/property_group.py +++ b/src/io_scene_vrm/editor/vrm1/property_group.py @@ -385,7 +385,7 @@ def fixup_human_bones(obj: Object) -> None: ): return - human_bones = armature_data.vrm_addon_extension.vrm1.humanoid.human_bones + human_bones = get_armature_vrm1_extension(armature_data).humanoid.human_bones # 複数のボーンマップに同一のBlenderのボーンが設定されていたら片方を削除 fixup = True @@ -438,7 +438,7 @@ def update_all_node_candidates( armature_data = context.blend_data.armatures.get(armature_data_name) if not isinstance(armature_data, Armature): return - human_bones = armature_data.vrm_addon_extension.vrm1.humanoid.human_bones + human_bones = get_armature_vrm1_extension(armature_data).humanoid.human_bones bone_names: list[str] = [] for bone in sorted(armature_data.bones.values(), key=lambda b: str(b.name)): bone_names.append(bone.name) @@ -667,7 +667,7 @@ def update_all_previews(context: Context) -> None: armature_data = armature_object.data if not isinstance(armature_data, Armature): continue - look_at = armature_data.vrm_addon_extension.vrm1.look_at + look_at = get_armature_vrm1_extension(armature_data).look_at look_at.update_preview(context, armature_object, armature_data) def update_preview( @@ -676,10 +676,7 @@ def update_preview( armature_object: Object, armature_data: Armature, ) -> None: - ext = armature_data.vrm_addon_extension - if not ext.is_vrm1(): - return - vrm1 = ext.vrm1 + vrm1 = get_armature_vrm1_extension(armature_data) preview_target_bpy_object = self.preview_target_bpy_object if not preview_target_bpy_object: return @@ -1237,11 +1234,12 @@ def set_custom_name(self, value: str) -> None: vrm1: Optional[Vrm1PropertyGroup] = None for search_armature in context.blend_data.armatures: - ext = search_armature.vrm_addon_extension - for custom_expression in ext.vrm1.expressions.custom: + for custom_expression in get_armature_vrm1_extension( + search_armature + ).expressions.custom: if custom_expression != self: continue - vrm1 = search_armature.vrm_addon_extension.vrm1 + vrm1 = get_armature_vrm1_extension(search_armature) break if vrm1 is None: logger.error(f"No armature extension for {self}") @@ -1553,3 +1551,10 @@ class Vrm1PropertyGroup(PropertyGroup): first_person: Vrm1FirstPersonPropertyGroup # type: ignore[no-redef] look_at: Vrm1LookAtPropertyGroup # type: ignore[no-redef] expressions: Vrm1ExpressionsPropertyGroup # type: ignore[no-redef] + + +def get_armature_vrm1_extension(armature: Armature) -> Vrm1PropertyGroup: + from ..extension import get_armature_extension + + vrm1: Vrm1PropertyGroup = get_armature_extension(armature).vrm1 + return vrm1 diff --git a/src/io_scene_vrm/exporter/abstract_base_vrm_exporter.py b/src/io_scene_vrm/exporter/abstract_base_vrm_exporter.py index c3ce26fa7..0640e8105 100644 --- a/src/io_scene_vrm/exporter/abstract_base_vrm_exporter.py +++ b/src/io_scene_vrm/exporter/abstract_base_vrm_exporter.py @@ -13,6 +13,7 @@ from ..common.convert import Json from ..common.deep import make_json from ..common.workspace import save_workspace +from ..editor.extension import get_armature_extension from ..editor.vrm0.property_group import Vrm0HumanoidPropertyGroup from ..editor.vrm1.property_group import Vrm1HumanoidPropertyGroup from ..external import io_scene_gltf2_support @@ -85,7 +86,7 @@ def setup_pose( bone.name: bone.matrix.copy() for bone in armature.pose.bones } - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) saved_vrm1_look_at_preview = ext.vrm1.look_at.enable_preview if ext.is_vrm1() and ext.vrm1.look_at.enable_preview: # TODO: エクスポート時にここに到達する場合は事前に警告をすると親切 @@ -148,7 +149,7 @@ def setup_pose( armature_data.pose_position = saved_pose_position bpy.ops.object.mode_set(mode="OBJECT") - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) if ( ext.is_vrm1() and ext.vrm1.look_at.enable_preview != saved_vrm1_look_at_preview @@ -159,7 +160,7 @@ def setup_pose( def clear_blend_shape_proxy_previews( self, armature_data: Armature ) -> Iterator[None]: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) saved_vrm0_previews: list[float] = [] for blend_shape_group in ext.vrm0.blend_shape_master.blend_shape_groups: diff --git a/src/io_scene_vrm/exporter/export_scene.py b/src/io_scene_vrm/exporter/export_scene.py index 1909dfcd8..71e0e75cc 100644 --- a/src/io_scene_vrm/exporter/export_scene.py +++ b/src/io_scene_vrm/exporter/export_scene.py @@ -25,6 +25,7 @@ get_preferences, ) from ..editor import search, validation +from ..editor.extension import get_armature_extension from ..editor.ops import VRM_OT_open_url_in_web_browser, layout_operator from ..editor.property_group import CollectionPropertyProtocol, StringPropertyGroup from ..editor.validation import VrmValidationError @@ -147,7 +148,7 @@ def execute(self, context: Context) -> set[str]: is_vrm1 = any( obj.type == "ARMATURE" and isinstance(obj.data, Armature) - and obj.data.vrm_addon_extension.is_vrm1() + and get_armature_extension(obj.data).is_vrm1() for obj in export_objects ) @@ -196,12 +197,12 @@ def invoke(self, context: Context, event: Event) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): pass - elif armature_data.vrm_addon_extension.is_vrm0(): + elif get_armature_extension(armature_data).is_vrm0(): Vrm0HumanoidPropertyGroup.fixup_human_bones(armature) Vrm0HumanoidPropertyGroup.update_all_node_candidates( context, armature_data.name ) - humanoid = armature_data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(armature_data).vrm0.humanoid if all( b.node.bone_name not in b.node_candidates for b in humanoid.human_bones @@ -214,14 +215,14 @@ def invoke(self, context: Context, event: Event) -> set[str]: "INVOKE_DEFAULT", armature_object_name=self.armature_object_name, ) - elif armature_data.vrm_addon_extension.is_vrm1(): + elif get_armature_extension(armature_data).is_vrm1(): Vrm1HumanBonesPropertyGroup.fixup_human_bones(armature) Vrm1HumanBonesPropertyGroup.update_all_node_candidates( context, armature_data.name ) - human_bones = ( - armature_data.vrm_addon_extension.vrm1.humanoid.human_bones - ) + human_bones = get_armature_extension( + armature_data + ).vrm1.humanoid.human_bones if all( human_bone.node.bone_name not in human_bone.node_candidates for human_bone in ( @@ -438,20 +439,22 @@ def execute(self, context: Context) -> set[str]: armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - if armature_data.vrm_addon_extension.is_vrm0(): + if get_armature_extension(armature_data).is_vrm0(): Vrm0HumanoidPropertyGroup.fixup_human_bones(armature) Vrm0HumanoidPropertyGroup.update_all_node_candidates( context, armature_data.name ) - humanoid = armature_data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(armature_data).vrm0.humanoid if not humanoid.all_required_bones_are_assigned(): return {"CANCELLED"} - elif armature_data.vrm_addon_extension.is_vrm1(): + elif get_armature_extension(armature_data).is_vrm1(): Vrm1HumanBonesPropertyGroup.fixup_human_bones(armature) Vrm1HumanBonesPropertyGroup.update_all_node_candidates( context, armature_data.name ) - human_bones = armature_data.vrm_addon_extension.vrm1.humanoid.human_bones + human_bones = get_armature_extension( + armature_data + ).vrm1.humanoid.human_bones if ( not human_bones.all_required_bones_are_assigned() and not human_bones.allow_non_humanoid_rig @@ -486,9 +489,9 @@ def draw(self, context: Context) -> None: if not isinstance(armature_data, Armature): return - if armature_data.vrm_addon_extension.is_vrm0(): + if get_armature_extension(armature_data).is_vrm0(): WM_OT_vrm_export_human_bones_assignment.draw_vrm0(self.layout, armature) - elif armature_data.vrm_addon_extension.is_vrm1(): + elif get_armature_extension(armature_data).is_vrm1(): WM_OT_vrm_export_human_bones_assignment.draw_vrm1(self.layout, armature) @staticmethod @@ -497,7 +500,7 @@ def draw_vrm0(layout: UILayout, armature: Object) -> None: if not isinstance(armature_data, Armature): return - humanoid = armature_data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(armature_data).vrm0.humanoid if humanoid.all_required_bones_are_assigned(): alert_box = layout.box() alert_box.label( @@ -521,7 +524,7 @@ def draw_vrm1(layout: UILayout, armature: Object) -> None: if not isinstance(armature_data, Armature): return - human_bones = armature_data.vrm_addon_extension.vrm1.humanoid.human_bones + human_bones = get_armature_extension(armature_data).vrm1.humanoid.human_bones if human_bones.all_required_bones_are_assigned(): alert_box = layout.box() alert_box.label( @@ -720,8 +723,8 @@ def detect_errors(context: Context, armature_object_name: str) -> list[str]: error_messages.append(pgettext("Armature not found")) return error_messages - ext = armature_data.vrm_addon_extension - if armature_data.vrm_addon_extension.is_vrm1(): + ext = get_armature_extension(armature_data) + if get_armature_extension(armature_data).is_vrm1(): humanoid = ext.vrm1.humanoid if not humanoid.human_bones.all_required_bones_are_assigned(): error_messages.append(pgettext("Please assign required human bones")) @@ -781,8 +784,8 @@ def draw(self, context: Context) -> None: if armature: armature_data = armature.data if isinstance(armature_data, Armature): - ext = armature_data.vrm_addon_extension - if armature_data.vrm_addon_extension.is_vrm1(): + ext = get_armature_extension(armature_data) + if get_armature_extension(armature_data).is_vrm1(): humanoid = ext.vrm1.humanoid if not humanoid.human_bones.all_required_bones_are_assigned(): WM_OT_vrm_export_human_bones_assignment.draw_vrm1( diff --git a/src/io_scene_vrm/exporter/vrm0_exporter.py b/src/io_scene_vrm/exporter/vrm0_exporter.py index f98bc49a2..df7134918 100644 --- a/src/io_scene_vrm/exporter/vrm0_exporter.py +++ b/src/io_scene_vrm/exporter/vrm0_exporter.py @@ -56,6 +56,7 @@ from ..common.vrm0.human_bone import HumanBoneSpecifications from ..common.workspace import save_workspace from ..editor import migration, search +from ..editor.extension import get_armature_extension, get_material_extension from ..editor.mtoon1.property_group import ( Mtoon0TexturePropertyGroup, Mtoon1KhrTextureTransformPropertyGroup, @@ -129,7 +130,7 @@ def export_vrm(self) -> Optional[bytes]: self.setup_pose( self.armature, self.armature_data, - self.armature_data.vrm_addon_extension.vrm0.humanoid, + get_armature_extension(self.armature_data).vrm0.humanoid, ), ): wm.progress_update(1) @@ -267,9 +268,9 @@ def image_to_bin(self) -> None: # MToon 1.0 downgraded for mat in used_materials: - if not mat.vrm_addon_extension.mtoon1.enabled: + if not get_material_extension(mat).mtoon1.enabled: continue - for texture in mat.vrm_addon_extension.mtoon1.all_textures( + for texture in get_material_extension(mat).mtoon1.all_textures( downgrade_to_mtoon0=True ): source = texture.source @@ -277,7 +278,7 @@ def image_to_bin(self) -> None: used_images.append(source) # thumbnail - ext = self.armature_data.vrm_addon_extension + ext = get_armature_extension(self.armature_data) if ( ext.vrm0.meta.texture and ext.vrm0.meta.texture.name @@ -328,7 +329,7 @@ def make_scene_node_skin_dicts(self) -> None: human_bone_node_names = [ human_bone.node.bone_name for human_bone in ( - self.armature_data.vrm_addon_extension.vrm0.humanoid.human_bones + get_armature_extension(self.armature_data).vrm0.humanoid.human_bones ) ] @@ -1502,7 +1503,7 @@ def make_mtoon1_downgraded_mat_dict( sampler_tuple_to_index_dict: dict[tuple[int, int, int, int], int], texture_tuple_to_index_dict: dict[tuple[int, int], int], ) -> tuple[dict[str, Json], dict[str, Json]]: - gltf = material.vrm_addon_extension.mtoon1 + gltf = get_material_extension(material).mtoon1 mtoon = gltf.extensions.vrmc_materials_mtoon material_dict: dict[str, Json] = { @@ -1822,7 +1823,7 @@ def material_to_dict(self) -> None: for material in search.export_materials(self.context, self.export_objects): material_properties_dict: dict[str, Json] = {} pbr_dict: dict[str, Json] = {} - if material.vrm_addon_extension.mtoon1.enabled: + if get_material_extension(material).mtoon1.enabled: ( material_properties_dict, pbr_dict, @@ -1935,9 +1936,9 @@ def fetch_morph_vertex_normal_difference( material = context.blend_data.materials.get(material.name) if material is None: continue - if material.vrm_addon_extension.mtoon1.export_shape_key_normals: + if get_material_extension(material).mtoon1.export_shape_key_normals: continue - if material.vrm_addon_extension.mtoon1.enabled: + if get_material_extension(material).mtoon1.enabled: exclusion_vertex_indices.update(polygon.vertices) continue node, vrm_shader_name = search.vrm_shader_node(material) @@ -2481,7 +2482,7 @@ def mesh_to_bin_and_dict(self) -> None: break mesh_parent = mesh.parent if not bone_name: - ext = self.armature_data.vrm_addon_extension + ext = get_armature_extension(self.armature_data) for human_bone in ext.vrm0.humanoid.human_bones: if human_bone.bone == "hips": bone_name = human_bone.node.bone_name @@ -2752,7 +2753,7 @@ def vrm_meta_to_dict(self) -> None: # materialProperties は material_to_dict()で処理する # vrm extension - meta = self.armature_data.vrm_addon_extension.vrm0.meta + meta = get_armature_extension(self.armature_data).vrm0.meta vrm_extension_dict: dict[str, Json] = { "exporterVersion": self.exporter_name(), "specVersion": "0.0", @@ -2816,7 +2817,7 @@ def vrm_meta_to_dict(self) -> None: human_bone_dicts: list[Json] = [] humanoid_dict: dict[str, Json] = {"humanBones": human_bone_dicts} vrm_extension_dict["humanoid"] = humanoid_dict - humanoid = self.armature_data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(self.armature_data).vrm0.humanoid for human_bone_name in HumanBoneSpecifications.all_names: for human_bone in humanoid.human_bones: if ( @@ -2865,7 +2866,7 @@ def vrm_meta_to_dict(self) -> None: # firstPerson first_person_dict: dict[str, Json] = {} vrm_extension_dict["firstPerson"] = first_person_dict - first_person = self.armature_data.vrm_addon_extension.vrm0.first_person + first_person = get_armature_extension(self.armature_data).vrm0.first_person if first_person.first_person_bone.bone_name: first_person_dict["firstPersonBone"] = node_name_id_dict[ @@ -2875,7 +2876,7 @@ def vrm_meta_to_dict(self) -> None: name = next( human_bone.node.bone_name for human_bone in ( - self.armature_data.vrm_addon_extension.vrm0.humanoid.human_bones + get_armature_extension(self.armature_data).vrm0.humanoid.human_bones ) if human_bone.bone == "head" ) @@ -2954,9 +2955,9 @@ def vrm_meta_to_dict(self) -> None: # meshを名前からid # weightを0-1から0-100に # shape_indexを名前からindexに - blend_shape_master = ( - self.armature_data.vrm_addon_extension.vrm0.blend_shape_master - ) + blend_shape_master = get_armature_extension( + self.armature_data + ).vrm0.blend_shape_master for blend_shape_group in blend_shape_master.blend_shape_groups: blend_shape_group_dict: dict[str, Json] = {} @@ -3047,9 +3048,9 @@ def vrm_meta_to_dict(self) -> None: vrm_extension_dict["secondaryAnimation"] = secondary_animation_dict collider_group_dicts: list[Json] = [] secondary_animation_dict["colliderGroups"] = collider_group_dicts - secondary_animation = ( - self.armature_data.vrm_addon_extension.vrm0.secondary_animation - ) + secondary_animation = get_armature_extension( + self.armature_data + ).vrm0.secondary_animation filtered_collider_groups = [ collider_group for collider_group in secondary_animation.collider_groups diff --git a/src/io_scene_vrm/exporter/vrm1_exporter.py b/src/io_scene_vrm/exporter/vrm1_exporter.py index 864cc8ef6..ac7a1d05d 100644 --- a/src/io_scene_vrm/exporter/vrm1_exporter.py +++ b/src/io_scene_vrm/exporter/vrm1_exporter.py @@ -33,6 +33,7 @@ from ..common.vrm1.human_bone import HumanBoneName from ..common.workspace import save_workspace from ..editor import search +from ..editor.extension import get_armature_extension, get_material_extension from ..editor.mtoon1.property_group import ( Mtoon1SamplerPropertyGroup, Mtoon1TextureInfoPropertyGroup, @@ -84,7 +85,7 @@ def __init__( message = f"{type(armature_data)} is not an Armature" raise TypeError(message) - for collider in armature_data.vrm_addon_extension.spring_bone1.colliders: + for collider in get_armature_extension(armature_data).spring_bone1.colliders: if not collider.bpy_object: continue if collider.bpy_object in self.export_objects: @@ -932,7 +933,7 @@ def create_mtoon1_material_dict( "specVersion": "1.0", } - gltf = material.vrm_addon_extension.mtoon1 + gltf = get_material_extension(material).mtoon1 mtoon = gltf.extensions.vrmc_materials_mtoon extensions_dict: dict[str, Json] = { @@ -1625,7 +1626,7 @@ def save_vrm_materials( ): continue - if material.vrm_addon_extension.mtoon1.enabled: + if get_material_extension(material).mtoon1.enabled: material_dicts[index] = cls.create_mtoon1_material_dict( json_dict, body_binary, @@ -1682,7 +1683,7 @@ def disable_mtoon1_material_nodes(cls, context: Context) -> Iterator[None]: for material in context.blend_data.materials: if not material: continue - if material.vrm_addon_extension.mtoon1.enabled and material.use_nodes: + if get_material_extension(material).mtoon1.enabled and material.use_nodes: material.use_nodes = False disabled_material_names.append(material.name) try: @@ -1730,9 +1731,9 @@ def unassign_normal_from_mtoon_primitive_morph_target( material = context.blend_data.materials.get(search_material_name) if not material: continue - if material.vrm_addon_extension.mtoon1.export_shape_key_normals: + if get_material_extension(material).mtoon1.export_shape_key_normals: continue - if material.vrm_addon_extension.mtoon1.enabled: + if get_material_extension(material).mtoon1.enabled: skip = False break node, vrm_shader_name = search.vrm_shader_node(material) @@ -1760,7 +1761,7 @@ def setup_dummy_human_bones( armature: Object, armature_data: Armature, ) -> Iterator[None]: - ext = armature_data.vrm_addon_extension + ext = get_armature_extension(armature_data) human_bones = ext.vrm1.humanoid.human_bones if human_bones.all_required_bones_are_assigned(): yield @@ -1981,7 +1982,7 @@ def export_vrm(self) -> Optional[bytes]: message = f"{type(armature_data)} is not an Armature" raise TypeError(message) - vrm = armature_data.vrm_addon_extension.vrm1 + vrm = get_armature_extension(armature_data).vrm1 with ( save_workspace(self.context), self.setup_dummy_human_bones(self.context, self.armature, armature_data), @@ -2041,7 +2042,7 @@ def add_vrm_extension_to_glb( message = f"{type(armature_data)} is not an Armature" raise TypeError(message) - vrm = armature_data.vrm_addon_extension.vrm1 + vrm = get_armature_extension(armature_data).vrm1 json_dict, body_binary = parse_glb(extra_name_assigned_glb) body_binary = bytearray(body_binary) @@ -2309,7 +2310,7 @@ def add_vrm_extension_to_glb( extensions_used.append("VRMC_vrm") extensions["VRMC_vrm"] = { - "specVersion": armature_data.vrm_addon_extension.spec_version, + "specVersion": get_armature_extension(armature_data).spec_version, "meta": self.create_meta_dict( vrm.meta, json_dict, @@ -2332,7 +2333,7 @@ def add_vrm_extension_to_glb( ), } - spring_bone = armature_data.vrm_addon_extension.spring_bone1 + spring_bone = get_armature_extension(armature_data).spring_bone1 spring_bone_dict: dict[str, Json] = {} ( diff --git a/src/io_scene_vrm/exporter/vrm_animation_exporter.py b/src/io_scene_vrm/exporter/vrm_animation_exporter.py index fcb429e47..731913689 100644 --- a/src/io_scene_vrm/exporter/vrm_animation_exporter.py +++ b/src/io_scene_vrm/exporter/vrm_animation_exporter.py @@ -20,6 +20,7 @@ HumanBoneSpecifications, ) from ..common.workspace import save_workspace +from ..editor.extension import get_armature_extension logger = get_logger(__name__) @@ -64,7 +65,7 @@ def work_in_progress_2(context: Context, armature: Object) -> bytes: if not isinstance(armature_data, Armature): message = "Armature data is not an Armature" raise TypeError(message) - vrm1 = armature_data.vrm_addon_extension.vrm1 + vrm1 = get_armature_extension(armature_data).vrm1 human_bone_name_to_node_dict: dict[HumanBoneName, dict[str, Json]] = {} human_bone_name_to_node_index: dict[HumanBoneName, int] = {} human_bone_name_to_human_bone = ( @@ -893,14 +894,14 @@ def work_in_progress(context: Context, path: Path, armature: Object) -> set[str] armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - humanoid = armature_data.vrm_addon_extension.vrm1.humanoid + humanoid = get_armature_extension(armature_data).vrm1.humanoid if not humanoid.human_bones.all_required_bones_are_assigned(): return {"CANCELLED"} # saved_current_pose_matrix_basis_dict = {} # saved_current_pose_matrix_dict = {} saved_pose_position = armature_data.pose_position - # vrm1 = armature.data.vrm_addon_extension.vrm1 + # vrm1 = get_armature_extension(armature.data).vrm1 output_bytes = None # TODO: 現状restがTポーズの時しか動作しない diff --git a/src/io_scene_vrm/importer/abstract_base_vrm_importer.py b/src/io_scene_vrm/importer/abstract_base_vrm_importer.py index f22a5555a..719ee29d7 100644 --- a/src/io_scene_vrm/importer/abstract_base_vrm_importer.py +++ b/src/io_scene_vrm/importer/abstract_base_vrm_importer.py @@ -42,6 +42,7 @@ from ..common.logging import get_logger from ..common.preferences import ImportPreferencesProtocol from ..common.workspace import save_workspace +from ..editor.extension import get_armature_extension from .gltf2_addon_importer_user_extension import Gltf2AddonImporterUserExtension from .vrm_parser import ParseResult, remove_unsafe_path_chars @@ -954,10 +955,10 @@ def import_gltf2_with_indices(self) -> None: continue if self.parse_result.spec_version_number < (1, 0): - vrm0_humanoid = data.vrm_addon_extension.vrm0.humanoid + vrm0_humanoid = get_armature_extension(data).vrm0.humanoid vrm0_humanoid.initial_automatic_bone_assignment = False else: - vrm1_humanoid = data.vrm_addon_extension.vrm1.humanoid + vrm1_humanoid = get_armature_extension(data).vrm1.humanoid vrm1_humanoid.human_bones.initial_automatic_bone_assignment = False self.armature = obj diff --git a/src/io_scene_vrm/importer/import_scene.py b/src/io_scene_vrm/importer/import_scene.py index 5fe3e6acb..8223539f4 100644 --- a/src/io_scene_vrm/importer/import_scene.py +++ b/src/io_scene_vrm/importer/import_scene.py @@ -27,6 +27,7 @@ get_preferences, ) from ..editor import search +from ..editor.extension import get_armature_extension from ..editor.ops import VRM_OT_open_url_in_web_browser, layout_operator from ..editor.property_group import CollectionPropertyProtocol, StringPropertyGroup from .abstract_base_vrm_importer import AbstractBaseVrmImporter @@ -442,8 +443,8 @@ def detect_errors(context: Context, armature_object_name: str) -> list[str]: error_messages.append(pgettext("Armature not found")) return error_messages - ext = armature_data.vrm_addon_extension - if armature_data.vrm_addon_extension.is_vrm1(): + ext = get_armature_extension(armature_data) + if get_armature_extension(armature_data).is_vrm1(): humanoid = ext.vrm1.humanoid if not humanoid.human_bones.all_required_bones_are_assigned(): error_messages.append(pgettext("Please assign required human bones")) diff --git a/src/io_scene_vrm/importer/vrm0_importer.py b/src/io_scene_vrm/importer/vrm0_importer.py index 4e85afee0..71e534ad6 100644 --- a/src/io_scene_vrm/importer/vrm0_importer.py +++ b/src/io_scene_vrm/importer/vrm0_importer.py @@ -21,6 +21,7 @@ from ..common.version import addon_version from ..common.vrm0.human_bone import HumanBoneName, HumanBoneSpecifications from ..editor import make_armature, migration +from ..editor.extension import get_armature_extension, get_material_extension from ..editor.make_armature import ( connect_parent_tail_and_child_head_if_very_close_position, ) @@ -157,7 +158,7 @@ def build_material_from_mtoon0( # https://github.com/saturday06/VRM-Addon-for-Blender/blob/2_15_26/io_scene_vrm/editor/mtoon1/ops.py#L98 material.use_backface_culling = True - gltf = material.vrm_addon_extension.mtoon1 + gltf = get_material_extension(material).mtoon1 gltf.addon_version = addon_version() gltf.enabled = True gltf.show_expanded_mtoon0 = True @@ -426,7 +427,7 @@ def build_material_from_transparent_z_write( material: Material, vrm0_material_property: Vrm0MaterialProperty, ) -> None: - gltf = material.vrm_addon_extension.mtoon1 + gltf = get_material_extension(material).mtoon1 gltf.enabled = True mtoon = gltf.extensions.vrmc_materials_mtoon @@ -467,7 +468,7 @@ def load_gltf_extensions(self) -> None: armature = self.armature if not armature: return - addon_extension = self.armature_data.vrm_addon_extension + addon_extension = get_armature_extension(self.armature_data) addon_extension.spec_version = addon_extension.SPEC_VERSION_VRM0 vrm0 = addon_extension.vrm0 @@ -1086,7 +1087,7 @@ def setup_bones(context: Context, armature: Object) -> None: """ if not isinstance(armature.data, Armature): return - addon_extension = armature.data.vrm_addon_extension + addon_extension = get_armature_extension(armature.data) Vrm0HumanoidPropertyGroup.fixup_human_bones(armature) Vrm0HumanoidPropertyGroup.update_all_node_candidates( diff --git a/src/io_scene_vrm/importer/vrm1_importer.py b/src/io_scene_vrm/importer/vrm1_importer.py index cf3efe3f1..60c24b30c 100644 --- a/src/io_scene_vrm/importer/vrm1_importer.py +++ b/src/io_scene_vrm/importer/vrm1_importer.py @@ -21,7 +21,15 @@ from ..common.vrm1 import human_bone as vrm1_human_bone from ..common.vrm1.human_bone import HumanBoneName, HumanBoneSpecifications from ..editor import make_armature, migration -from ..editor.extension import VrmAddonBoneExtensionPropertyGroup as BoneExtension +from ..editor.extension import ( + VrmAddonBoneExtensionPropertyGroup as BoneExtension, +) +from ..editor.extension import ( + get_armature_extension, + get_bone_extension, + get_material_extension, + get_object_extension, +) from ..editor.make_armature import ( connect_parent_tail_and_child_head_if_very_close_position, ) @@ -161,7 +169,7 @@ def make_mtoon1_material( self.reset_material(material) material.use_backface_culling = True - gltf = material.vrm_addon_extension.mtoon1 + gltf = get_material_extension(material).mtoon1 gltf.addon_version = addon_version() gltf.enabled = True mtoon = gltf.extensions.vrmc_materials_mtoon @@ -432,7 +440,7 @@ def setup_vrm1_humanoid_bones(self) -> None: armature = self.armature if not armature: return - addon_extension = self.armature_data.vrm_addon_extension + addon_extension = get_armature_extension(self.armature_data) Vrm1HumanBonesPropertyGroup.update_all_node_candidates( self.context, self.armature_data.name, force=True @@ -763,8 +771,10 @@ def setup_vrm1_humanoid_bones(self) -> None: data_bone = armature_data.bones.get(bone_name) if not data_bone: continue - data_bone.vrm_addon_extension.axis_translation = ( - BoneExtension.reverse_axis_translation(axis_translation) + get_bone_extension( + data_bone + ).axis_translation = BoneExtension.reverse_axis_translation( + axis_translation ) for node_index in set(constraint_node_index_to_source_index.keys()) | set( @@ -784,7 +794,9 @@ def setup_vrm1_humanoid_bones(self) -> None: self.translate_object_axis( object_or_bone, BoneExtension.reverse_axis_translation( - group_object_or_bone.bone.vrm_addon_extension.axis_translation + get_bone_extension( + group_object_or_bone.bone + ).axis_translation ), ) break @@ -800,15 +812,15 @@ def translate_object_axis(self, obj: Object, axis_translation: str) -> None: obj.select_set(True) bpy.ops.object.origin_set(type="ORIGIN_CURSOR", center="MEDIAN") - obj.vrm_addon_extension.axis_translation = ( - BoneExtension.reverse_axis_translation(axis_translation) - ) + get_object_extension( + obj + ).axis_translation = BoneExtension.reverse_axis_translation(axis_translation) def load_gltf_extensions(self) -> None: armature = self.armature if not armature: return - addon_extension = self.armature_data.vrm_addon_extension + addon_extension = get_armature_extension(self.armature_data) vrm1 = addon_extension.vrm1 addon_extension.spec_version = addon_extension.SPEC_VERSION_VRM1 @@ -1002,7 +1014,7 @@ def load_vrm1_look_at( ) ) - humanoid = self.armature_data.vrm_addon_extension.vrm1.humanoid + humanoid = get_armature_extension(self.armature_data).vrm1.humanoid head_bone_name = humanoid.human_bones.head.node.bone_name head_bone = self.armature_data.bones.get(head_bone_name) if head_bone: @@ -1011,7 +1023,7 @@ def load_vrm1_look_at( @ BoneExtension.translate_axis( Matrix(), BoneExtension.reverse_axis_translation( - head_bone.vrm_addon_extension.axis_translation + get_bone_extension(head_bone).axis_translation ), ) ) @@ -1260,7 +1272,7 @@ def load_spring_bone1_colliders( ) ) if bone: - axis_translation = bone.vrm_addon_extension.axis_translation + axis_translation = get_bone_extension(bone).axis_translation offset = Vector(offset) @ BoneExtension.translate_axis( Matrix(), BoneExtension.reverse_axis_translation(axis_translation), @@ -1283,7 +1295,7 @@ def load_spring_bone1_colliders( ) ) if bone: - axis_translation = bone.vrm_addon_extension.axis_translation + axis_translation = get_bone_extension(bone).axis_translation offset = Vector(offset) @ BoneExtension.translate_axis( Matrix(), BoneExtension.reverse_axis_translation(axis_translation), @@ -1300,7 +1312,7 @@ def load_spring_bone1_colliders( ) ) if bone: - axis_translation = bone.vrm_addon_extension.axis_translation + axis_translation = get_bone_extension(bone).axis_translation tail = Vector(tail) @ BoneExtension.translate_axis( Matrix(), BoneExtension.reverse_axis_translation(axis_translation), @@ -1543,9 +1555,9 @@ def load_node_constraint1( continue axis_translation = BoneExtension.reverse_axis_translation( - object_or_bone.bone.vrm_addon_extension.axis_translation + get_bone_extension(object_or_bone.bone).axis_translation if isinstance(object_or_bone, PoseBone) - else object_or_bone.vrm_addon_extension.axis_translation + else get_object_extension(object_or_bone).axis_translation ) if isinstance(roll_dict, dict): diff --git a/src/io_scene_vrm/importer/vrm_animation_importer.py b/src/io_scene_vrm/importer/vrm_animation_importer.py index 603f58886..768df7b18 100644 --- a/src/io_scene_vrm/importer/vrm_animation_importer.py +++ b/src/io_scene_vrm/importer/vrm_animation_importer.py @@ -28,6 +28,7 @@ from ..common.logging import get_logger from ..common.vrm1.human_bone import HumanBoneName from ..common.workspace import save_workspace +from ..editor.extension import get_armature_extension logger = get_logger(__name__) @@ -308,12 +309,12 @@ def work_in_progress(context: Context, path: Path, armature: Object) -> set[str] armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - humanoid = armature_data.vrm_addon_extension.vrm1.humanoid + humanoid = get_armature_extension(armature_data).vrm1.humanoid if not humanoid.human_bones.all_required_bones_are_assigned(): return {"CANCELLED"} saved_pose_position = armature_data.pose_position - vrm1 = armature_data.vrm_addon_extension.vrm1 + vrm1 = get_armature_extension(armature_data).vrm1 # TODO: 現状restがTポーズの時しか動作しない # TODO: 自動でTポーズを作成する @@ -361,10 +362,10 @@ def work_in_progress_2(context: Context, path: Path, armature: Object) -> set[st armature_data = armature.data if not isinstance(armature_data, Armature): return {"CANCELLED"} - humanoid = armature_data.vrm_addon_extension.vrm1.humanoid + humanoid = get_armature_extension(armature_data).vrm1.humanoid if not humanoid.human_bones.all_required_bones_are_assigned(): return {"CANCELLED"} - look_at = armature_data.vrm_addon_extension.vrm1.look_at + look_at = get_armature_extension(armature_data).vrm1.look_at vrma_dict, buffer0_bytes = parse_glb(path.read_bytes()) @@ -729,7 +730,7 @@ def assign_expression_keyframe( frame_count: int, timestamp: float, ) -> None: - expressions = armature_data.vrm_addon_extension.vrm1.expressions + expressions = get_armature_extension(armature_data).vrm1.expressions expression_name_to_expression = expressions.all_name_to_expression_dict() for ( expression_name, @@ -881,7 +882,7 @@ def assign_humanoid_keyframe( HumanBoneName.LEFT_EYE, HumanBoneName.RIGHT_EYE, ]: - human_bones = armature_data.vrm_addon_extension.vrm1.humanoid.human_bones + human_bones = get_armature_extension(armature_data).vrm1.humanoid.human_bones human_bone = human_bones.human_bone_name_to_human_bone().get(human_bone_name) if human_bone: bone = armature.pose.bones.get(human_bone.node.bone_name) diff --git a/src/io_scene_vrm/registration.py b/src/io_scene_vrm/registration.py index 1cab85e1b..9f9413737 100644 --- a/src/io_scene_vrm/registration.py +++ b/src/io_scene_vrm/registration.py @@ -453,27 +453,27 @@ def register() -> None: for cls in classes: bpy.utils.register_class(cls) - NodeTree.vrm_addon_extension = PointerProperty( # type: ignore[assignment] + NodeTree.vrm_addon_extension = PointerProperty( # type: ignore[attr-defined] type=extension.VrmAddonNodeTreeExtensionPropertyGroup ) - Material.vrm_addon_extension = PointerProperty( # type: ignore[assignment] + Material.vrm_addon_extension = PointerProperty( # type: ignore[attr-defined] type=extension.VrmAddonMaterialExtensionPropertyGroup ) - Scene.vrm_addon_extension = PointerProperty( # type: ignore[assignment] + Scene.vrm_addon_extension = PointerProperty( # type: ignore[attr-defined] type=extension.VrmAddonSceneExtensionPropertyGroup ) - Bone.vrm_addon_extension = PointerProperty( # type: ignore[assignment] + Bone.vrm_addon_extension = PointerProperty( # type: ignore[attr-defined] type=extension.VrmAddonBoneExtensionPropertyGroup ) - Armature.vrm_addon_extension = PointerProperty( # type: ignore[assignment] + Armature.vrm_addon_extension = PointerProperty( # type: ignore[attr-defined] type=extension.VrmAddonArmatureExtensionPropertyGroup ) - Object.vrm_addon_extension = PointerProperty( # type: ignore[assignment] + Object.vrm_addon_extension = PointerProperty( # type: ignore[attr-defined] type=extension.VrmAddonObjectExtensionPropertyGroup ) diff --git a/tests/blender_test_bone_order_validation.py b/tests/blender_test_bone_order_validation.py index 6642f0d06..7e49dcc86 100644 --- a/tests/blender_test_bone_order_validation.py +++ b/tests/blender_test_bone_order_validation.py @@ -1,6 +1,8 @@ import bpy from bpy.types import Armature, Context +from io_scene_vrm.editor.extension import get_armature_extension + def test(context: Context) -> None: bpy.ops.icyp.make_basic_armature() @@ -10,7 +12,7 @@ def test(context: Context) -> None: if not isinstance(armature.data, Armature): raise TypeError - humanoid = armature.data.vrm_addon_extension.vrm0.humanoid + humanoid = get_armature_extension(armature.data).vrm0.humanoid assert bpy.ops.vrm.model_validate() == {"FINISHED"} spine_bone = next(b for b in humanoid.human_bones if b.bone == "spine") diff --git a/tests/blender_test_fixup_human_bones.py b/tests/blender_test_fixup_human_bones.py index 2699963e2..e7ebaef50 100644 --- a/tests/blender_test_fixup_human_bones.py +++ b/tests/blender_test_fixup_human_bones.py @@ -2,6 +2,7 @@ from bpy.types import Armature, Context from io_scene_vrm.common.vrm0.human_bone import HumanBoneName +from io_scene_vrm.editor.extension import get_armature_extension from io_scene_vrm.editor.vrm0.property_group import Vrm0HumanoidPropertyGroup @@ -13,7 +14,7 @@ def test(context: Context) -> None: if not isinstance(armature.data, Armature): raise TypeError - human_bones = armature.data.vrm_addon_extension.vrm0.humanoid.human_bones + human_bones = get_armature_extension(armature.data).vrm0.humanoid.human_bones original = [(str(b.node.bone_name), str(b.bone)) for b in human_bones] diff --git a/tests/blender_test_load_human_bone_mappings.py b/tests/blender_test_load_human_bone_mappings.py index 0a7a5b5d4..037a2ff34 100644 --- a/tests/blender_test_load_human_bone_mappings.py +++ b/tests/blender_test_load_human_bone_mappings.py @@ -4,6 +4,8 @@ import bpy from bpy.types import Armature, Context +from io_scene_vrm.editor.extension import get_armature_extension + def test(context: Context) -> None: bpy.ops.icyp.make_basic_armature() @@ -22,7 +24,7 @@ def test(context: Context) -> None: b = next( human_bone - for human_bone in data.vrm_addon_extension.vrm0.humanoid.human_bones + for human_bone in get_armature_extension(data).vrm0.humanoid.human_bones if human_bone.bone == "head" ) assert ( diff --git a/tests/blender_test_spring_bone.py b/tests/blender_test_spring_bone.py index 4bfbc9721..48c47a74c 100644 --- a/tests/blender_test_spring_bone.py +++ b/tests/blender_test_spring_bone.py @@ -7,7 +7,10 @@ from mathutils import Euler, Quaternion, Vector from io_scene_vrm.common import version -from io_scene_vrm.editor.extension import VrmAddonArmatureExtensionPropertyGroup +from io_scene_vrm.editor.extension import ( + VrmAddonArmatureExtensionPropertyGroup, + get_armature_extension, +) addon_version = version.addon_version() spec_version = VrmAddonArmatureExtensionPropertyGroup.SPEC_VERSION_VRM1 @@ -54,9 +57,9 @@ def one_joint_extending_in_y_direction(context: Context) -> None: if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -84,7 +87,7 @@ def one_joint_extending_in_y_direction(context: Context) -> None: armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 1 joints[0].drag_force = 1 @@ -134,9 +137,9 @@ def one_joint_extending_in_y_direction_with_rotating_armature(context: Context) if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -164,7 +167,7 @@ def one_joint_extending_in_y_direction_with_rotating_armature(context: Context) armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 1 joints[0].drag_force = 1 @@ -216,9 +219,9 @@ def one_joint_extending_in_y_direction_with_rotating_armature_stiffness( if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -250,7 +253,7 @@ def one_joint_extending_in_y_direction_with_rotating_armature_stiffness( armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 0 joints[0].drag_force = 1 @@ -298,9 +301,9 @@ def two_joints_extending_in_y_direction(context: Context) -> None: if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -336,7 +339,7 @@ def two_joints_extending_in_y_direction(context: Context) -> None: armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 1 joints[0].drag_force = 1 @@ -397,9 +400,9 @@ def two_joints_extending_in_y_direction_roll(context: Context) -> None: if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -438,7 +441,7 @@ def two_joints_extending_in_y_direction_roll(context: Context) -> None: armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 1 joints[0].drag_force = 1 @@ -499,9 +502,9 @@ def two_joints_extending_in_y_direction_local_translation(context: Context) -> N if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -541,7 +544,7 @@ def two_joints_extending_in_y_direction_local_translation(context: Context) -> N armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 1 joints[0].drag_force = 1 @@ -602,9 +605,9 @@ def two_joints_extending_in_y_direction_connected(context: Context) -> None: if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -644,7 +647,7 @@ def two_joints_extending_in_y_direction_connected(context: Context) -> None: armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 1 joints[0].drag_force = 1 @@ -707,9 +710,9 @@ def one_joint_extending_in_y_direction_gravity_y_object_move_to_z( if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -737,7 +740,7 @@ def one_joint_extending_in_y_direction_gravity_y_object_move_to_z( armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 1 joints[0].gravity_dir = (0, 1, 0) @@ -801,9 +804,9 @@ def one_joint_extending_in_y_direction_rounding_180_degree(context: Context) -> if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -831,7 +834,7 @@ def one_joint_extending_in_y_direction_rounding_180_degree(context: Context) -> armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 1 # はじめに重力で勢いをつける joints[0].drag_force = 0 @@ -865,9 +868,9 @@ def two_joints_extending_in_y_direction_root_down(context: Context) -> None: if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -903,7 +906,7 @@ def two_joints_extending_in_y_direction_root_down(context: Context) -> None: armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 1 joints[0].drag_force = 1 @@ -960,9 +963,9 @@ def two_joints_extending_in_y_direction_with_child_stiffness(context: Context) - if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -998,7 +1001,7 @@ def two_joints_extending_in_y_direction_with_child_stiffness(context: Context) - armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 0 joints[0].drag_force = 1 @@ -1087,9 +1090,9 @@ def one_joint_extending_in_y_direction_with_roll_stiffness(context: Context) -> if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") root_bone = armature.data.edit_bones.new("root") @@ -1118,7 +1121,7 @@ def one_joint_extending_in_y_direction_with_roll_stiffness(context: Context) -> armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - joints = armature.data.vrm_addon_extension.spring_bone1.springs[0].joints + joints = get_armature_extension(armature.data).spring_bone1.springs[0].joints joints[0].node.bone_name = "joint0" joints[0].gravity_power = 0 joints[0].drag_force = 1 @@ -1164,9 +1167,9 @@ def two_joints_extending_in_y_direction_center_move_to_z(context: Context) -> No if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") joint_bone0 = armature.data.edit_bones.new("joint0") @@ -1197,7 +1200,7 @@ def two_joints_extending_in_y_direction_center_move_to_z(context: Context) -> No armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - spring = armature.data.vrm_addon_extension.spring_bone1.springs[0] + spring = get_armature_extension(armature.data).spring_bone1.springs[0] spring.center.bone_name = "joint0" joints = spring.joints joints[0].node.bone_name = "joint0" @@ -1255,9 +1258,9 @@ def two_joints_extending_in_y_direction_center_move_to_z_no_inertia( if not armature or not isinstance(armature.data, Armature): raise AssertionError - armature.data.vrm_addon_extension.addon_version = addon_version - armature.data.vrm_addon_extension.spec_version = spec_version - armature.data.vrm_addon_extension.spring_bone1.enable_animation = True + get_armature_extension(armature.data).addon_version = addon_version + get_armature_extension(armature.data).spec_version = spec_version + get_armature_extension(armature.data).spring_bone1.enable_animation = True bpy.ops.object.mode_set(mode="EDIT") joint_bone0 = armature.data.edit_bones.new("joint0") @@ -1288,7 +1291,7 @@ def two_joints_extending_in_y_direction_center_move_to_z_no_inertia( armature_name=armature.name, spring_index=0 ) == {"FINISHED"} - spring = armature.data.vrm_addon_extension.spring_bone1.springs[0] + spring = get_armature_extension(armature.data).spring_bone1.springs[0] spring.center.bone_name = "joint0" joints = spring.joints joints[0].node.bone_name = "joint0"