@volter/blender-engine 0.1.147 → 0.1.149
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 +16 -0
- 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 +60 -128
- package/browser/blender-engine.mts +20 -186
- package/browser/blender-wali-engine.mts +35 -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 +2 -0
- package/browser/protocol.ts +119 -35
- package/browser/pull-job.mts +2 -10
- package/browser/rna.ts +190 -73
- package/browser/runtime.ts +197 -82
- package/browser/session-addons.mts +33 -0
- package/browser/session-frame.mts +5 -24
- package/browser/session.py +1338 -1427
- 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 +505 -283
- 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 +156 -151
- 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,682 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
|
|
2
|
+
from collections.abc import Sequence
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Final, Optional, Union
|
|
5
|
+
|
|
6
|
+
from bpy.app.translations import pgettext
|
|
7
|
+
from bpy.types import (
|
|
8
|
+
Armature,
|
|
9
|
+
Collection,
|
|
10
|
+
Constraint,
|
|
11
|
+
Context,
|
|
12
|
+
CopyRotationConstraint,
|
|
13
|
+
Curve,
|
|
14
|
+
DampedTrackConstraint,
|
|
15
|
+
Material,
|
|
16
|
+
Mesh,
|
|
17
|
+
Object,
|
|
18
|
+
ObjectConstraints,
|
|
19
|
+
PoseBoneConstraints,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from ..common.logger import get_logger
|
|
23
|
+
from .extension_accessor import get_armature_extension
|
|
24
|
+
|
|
25
|
+
_logger = get_logger(__name__)
|
|
26
|
+
|
|
27
|
+
MESH_CONVERTIBLE_OBJECT_TYPES: Final[tuple[str, ...]] = (
|
|
28
|
+
"CURVE",
|
|
29
|
+
"FONT",
|
|
30
|
+
"MESH",
|
|
31
|
+
# "META", # Disable until the glTF 2.0 add-on supports it
|
|
32
|
+
"SURFACE",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def export_materials(context: Context, objects: Sequence[Object]) -> Sequence[Material]:
|
|
37
|
+
result: list[Material] = []
|
|
38
|
+
for obj in objects:
|
|
39
|
+
if obj.type not in MESH_CONVERTIBLE_OBJECT_TYPES:
|
|
40
|
+
continue
|
|
41
|
+
|
|
42
|
+
mesh_convertible = obj.data
|
|
43
|
+
if isinstance(mesh_convertible, (Curve, Mesh)):
|
|
44
|
+
for material_ref in mesh_convertible.materials:
|
|
45
|
+
if not isinstance(material_ref, Material):
|
|
46
|
+
continue
|
|
47
|
+
material = context.blend_data.materials.get(material_ref.name)
|
|
48
|
+
if not isinstance(material, Material):
|
|
49
|
+
continue
|
|
50
|
+
result.append(material)
|
|
51
|
+
else:
|
|
52
|
+
_logger.error(
|
|
53
|
+
"Unexpected mesh convertible object type: %s", type(mesh_convertible)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
for material_slot in obj.material_slots:
|
|
57
|
+
if not material_slot:
|
|
58
|
+
continue
|
|
59
|
+
material_ref = material_slot.material
|
|
60
|
+
if not material_ref:
|
|
61
|
+
continue
|
|
62
|
+
material = context.blend_data.materials.get(material_ref.name)
|
|
63
|
+
if not isinstance(material, Material):
|
|
64
|
+
continue
|
|
65
|
+
result.append(material)
|
|
66
|
+
|
|
67
|
+
return list(dict.fromkeys(result)) # Remove duplicates
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def object_distance(
|
|
71
|
+
source: Object,
|
|
72
|
+
target: Object,
|
|
73
|
+
collection_child_to_parent: dict[Collection, Optional[Collection]],
|
|
74
|
+
) -> tuple[int, int, int, int, int, int, int]:
|
|
75
|
+
if source == target:
|
|
76
|
+
return (0, 0, 0, 0, 0, 0, 0)
|
|
77
|
+
|
|
78
|
+
source_collection_path: list[Collection] = []
|
|
79
|
+
source_collections = [
|
|
80
|
+
collection
|
|
81
|
+
for collection in source.users_collection
|
|
82
|
+
if collection in collection_child_to_parent
|
|
83
|
+
]
|
|
84
|
+
if source_collections:
|
|
85
|
+
source_collection: Optional[Collection] = source_collections[0]
|
|
86
|
+
while source_collection:
|
|
87
|
+
source_collection_path.insert(0, source_collection)
|
|
88
|
+
source_collection = collection_child_to_parent.get(source_collection)
|
|
89
|
+
|
|
90
|
+
target_collection_path: list[Collection] = []
|
|
91
|
+
target_collections = [
|
|
92
|
+
collection
|
|
93
|
+
for collection in target.users_collection
|
|
94
|
+
if collection in collection_child_to_parent
|
|
95
|
+
]
|
|
96
|
+
if target_collections:
|
|
97
|
+
target_collection: Optional[Collection] = target_collections[0]
|
|
98
|
+
while target_collection:
|
|
99
|
+
target_collection_path.insert(0, target_collection)
|
|
100
|
+
target_collection = collection_child_to_parent.get(target_collection)
|
|
101
|
+
|
|
102
|
+
while (
|
|
103
|
+
source_collection_path
|
|
104
|
+
and target_collection_path
|
|
105
|
+
and source_collection_path[0] == target_collection_path[0]
|
|
106
|
+
):
|
|
107
|
+
source_collection_path.pop(0)
|
|
108
|
+
target_collection_path.pop(0)
|
|
109
|
+
|
|
110
|
+
source_parent_path: list[Object] = []
|
|
111
|
+
traversing_source: Optional[Object] = source
|
|
112
|
+
while traversing_source:
|
|
113
|
+
source_parent_path.insert(0, traversing_source)
|
|
114
|
+
traversing_source = traversing_source.parent
|
|
115
|
+
|
|
116
|
+
target_parent_path: list[Object] = []
|
|
117
|
+
traversing_target: Optional[Object] = target
|
|
118
|
+
while traversing_target:
|
|
119
|
+
target_parent_path.insert(0, traversing_target)
|
|
120
|
+
traversing_target = traversing_target.parent
|
|
121
|
+
|
|
122
|
+
while (
|
|
123
|
+
source_parent_path
|
|
124
|
+
and target_parent_path
|
|
125
|
+
and source_parent_path[0] == target_parent_path[0]
|
|
126
|
+
):
|
|
127
|
+
source_parent_path.pop(0)
|
|
128
|
+
target_parent_path.pop(0)
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
int(not target.select_get()),
|
|
132
|
+
int(target.hide_get()),
|
|
133
|
+
len(source_parent_path),
|
|
134
|
+
len(target_parent_path),
|
|
135
|
+
len(source_collection_path),
|
|
136
|
+
len(target_collection_path),
|
|
137
|
+
int(target.hide_render),
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def armature_exists(context: Context) -> bool:
|
|
142
|
+
return any(armature.users > 0 for armature in context.blend_data.armatures) and any(
|
|
143
|
+
obj.type == "ARMATURE" for obj in context.blend_data.objects
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def current_armature_is_vrm0(context: Context) -> bool:
|
|
148
|
+
live_armature_datum = [
|
|
149
|
+
armature_data
|
|
150
|
+
for armature_data in context.blend_data.armatures
|
|
151
|
+
if armature_data.users
|
|
152
|
+
]
|
|
153
|
+
if not live_armature_datum:
|
|
154
|
+
return False
|
|
155
|
+
if all(
|
|
156
|
+
get_armature_extension(armature_data).is_vrm0()
|
|
157
|
+
for armature_data in live_armature_datum
|
|
158
|
+
) and any(obj.type == "ARMATURE" for obj in context.blend_data.objects):
|
|
159
|
+
return True
|
|
160
|
+
armature = current_armature(context)
|
|
161
|
+
if armature is None:
|
|
162
|
+
return False
|
|
163
|
+
armature_data = armature.data
|
|
164
|
+
if not isinstance(armature_data, Armature):
|
|
165
|
+
return False
|
|
166
|
+
return get_armature_extension(armature_data).is_vrm0()
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def current_armature_is_vrm1(context: Context) -> bool:
|
|
170
|
+
live_armature_datum = [
|
|
171
|
+
armature_data
|
|
172
|
+
for armature_data in context.blend_data.armatures
|
|
173
|
+
if armature_data.users
|
|
174
|
+
]
|
|
175
|
+
if not live_armature_datum:
|
|
176
|
+
return False
|
|
177
|
+
if all(
|
|
178
|
+
get_armature_extension(armature_data).is_vrm1()
|
|
179
|
+
for armature_data in live_armature_datum
|
|
180
|
+
) and any(obj.type == "ARMATURE" for obj in context.blend_data.objects):
|
|
181
|
+
return True
|
|
182
|
+
armature = current_armature(context)
|
|
183
|
+
if armature is None:
|
|
184
|
+
return False
|
|
185
|
+
armature_data = armature.data
|
|
186
|
+
if not isinstance(armature_data, Armature):
|
|
187
|
+
return False
|
|
188
|
+
return get_armature_extension(armature_data).is_vrm1()
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def multiple_armatures_exist(context: Context) -> bool:
|
|
192
|
+
first_data_exists = False
|
|
193
|
+
for data in context.blend_data.armatures:
|
|
194
|
+
if not data.users:
|
|
195
|
+
continue
|
|
196
|
+
if not first_data_exists:
|
|
197
|
+
first_data_exists = True
|
|
198
|
+
continue
|
|
199
|
+
|
|
200
|
+
first_obj_exists = False
|
|
201
|
+
for obj in context.blend_data.objects:
|
|
202
|
+
if obj.type == "ARMATURE":
|
|
203
|
+
if first_obj_exists:
|
|
204
|
+
return True
|
|
205
|
+
first_obj_exists = True
|
|
206
|
+
break
|
|
207
|
+
return False
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def current_armature(context: Context) -> Optional[Object]:
|
|
211
|
+
objects = [obj for obj in context.blend_data.objects if obj.type == "ARMATURE"]
|
|
212
|
+
if not objects:
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
if len(objects) == 1:
|
|
216
|
+
return objects[0]
|
|
217
|
+
|
|
218
|
+
active_object = getattr(context, "active_object", None)
|
|
219
|
+
if not isinstance(active_object, Object):
|
|
220
|
+
active_object = context.view_layer.objects.active
|
|
221
|
+
if not active_object:
|
|
222
|
+
return objects[0]
|
|
223
|
+
|
|
224
|
+
collection_child_to_parent: dict[Collection, Optional[Collection]] = {
|
|
225
|
+
context.scene.collection: None
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
collections = [context.scene.collection]
|
|
229
|
+
while collections:
|
|
230
|
+
parent = collections.pop()
|
|
231
|
+
for child in parent.children:
|
|
232
|
+
collections.append(child)
|
|
233
|
+
collection_child_to_parent[child] = parent
|
|
234
|
+
|
|
235
|
+
min_distance: Optional[tuple[int, int, int, int, int, int, int]] = None
|
|
236
|
+
nearest_object: Optional[Object] = None
|
|
237
|
+
for obj in objects:
|
|
238
|
+
distance = object_distance(active_object, obj, collection_child_to_parent)
|
|
239
|
+
if min_distance is None or min_distance > distance:
|
|
240
|
+
min_distance = distance
|
|
241
|
+
nearest_object = obj
|
|
242
|
+
|
|
243
|
+
return objects[0] if nearest_object is None else nearest_object
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def export_objects(
|
|
247
|
+
context: Context,
|
|
248
|
+
armature_object_name: Optional[str],
|
|
249
|
+
*,
|
|
250
|
+
export_invisibles: bool,
|
|
251
|
+
export_only_selections: bool,
|
|
252
|
+
export_lights: bool,
|
|
253
|
+
) -> list[Object]:
|
|
254
|
+
selected_objects = []
|
|
255
|
+
if export_only_selections:
|
|
256
|
+
selected_objects = list(context.selected_objects)
|
|
257
|
+
elif export_invisibles:
|
|
258
|
+
selected_objects = list(context.blend_data.objects)
|
|
259
|
+
else:
|
|
260
|
+
selected_objects = list(context.selectable_objects)
|
|
261
|
+
|
|
262
|
+
objects: list[Object] = []
|
|
263
|
+
|
|
264
|
+
# https://projects.blender.org/blender/blender/issues/113378
|
|
265
|
+
context.view_layer.update()
|
|
266
|
+
|
|
267
|
+
armature_object = None
|
|
268
|
+
if armature_object_name:
|
|
269
|
+
armature_object = context.blend_data.objects.get(armature_object_name)
|
|
270
|
+
if armature_object and armature_object.name in context.view_layer.objects:
|
|
271
|
+
objects.append(armature_object)
|
|
272
|
+
else:
|
|
273
|
+
armature_object = None
|
|
274
|
+
if not armature_object:
|
|
275
|
+
objects.extend(
|
|
276
|
+
obj
|
|
277
|
+
for obj in context.blend_data.objects
|
|
278
|
+
if obj.type == "ARMATURE" and obj.name in context.view_layer.objects
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
collider_bpy_objects: list[Optional[Object]] = []
|
|
282
|
+
for armature_data in context.blend_data.armatures:
|
|
283
|
+
ext = get_armature_extension(armature_data)
|
|
284
|
+
for spring_bone1_collider in ext.spring_bone1.colliders:
|
|
285
|
+
spring_bone1_collider_bpy_object = spring_bone1_collider.bpy_object
|
|
286
|
+
if not spring_bone1_collider_bpy_object:
|
|
287
|
+
continue
|
|
288
|
+
collider_bpy_objects.append(spring_bone1_collider_bpy_object)
|
|
289
|
+
collider_bpy_objects.extend(spring_bone1_collider_bpy_object.children)
|
|
290
|
+
for collider_group in ext.vrm0.secondary_animation.collider_groups:
|
|
291
|
+
collider_bpy_objects.extend(
|
|
292
|
+
collider.bpy_object for collider in collider_group.colliders
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
for obj in selected_objects:
|
|
296
|
+
if obj.type in {"ARMATURE", "CAMERA"}:
|
|
297
|
+
continue
|
|
298
|
+
if obj.type == "LIGHT" and not export_lights:
|
|
299
|
+
continue
|
|
300
|
+
if obj.name not in context.view_layer.objects:
|
|
301
|
+
continue
|
|
302
|
+
if not export_invisibles and not obj.visible_get():
|
|
303
|
+
continue
|
|
304
|
+
objects.append(obj)
|
|
305
|
+
|
|
306
|
+
return [
|
|
307
|
+
# Remove colliders and duplicates
|
|
308
|
+
obj
|
|
309
|
+
for obj in dict.fromkeys(objects)
|
|
310
|
+
if obj not in collider_bpy_objects
|
|
311
|
+
]
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
@dataclass(frozen=True)
|
|
315
|
+
class ExportConstraint:
|
|
316
|
+
roll_constraints: dict[str, CopyRotationConstraint]
|
|
317
|
+
aim_constraints: dict[str, DampedTrackConstraint]
|
|
318
|
+
rotation_constraints: dict[str, CopyRotationConstraint]
|
|
319
|
+
|
|
320
|
+
@property
|
|
321
|
+
def all_constraints(self) -> list[tuple[str, Constraint]]:
|
|
322
|
+
all_constraints: list[tuple[str, Constraint]] = [
|
|
323
|
+
*self.roll_constraints.items(),
|
|
324
|
+
*self.aim_constraints.items(),
|
|
325
|
+
*self.rotation_constraints.items(),
|
|
326
|
+
]
|
|
327
|
+
return all_constraints
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def roll_constraint_or_none(
|
|
331
|
+
constraint: Constraint,
|
|
332
|
+
objs: Sequence[Object],
|
|
333
|
+
armature: Object,
|
|
334
|
+
) -> Optional[CopyRotationConstraint]:
|
|
335
|
+
if (
|
|
336
|
+
not isinstance(constraint, CopyRotationConstraint)
|
|
337
|
+
or not constraint.is_valid
|
|
338
|
+
or constraint.mute
|
|
339
|
+
or not (constraint_target := constraint.target)
|
|
340
|
+
or constraint_target not in objs
|
|
341
|
+
or constraint.mix_mode != "ADD"
|
|
342
|
+
or (int(constraint.use_x) + int(constraint.use_y) + int(constraint.use_z)) != 1
|
|
343
|
+
or constraint.owner_space != "LOCAL"
|
|
344
|
+
or constraint.target_space != "LOCAL"
|
|
345
|
+
):
|
|
346
|
+
return None
|
|
347
|
+
|
|
348
|
+
if constraint_target.type != "ARMATURE":
|
|
349
|
+
return constraint
|
|
350
|
+
|
|
351
|
+
if constraint_target != armature:
|
|
352
|
+
return None
|
|
353
|
+
|
|
354
|
+
armature_data = armature.data
|
|
355
|
+
if (
|
|
356
|
+
not isinstance(armature_data, Armature)
|
|
357
|
+
or constraint.subtarget not in armature_data.bones
|
|
358
|
+
):
|
|
359
|
+
return None
|
|
360
|
+
|
|
361
|
+
return constraint
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def aim_constraint_or_none(
|
|
365
|
+
constraint: Constraint,
|
|
366
|
+
objs: Sequence[Object],
|
|
367
|
+
armature: Object,
|
|
368
|
+
) -> Optional[DampedTrackConstraint]:
|
|
369
|
+
if (
|
|
370
|
+
not isinstance(constraint, DampedTrackConstraint)
|
|
371
|
+
or not constraint.is_valid
|
|
372
|
+
or constraint.mute
|
|
373
|
+
or not (constraint_target := constraint.target)
|
|
374
|
+
or constraint_target not in objs
|
|
375
|
+
):
|
|
376
|
+
return None
|
|
377
|
+
|
|
378
|
+
if constraint_target.type != "ARMATURE":
|
|
379
|
+
return constraint
|
|
380
|
+
|
|
381
|
+
if constraint_target != armature:
|
|
382
|
+
return None
|
|
383
|
+
|
|
384
|
+
armature_data = armature.data
|
|
385
|
+
if (
|
|
386
|
+
not isinstance(armature_data, Armature)
|
|
387
|
+
or constraint.subtarget not in armature_data.bones
|
|
388
|
+
or abs(constraint.head_tail) > 0
|
|
389
|
+
):
|
|
390
|
+
return None
|
|
391
|
+
|
|
392
|
+
return constraint
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def rotation_constraint_or_none(
|
|
396
|
+
constraint: Constraint,
|
|
397
|
+
objs: Sequence[Object],
|
|
398
|
+
armature: Object,
|
|
399
|
+
) -> Optional[CopyRotationConstraint]:
|
|
400
|
+
if (
|
|
401
|
+
not isinstance(constraint, CopyRotationConstraint)
|
|
402
|
+
or not constraint.is_valid
|
|
403
|
+
or constraint.mute
|
|
404
|
+
or not (constraint_target := constraint.target)
|
|
405
|
+
or constraint.target not in objs
|
|
406
|
+
or constraint.invert_x
|
|
407
|
+
or constraint.invert_y
|
|
408
|
+
or constraint.invert_z
|
|
409
|
+
or constraint.mix_mode != "ADD"
|
|
410
|
+
or not constraint.use_x
|
|
411
|
+
or not constraint.use_y
|
|
412
|
+
or not constraint.use_z
|
|
413
|
+
or constraint.owner_space != "LOCAL"
|
|
414
|
+
or constraint.target_space != "LOCAL"
|
|
415
|
+
):
|
|
416
|
+
return None
|
|
417
|
+
|
|
418
|
+
if constraint_target.type != "ARMATURE":
|
|
419
|
+
return constraint
|
|
420
|
+
|
|
421
|
+
if constraint_target != armature:
|
|
422
|
+
return None
|
|
423
|
+
|
|
424
|
+
armature_data = armature.data
|
|
425
|
+
if (
|
|
426
|
+
not isinstance(armature_data, Armature)
|
|
427
|
+
or constraint.subtarget not in armature_data.bones
|
|
428
|
+
):
|
|
429
|
+
return None
|
|
430
|
+
|
|
431
|
+
return constraint
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def export_object_constraints(
|
|
435
|
+
objs: Sequence[Object],
|
|
436
|
+
armature: Object,
|
|
437
|
+
) -> ExportConstraint:
|
|
438
|
+
roll_constraints: dict[str, CopyRotationConstraint] = {}
|
|
439
|
+
aim_constraints: dict[str, DampedTrackConstraint] = {}
|
|
440
|
+
rotation_constraints: dict[str, CopyRotationConstraint] = {}
|
|
441
|
+
|
|
442
|
+
for obj in objs:
|
|
443
|
+
for constraint in obj.constraints:
|
|
444
|
+
if not isinstance(constraint, Constraint):
|
|
445
|
+
continue
|
|
446
|
+
roll_constraint = roll_constraint_or_none(constraint, objs, armature)
|
|
447
|
+
if roll_constraint:
|
|
448
|
+
roll_constraints[obj.name] = roll_constraint
|
|
449
|
+
break
|
|
450
|
+
aim_constraint = aim_constraint_or_none(constraint, objs, armature)
|
|
451
|
+
if aim_constraint:
|
|
452
|
+
aim_constraints[obj.name] = aim_constraint
|
|
453
|
+
break
|
|
454
|
+
rotation_constraint = rotation_constraint_or_none(
|
|
455
|
+
constraint, objs, armature
|
|
456
|
+
)
|
|
457
|
+
if rotation_constraint:
|
|
458
|
+
rotation_constraints[obj.name] = rotation_constraint
|
|
459
|
+
break
|
|
460
|
+
|
|
461
|
+
return ExportConstraint(
|
|
462
|
+
roll_constraints=roll_constraints,
|
|
463
|
+
aim_constraints=aim_constraints,
|
|
464
|
+
rotation_constraints=rotation_constraints,
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
def export_bone_constraints(
|
|
469
|
+
objs: Sequence[Object],
|
|
470
|
+
armature: Object,
|
|
471
|
+
) -> ExportConstraint:
|
|
472
|
+
roll_constraints: dict[str, CopyRotationConstraint] = {}
|
|
473
|
+
aim_constraints: dict[str, DampedTrackConstraint] = {}
|
|
474
|
+
rotation_constraints: dict[str, CopyRotationConstraint] = {}
|
|
475
|
+
|
|
476
|
+
for bone in armature.pose.bones:
|
|
477
|
+
for constraint in bone.constraints:
|
|
478
|
+
if not isinstance(constraint, Constraint):
|
|
479
|
+
continue
|
|
480
|
+
roll_constraint = roll_constraint_or_none(constraint, objs, armature)
|
|
481
|
+
if roll_constraint:
|
|
482
|
+
roll_constraints[bone.name] = roll_constraint
|
|
483
|
+
break
|
|
484
|
+
aim_constraint = aim_constraint_or_none(constraint, objs, armature)
|
|
485
|
+
if aim_constraint:
|
|
486
|
+
aim_constraints[bone.name] = aim_constraint
|
|
487
|
+
break
|
|
488
|
+
rotation_constraint = rotation_constraint_or_none(
|
|
489
|
+
constraint, objs, armature
|
|
490
|
+
)
|
|
491
|
+
if rotation_constraint:
|
|
492
|
+
rotation_constraints[bone.name] = rotation_constraint
|
|
493
|
+
break
|
|
494
|
+
|
|
495
|
+
return ExportConstraint(
|
|
496
|
+
roll_constraints=roll_constraints,
|
|
497
|
+
aim_constraints=aim_constraints,
|
|
498
|
+
rotation_constraints=rotation_constraints,
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def export_constraints(
|
|
503
|
+
objs: Sequence[Object],
|
|
504
|
+
armature: Object,
|
|
505
|
+
) -> tuple[ExportConstraint, ExportConstraint, Sequence[str]]:
|
|
506
|
+
messages: list[str] = []
|
|
507
|
+
object_constraints = export_object_constraints(objs, armature)
|
|
508
|
+
bone_constraints = export_bone_constraints(objs, armature)
|
|
509
|
+
|
|
510
|
+
all_constraints: list[Constraint] = [
|
|
511
|
+
*object_constraints.roll_constraints.values(),
|
|
512
|
+
*bone_constraints.roll_constraints.values(),
|
|
513
|
+
*object_constraints.rotation_constraints.values(),
|
|
514
|
+
*bone_constraints.rotation_constraints.values(),
|
|
515
|
+
# TODO: Aim Constraint's circular dependency detection
|
|
516
|
+
# *object_constraints.aim_constraints.values(),
|
|
517
|
+
# *bone_constraints.aim_constraints.values(),
|
|
518
|
+
]
|
|
519
|
+
|
|
520
|
+
excluded_constraints: list[
|
|
521
|
+
Union[
|
|
522
|
+
CopyRotationConstraint,
|
|
523
|
+
DampedTrackConstraint,
|
|
524
|
+
]
|
|
525
|
+
] = []
|
|
526
|
+
|
|
527
|
+
for search_constraint in all_constraints:
|
|
528
|
+
if not isinstance(search_constraint, CopyRotationConstraint):
|
|
529
|
+
continue
|
|
530
|
+
current_constraints = [
|
|
531
|
+
(
|
|
532
|
+
search_constraint,
|
|
533
|
+
(
|
|
534
|
+
search_constraint.use_x,
|
|
535
|
+
search_constraint.use_y,
|
|
536
|
+
search_constraint.use_z,
|
|
537
|
+
),
|
|
538
|
+
)
|
|
539
|
+
]
|
|
540
|
+
iterated_constraints: set[Constraint] = set()
|
|
541
|
+
while current_constraints:
|
|
542
|
+
current_constraint, current_axis = current_constraints.pop()
|
|
543
|
+
|
|
544
|
+
if current_constraint in iterated_constraints:
|
|
545
|
+
break
|
|
546
|
+
iterated_constraints.add(current_constraint)
|
|
547
|
+
|
|
548
|
+
found = False
|
|
549
|
+
|
|
550
|
+
target = current_constraint.target
|
|
551
|
+
if not target:
|
|
552
|
+
continue
|
|
553
|
+
|
|
554
|
+
if target.type == "ARMATURE":
|
|
555
|
+
bone = target.pose.bones[current_constraint.subtarget]
|
|
556
|
+
owner_name = bone.name
|
|
557
|
+
target_constraints: Union[ObjectConstraints, PoseBoneConstraints] = (
|
|
558
|
+
bone.constraints
|
|
559
|
+
)
|
|
560
|
+
else:
|
|
561
|
+
owner_name = target.name
|
|
562
|
+
target_constraints = target.constraints
|
|
563
|
+
|
|
564
|
+
for target_constraint in target_constraints:
|
|
565
|
+
if not isinstance(target_constraint, CopyRotationConstraint):
|
|
566
|
+
continue
|
|
567
|
+
if target_constraint not in all_constraints:
|
|
568
|
+
continue
|
|
569
|
+
|
|
570
|
+
next_target_axis = (
|
|
571
|
+
current_axis[0] and target_constraint.use_x,
|
|
572
|
+
current_axis[1] and target_constraint.use_y,
|
|
573
|
+
current_axis[2] and target_constraint.use_z,
|
|
574
|
+
)
|
|
575
|
+
if next_target_axis == (False, False, False):
|
|
576
|
+
continue
|
|
577
|
+
|
|
578
|
+
if target_constraint != search_constraint:
|
|
579
|
+
current_constraints.append((target_constraint, next_target_axis))
|
|
580
|
+
continue
|
|
581
|
+
|
|
582
|
+
excluded_constraints.append(search_constraint)
|
|
583
|
+
messages.append(
|
|
584
|
+
pgettext(
|
|
585
|
+
'Node Constraint "{owner_name} / {constraint_name}" has'
|
|
586
|
+
+ " a circular dependency"
|
|
587
|
+
).format(
|
|
588
|
+
owner_name=owner_name,
|
|
589
|
+
constraint_name=search_constraint.name,
|
|
590
|
+
)
|
|
591
|
+
)
|
|
592
|
+
found = True
|
|
593
|
+
break
|
|
594
|
+
|
|
595
|
+
if found:
|
|
596
|
+
break
|
|
597
|
+
|
|
598
|
+
return (
|
|
599
|
+
ExportConstraint(
|
|
600
|
+
roll_constraints={
|
|
601
|
+
k: v
|
|
602
|
+
for k, v in object_constraints.roll_constraints.items()
|
|
603
|
+
if v not in excluded_constraints
|
|
604
|
+
},
|
|
605
|
+
aim_constraints={
|
|
606
|
+
k: v
|
|
607
|
+
for k, v in object_constraints.aim_constraints.items()
|
|
608
|
+
if v not in excluded_constraints
|
|
609
|
+
},
|
|
610
|
+
rotation_constraints={
|
|
611
|
+
k: v
|
|
612
|
+
for k, v in object_constraints.rotation_constraints.items()
|
|
613
|
+
if v not in excluded_constraints
|
|
614
|
+
},
|
|
615
|
+
),
|
|
616
|
+
ExportConstraint(
|
|
617
|
+
roll_constraints={
|
|
618
|
+
k: v
|
|
619
|
+
for k, v in bone_constraints.roll_constraints.items()
|
|
620
|
+
if v not in excluded_constraints
|
|
621
|
+
},
|
|
622
|
+
aim_constraints={
|
|
623
|
+
k: v
|
|
624
|
+
for k, v in bone_constraints.aim_constraints.items()
|
|
625
|
+
if v not in excluded_constraints
|
|
626
|
+
},
|
|
627
|
+
rotation_constraints={
|
|
628
|
+
k: v
|
|
629
|
+
for k, v in bone_constraints.rotation_constraints.items()
|
|
630
|
+
if v not in excluded_constraints
|
|
631
|
+
},
|
|
632
|
+
),
|
|
633
|
+
messages,
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
def active_object_is_vrm1_armature(context: Context) -> bool:
|
|
638
|
+
active_object = context.active_object
|
|
639
|
+
if not active_object:
|
|
640
|
+
return False
|
|
641
|
+
if active_object.type != "ARMATURE":
|
|
642
|
+
return False
|
|
643
|
+
armature_data = active_object.data
|
|
644
|
+
if not isinstance(armature_data, Armature):
|
|
645
|
+
return False
|
|
646
|
+
return get_armature_extension(armature_data).is_vrm1()
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
def active_object_is_vrm0_armature(context: Context) -> bool:
|
|
650
|
+
active_object = context.active_object
|
|
651
|
+
if not active_object:
|
|
652
|
+
return False
|
|
653
|
+
if active_object.type != "ARMATURE":
|
|
654
|
+
return False
|
|
655
|
+
armature_data = active_object.data
|
|
656
|
+
if not isinstance(armature_data, Armature):
|
|
657
|
+
return False
|
|
658
|
+
return get_armature_extension(armature_data).is_vrm0()
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
def active_object_is_vrm_armature(context: Context) -> bool:
|
|
662
|
+
active_object = context.active_object
|
|
663
|
+
if not active_object:
|
|
664
|
+
return False
|
|
665
|
+
if active_object.type != "ARMATURE":
|
|
666
|
+
return False
|
|
667
|
+
armature_data = active_object.data
|
|
668
|
+
if not isinstance(armature_data, Armature):
|
|
669
|
+
return False
|
|
670
|
+
return get_armature_extension(armature_data).is_vrm0()
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
def active_object_is_khr_character_armature(context: Context) -> bool:
|
|
674
|
+
active_object = context.active_object
|
|
675
|
+
if not active_object:
|
|
676
|
+
return False
|
|
677
|
+
if active_object.type != "ARMATURE":
|
|
678
|
+
return False
|
|
679
|
+
armature_data = active_object.data
|
|
680
|
+
if not isinstance(armature_data, Armature):
|
|
681
|
+
return False
|
|
682
|
+
return get_armature_extension(armature_data).is_khr_character()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
|