@volter/blender-engine 0.1.148 → 0.1.150
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -5
- package/README.md +4 -11
- package/browser/addons/vrm/LICENSE_(OPTION1)_MIT.txt +22 -0
- package/browser/addons/vrm/LICENSE_(OPTION2)_GPL-3_0.txt +674 -0
- package/browser/addons/vrm/LICENSE_MAIN.txt +1 -0
- package/browser/addons/vrm/README.txt +3 -0
- package/browser/addons/vrm/__init__.py +41 -0
- package/browser/addons/vrm/blender_manifest.toml +16 -0
- package/browser/addons/vrm/common/__init__.py +1 -0
- package/browser/addons/vrm/common/animation.py +58 -0
- package/browser/addons/vrm/common/blender_manifest.py +82 -0
- package/browser/addons/vrm/common/char.py +16 -0
- package/browser/addons/vrm/common/convert.py +287 -0
- package/browser/addons/vrm/common/convert_any.py +48 -0
- package/browser/addons/vrm/common/debug.py +40 -0
- package/browser/addons/vrm/common/deep.py +162 -0
- package/browser/addons/vrm/common/error_dialog.py +274 -0
- package/browser/addons/vrm/common/fs.py +71 -0
- package/browser/addons/vrm/common/gl.py +20 -0
- package/browser/addons/vrm/common/gltf.py +1149 -0
- package/browser/addons/vrm/common/human_bone_mapper/__init__.py +1 -0
- package/browser/addons/vrm/common/human_bone_mapper/biped_mapping.py +84 -0
- package/browser/addons/vrm/common/human_bone_mapper/cats_blender_plugin_fix_model_mapping.py +63 -0
- package/browser/addons/vrm/common/human_bone_mapper/human_bone_mapper.py +203 -0
- package/browser/addons/vrm/common/human_bone_mapper/microsoft_rocketbox_mapping.py +69 -0
- package/browser/addons/vrm/common/human_bone_mapper/mixamo_mapping.py +62 -0
- package/browser/addons/vrm/common/human_bone_mapper/mmd_mapping.py +115 -0
- package/browser/addons/vrm/common/human_bone_mapper/mpfb_mapping.py +120 -0
- package/browser/addons/vrm/common/human_bone_mapper/ready_player_me_mapping.py +65 -0
- package/browser/addons/vrm/common/human_bone_mapper/reallusion_mapping.py +94 -0
- package/browser/addons/vrm/common/human_bone_mapper/rigify_meta_rig_mapping.py +65 -0
- package/browser/addons/vrm/common/human_bone_mapper/structure_based_mapping.py +891 -0
- package/browser/addons/vrm/common/human_bone_mapper/unreal_mapping.py +62 -0
- package/browser/addons/vrm/common/human_bone_mapper/vrm_addon_mapping.py +112 -0
- package/browser/addons/vrm/common/human_bone_mapper/vroid_mapping.py +89 -0
- package/browser/addons/vrm/common/legacy_gltf.py +16 -0
- package/browser/addons/vrm/common/logger.py +84 -0
- package/browser/addons/vrm/common/mtoon0.blend +0 -0
- package/browser/addons/vrm/common/mtoon1.blend +0 -0
- package/browser/addons/vrm/common/mtoon1_outline.blend +0 -0
- package/browser/addons/vrm/common/mtoon_auto_setup.blend +0 -0
- package/browser/addons/vrm/common/mtoon_unversioned.py +62 -0
- package/browser/addons/vrm/common/ops/__init__.py +10 -0
- package/browser/addons/vrm/common/ops/export_scene.py +67 -0
- package/browser/addons/vrm/common/ops/icyp.py +53 -0
- package/browser/addons/vrm/common/ops/import_scene.py +57 -0
- package/browser/addons/vrm/common/ops/vrm.py +2380 -0
- package/browser/addons/vrm/common/ops/wm.py +167 -0
- package/browser/addons/vrm/common/preferences.py +362 -0
- package/browser/addons/vrm/common/progress.py +87 -0
- package/browser/addons/vrm/common/rotation.py +89 -0
- package/browser/addons/vrm/common/safe_removal.py +46 -0
- package/browser/addons/vrm/common/scene_watcher.py +230 -0
- package/browser/addons/vrm/common/shader.py +2243 -0
- package/browser/addons/vrm/common/shape_key_mapper/__init__.py +1 -0
- package/browser/addons/vrm/common/shape_key_mapper/arkit_mapping.py +168 -0
- package/browser/addons/vrm/common/shape_key_mapper/mmd_mapping.py +62 -0
- package/browser/addons/vrm/common/shape_key_mapper/ready_player_me_mapping.py +52 -0
- package/browser/addons/vrm/common/shape_key_mapper/vrchat_mapping.py +17 -0
- package/browser/addons/vrm/common/third_party_user_extension.py +214 -0
- package/browser/addons/vrm/common/transparent_z_write.blend +0 -0
- package/browser/addons/vrm/common/version.py +161 -0
- package/browser/addons/vrm/common/vrm0/__init__.py +1 -0
- package/browser/addons/vrm/common/vrm0/human_bone.py +662 -0
- package/browser/addons/vrm/common/vrm0/material_property.py +346 -0
- package/browser/addons/vrm/common/vrm1/__init__.py +1 -0
- package/browser/addons/vrm/common/vrm1/expression_preset.py +207 -0
- package/browser/addons/vrm/common/vrm1/human_bone.py +822 -0
- package/browser/addons/vrm/common/workspace.py +227 -0
- package/browser/addons/vrm/common/writable_context.py +77 -0
- package/browser/addons/vrm/documentation/en-us/animation/index.md +63 -0
- package/browser/addons/vrm/documentation/en-us/create-humanoid-vrm-from-scratch/index.md +131 -0
- package/browser/addons/vrm/documentation/en-us/create-simple-vrm-from-scratch/index.md +30 -0
- package/browser/addons/vrm/documentation/en-us/development/index.md +136 -0
- package/browser/addons/vrm/documentation/en-us/index.md +41 -0
- package/browser/addons/vrm/documentation/en-us/installation/index.md +152 -0
- package/browser/addons/vrm/documentation/en-us/material-mtoon/index.md +122 -0
- package/browser/addons/vrm/documentation/en-us/material-pbr/index.md +94 -0
- package/browser/addons/vrm/documentation/en-us/scripting-api/index.md +391 -0
- package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrm/index.md +57 -0
- package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrma/index.md +17 -0
- package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrm/index.md +61 -0
- package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrma/index.md +13 -0
- package/browser/addons/vrm/documentation/ja-jp/animation/index.md +57 -0
- package/browser/addons/vrm/documentation/ja-jp/create-humanoid-vrm-from-scratch/index.md +129 -0
- package/browser/addons/vrm/documentation/ja-jp/create-simple-vrm-from-scratch/index.md +29 -0
- package/browser/addons/vrm/documentation/ja-jp/development/index.md +137 -0
- package/browser/addons/vrm/documentation/ja-jp/index.md +37 -0
- package/browser/addons/vrm/documentation/ja-jp/installation/index.md +150 -0
- package/browser/addons/vrm/documentation/ja-jp/material-mtoon/index.md +113 -0
- package/browser/addons/vrm/documentation/ja-jp/material-pbr/index.md +90 -0
- package/browser/addons/vrm/documentation/ja-jp/scripting-api/index.md +389 -0
- package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrm/index.md +55 -0
- package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrma/index.md +19 -0
- package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrm/index.md +56 -0
- package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrma/index.md +14 -0
- package/browser/addons/vrm/editor/__init__.py +1 -0
- package/browser/addons/vrm/editor/extension.py +425 -0
- package/browser/addons/vrm/editor/extension_accessor.py +75 -0
- package/browser/addons/vrm/editor/handler.py +84 -0
- package/browser/addons/vrm/editor/khr_character/__init__.py +1 -0
- package/browser/addons/vrm/editor/khr_character/panel.py +69 -0
- package/browser/addons/vrm/editor/khr_character/property_group.py +27 -0
- package/browser/addons/vrm/editor/khr_xmp_json_ld/__init__.py +1 -0
- package/browser/addons/vrm/editor/khr_xmp_json_ld/ops.py +464 -0
- package/browser/addons/vrm/editor/khr_xmp_json_ld/panel.py +136 -0
- package/browser/addons/vrm/editor/khr_xmp_json_ld/property_group.py +83 -0
- package/browser/addons/vrm/editor/khr_xmp_json_ld/ui_list.py +198 -0
- package/browser/addons/vrm/editor/make_armature.py +709 -0
- package/browser/addons/vrm/editor/menu.py +147 -0
- package/browser/addons/vrm/editor/migration.py +297 -0
- package/browser/addons/vrm/editor/mtoon1/__init__.py +1 -0
- package/browser/addons/vrm/editor/mtoon1/handler.py +20 -0
- package/browser/addons/vrm/editor/mtoon1/migration.py +536 -0
- package/browser/addons/vrm/editor/mtoon1/ops.py +304 -0
- package/browser/addons/vrm/editor/mtoon1/panel.py +442 -0
- package/browser/addons/vrm/editor/mtoon1/property_group.py +4977 -0
- package/browser/addons/vrm/editor/mtoon1/scene_watcher.py +381 -0
- package/browser/addons/vrm/editor/node_constraint1/__init__.py +1 -0
- package/browser/addons/vrm/editor/node_constraint1/panel.py +317 -0
- package/browser/addons/vrm/editor/node_constraint1/property_group.py +25 -0
- package/browser/addons/vrm/editor/ops.py +471 -0
- package/browser/addons/vrm/editor/panel.py +315 -0
- package/browser/addons/vrm/editor/property_group.py +888 -0
- package/browser/addons/vrm/editor/search.py +682 -0
- package/browser/addons/vrm/editor/spring_bone1/__init__.py +1 -0
- package/browser/addons/vrm/editor/spring_bone1/handler.py +994 -0
- package/browser/addons/vrm/editor/spring_bone1/menu.py +246 -0
- package/browser/addons/vrm/editor/spring_bone1/migration.py +86 -0
- package/browser/addons/vrm/editor/spring_bone1/ops.py +1679 -0
- package/browser/addons/vrm/editor/spring_bone1/panel.py +605 -0
- package/browser/addons/vrm/editor/spring_bone1/property_group.py +1457 -0
- package/browser/addons/vrm/editor/spring_bone1/ui_list.py +408 -0
- package/browser/addons/vrm/editor/subscription.py +123 -0
- package/browser/addons/vrm/editor/t_pose.py +713 -0
- package/browser/addons/vrm/editor/validation.py +1271 -0
- package/browser/addons/vrm/editor/vrm0/__init__.py +1 -0
- package/browser/addons/vrm/editor/vrm0/gizmo_group.py +63 -0
- package/browser/addons/vrm/editor/vrm0/handler.py +23 -0
- package/browser/addons/vrm/editor/vrm0/menu.py +145 -0
- package/browser/addons/vrm/editor/vrm0/migration.py +761 -0
- package/browser/addons/vrm/editor/vrm0/ops.py +2145 -0
- package/browser/addons/vrm/editor/vrm0/panel.py +1333 -0
- package/browser/addons/vrm/editor/vrm0/property_group.py +1818 -0
- package/browser/addons/vrm/editor/vrm0/ui_list.py +688 -0
- package/browser/addons/vrm/editor/vrm1/__init__.py +1 -0
- package/browser/addons/vrm/editor/vrm1/handler.py +28 -0
- package/browser/addons/vrm/editor/vrm1/menu.py +76 -0
- package/browser/addons/vrm/editor/vrm1/migration.py +321 -0
- package/browser/addons/vrm/editor/vrm1/ops.py +2679 -0
- package/browser/addons/vrm/editor/vrm1/panel.py +1243 -0
- package/browser/addons/vrm/editor/vrm1/property_group.py +2087 -0
- package/browser/addons/vrm/editor/vrm1/scene_watcher.py +90 -0
- package/browser/addons/vrm/editor/vrm1/ui_list.py +533 -0
- package/browser/addons/vrm/exporter/__init__.py +1 -0
- package/browser/addons/vrm/exporter/abstract_base_vrm_exporter.py +628 -0
- package/browser/addons/vrm/exporter/export_scene.py +930 -0
- package/browser/addons/vrm/exporter/gltf2_export_user_extension.py +45 -0
- package/browser/addons/vrm/exporter/khr_character_exporter.py +34 -0
- package/browser/addons/vrm/exporter/vrm0_exporter.py +4020 -0
- package/browser/addons/vrm/exporter/vrm1_exporter.py +3682 -0
- package/browser/addons/vrm/exporter/vrm_animation_exporter.py +1035 -0
- package/browser/addons/vrm/external/__init__.py +1 -0
- package/browser/addons/vrm/external/auto_rig_pro_support.py +3 -0
- package/browser/addons/vrm/external/io_scene_gltf2_support.py +418 -0
- package/browser/addons/vrm/external/rigify_support.py +1 -0
- package/browser/addons/vrm/importer/__init__.py +1 -0
- package/browser/addons/vrm/importer/abstract_base_vrm_importer.py +1548 -0
- package/browser/addons/vrm/importer/file_handler.py +34 -0
- package/browser/addons/vrm/importer/gltf2_import_user_extension.py +268 -0
- package/browser/addons/vrm/importer/import_scene.py +646 -0
- package/browser/addons/vrm/importer/license_validation.py +198 -0
- package/browser/addons/vrm/importer/vrm0_importer.py +1723 -0
- package/browser/addons/vrm/importer/vrm1_importer.py +2014 -0
- package/browser/addons/vrm/importer/vrm_animation_importer.py +763 -0
- package/browser/addons/vrm/importer/vrm_diff.py +316 -0
- package/browser/addons/vrm/locale/__init__.py +1 -0
- package/browser/addons/vrm/locale/ja_jp.py +826 -0
- package/browser/addons/vrm/locale/ruff.toml +8 -0
- package/browser/addons/vrm/locale/translation_dictionary.py +10 -0
- package/browser/addons/vrm/locale/zh_hans.py +928 -0
- package/browser/addons/vrm/registration.py +670 -0
- package/browser/addons/vrm.json +18 -0
- package/browser/blender-emscripten-engine.mts +66 -129
- package/browser/blender-engine.mts +20 -186
- package/browser/blender-wali-engine.mts +37 -81
- package/browser/describe-thrown.mts +3 -6
- package/browser/document-chunks.mts +4 -16
- package/browser/gltf_export.py +3161 -0
- package/browser/heap-growth.mts +23 -0
- package/browser/index.ts +3 -0
- package/browser/protocol.ts +130 -43
- package/browser/pull-job.mts +2 -10
- package/browser/rna.ts +190 -73
- package/browser/runtime.ts +271 -106
- package/browser/session-addons.mts +33 -0
- package/browser/session-frame.mts +5 -24
- package/browser/session.py +1389 -1446
- package/browser/three/attach-presenter.ts +11 -39
- package/browser/three/blender-base64.ts +1 -36
- package/browser/three/blender-corner-normals.ts +1 -23
- package/browser/three/blender-display-shaders.json +1 -1
- package/browser/three/blender-display-shaders.lut +0 -0
- package/browser/three/blender-display-transform.ts +2 -1
- package/browser/three/blender-frame-columns.ts +5 -13
- package/browser/three/blender-graph-material.ts +18 -3
- package/browser/three/blender-node-graph.ts +10 -34
- package/browser/three/blender-physical-material.ts +2 -31
- package/browser/three/blender-runtime-armature.ts +7 -60
- package/browser/three/blender-runtime-frame.ts +9 -23
- package/browser/three/blender-runtime-geometry.ts +22 -26
- package/browser/three/blender-runtime-lighting.ts +48 -178
- package/browser/three/blender-runtime-shadows.ts +187 -1
- package/browser/three/blender-runtime-skeleton.ts +53 -1
- package/browser/three/blender-runtime-view.ts +492 -306
- package/browser/three/blender-runtime-weights.ts +9 -72
- package/browser/three/blender-sky.ts +13 -33
- package/browser/three/blender-triangulate.ts +7 -35
- package/browser/three/blender-viewport-sampling.ts +235 -0
- package/browser/three/blender-workbench-material.ts +25 -29
- package/browser/three/blender-workbench-outline.ts +199 -0
- package/browser/three/blender-world-volume.ts +62 -10
- package/browser/three/presenter.ts +10 -26
- package/browser/three/release.ts +5 -21
- package/browser/three/sky-precompute-worker.ts +1 -18
- package/browser/three/sky-worker.ts +5 -23
- package/browser/three/world-field-sampler.ts +12 -26
- package/browser/volter_three.py +9 -105
- package/browser/worker.ts +195 -180
- package/package.json +5 -2
- package/wasm/BUNDLE.json +17 -17
- package/wasm/DEPENDENCY-LICENSES.txt +14 -0
- package/wasm/blender_browser.data.br +0 -0
- package/wasm/blender_browser.js +1 -1
- package/wasm/blender_browser.wasm.br +0 -0
- package/browser/frame-transfer.mts +0 -19
- package/browser/three/agx-base-srgb.lut +0 -0
- package/browser/three/agx-look-medium-high-contrast.lut +0 -0
- package/browser/three/agx-look-punchy.lut +0 -0
- package/browser/three/blender-agx.ts +0 -235
- package/browser/three/blender-display-lut.ts +0 -145
- package/browser/three/blender-filmic.ts +0 -49
- package/browser/three/blender-standard.ts +0 -68
- package/browser/three/blender-world-visibility.ts +0 -278
- package/browser/three/filmic-srgb.lut +0 -0
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
|
|
2
|
+
import secrets
|
|
3
|
+
import string
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from collections.abc import Generator, Mapping, Sequence
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Optional, TypeVar, Union
|
|
9
|
+
|
|
10
|
+
import bmesh
|
|
11
|
+
import bpy
|
|
12
|
+
from bpy.types import Armature, Constraint, Context, Mesh, NodesModifier, Object
|
|
13
|
+
from mathutils import Vector
|
|
14
|
+
|
|
15
|
+
from ..common import shader
|
|
16
|
+
from ..common.convert import Json
|
|
17
|
+
from ..common.deep import make_json
|
|
18
|
+
from ..common.logger import get_logger
|
|
19
|
+
from ..common.vrm0 import human_bone as vrm0_human_bone
|
|
20
|
+
from ..common.vrm1 import human_bone as vrm1_human_bone
|
|
21
|
+
from ..common.workspace import save_workspace
|
|
22
|
+
from ..editor.extension_accessor import get_armature_extension, get_material_extension
|
|
23
|
+
from ..editor.property_group import BonePropertyGroup, BonePropertyGroupType
|
|
24
|
+
from ..editor.search import MESH_CONVERTIBLE_OBJECT_TYPES
|
|
25
|
+
from ..external import io_scene_gltf2_support
|
|
26
|
+
|
|
27
|
+
HumanBoneSpecification = TypeVar(
|
|
28
|
+
"HumanBoneSpecification",
|
|
29
|
+
vrm0_human_bone.HumanBoneSpecification,
|
|
30
|
+
vrm1_human_bone.HumanBoneSpecification,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
_logger = get_logger(__name__)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(frozen=True)
|
|
38
|
+
class FlexibleHierarchyBoneSetup:
|
|
39
|
+
original_bone_settings: Mapping[str, tuple[Optional[str], bool]]
|
|
40
|
+
pose_bone_name_and_muted_constraint_name: list[tuple[str, str]]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class AbstractBaseVrmExporter(ABC):
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
context: Context,
|
|
47
|
+
export_objects: Sequence[Object],
|
|
48
|
+
armature: Object,
|
|
49
|
+
) -> None:
|
|
50
|
+
self._context = context
|
|
51
|
+
self._export_objects = export_objects
|
|
52
|
+
self._armature = armature
|
|
53
|
+
self._export_id = "BlenderVrmAddonExport" + (
|
|
54
|
+
"".join(secrets.choice(string.digits) for _ in range(15))
|
|
55
|
+
)
|
|
56
|
+
self._gltf2_addon_export_settings = (
|
|
57
|
+
io_scene_gltf2_support.create_export_settings()
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
armature_data = self._armature.data
|
|
61
|
+
if not isinstance(armature_data, Armature):
|
|
62
|
+
message = f"{type(armature_data)} is not an Armature"
|
|
63
|
+
raise TypeError(message)
|
|
64
|
+
|
|
65
|
+
self.generator_postfix = ""
|
|
66
|
+
|
|
67
|
+
@abstractmethod
|
|
68
|
+
def export(self) -> Optional[bytes]:
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def enter_clear_blend_shape_proxy_previews(
|
|
73
|
+
context: Context,
|
|
74
|
+
armature_data: Armature,
|
|
75
|
+
) -> tuple[Sequence[float], Mapping[str, float], Mapping[str, Mapping[str, float]]]:
|
|
76
|
+
saved_key_block_values: dict[str, Mapping[str, float]] = {}
|
|
77
|
+
for mesh in context.blend_data.meshes:
|
|
78
|
+
shape_keys = mesh.shape_keys
|
|
79
|
+
if not shape_keys:
|
|
80
|
+
continue
|
|
81
|
+
saved_key_block_values[mesh.name] = {
|
|
82
|
+
key_block.name: key_block.value for key_block in shape_keys.key_blocks
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
ext = get_armature_extension(armature_data)
|
|
86
|
+
|
|
87
|
+
saved_vrm1_previews: dict[str, float] = {}
|
|
88
|
+
for (
|
|
89
|
+
name,
|
|
90
|
+
expression,
|
|
91
|
+
) in ext.vrm1.expressions.all_name_to_expression_dict().items():
|
|
92
|
+
saved_vrm1_previews[name] = expression.preview
|
|
93
|
+
expression.preview = 0
|
|
94
|
+
|
|
95
|
+
saved_vrm0_previews: list[float] = []
|
|
96
|
+
for blend_shape_group in ext.vrm0.blend_shape_master.blend_shape_groups:
|
|
97
|
+
saved_vrm0_previews.append(blend_shape_group.preview)
|
|
98
|
+
blend_shape_group.preview = 0
|
|
99
|
+
|
|
100
|
+
return saved_vrm0_previews, saved_vrm1_previews, saved_key_block_values
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def leave_clear_blend_shape_proxy_previews(
|
|
104
|
+
context: Context,
|
|
105
|
+
armature_data: Armature,
|
|
106
|
+
saved_vrm0_previews: Sequence[float],
|
|
107
|
+
saved_vrm1_previews: Mapping[str, float],
|
|
108
|
+
saved_key_block_values: Mapping[str, Mapping[str, float]],
|
|
109
|
+
) -> None:
|
|
110
|
+
ext = get_armature_extension(armature_data)
|
|
111
|
+
|
|
112
|
+
for blend_shape_group, blend_shape_preview in reversed(
|
|
113
|
+
list(
|
|
114
|
+
zip(ext.vrm0.blend_shape_master.blend_shape_groups, saved_vrm0_previews)
|
|
115
|
+
)
|
|
116
|
+
):
|
|
117
|
+
blend_shape_group.preview = blend_shape_preview
|
|
118
|
+
|
|
119
|
+
for (
|
|
120
|
+
name,
|
|
121
|
+
expression,
|
|
122
|
+
) in ext.vrm1.expressions.all_name_to_expression_dict().items():
|
|
123
|
+
expression_preview = saved_vrm1_previews.get(name)
|
|
124
|
+
if expression_preview is not None:
|
|
125
|
+
expression.preview = expression_preview
|
|
126
|
+
|
|
127
|
+
for mesh_name, key_block_name_to_values in reversed(
|
|
128
|
+
list(saved_key_block_values.items())
|
|
129
|
+
):
|
|
130
|
+
mesh = context.blend_data.meshes.get(mesh_name)
|
|
131
|
+
if not mesh:
|
|
132
|
+
continue
|
|
133
|
+
|
|
134
|
+
shape_keys = mesh.shape_keys
|
|
135
|
+
if not shape_keys:
|
|
136
|
+
continue
|
|
137
|
+
|
|
138
|
+
for key_block in shape_keys.key_blocks:
|
|
139
|
+
shape_key_value = key_block_name_to_values.get(key_block.name)
|
|
140
|
+
if shape_key_value is not None:
|
|
141
|
+
key_block.value = shape_key_value
|
|
142
|
+
|
|
143
|
+
@contextmanager
|
|
144
|
+
def clear_blend_shape_proxy_previews(
|
|
145
|
+
self, context: Context, armature_data: Armature
|
|
146
|
+
) -> Generator[None]:
|
|
147
|
+
saved_vrm0_previews, saved_vrm1_previews, saved_key_block_values = (
|
|
148
|
+
self.enter_clear_blend_shape_proxy_previews(context, armature_data)
|
|
149
|
+
)
|
|
150
|
+
try:
|
|
151
|
+
yield
|
|
152
|
+
# After yield, native bpy objects may be deleted or frames may advance,
|
|
153
|
+
# becoming invalid. Accessing them in this state causes crashes, so
|
|
154
|
+
# be careful not to access potentially invalid native objects after yield
|
|
155
|
+
finally:
|
|
156
|
+
self.leave_clear_blend_shape_proxy_previews(
|
|
157
|
+
context,
|
|
158
|
+
armature_data,
|
|
159
|
+
saved_vrm0_previews,
|
|
160
|
+
saved_vrm1_previews,
|
|
161
|
+
saved_key_block_values,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
def enter_enable_deform_for_all_referenced_bones(
|
|
165
|
+
self, armature_data: Armature
|
|
166
|
+
) -> list[str]:
|
|
167
|
+
ext = get_armature_extension(armature_data)
|
|
168
|
+
modified_non_deform_bone_names = list[str]()
|
|
169
|
+
for (
|
|
170
|
+
bone_property_group,
|
|
171
|
+
bone_property_group_type,
|
|
172
|
+
) in BonePropertyGroup.get_all_bone_property_groups(armature_data):
|
|
173
|
+
bone = armature_data.bones.get(bone_property_group.bone_name)
|
|
174
|
+
if not bone or bone.use_deform:
|
|
175
|
+
continue
|
|
176
|
+
if (
|
|
177
|
+
ext.is_vrm0()
|
|
178
|
+
and BonePropertyGroupType.is_vrm0(bone_property_group_type)
|
|
179
|
+
) or (
|
|
180
|
+
ext.is_vrm1()
|
|
181
|
+
and BonePropertyGroupType.is_vrm1(bone_property_group_type)
|
|
182
|
+
):
|
|
183
|
+
bone.use_deform = True
|
|
184
|
+
modified_non_deform_bone_names.append(bone.name)
|
|
185
|
+
|
|
186
|
+
if ext.is_vrm1() and bpy.app.version >= (4, 4):
|
|
187
|
+
# Enable deformation for root bone when Blender 4.4+ and VRM 1.0.
|
|
188
|
+
#
|
|
189
|
+
# For VRM 1.0, export is done using the glTF 2.0 add-on, but export
|
|
190
|
+
# becomes unstable when root bone deformation is not present.
|
|
191
|
+
# Compatibility for versions before Blender 4.4 is already handled
|
|
192
|
+
# separately, so here we enable root bone deformation only for 4.4+.
|
|
193
|
+
# https://github.com/KhronosGroup/glTF-Blender-IO/issues/2697
|
|
194
|
+
# https://github.com/saturday06/VRM-Addon-for-Blender/issues/1244
|
|
195
|
+
for bone in armature_data.bones:
|
|
196
|
+
if bone.parent:
|
|
197
|
+
continue
|
|
198
|
+
if bone.use_deform:
|
|
199
|
+
continue
|
|
200
|
+
bone.use_deform = True
|
|
201
|
+
modified_non_deform_bone_names.append(bone.name)
|
|
202
|
+
|
|
203
|
+
return modified_non_deform_bone_names
|
|
204
|
+
|
|
205
|
+
def leave_enable_deform_for_all_referenced_bones(
|
|
206
|
+
self, armature_data: Armature, modified_non_deform_bone_names: list[str]
|
|
207
|
+
) -> None:
|
|
208
|
+
for modified_non_deform_bone_name in reversed(modified_non_deform_bone_names):
|
|
209
|
+
bone = armature_data.bones.get(modified_non_deform_bone_name)
|
|
210
|
+
if bone and bone.use_deform:
|
|
211
|
+
bone.use_deform = False
|
|
212
|
+
|
|
213
|
+
@contextmanager
|
|
214
|
+
def enable_deform_for_all_referenced_bones(
|
|
215
|
+
self, armature_data: Armature
|
|
216
|
+
) -> Generator[None]:
|
|
217
|
+
modified_non_deform_bone_names = (
|
|
218
|
+
self.enter_enable_deform_for_all_referenced_bones(armature_data)
|
|
219
|
+
)
|
|
220
|
+
try:
|
|
221
|
+
yield
|
|
222
|
+
finally:
|
|
223
|
+
self.leave_enable_deform_for_all_referenced_bones(
|
|
224
|
+
armature_data, modified_non_deform_bone_names
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
@staticmethod
|
|
228
|
+
def enter_hide_mtoon1_outline_geometry_nodes(
|
|
229
|
+
context: Context,
|
|
230
|
+
) -> dict[str, list[tuple[str, bool, bool]]]:
|
|
231
|
+
object_name_to_modifiers: dict[str, list[tuple[str, bool, bool]]] = {}
|
|
232
|
+
for obj in context.blend_data.objects:
|
|
233
|
+
for modifier in obj.modifiers:
|
|
234
|
+
if not modifier.show_viewport:
|
|
235
|
+
continue
|
|
236
|
+
if modifier.type != "NODES":
|
|
237
|
+
continue
|
|
238
|
+
if not isinstance(modifier, NodesModifier):
|
|
239
|
+
continue
|
|
240
|
+
node_group = modifier.node_group
|
|
241
|
+
if (
|
|
242
|
+
not node_group
|
|
243
|
+
or node_group.name != shader.OUTLINE_GEOMETRY_GROUP_NAME
|
|
244
|
+
):
|
|
245
|
+
continue
|
|
246
|
+
modifiers = object_name_to_modifiers.get(obj.name)
|
|
247
|
+
if modifiers is None:
|
|
248
|
+
modifiers = []
|
|
249
|
+
object_name_to_modifiers[obj.name] = modifiers
|
|
250
|
+
modifiers = object_name_to_modifiers[obj.name]
|
|
251
|
+
modifiers.append(
|
|
252
|
+
(
|
|
253
|
+
modifier.name,
|
|
254
|
+
modifier.show_render,
|
|
255
|
+
modifier.show_viewport,
|
|
256
|
+
)
|
|
257
|
+
)
|
|
258
|
+
if modifier.show_render:
|
|
259
|
+
modifier.show_render = False
|
|
260
|
+
if modifier.show_viewport:
|
|
261
|
+
modifier.show_viewport = False
|
|
262
|
+
return object_name_to_modifiers
|
|
263
|
+
|
|
264
|
+
@staticmethod
|
|
265
|
+
def exit_hide_mtoon1_outline_geometry_nodes(
|
|
266
|
+
context: Context,
|
|
267
|
+
object_name_to_modifiers: dict[str, list[tuple[str, bool, bool]]],
|
|
268
|
+
) -> None:
|
|
269
|
+
for object_name, modifiers in reversed(list(object_name_to_modifiers.items())):
|
|
270
|
+
for modifier_name, render, viewport in reversed(modifiers):
|
|
271
|
+
obj = context.blend_data.objects.get(object_name)
|
|
272
|
+
if not obj:
|
|
273
|
+
continue
|
|
274
|
+
modifier = obj.modifiers.get(modifier_name)
|
|
275
|
+
if (
|
|
276
|
+
not modifier
|
|
277
|
+
or modifier.type != "NODES"
|
|
278
|
+
or not isinstance(modifier, NodesModifier)
|
|
279
|
+
):
|
|
280
|
+
continue
|
|
281
|
+
node_group = modifier.node_group
|
|
282
|
+
if (
|
|
283
|
+
not node_group
|
|
284
|
+
or node_group.name != shader.OUTLINE_GEOMETRY_GROUP_NAME
|
|
285
|
+
):
|
|
286
|
+
continue
|
|
287
|
+
if modifier.show_render != render:
|
|
288
|
+
modifier.show_render = render
|
|
289
|
+
if modifier.show_viewport != viewport:
|
|
290
|
+
modifier.show_viewport = viewport
|
|
291
|
+
|
|
292
|
+
@staticmethod
|
|
293
|
+
@contextmanager
|
|
294
|
+
def hide_mtoon1_outline_geometry_nodes(context: Context) -> Generator[None]:
|
|
295
|
+
object_name_to_modifier_names = (
|
|
296
|
+
AbstractBaseVrmExporter.enter_hide_mtoon1_outline_geometry_nodes(context)
|
|
297
|
+
)
|
|
298
|
+
try:
|
|
299
|
+
yield
|
|
300
|
+
# After yield, native bpy objects may be deleted or frames may advance,
|
|
301
|
+
# becoming invalid. Accessing them in this state causes crashes, so
|
|
302
|
+
# be careful not to access potentially invalid native objects after yield
|
|
303
|
+
finally:
|
|
304
|
+
AbstractBaseVrmExporter.exit_hide_mtoon1_outline_geometry_nodes(
|
|
305
|
+
context, object_name_to_modifier_names
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
@staticmethod
|
|
309
|
+
def create_child_bone_name_to_parent_bone_name(
|
|
310
|
+
armature_data: Armature,
|
|
311
|
+
assigned_human_bone_specification_to_bone_name: Mapping[
|
|
312
|
+
HumanBoneSpecification, str
|
|
313
|
+
],
|
|
314
|
+
all_human_bone_specifications: Sequence[HumanBoneSpecification],
|
|
315
|
+
) -> Mapping[str, str]:
|
|
316
|
+
assigned_bone_names = set(
|
|
317
|
+
assigned_human_bone_specification_to_bone_name.values()
|
|
318
|
+
)
|
|
319
|
+
child_bone_name_to_parent_bone_name: dict[str, str] = {}
|
|
320
|
+
for human_bone_specification in all_human_bone_specifications:
|
|
321
|
+
child_bone_name = assigned_human_bone_specification_to_bone_name.get(
|
|
322
|
+
human_bone_specification
|
|
323
|
+
)
|
|
324
|
+
if not child_bone_name:
|
|
325
|
+
continue
|
|
326
|
+
child_bone = armature_data.bones.get(child_bone_name)
|
|
327
|
+
if not child_bone:
|
|
328
|
+
continue
|
|
329
|
+
ancestor = human_bone_specification.parent
|
|
330
|
+
while ancestor:
|
|
331
|
+
ancestor_bone_name = assigned_human_bone_specification_to_bone_name.get(
|
|
332
|
+
ancestor
|
|
333
|
+
)
|
|
334
|
+
if not ancestor_bone_name:
|
|
335
|
+
if ancestor.requirement:
|
|
336
|
+
break
|
|
337
|
+
ancestor = ancestor.parent
|
|
338
|
+
continue
|
|
339
|
+
|
|
340
|
+
search_bone = child_bone.parent
|
|
341
|
+
while search_bone:
|
|
342
|
+
if search_bone.name in assigned_bone_names:
|
|
343
|
+
break
|
|
344
|
+
search_bone = search_bone.parent
|
|
345
|
+
if search_bone and search_bone.name == ancestor_bone_name:
|
|
346
|
+
break
|
|
347
|
+
|
|
348
|
+
child_bone_name_to_parent_bone_name[child_bone_name] = (
|
|
349
|
+
ancestor_bone_name
|
|
350
|
+
)
|
|
351
|
+
break
|
|
352
|
+
|
|
353
|
+
return child_bone_name_to_parent_bone_name
|
|
354
|
+
|
|
355
|
+
@staticmethod
|
|
356
|
+
def reparent_edit_bones(
|
|
357
|
+
context: Context,
|
|
358
|
+
armature_object: Object,
|
|
359
|
+
assigned_bone_names: Mapping[HumanBoneSpecification, str],
|
|
360
|
+
child_bone_name_to_parent_bone_name: Mapping[str, str],
|
|
361
|
+
) -> Mapping[str, tuple[Optional[str], bool]]:
|
|
362
|
+
if not isinstance(armature_data := armature_object.data, Armature):
|
|
363
|
+
return {}
|
|
364
|
+
original_bone_settings: dict[str, tuple[Optional[str], bool]] = {}
|
|
365
|
+
with save_workspace(context, armature_object, mode="EDIT"):
|
|
366
|
+
for bone_name in assigned_bone_names.values():
|
|
367
|
+
edit_bone = armature_data.edit_bones.get(bone_name)
|
|
368
|
+
if not edit_bone:
|
|
369
|
+
continue
|
|
370
|
+
original_bone_settings[bone_name] = (
|
|
371
|
+
edit_bone.parent.name if edit_bone.parent else None,
|
|
372
|
+
edit_bone.use_connect,
|
|
373
|
+
)
|
|
374
|
+
edit_bone.use_connect = False
|
|
375
|
+
|
|
376
|
+
for (
|
|
377
|
+
child_bone_name,
|
|
378
|
+
ancestor_bone_name,
|
|
379
|
+
) in child_bone_name_to_parent_bone_name.items():
|
|
380
|
+
child_edit_bone = armature_data.edit_bones.get(child_bone_name)
|
|
381
|
+
parent_edit_bone = armature_data.edit_bones.get(ancestor_bone_name)
|
|
382
|
+
if not child_edit_bone or not parent_edit_bone:
|
|
383
|
+
continue
|
|
384
|
+
child_edit_bone.parent = parent_edit_bone
|
|
385
|
+
|
|
386
|
+
return original_bone_settings
|
|
387
|
+
|
|
388
|
+
@staticmethod
|
|
389
|
+
def enter_setup_flexible_hierarchy_bones(
|
|
390
|
+
_context: Context,
|
|
391
|
+
_armature_object: Object,
|
|
392
|
+
_export_objects: Sequence[Object],
|
|
393
|
+
) -> Optional[FlexibleHierarchyBoneSetup]:
|
|
394
|
+
"""Build the flexible hierarchy setup when a subclass supports it.
|
|
395
|
+
|
|
396
|
+
Subclasses can override this to build the assigned-bone map and call
|
|
397
|
+
``reparent_edit_bones``. The default returns ``None``.
|
|
398
|
+
"""
|
|
399
|
+
return None
|
|
400
|
+
|
|
401
|
+
@staticmethod
|
|
402
|
+
def leave_setup_flexible_hierarchy_bones(
|
|
403
|
+
context: Context,
|
|
404
|
+
armature_object: Object,
|
|
405
|
+
flexible_hierarchy_bone_setup: FlexibleHierarchyBoneSetup,
|
|
406
|
+
) -> None:
|
|
407
|
+
"""Restore bone parents to the saved state.
|
|
408
|
+
|
|
409
|
+
Use the state recorded by ``enter_setup_flexible_hierarchy_bones``.
|
|
410
|
+
"""
|
|
411
|
+
armature_data = armature_object.data
|
|
412
|
+
if not isinstance(armature_data, Armature):
|
|
413
|
+
return
|
|
414
|
+
|
|
415
|
+
with save_workspace(context, armature_object, mode="EDIT"):
|
|
416
|
+
for (
|
|
417
|
+
bone_name
|
|
418
|
+
) in flexible_hierarchy_bone_setup.original_bone_settings.keys():
|
|
419
|
+
edit_bone = armature_data.edit_bones.get(bone_name)
|
|
420
|
+
if edit_bone:
|
|
421
|
+
edit_bone.parent = None
|
|
422
|
+
edit_bone.use_connect = False
|
|
423
|
+
|
|
424
|
+
for bone_name, (
|
|
425
|
+
parent_name,
|
|
426
|
+
use_connect,
|
|
427
|
+
) in flexible_hierarchy_bone_setup.original_bone_settings.items():
|
|
428
|
+
edit_bone = armature_data.edit_bones.get(bone_name)
|
|
429
|
+
if not edit_bone:
|
|
430
|
+
continue
|
|
431
|
+
if parent_name:
|
|
432
|
+
parent_edit_bone = armature_data.edit_bones.get(parent_name)
|
|
433
|
+
if parent_edit_bone:
|
|
434
|
+
edit_bone.parent = parent_edit_bone
|
|
435
|
+
edit_bone.use_connect = use_connect
|
|
436
|
+
|
|
437
|
+
for pose_bone_name, muted_constraint_name in reversed(
|
|
438
|
+
flexible_hierarchy_bone_setup.pose_bone_name_and_muted_constraint_name
|
|
439
|
+
):
|
|
440
|
+
pose_bone = armature_object.pose.bones.get(pose_bone_name)
|
|
441
|
+
if not pose_bone:
|
|
442
|
+
continue
|
|
443
|
+
constraint = pose_bone.constraints.get(muted_constraint_name)
|
|
444
|
+
if isinstance(constraint, Constraint) and constraint.mute:
|
|
445
|
+
constraint.mute = False
|
|
446
|
+
|
|
447
|
+
@classmethod
|
|
448
|
+
@contextmanager
|
|
449
|
+
def setup_flexible_hierarchy_bones(
|
|
450
|
+
cls,
|
|
451
|
+
context: Context,
|
|
452
|
+
armature: Object,
|
|
453
|
+
export_objects: Sequence[Object],
|
|
454
|
+
) -> Generator[None]:
|
|
455
|
+
flexible_hierarchy_bone_setup = cls.enter_setup_flexible_hierarchy_bones(
|
|
456
|
+
context,
|
|
457
|
+
armature,
|
|
458
|
+
export_objects,
|
|
459
|
+
)
|
|
460
|
+
try:
|
|
461
|
+
yield
|
|
462
|
+
finally:
|
|
463
|
+
if flexible_hierarchy_bone_setup is not None:
|
|
464
|
+
cls.leave_setup_flexible_hierarchy_bones(
|
|
465
|
+
context,
|
|
466
|
+
armature,
|
|
467
|
+
flexible_hierarchy_bone_setup,
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
@staticmethod
|
|
471
|
+
def setup_mtoon_gltf_fallback_nodes(context: Context, *, is_vrm0: bool) -> None:
|
|
472
|
+
"""Reflect MToon node values to nodes used for glTF fallback values.
|
|
473
|
+
|
|
474
|
+
When MToon nodes are directly edited, glTF fallback values are not
|
|
475
|
+
automatically set. Therefore, we explicitly set values during export.
|
|
476
|
+
"""
|
|
477
|
+
for material in context.blend_data.materials:
|
|
478
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
479
|
+
if not mtoon1.enabled:
|
|
480
|
+
continue
|
|
481
|
+
mtoon1.pbr_metallic_roughness.base_color_factor = (
|
|
482
|
+
mtoon1.pbr_metallic_roughness.base_color_factor
|
|
483
|
+
)
|
|
484
|
+
mtoon1.emissive_factor = mtoon1.emissive_factor
|
|
485
|
+
mtoon1.normal_texture.scale = mtoon1.normal_texture.scale
|
|
486
|
+
mtoon1.extensions.khr_materials_emissive_strength.emissive_strength = (
|
|
487
|
+
mtoon1.extensions.khr_materials_emissive_strength.emissive_strength
|
|
488
|
+
)
|
|
489
|
+
for texture in mtoon1.all_textures(downgrade_to_mtoon0=is_vrm0):
|
|
490
|
+
texture.source = texture.get_connected_node_image()
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def assign_dict(
|
|
494
|
+
target: dict[str, Json],
|
|
495
|
+
key: str,
|
|
496
|
+
value: Union[Json, tuple[float, float, float], tuple[float, float, float, float]],
|
|
497
|
+
default_value: Json = None,
|
|
498
|
+
) -> bool:
|
|
499
|
+
if value is None or value == default_value:
|
|
500
|
+
return False
|
|
501
|
+
target[key] = make_json(value)
|
|
502
|
+
return True
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
def generate_evaluated_mesh(context: Context, obj: Object) -> Optional[Mesh]:
|
|
506
|
+
obj_data = obj.data
|
|
507
|
+
if obj_data is None:
|
|
508
|
+
return None
|
|
509
|
+
|
|
510
|
+
# https://docs.blender.org/api/2.80/Depsgraph.html
|
|
511
|
+
# TODO: Shape keys may sometimes break
|
|
512
|
+
depsgraph = context.evaluated_depsgraph_get()
|
|
513
|
+
evaluated_obj = obj.evaluated_get(depsgraph)
|
|
514
|
+
evaluated_temporary_mesh = evaluated_obj.to_mesh(
|
|
515
|
+
preserve_all_data_layers=True, depsgraph=depsgraph
|
|
516
|
+
)
|
|
517
|
+
if not evaluated_temporary_mesh:
|
|
518
|
+
return None
|
|
519
|
+
|
|
520
|
+
# The documentation says to use BlendDataMeshes.new_from_object(), but
|
|
521
|
+
# that doesn't preserve shape keys.
|
|
522
|
+
if isinstance(obj_data, Mesh):
|
|
523
|
+
evaluated_mesh = obj_data.copy()
|
|
524
|
+
else:
|
|
525
|
+
_logger.error(
|
|
526
|
+
"Unexpected object type: %s name=%s",
|
|
527
|
+
type(obj_data),
|
|
528
|
+
obj_data.name,
|
|
529
|
+
)
|
|
530
|
+
evaluated_mesh = context.blend_data.meshes.new(name=obj_data.name)
|
|
531
|
+
|
|
532
|
+
bm = bmesh.new()
|
|
533
|
+
bm.from_mesh(evaluated_temporary_mesh)
|
|
534
|
+
bm.to_mesh(evaluated_mesh)
|
|
535
|
+
bm.free()
|
|
536
|
+
|
|
537
|
+
evaluated_obj.to_mesh_clear()
|
|
538
|
+
return evaluated_mesh
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
def force_apply_modifiers(context: Context, obj: Object) -> Optional[Mesh]:
|
|
542
|
+
if obj.type not in MESH_CONVERTIBLE_OBJECT_TYPES:
|
|
543
|
+
return None
|
|
544
|
+
|
|
545
|
+
key_block_name_to_value: dict[str, float] = {}
|
|
546
|
+
if isinstance(mesh_data := obj.data, Mesh) and (shape_keys := mesh_data.shape_keys):
|
|
547
|
+
for key_block in shape_keys.key_blocks:
|
|
548
|
+
key_block_name_to_value[key_block.name] = key_block.value
|
|
549
|
+
key_block.value = 0
|
|
550
|
+
|
|
551
|
+
context.view_layer.update()
|
|
552
|
+
|
|
553
|
+
evaluated_mesh_data: Optional[Mesh] = None
|
|
554
|
+
try:
|
|
555
|
+
evaluated_mesh_data = generate_evaluated_mesh(context, obj)
|
|
556
|
+
if evaluated_mesh_data is None:
|
|
557
|
+
return None
|
|
558
|
+
|
|
559
|
+
obj_data = obj.data
|
|
560
|
+
if obj_data is None:
|
|
561
|
+
return evaluated_mesh_data
|
|
562
|
+
|
|
563
|
+
if not isinstance(obj_data, Mesh):
|
|
564
|
+
return evaluated_mesh_data
|
|
565
|
+
|
|
566
|
+
shape_keys = obj_data.shape_keys
|
|
567
|
+
if not shape_keys:
|
|
568
|
+
return evaluated_mesh_data
|
|
569
|
+
|
|
570
|
+
evaluated_mesh_data_shape_keys = evaluated_mesh_data.shape_keys
|
|
571
|
+
if not evaluated_mesh_data_shape_keys:
|
|
572
|
+
return evaluated_mesh_data
|
|
573
|
+
|
|
574
|
+
# If the mesh has shape keys, reproduce them as much as possible
|
|
575
|
+
for key_block in shape_keys.key_blocks:
|
|
576
|
+
evaluated_key_block = evaluated_mesh_data_shape_keys.key_blocks.get(
|
|
577
|
+
key_block.name
|
|
578
|
+
)
|
|
579
|
+
if not evaluated_key_block:
|
|
580
|
+
continue
|
|
581
|
+
|
|
582
|
+
if key_block.name == shape_keys.reference_key.name:
|
|
583
|
+
continue
|
|
584
|
+
|
|
585
|
+
key_block.value = 1.0
|
|
586
|
+
context.view_layer.update()
|
|
587
|
+
|
|
588
|
+
depsgraph = context.evaluated_depsgraph_get()
|
|
589
|
+
baked_key_block_obj = obj.evaluated_get(depsgraph)
|
|
590
|
+
baked_key_block_mesh = baked_key_block_obj.to_mesh(
|
|
591
|
+
preserve_all_data_layers=True, depsgraph=depsgraph
|
|
592
|
+
)
|
|
593
|
+
if baked_key_block_mesh:
|
|
594
|
+
evaluated_key_block_data = evaluated_key_block.data
|
|
595
|
+
baked_key_block_mesh_vertices = baked_key_block_mesh.vertices
|
|
596
|
+
|
|
597
|
+
# TODO: If the number of vertices is different, we should use advanced
|
|
598
|
+
# graph matching algorithm.
|
|
599
|
+
for i in range(
|
|
600
|
+
min(
|
|
601
|
+
len(evaluated_key_block_data),
|
|
602
|
+
len(baked_key_block_mesh_vertices),
|
|
603
|
+
)
|
|
604
|
+
):
|
|
605
|
+
evaluated_key_block_data[i].co = Vector(
|
|
606
|
+
baked_key_block_mesh_vertices[i].co
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
baked_key_block_obj.to_mesh_clear()
|
|
610
|
+
key_block.value = 0.0
|
|
611
|
+
|
|
612
|
+
return evaluated_mesh_data
|
|
613
|
+
finally:
|
|
614
|
+
for mesh_data in (obj.data, evaluated_mesh_data):
|
|
615
|
+
if not isinstance(mesh_data, Mesh):
|
|
616
|
+
continue
|
|
617
|
+
|
|
618
|
+
shape_keys = mesh_data.shape_keys
|
|
619
|
+
if not shape_keys:
|
|
620
|
+
continue
|
|
621
|
+
|
|
622
|
+
for shape_key_name, shape_key_value in key_block_name_to_value.items():
|
|
623
|
+
key_block = shape_keys.key_blocks.get(shape_key_name)
|
|
624
|
+
if key_block:
|
|
625
|
+
key_block.value = shape_key_value
|
|
626
|
+
context.view_layer.update()
|
|
627
|
+
|
|
628
|
+
return evaluated_mesh_data
|