Skip to content

Commit

Permalink
feat: apply modifiers for VRM1 in Blender 4.2
Browse files Browse the repository at this point in the history
  • Loading branch information
saturday06 committed Sep 5, 2024
1 parent df76a89 commit 8e56a0f
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 14 deletions.
39 changes: 34 additions & 5 deletions src/io_scene_vrm/exporter/abstract_base_vrm_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@
from contextlib import contextmanager
from typing import Optional, Union

import bmesh
import bpy
from bpy.types import Armature, Context, Mesh, NodesModifier, Object
from mathutils import Quaternion

from ..common import ops, shader
from ..common.convert import Json
from ..common.deep import make_json
from ..common.logging import get_logger
from ..common.workspace import save_workspace
from ..editor.extension import get_armature_extension, get_material_extension
from ..editor.search import MESH_CONVERTIBLE_OBJECT_TYPES
from ..editor.vrm0.property_group import Vrm0HumanoidPropertyGroup
from ..editor.vrm1.property_group import Vrm1HumanoidPropertyGroup
from ..external import io_scene_gltf2_support

logger = get_logger(__name__)


class AbstractBaseVrmExporter(ABC):
def __init__(
Expand Down Expand Up @@ -311,18 +315,43 @@ def assign_dict(
return True


def force_apply_modifiers(context: Context, obj: Object) -> Optional[Mesh]:
def force_apply_modifiers(
context: Context, obj: Object, *, persistent: bool
) -> Optional[Mesh]:
if obj.type not in MESH_CONVERTIBLE_OBJECT_TYPES:
return None
obj_data = obj.data
if obj_data is None:
return None

# https://docs.blender.org/api/2.80/Depsgraph.html
# TODO: シェイプキーが壊れることがあるらしい
depsgraph = context.evaluated_depsgraph_get()
mesh_owner = obj.evaluated_get(depsgraph)
mesh_from_mesh_owner = mesh_owner.to_mesh(
evaluated_obj = obj.evaluated_get(depsgraph)
evaluated_temporary_mesh = evaluated_obj.to_mesh(
preserve_all_data_layers=True, depsgraph=depsgraph
)
if not mesh_from_mesh_owner:
if not evaluated_temporary_mesh:
return None

return mesh_from_mesh_owner.copy()
if not persistent:
return evaluated_temporary_mesh.copy()

# ドキュメントにはBlendDataMeshes.new_from_object()を使うべきと書いてあるが、
# それだとシェイプキーが保持されない。
if isinstance(obj_data, Mesh):
evaluated_mesh = obj_data.copy()
else:
logger.error(
"Unexpected object type: %s name=%s",
type(obj_data),
obj_data.name,
)
evaluated_mesh = context.blend_data.meshes.new(name=obj_data.name)
bm = bmesh.new()
try:
bm.from_mesh(evaluated_temporary_mesh)
bm.to_mesh(evaluated_mesh)
finally:
bm.free()
return evaluated_mesh
8 changes: 6 additions & 2 deletions src/io_scene_vrm/exporter/vrm0_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2316,7 +2316,9 @@ def mesh_to_bin_and_dict(

shape_key_names: Sequence[str] = []
with save_workspace(self.context):
main_mesh_data = force_apply_modifiers(self.context, mesh)
main_mesh_data = force_apply_modifiers(
self.context, mesh, persistent=False
)
if not main_mesh_data:
continue
shape_key_name_to_mesh_data: dict[str, Mesh] = {}
Expand All @@ -2334,7 +2336,9 @@ def mesh_to_bin_and_dict(

shape_key.value = 1.0
self.context.view_layer.update()
shape_mesh = force_apply_modifiers(self.context, mesh)
shape_mesh = force_apply_modifiers(
self.context, mesh, persistent=False
)
shape_key.value = 0.0
self.context.view_layer.update()

Expand Down
14 changes: 8 additions & 6 deletions src/io_scene_vrm/exporter/vrm1_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
DampedTrackConstraint,
Image,
Material,
Mesh,
Node,
Object,
)
Expand Down Expand Up @@ -2755,7 +2756,7 @@ def force_apply_modifiers_to_object(
return

original_mesh_data = mesh_object.data
if not original_mesh_data:
if not isinstance(original_mesh_data, Mesh):
return

armature_modifier_name_to_show_render_and_show_viewport: dict[
Expand All @@ -2775,14 +2776,15 @@ def force_apply_modifiers_to_object(
mesh_data_name = original_mesh_data.name
original_mesh_data.name = "Backup-Apply-Data-" + uuid4().hex

mesh_data: Optional[ID] = force_apply_modifiers(context, mesh_object)
mesh_data: Optional[ID] = force_apply_modifiers(
context, mesh_object, persistent=True
)
if not mesh_data:
return

mesh_data.user_remap(original_mesh_data)
mesh_data = mesh_object.data
if not mesh_data:
return
original_mesh_data.user_remap(mesh_data)
if original_mesh_data.users <= 1:
context.blend_data.meshes.remove(original_mesh_data)

mesh_data.name = mesh_data_name
finally:
Expand Down

0 comments on commit 8e56a0f

Please sign in to comment.