@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,381 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
|
|
2
|
+
import sys
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Final, Optional
|
|
5
|
+
|
|
6
|
+
import bpy
|
|
7
|
+
from bpy.types import Context, Material, Mesh, ShaderNodeGroup, ShaderNodeOutputMaterial
|
|
8
|
+
|
|
9
|
+
from ...common.logger import get_logger
|
|
10
|
+
from ...common.scene_watcher import RunState, SceneWatcher
|
|
11
|
+
from ...common.shader import MTOON1_AUTO_SETUP_GROUP_NODE_TREE_CUSTOM_KEY
|
|
12
|
+
from ..extension_accessor import get_material_extension
|
|
13
|
+
from .property_group import (
|
|
14
|
+
generate_mtoon1_outline_material_name,
|
|
15
|
+
refresh_mtoon1_outline,
|
|
16
|
+
reset_shader_node_group,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
_logger = get_logger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
HAS_AUTO_SMOOTH: Final = tuple(bpy.app.version) < (4, 1)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class ComparisonMaterial:
|
|
27
|
+
name: str
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class ComparisonObject:
|
|
32
|
+
use_auto_smooth: Optional[bool] = None
|
|
33
|
+
comparison_materials: Final[list[Optional[ComparisonMaterial]]] = field(
|
|
34
|
+
default_factory=list[Optional[ComparisonMaterial]]
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class OutlineUpdater(SceneWatcher):
|
|
40
|
+
comparison_objects: Final[list[ComparisonObject]] = field(
|
|
41
|
+
default_factory=list[ComparisonObject]
|
|
42
|
+
)
|
|
43
|
+
outline_material_key_to_material_name: Final[dict[int, str]] = field(
|
|
44
|
+
default_factory=dict[int, str]
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
object_index: int = 0
|
|
48
|
+
comparison_object_index: int = 0
|
|
49
|
+
material_slot_index: int = 0
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def get_outline_material_key(material: Material) -> int:
|
|
53
|
+
return material.as_pointer() ^ 0x5F5FF5F5
|
|
54
|
+
|
|
55
|
+
def reset_run_progress(self) -> None:
|
|
56
|
+
self.object_index = 0
|
|
57
|
+
self.comparison_object_index = 0
|
|
58
|
+
self.material_slot_index = 0
|
|
59
|
+
self.outline_material_key_to_material_name.clear()
|
|
60
|
+
|
|
61
|
+
def run(self, context: Context) -> RunState:
|
|
62
|
+
"""Detect changes in material assignments to objects and assign outlines."""
|
|
63
|
+
# If this value becomes zero, return PREEMPT and interrupt the process.
|
|
64
|
+
# If a change is detected, set a virtually infinite value so that the
|
|
65
|
+
# process proceeds to the end.
|
|
66
|
+
preempt_countdown = 15
|
|
67
|
+
|
|
68
|
+
changed = False
|
|
69
|
+
|
|
70
|
+
create_modifier = False
|
|
71
|
+
|
|
72
|
+
objects = context.visible_objects
|
|
73
|
+
if not objects:
|
|
74
|
+
return RunState.FINISH
|
|
75
|
+
|
|
76
|
+
# If the number of objects is less than the previous state and the index
|
|
77
|
+
# range is exceeded, start over from the beginning
|
|
78
|
+
objects_len = len(objects)
|
|
79
|
+
if self.object_index >= objects_len:
|
|
80
|
+
self.object_index = 0
|
|
81
|
+
|
|
82
|
+
# Scan objects and check for differences with the comparison object
|
|
83
|
+
next_object_index = self.object_index
|
|
84
|
+
for obj in objects[self.object_index : objects_len]:
|
|
85
|
+
self.object_index = next_object_index
|
|
86
|
+
next_object_index += 1
|
|
87
|
+
|
|
88
|
+
preempt_countdown -= 1
|
|
89
|
+
if preempt_countdown <= 0:
|
|
90
|
+
return RunState.PREEMPT
|
|
91
|
+
|
|
92
|
+
# Only mesh objects are subject to investigation.
|
|
93
|
+
# Skip if it is not a mesh object
|
|
94
|
+
obj_data = obj.data
|
|
95
|
+
if not isinstance(obj_data, Mesh):
|
|
96
|
+
continue
|
|
97
|
+
mesh = obj_data
|
|
98
|
+
|
|
99
|
+
# If the number of comparison objects is insufficient, add a new
|
|
100
|
+
# comparison object
|
|
101
|
+
while self.comparison_object_index >= len(self.comparison_objects):
|
|
102
|
+
self.comparison_objects.append(ComparisonObject())
|
|
103
|
+
|
|
104
|
+
# Get a comparison object
|
|
105
|
+
comparison_object = self.comparison_objects[self.comparison_object_index]
|
|
106
|
+
|
|
107
|
+
# Comparison of use_auto_smooth
|
|
108
|
+
if HAS_AUTO_SMOOTH and (
|
|
109
|
+
(use_auto_smooth := comparison_object.use_auto_smooth) is None
|
|
110
|
+
or (use_auto_smooth != mesh.use_auto_smooth)
|
|
111
|
+
):
|
|
112
|
+
changed, preempt_countdown = True, sys.maxsize
|
|
113
|
+
# Resolve change differences
|
|
114
|
+
comparison_object.use_auto_smooth = mesh.use_auto_smooth
|
|
115
|
+
|
|
116
|
+
# If the number of MaterialSlots is less than the previous state and
|
|
117
|
+
# the index range is exceeded, start over from the beginning
|
|
118
|
+
material_slots = obj.material_slots
|
|
119
|
+
material_slots_len = len(material_slots)
|
|
120
|
+
if self.material_slot_index >= material_slots_len:
|
|
121
|
+
self.material_slot_index = 0
|
|
122
|
+
|
|
123
|
+
# Match the number of MaterialSlots and the number of comparison Materials
|
|
124
|
+
while material_slots_len > len(comparison_object.comparison_materials):
|
|
125
|
+
comparison_object.comparison_materials.append(None)
|
|
126
|
+
while material_slots_len < len(comparison_object.comparison_materials):
|
|
127
|
+
comparison_object.comparison_materials.pop()
|
|
128
|
+
|
|
129
|
+
# Scan MaterialSlots and check for differences with the comparison Material
|
|
130
|
+
next_material_slot_index = self.material_slot_index
|
|
131
|
+
for material_slot in material_slots[
|
|
132
|
+
self.material_slot_index : material_slots_len
|
|
133
|
+
]:
|
|
134
|
+
material_slot_index = self.material_slot_index = (
|
|
135
|
+
next_material_slot_index
|
|
136
|
+
)
|
|
137
|
+
next_material_slot_index += 1
|
|
138
|
+
|
|
139
|
+
preempt_countdown -= 1
|
|
140
|
+
if preempt_countdown <= 0:
|
|
141
|
+
return RunState.PREEMPT
|
|
142
|
+
|
|
143
|
+
# If the number of comparison objects is insufficient, add a new
|
|
144
|
+
# comparison object
|
|
145
|
+
while material_slot_index >= len(
|
|
146
|
+
comparison_object.comparison_materials
|
|
147
|
+
):
|
|
148
|
+
comparison_object.comparison_materials.append(None)
|
|
149
|
+
comparison_material = comparison_object.comparison_materials[
|
|
150
|
+
material_slot_index
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
# Difference check
|
|
154
|
+
if not (
|
|
155
|
+
(material := material_slot.material)
|
|
156
|
+
and (mtoon1 := get_material_extension(material).mtoon1)
|
|
157
|
+
and mtoon1.enabled
|
|
158
|
+
):
|
|
159
|
+
# MToon of the material in the material slot is disabled
|
|
160
|
+
if comparison_material is None:
|
|
161
|
+
# No updates
|
|
162
|
+
continue
|
|
163
|
+
# if the comparison object is enabled, a change is detected
|
|
164
|
+
changed, preempt_countdown = True, sys.maxsize
|
|
165
|
+
# Resolve change differences
|
|
166
|
+
comparison_object.comparison_materials[material_slot_index] = None
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
# MToon of the material in the material slot is enabled
|
|
170
|
+
|
|
171
|
+
outline_material = mtoon1.outline_material
|
|
172
|
+
outline_material_name = generate_mtoon1_outline_material_name(material)
|
|
173
|
+
|
|
174
|
+
if (
|
|
175
|
+
comparison_material
|
|
176
|
+
and comparison_material.name == material.name
|
|
177
|
+
and (
|
|
178
|
+
outline_material is None
|
|
179
|
+
or outline_material.name == outline_material_name
|
|
180
|
+
)
|
|
181
|
+
):
|
|
182
|
+
continue
|
|
183
|
+
|
|
184
|
+
# MToon of the material in the material slot is enabled,
|
|
185
|
+
# but if the comparison object does not exist or the name
|
|
186
|
+
# does not match, a change is detected
|
|
187
|
+
changed, preempt_countdown = True, sys.maxsize
|
|
188
|
+
# Resolve change differences
|
|
189
|
+
comparison_object.comparison_materials[material_slot_index] = (
|
|
190
|
+
ComparisonMaterial(material.name)
|
|
191
|
+
)
|
|
192
|
+
# A material with MToon enabled has been newly assigned
|
|
193
|
+
# to the object so, if necessary, create a new outline
|
|
194
|
+
# modifier.
|
|
195
|
+
# Originally, True/False should be set for each object and
|
|
196
|
+
# material pair, but for now, I think it's okay to fix it
|
|
197
|
+
# for practical use.
|
|
198
|
+
create_modifier = True
|
|
199
|
+
|
|
200
|
+
if outline_material is None:
|
|
201
|
+
continue
|
|
202
|
+
|
|
203
|
+
# When a material is copied, a single outline material may be
|
|
204
|
+
# shared by multiple MToon materials. To resolve this, copy the
|
|
205
|
+
# outline material and reassign it.
|
|
206
|
+
outline_material_key = self.get_outline_material_key(outline_material)
|
|
207
|
+
original_material_name = self.outline_material_key_to_material_name.get(
|
|
208
|
+
outline_material_key
|
|
209
|
+
)
|
|
210
|
+
if original_material_name is None:
|
|
211
|
+
self.outline_material_key_to_material_name[outline_material_key] = (
|
|
212
|
+
material.name
|
|
213
|
+
)
|
|
214
|
+
elif original_material_name != material.name:
|
|
215
|
+
outline_material = outline_material.copy()
|
|
216
|
+
outline_material_key = self.get_outline_material_key(
|
|
217
|
+
outline_material
|
|
218
|
+
)
|
|
219
|
+
self.outline_material_key_to_material_name[outline_material_key] = (
|
|
220
|
+
material.name
|
|
221
|
+
)
|
|
222
|
+
mtoon1.outline_material = outline_material
|
|
223
|
+
|
|
224
|
+
# The outline material name follows the naming changes of
|
|
225
|
+
# the base MToon material.
|
|
226
|
+
if outline_material.name != outline_material_name:
|
|
227
|
+
outline_material.name = outline_material_name
|
|
228
|
+
|
|
229
|
+
# Since the scanning of MaterialSlots is complete,
|
|
230
|
+
# reset the next scanning index to 0.
|
|
231
|
+
self.material_slot_index = 0
|
|
232
|
+
|
|
233
|
+
# Before scanning the next object,
|
|
234
|
+
# advance the index of the next comparison object.
|
|
235
|
+
self.comparison_object_index += 1
|
|
236
|
+
|
|
237
|
+
# Since the number of elements in self.comparison_objects may be
|
|
238
|
+
# unnecessarily large, reduce it to a sufficient size
|
|
239
|
+
while len(self.comparison_objects) > self.comparison_object_index:
|
|
240
|
+
self.comparison_objects.pop()
|
|
241
|
+
|
|
242
|
+
if not changed:
|
|
243
|
+
return RunState.FINISH
|
|
244
|
+
|
|
245
|
+
refresh_mtoon1_outline(context, create_modifier=create_modifier)
|
|
246
|
+
return RunState.FINISH
|
|
247
|
+
|
|
248
|
+
def create_fast_path_performance_test_objects(self, context: Context) -> None:
|
|
249
|
+
blend_data = context.blend_data
|
|
250
|
+
|
|
251
|
+
for i in range(100):
|
|
252
|
+
blend_data.materials.new(f"Material#{i}")
|
|
253
|
+
|
|
254
|
+
for i in range(100):
|
|
255
|
+
mesh = blend_data.meshes.new(f"Mesh#{i}")
|
|
256
|
+
obj = blend_data.objects.new(f"Object#{i}", mesh)
|
|
257
|
+
context.scene.collection.objects.link(obj)
|
|
258
|
+
for k in range(50):
|
|
259
|
+
material = blend_data.materials[(k * 3) % len(blend_data.materials)]
|
|
260
|
+
mesh.materials.append(material)
|
|
261
|
+
if k % 5 == 0:
|
|
262
|
+
get_material_extension(material).mtoon1.enabled = True
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@dataclass
|
|
266
|
+
class MToon1AutoSetup(SceneWatcher):
|
|
267
|
+
last_material_index: int = 0
|
|
268
|
+
last_node_index: int = 0
|
|
269
|
+
|
|
270
|
+
def reset_run_progress(self) -> None:
|
|
271
|
+
self.last_material_index: int = 0
|
|
272
|
+
self.last_node_index: int = 0
|
|
273
|
+
|
|
274
|
+
def run(self, context: Context) -> RunState:
|
|
275
|
+
"""Monitor the appearance of MToon auto-setup node groups and set them up.
|
|
276
|
+
|
|
277
|
+
Since this function is called frequently, keep the processing lightweight and
|
|
278
|
+
be careful to minimize IO and GC Allocation.
|
|
279
|
+
"""
|
|
280
|
+
# If this value becomes 0 or less, interrupt the process
|
|
281
|
+
search_preempt_countdown = 100
|
|
282
|
+
|
|
283
|
+
materials = context.blend_data.materials
|
|
284
|
+
|
|
285
|
+
# Restore the material traversal start position from the last interrupted state.
|
|
286
|
+
end_material_index = len(materials)
|
|
287
|
+
start_material_index = self.last_material_index
|
|
288
|
+
if start_material_index >= end_material_index:
|
|
289
|
+
self.last_material_index = 0
|
|
290
|
+
self.last_node_index = 0
|
|
291
|
+
start_material_index = 0
|
|
292
|
+
|
|
293
|
+
# Traverse the materials and enable MToon if necessary.
|
|
294
|
+
next_material_index = start_material_index
|
|
295
|
+
for material in materials[start_material_index:end_material_index]:
|
|
296
|
+
self.last_material_index = next_material_index
|
|
297
|
+
next_material_index += 1
|
|
298
|
+
|
|
299
|
+
search_preempt_countdown -= 1
|
|
300
|
+
if search_preempt_countdown <= 0:
|
|
301
|
+
return RunState.PREEMPT
|
|
302
|
+
|
|
303
|
+
if bpy.app.version < (5, 0, 0) and not material.use_nodes:
|
|
304
|
+
continue
|
|
305
|
+
node_tree = material.node_tree
|
|
306
|
+
if node_tree is None:
|
|
307
|
+
continue
|
|
308
|
+
|
|
309
|
+
nodes = node_tree.nodes
|
|
310
|
+
|
|
311
|
+
# Restore the node traversal start position from the last interrupted state.
|
|
312
|
+
end_node_index = len(nodes)
|
|
313
|
+
start_node_index = self.last_node_index
|
|
314
|
+
if start_node_index >= end_node_index:
|
|
315
|
+
start_node_index = 0
|
|
316
|
+
|
|
317
|
+
# Traverse the nodes and convert the material to MToon if the MToon
|
|
318
|
+
# placeholder node is connected to ShaderNodeOutputMaterial.
|
|
319
|
+
next_node_index = start_node_index
|
|
320
|
+
for node in nodes[start_node_index:end_node_index]:
|
|
321
|
+
self.last_node_index = next_node_index
|
|
322
|
+
next_node_index += 1
|
|
323
|
+
|
|
324
|
+
search_preempt_countdown -= 1
|
|
325
|
+
if search_preempt_countdown <= 0:
|
|
326
|
+
return RunState.PREEMPT
|
|
327
|
+
|
|
328
|
+
if not isinstance(node, ShaderNodeGroup):
|
|
329
|
+
continue
|
|
330
|
+
|
|
331
|
+
group_node_tree = node.node_tree
|
|
332
|
+
if group_node_tree is None:
|
|
333
|
+
continue
|
|
334
|
+
|
|
335
|
+
if not group_node_tree.get(
|
|
336
|
+
MTOON1_AUTO_SETUP_GROUP_NODE_TREE_CUSTOM_KEY
|
|
337
|
+
):
|
|
338
|
+
continue
|
|
339
|
+
|
|
340
|
+
found = False
|
|
341
|
+
for output in node.outputs:
|
|
342
|
+
for link in output.links:
|
|
343
|
+
if isinstance(link.to_node, ShaderNodeOutputMaterial):
|
|
344
|
+
found = True
|
|
345
|
+
break
|
|
346
|
+
if found:
|
|
347
|
+
break
|
|
348
|
+
if not found:
|
|
349
|
+
continue
|
|
350
|
+
|
|
351
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
352
|
+
if mtoon1.enabled:
|
|
353
|
+
reset_shader_node_group(
|
|
354
|
+
context,
|
|
355
|
+
material,
|
|
356
|
+
reset_material_node_tree=True,
|
|
357
|
+
reset_node_groups=True,
|
|
358
|
+
)
|
|
359
|
+
else:
|
|
360
|
+
mtoon1.enabled = True
|
|
361
|
+
break
|
|
362
|
+
self.last_node_index = 0
|
|
363
|
+
self.last_material_index = 0
|
|
364
|
+
|
|
365
|
+
return RunState.FINISH
|
|
366
|
+
|
|
367
|
+
def create_fast_path_performance_test_objects(self, context: Context) -> None:
|
|
368
|
+
blend_data = context.blend_data
|
|
369
|
+
|
|
370
|
+
for i in range(100):
|
|
371
|
+
blend_data.materials.new(f"Material#{i}")
|
|
372
|
+
|
|
373
|
+
for i in range(100):
|
|
374
|
+
mesh = blend_data.meshes.new(f"Mesh#{i}")
|
|
375
|
+
obj = blend_data.objects.new(f"Object#{i}", mesh)
|
|
376
|
+
context.scene.collection.objects.link(obj)
|
|
377
|
+
for k in range(50):
|
|
378
|
+
material = blend_data.materials[(k * 3) % len(blend_data.materials)]
|
|
379
|
+
mesh.materials.append(material)
|
|
380
|
+
if k % 5 == 0:
|
|
381
|
+
get_material_extension(material).mtoon1.enabled = True
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
|
|
2
|
+
|
|
3
|
+
from typing import ClassVar
|
|
4
|
+
|
|
5
|
+
from bpy.app.translations import pgettext
|
|
6
|
+
from bpy.types import (
|
|
7
|
+
Armature,
|
|
8
|
+
Context,
|
|
9
|
+
CopyRotationConstraint,
|
|
10
|
+
DampedTrackConstraint,
|
|
11
|
+
Object,
|
|
12
|
+
Panel,
|
|
13
|
+
UILayout,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from ...common.preferences import get_preferences
|
|
17
|
+
from .. import search
|
|
18
|
+
from ..extension_accessor import get_armature_extension
|
|
19
|
+
from ..panel import VRM_PT_vrm_armature_object_property
|
|
20
|
+
from ..search import active_object_is_vrm1_armature
|
|
21
|
+
from .property_group import NodeConstraint1NodeConstraintPropertyGroup
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _draw_roll_constraint_layout(
|
|
25
|
+
layout: UILayout,
|
|
26
|
+
node_constraint: NodeConstraint1NodeConstraintPropertyGroup,
|
|
27
|
+
object_constraints: dict[str, CopyRotationConstraint],
|
|
28
|
+
bone_constraints: dict[str, CopyRotationConstraint],
|
|
29
|
+
) -> None:
|
|
30
|
+
constraints_box = layout.box()
|
|
31
|
+
constraints_row = constraints_box.row()
|
|
32
|
+
constraints_row.alignment = "LEFT"
|
|
33
|
+
constraints_row.prop(
|
|
34
|
+
node_constraint,
|
|
35
|
+
"show_expanded_roll_constraints",
|
|
36
|
+
icon="TRIA_DOWN"
|
|
37
|
+
if node_constraint.show_expanded_roll_constraints
|
|
38
|
+
else "TRIA_RIGHT",
|
|
39
|
+
emboss=False,
|
|
40
|
+
)
|
|
41
|
+
if not node_constraint.show_expanded_roll_constraints:
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
constraints_column = constraints_box.column()
|
|
45
|
+
if object_constraints or bone_constraints:
|
|
46
|
+
constraints_expanded_column = constraints_column.column()
|
|
47
|
+
for object_name, constraint in object_constraints.items():
|
|
48
|
+
constraint_row = constraints_expanded_column.row()
|
|
49
|
+
constraint_row.alignment = "LEFT"
|
|
50
|
+
constraint_row.label(
|
|
51
|
+
text=object_name + ": " + constraint.name,
|
|
52
|
+
icon="CONSTRAINT",
|
|
53
|
+
translate=False,
|
|
54
|
+
)
|
|
55
|
+
for bone_name, constraint in bone_constraints.items():
|
|
56
|
+
constraint_row = constraints_expanded_column.row()
|
|
57
|
+
constraint_row.alignment = "LEFT"
|
|
58
|
+
constraint_row.label(
|
|
59
|
+
text=bone_name + ": " + constraint.name,
|
|
60
|
+
icon="CONSTRAINT_BONE",
|
|
61
|
+
translate=False,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
constraints_help_column = constraints_column.box().column(align=True)
|
|
65
|
+
help_message = pgettext(
|
|
66
|
+
"Conditions exported as Roll Constraint\n"
|
|
67
|
+
+ " - {copy_rotation}\n"
|
|
68
|
+
+ " - Enabled\n"
|
|
69
|
+
+ " - No Vertex Group\n"
|
|
70
|
+
+ " - {axis} is one of X, Y and Z\n"
|
|
71
|
+
+ " - No Inverted\n"
|
|
72
|
+
+ " - {mix} is {add}\n"
|
|
73
|
+
+ " - {target} is {local_space}\n"
|
|
74
|
+
+ " - {owner} is {local_space}\n"
|
|
75
|
+
+ " - No circular dependencies\n"
|
|
76
|
+
+ " - The one at the top of the list of\n"
|
|
77
|
+
+ " those that meet all the conditions\n",
|
|
78
|
+
).format(
|
|
79
|
+
copy_rotation=pgettext("Copy Rotation"),
|
|
80
|
+
axis=pgettext("Axis"),
|
|
81
|
+
mix=pgettext("Mix"),
|
|
82
|
+
add=pgettext("Add"),
|
|
83
|
+
target=pgettext("Target"),
|
|
84
|
+
local_space=pgettext("Local Space"),
|
|
85
|
+
owner=pgettext("Owner"),
|
|
86
|
+
)
|
|
87
|
+
for index, help_line in enumerate(help_message.splitlines()):
|
|
88
|
+
constraints_help_column.label(
|
|
89
|
+
text=help_line, translate=False, icon="HELP" if index == 0 else "NONE"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _draw_aim_constraint_layout(
|
|
94
|
+
layout: UILayout,
|
|
95
|
+
node_constraint: NodeConstraint1NodeConstraintPropertyGroup,
|
|
96
|
+
object_constraints: dict[str, DampedTrackConstraint],
|
|
97
|
+
bone_constraints: dict[str, DampedTrackConstraint],
|
|
98
|
+
) -> None:
|
|
99
|
+
constraints_box = layout.box()
|
|
100
|
+
constraints_row = constraints_box.row()
|
|
101
|
+
constraints_row.alignment = "LEFT"
|
|
102
|
+
constraints_row.prop(
|
|
103
|
+
node_constraint,
|
|
104
|
+
"show_expanded_aim_constraints",
|
|
105
|
+
icon="TRIA_DOWN"
|
|
106
|
+
if node_constraint.show_expanded_aim_constraints
|
|
107
|
+
else "TRIA_RIGHT",
|
|
108
|
+
emboss=False,
|
|
109
|
+
)
|
|
110
|
+
if not node_constraint.show_expanded_aim_constraints:
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
constraints_column = constraints_box.column()
|
|
114
|
+
if object_constraints or bone_constraints:
|
|
115
|
+
constraints_expanded_column = constraints_column.column()
|
|
116
|
+
for object_name, constraint in object_constraints.items():
|
|
117
|
+
constraint_row = constraints_expanded_column.row()
|
|
118
|
+
constraint_row.alignment = "LEFT"
|
|
119
|
+
constraint_row.label(
|
|
120
|
+
text=object_name + ": " + constraint.name,
|
|
121
|
+
icon="CONSTRAINT",
|
|
122
|
+
translate=False,
|
|
123
|
+
)
|
|
124
|
+
for bone_name, constraint in bone_constraints.items():
|
|
125
|
+
constraint_row = constraints_expanded_column.row()
|
|
126
|
+
constraint_row.alignment = "LEFT"
|
|
127
|
+
constraint_row.label(
|
|
128
|
+
text=bone_name + ": " + constraint.name,
|
|
129
|
+
icon="CONSTRAINT_BONE",
|
|
130
|
+
translate=False,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
constraints_help_column = constraints_column.box().column(align=True)
|
|
134
|
+
help_message = pgettext(
|
|
135
|
+
"Conditions exported as Aim Constraint\n"
|
|
136
|
+
+ " - {damped_track}\n"
|
|
137
|
+
+ " - Enabled\n"
|
|
138
|
+
+ " - Target Bone {head_tail} is 0\n"
|
|
139
|
+
+ " - No Follow Target Bone B-Bone\n"
|
|
140
|
+
+ " - No circular dependencies\n"
|
|
141
|
+
+ " - The one at the top of the list of\n"
|
|
142
|
+
+ " those that meet all the conditions\n"
|
|
143
|
+
).format(
|
|
144
|
+
damped_track=pgettext("Damped Track"),
|
|
145
|
+
head_tail=pgettext("Head/Tail"),
|
|
146
|
+
)
|
|
147
|
+
for index, help_line in enumerate(help_message.splitlines()):
|
|
148
|
+
constraints_help_column.label(
|
|
149
|
+
text=help_line, translate=False, icon="HELP" if index == 0 else "NONE"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _draw_rotation_constraint_layout(
|
|
154
|
+
layout: UILayout,
|
|
155
|
+
node_constraint: NodeConstraint1NodeConstraintPropertyGroup,
|
|
156
|
+
object_constraints: dict[str, CopyRotationConstraint],
|
|
157
|
+
bone_constraints: dict[str, CopyRotationConstraint],
|
|
158
|
+
) -> None:
|
|
159
|
+
constraints_box = layout.box()
|
|
160
|
+
constraints_row = constraints_box.row()
|
|
161
|
+
constraints_row.alignment = "LEFT"
|
|
162
|
+
constraints_row.prop(
|
|
163
|
+
node_constraint,
|
|
164
|
+
"show_expanded_rotation_constraints",
|
|
165
|
+
icon="TRIA_DOWN"
|
|
166
|
+
if node_constraint.show_expanded_rotation_constraints
|
|
167
|
+
else "TRIA_RIGHT",
|
|
168
|
+
emboss=False,
|
|
169
|
+
)
|
|
170
|
+
if not node_constraint.show_expanded_rotation_constraints:
|
|
171
|
+
return
|
|
172
|
+
|
|
173
|
+
constraints_column = constraints_box.column()
|
|
174
|
+
if object_constraints or bone_constraints:
|
|
175
|
+
constraints_expanded_column = constraints_column.column()
|
|
176
|
+
for object_name, constraint in object_constraints.items():
|
|
177
|
+
constraint_row = constraints_expanded_column.row()
|
|
178
|
+
constraint_row.alignment = "LEFT"
|
|
179
|
+
constraint_row.label(
|
|
180
|
+
text=object_name + ": " + constraint.name,
|
|
181
|
+
icon="CONSTRAINT",
|
|
182
|
+
translate=False,
|
|
183
|
+
)
|
|
184
|
+
for bone_name, constraint in bone_constraints.items():
|
|
185
|
+
constraint_row = constraints_expanded_column.row()
|
|
186
|
+
constraint_row.alignment = "LEFT"
|
|
187
|
+
constraint_row.label(
|
|
188
|
+
text=bone_name + ": " + constraint.name,
|
|
189
|
+
icon="CONSTRAINT_BONE",
|
|
190
|
+
translate=False,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
constraints_help_column = constraints_column.box().column(align=True)
|
|
194
|
+
help_message = pgettext(
|
|
195
|
+
"Conditions exported as Rotation Constraint\n"
|
|
196
|
+
+ " - {copy_rotation}\n"
|
|
197
|
+
+ " - Enabled\n"
|
|
198
|
+
+ " - No Vertex Group\n"
|
|
199
|
+
+ " - {axis} is X, Y and Z\n"
|
|
200
|
+
+ " - No Inverted\n"
|
|
201
|
+
+ " - {mix} is {add}\n"
|
|
202
|
+
+ " - {target} is {local_space}\n"
|
|
203
|
+
+ " - {owner} is {local_space}\n"
|
|
204
|
+
+ " - No circular dependencies\n"
|
|
205
|
+
+ " - The one at the top of the list of\n"
|
|
206
|
+
+ " those that meet all the conditions\n"
|
|
207
|
+
).format(
|
|
208
|
+
copy_rotation=pgettext("Copy Rotation"),
|
|
209
|
+
axis=pgettext("Axis"),
|
|
210
|
+
mix=pgettext("Mix"),
|
|
211
|
+
add=pgettext("Add"),
|
|
212
|
+
target=pgettext("Target"),
|
|
213
|
+
local_space=pgettext("Local Space"),
|
|
214
|
+
owner=pgettext("Owner"),
|
|
215
|
+
)
|
|
216
|
+
for index, help_line in enumerate(help_message.splitlines()):
|
|
217
|
+
constraints_help_column.label(
|
|
218
|
+
text=help_line, translate=False, icon="HELP" if index == 0 else "NONE"
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _draw_node_constraint1_layout(
|
|
223
|
+
context: Context,
|
|
224
|
+
armature: Object,
|
|
225
|
+
layout: UILayout,
|
|
226
|
+
node_constraint: NodeConstraint1NodeConstraintPropertyGroup,
|
|
227
|
+
) -> None:
|
|
228
|
+
preferences = get_preferences(context)
|
|
229
|
+
objs = search.export_objects(
|
|
230
|
+
context,
|
|
231
|
+
armature_object_name=armature.name,
|
|
232
|
+
export_invisibles=preferences.export_invisibles,
|
|
233
|
+
export_only_selections=False,
|
|
234
|
+
export_lights=False,
|
|
235
|
+
)
|
|
236
|
+
object_constraints, bone_constraints, _ = search.export_constraints(objs, armature)
|
|
237
|
+
_draw_roll_constraint_layout(
|
|
238
|
+
layout,
|
|
239
|
+
node_constraint,
|
|
240
|
+
object_constraints.roll_constraints,
|
|
241
|
+
bone_constraints.roll_constraints,
|
|
242
|
+
)
|
|
243
|
+
_draw_aim_constraint_layout(
|
|
244
|
+
layout,
|
|
245
|
+
node_constraint,
|
|
246
|
+
object_constraints.aim_constraints,
|
|
247
|
+
bone_constraints.aim_constraints,
|
|
248
|
+
)
|
|
249
|
+
_draw_rotation_constraint_layout(
|
|
250
|
+
layout,
|
|
251
|
+
node_constraint,
|
|
252
|
+
object_constraints.rotation_constraints,
|
|
253
|
+
bone_constraints.rotation_constraints,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class VRM_PT_node_constraint1_armature_object_property(Panel):
|
|
258
|
+
bl_idname = "VRM_PT_node_constraint1_armature_object_property"
|
|
259
|
+
bl_label = "Node Constraint"
|
|
260
|
+
bl_translation_context = "VRM"
|
|
261
|
+
bl_space_type = "PROPERTIES"
|
|
262
|
+
bl_region_type = "WINDOW"
|
|
263
|
+
bl_context = "object"
|
|
264
|
+
bl_options: ClassVar = {"DEFAULT_CLOSED"}
|
|
265
|
+
bl_parent_id = VRM_PT_vrm_armature_object_property.bl_idname
|
|
266
|
+
|
|
267
|
+
@classmethod
|
|
268
|
+
def poll(cls, context: Context) -> bool:
|
|
269
|
+
return active_object_is_vrm1_armature(context)
|
|
270
|
+
|
|
271
|
+
def draw_header(self, _context: Context) -> None:
|
|
272
|
+
self.layout.label(icon="CONSTRAINT")
|
|
273
|
+
|
|
274
|
+
def draw(self, context: Context) -> None:
|
|
275
|
+
active_object = context.active_object
|
|
276
|
+
if not active_object:
|
|
277
|
+
return
|
|
278
|
+
armature_data = active_object.data
|
|
279
|
+
if not isinstance(armature_data, Armature):
|
|
280
|
+
return
|
|
281
|
+
_draw_node_constraint1_layout(
|
|
282
|
+
context,
|
|
283
|
+
active_object,
|
|
284
|
+
self.layout,
|
|
285
|
+
get_armature_extension(armature_data).node_constraint1,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class VRM_PT_node_constraint1_ui(Panel):
|
|
290
|
+
bl_idname = "VRM_PT_node_constraint1_ui"
|
|
291
|
+
bl_label = "Node Constraint"
|
|
292
|
+
bl_translation_context = "VRM"
|
|
293
|
+
bl_space_type = "VIEW_3D"
|
|
294
|
+
bl_region_type = "UI"
|
|
295
|
+
bl_category = "VRM"
|
|
296
|
+
bl_options: ClassVar = {"DEFAULT_CLOSED"}
|
|
297
|
+
|
|
298
|
+
@classmethod
|
|
299
|
+
def poll(cls, context: Context) -> bool:
|
|
300
|
+
return search.current_armature_is_vrm1(context)
|
|
301
|
+
|
|
302
|
+
def draw_header(self, _context: Context) -> None:
|
|
303
|
+
self.layout.label(icon="CONSTRAINT")
|
|
304
|
+
|
|
305
|
+
def draw(self, context: Context) -> None:
|
|
306
|
+
armature = search.current_armature(context)
|
|
307
|
+
if not armature:
|
|
308
|
+
return
|
|
309
|
+
armature_data = armature.data
|
|
310
|
+
if not isinstance(armature_data, Armature):
|
|
311
|
+
return
|
|
312
|
+
_draw_node_constraint1_layout(
|
|
313
|
+
context,
|
|
314
|
+
armature,
|
|
315
|
+
self.layout,
|
|
316
|
+
get_armature_extension(armature_data).node_constraint1,
|
|
317
|
+
)
|