Skip to content

Commit

Permalink
fix: vrm 1.0 bone child object translation importing
Browse files Browse the repository at this point in the history
  • Loading branch information
saturday06 committed Jun 5, 2024
1 parent a5ab754 commit 7a69aaa
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 24 deletions.
37 changes: 37 additions & 0 deletions src/io_scene_vrm/importer/abstract_base_vrm_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import struct
import tempfile
from abc import ABC, abstractmethod
from collections.abc import Iterator
from pathlib import Path
from typing import Optional

Expand Down Expand Up @@ -144,6 +145,42 @@ def load_bone_child_object_world_matrices(self, armature: Object) -> None:
obj.name
].copy()

@staticmethod
@contextlib.contextmanager
def save_bone_child_object_transforms(
context: Context, armature: Object
) -> Iterator[Armature]:
if not isinstance(armature.data, Armature):
message = f"{type(armature.data)} is not an Armature"
raise TypeError(message)

# 編集前のボーンの子オブジェクトのワールド行列を保存
context.view_layer.update()
bone_child_object_world_matrices: dict[str, Matrix] = {}
for obj in context.blend_data.objects:
if (
obj.parent_type == "BONE"
and obj.parent == armature
and obj.parent_bone in armature.data.bones
):
bone_child_object_world_matrices[obj.name] = obj.matrix_world.copy()

try:
with save_workspace(context, armature, mode="EDIT"):
yield armature.data
finally:
# 編集前のボーンの子オブジェクトのワールド行列を復元
context.view_layer.update()
for name, matrix_world in bone_child_object_world_matrices.items():
restore_obj = context.blend_data.objects.get(name)
if (
restore_obj
and restore_obj.parent_type == "BONE"
and restore_obj.parent == armature
and restore_obj.parent_bone in armature.data.bones
):
restore_obj.matrix_world = matrix_world.copy()

def use_fake_user_for_thumbnail(self) -> None:
# サムネイルはVRMの仕様ではimageのインデックスとあるが、UniVRMの実装ではtexture
# のインデックスになっている
Expand Down
32 changes: 8 additions & 24 deletions src/io_scene_vrm/importer/vrm1/vrm_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,11 +452,9 @@ def setup_vrm1_humanoid_bones(self) -> None:
# Missing required bones
return

previous_active = self.context.view_layer.objects.active
previous_cursor_matrix = self.context.scene.cursor.matrix
try:
self.context.view_layer.objects.active = armature

with self.save_bone_child_object_transforms(
self.context, armature
) as armature_data:
bone_name_to_human_bone_name: dict[str, HumanBoneName] = {}
for (
human_bone_name,
Expand All @@ -468,8 +466,6 @@ def setup_vrm1_humanoid_bones(self) -> None:
human_bone_name
)

bpy.ops.object.mode_set(mode="EDIT")

# ボーンの子が複数ある場合
# そのボーン名からテールを向ける先の子ボーン名を拾えるdictを作る
bone_name_to_main_child_bone_name: dict[str, str] = {}
Expand All @@ -487,7 +483,7 @@ def setup_vrm1_humanoid_bones(self) -> None:
if human_bone_name in [HumanBoneName.RIGHT_EYE, HumanBoneName.LEFT_EYE]:
continue

bone = self.armature_data.edit_bones.get(bone_name)
bone = armature_data.edit_bones.get(bone_name)
if not bone:
continue
last_human_bone_name = human_bone_name
Expand Down Expand Up @@ -550,7 +546,7 @@ def setup_vrm1_humanoid_bones(self) -> None:
# ヒューマンボーンとその先祖ボーンを得る
human_bone_tree_bone_names: set[str] = set()
for bone_name in bone_name_to_human_bone_name:
bone = self.armature_data.edit_bones.get(bone_name)
bone = armature_data.edit_bones.get(bone_name)
while bone:
human_bone_tree_bone_names.add(bone.name)
bone = bone.parent
Expand Down Expand Up @@ -613,7 +609,7 @@ def setup_vrm1_humanoid_bones(self) -> None:
# その先祖ボーンを優先したいので、それらを深さ優先で先に処理し、
# その後その他のボーンを深さ優先で処理する
unsorted_bones = [
bone for bone in self.armature_data.edit_bones if not bone.parent
bone for bone in armature_data.edit_bones if not bone.parent
]
while unsorted_bones:
bone = unsorted_bones.pop()
Expand Down Expand Up @@ -760,13 +756,11 @@ def setup_vrm1_humanoid_bones(self) -> None:
)
bone_name_to_axis_translation[bone.name] = axis_translation

connect_parent_tail_and_child_head_if_very_close_position(
self.armature_data
)
connect_parent_tail_and_child_head_if_very_close_position(armature_data)

bpy.ops.object.mode_set(mode="OBJECT")
for bone_name, axis_translation in bone_name_to_axis_translation.items():
data_bone = self.armature_data.bones.get(bone_name)
data_bone = armature_data.bones.get(bone_name)
if not data_bone:
continue
data_bone.vrm_addon_extension.axis_translation = (
Expand All @@ -793,16 +787,6 @@ def setup_vrm1_humanoid_bones(self) -> None:
),
)
break
finally:
if (
self.context.view_layer.objects.active
and self.context.view_layer.objects.active.mode != "OBJECT"
):
bpy.ops.object.mode_set(mode="OBJECT")
self.context.view_layer.objects.active = previous_active
self.context.scene.cursor.matrix = previous_cursor_matrix

self.load_bone_child_object_world_matrices(armature)

def translate_object_axis(self, obj: Object, axis_translation: str) -> None:
if axis_translation != BoneExtension.AXIS_TRANSLATION_AUTO_ID:
Expand Down

0 comments on commit 7a69aaa

Please sign in to comment.