@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.
Files changed (245) hide show
  1. package/LICENSE +22 -5
  2. package/README.md +4 -11
  3. package/browser/addons/vrm/LICENSE_(OPTION1)_MIT.txt +22 -0
  4. package/browser/addons/vrm/LICENSE_(OPTION2)_GPL-3_0.txt +674 -0
  5. package/browser/addons/vrm/LICENSE_MAIN.txt +1 -0
  6. package/browser/addons/vrm/README.txt +3 -0
  7. package/browser/addons/vrm/__init__.py +41 -0
  8. package/browser/addons/vrm/blender_manifest.toml +16 -0
  9. package/browser/addons/vrm/common/__init__.py +1 -0
  10. package/browser/addons/vrm/common/animation.py +58 -0
  11. package/browser/addons/vrm/common/blender_manifest.py +82 -0
  12. package/browser/addons/vrm/common/char.py +16 -0
  13. package/browser/addons/vrm/common/convert.py +287 -0
  14. package/browser/addons/vrm/common/convert_any.py +48 -0
  15. package/browser/addons/vrm/common/debug.py +40 -0
  16. package/browser/addons/vrm/common/deep.py +162 -0
  17. package/browser/addons/vrm/common/error_dialog.py +274 -0
  18. package/browser/addons/vrm/common/fs.py +71 -0
  19. package/browser/addons/vrm/common/gl.py +20 -0
  20. package/browser/addons/vrm/common/gltf.py +1149 -0
  21. package/browser/addons/vrm/common/human_bone_mapper/__init__.py +1 -0
  22. package/browser/addons/vrm/common/human_bone_mapper/biped_mapping.py +84 -0
  23. package/browser/addons/vrm/common/human_bone_mapper/cats_blender_plugin_fix_model_mapping.py +63 -0
  24. package/browser/addons/vrm/common/human_bone_mapper/human_bone_mapper.py +203 -0
  25. package/browser/addons/vrm/common/human_bone_mapper/microsoft_rocketbox_mapping.py +69 -0
  26. package/browser/addons/vrm/common/human_bone_mapper/mixamo_mapping.py +62 -0
  27. package/browser/addons/vrm/common/human_bone_mapper/mmd_mapping.py +115 -0
  28. package/browser/addons/vrm/common/human_bone_mapper/mpfb_mapping.py +120 -0
  29. package/browser/addons/vrm/common/human_bone_mapper/ready_player_me_mapping.py +65 -0
  30. package/browser/addons/vrm/common/human_bone_mapper/reallusion_mapping.py +94 -0
  31. package/browser/addons/vrm/common/human_bone_mapper/rigify_meta_rig_mapping.py +65 -0
  32. package/browser/addons/vrm/common/human_bone_mapper/structure_based_mapping.py +891 -0
  33. package/browser/addons/vrm/common/human_bone_mapper/unreal_mapping.py +62 -0
  34. package/browser/addons/vrm/common/human_bone_mapper/vrm_addon_mapping.py +112 -0
  35. package/browser/addons/vrm/common/human_bone_mapper/vroid_mapping.py +89 -0
  36. package/browser/addons/vrm/common/legacy_gltf.py +16 -0
  37. package/browser/addons/vrm/common/logger.py +84 -0
  38. package/browser/addons/vrm/common/mtoon0.blend +0 -0
  39. package/browser/addons/vrm/common/mtoon1.blend +0 -0
  40. package/browser/addons/vrm/common/mtoon1_outline.blend +0 -0
  41. package/browser/addons/vrm/common/mtoon_auto_setup.blend +0 -0
  42. package/browser/addons/vrm/common/mtoon_unversioned.py +62 -0
  43. package/browser/addons/vrm/common/ops/__init__.py +10 -0
  44. package/browser/addons/vrm/common/ops/export_scene.py +67 -0
  45. package/browser/addons/vrm/common/ops/icyp.py +53 -0
  46. package/browser/addons/vrm/common/ops/import_scene.py +57 -0
  47. package/browser/addons/vrm/common/ops/vrm.py +2380 -0
  48. package/browser/addons/vrm/common/ops/wm.py +167 -0
  49. package/browser/addons/vrm/common/preferences.py +362 -0
  50. package/browser/addons/vrm/common/progress.py +87 -0
  51. package/browser/addons/vrm/common/rotation.py +89 -0
  52. package/browser/addons/vrm/common/safe_removal.py +46 -0
  53. package/browser/addons/vrm/common/scene_watcher.py +230 -0
  54. package/browser/addons/vrm/common/shader.py +2243 -0
  55. package/browser/addons/vrm/common/shape_key_mapper/__init__.py +1 -0
  56. package/browser/addons/vrm/common/shape_key_mapper/arkit_mapping.py +168 -0
  57. package/browser/addons/vrm/common/shape_key_mapper/mmd_mapping.py +62 -0
  58. package/browser/addons/vrm/common/shape_key_mapper/ready_player_me_mapping.py +52 -0
  59. package/browser/addons/vrm/common/shape_key_mapper/vrchat_mapping.py +17 -0
  60. package/browser/addons/vrm/common/third_party_user_extension.py +214 -0
  61. package/browser/addons/vrm/common/transparent_z_write.blend +0 -0
  62. package/browser/addons/vrm/common/version.py +161 -0
  63. package/browser/addons/vrm/common/vrm0/__init__.py +1 -0
  64. package/browser/addons/vrm/common/vrm0/human_bone.py +662 -0
  65. package/browser/addons/vrm/common/vrm0/material_property.py +346 -0
  66. package/browser/addons/vrm/common/vrm1/__init__.py +1 -0
  67. package/browser/addons/vrm/common/vrm1/expression_preset.py +207 -0
  68. package/browser/addons/vrm/common/vrm1/human_bone.py +822 -0
  69. package/browser/addons/vrm/common/workspace.py +227 -0
  70. package/browser/addons/vrm/common/writable_context.py +77 -0
  71. package/browser/addons/vrm/documentation/en-us/animation/index.md +63 -0
  72. package/browser/addons/vrm/documentation/en-us/create-humanoid-vrm-from-scratch/index.md +131 -0
  73. package/browser/addons/vrm/documentation/en-us/create-simple-vrm-from-scratch/index.md +30 -0
  74. package/browser/addons/vrm/documentation/en-us/development/index.md +136 -0
  75. package/browser/addons/vrm/documentation/en-us/index.md +41 -0
  76. package/browser/addons/vrm/documentation/en-us/installation/index.md +152 -0
  77. package/browser/addons/vrm/documentation/en-us/material-mtoon/index.md +122 -0
  78. package/browser/addons/vrm/documentation/en-us/material-pbr/index.md +94 -0
  79. package/browser/addons/vrm/documentation/en-us/scripting-api/index.md +391 -0
  80. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrm/index.md +57 -0
  81. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrma/index.md +17 -0
  82. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrm/index.md +61 -0
  83. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrma/index.md +13 -0
  84. package/browser/addons/vrm/documentation/ja-jp/animation/index.md +57 -0
  85. package/browser/addons/vrm/documentation/ja-jp/create-humanoid-vrm-from-scratch/index.md +129 -0
  86. package/browser/addons/vrm/documentation/ja-jp/create-simple-vrm-from-scratch/index.md +29 -0
  87. package/browser/addons/vrm/documentation/ja-jp/development/index.md +137 -0
  88. package/browser/addons/vrm/documentation/ja-jp/index.md +37 -0
  89. package/browser/addons/vrm/documentation/ja-jp/installation/index.md +150 -0
  90. package/browser/addons/vrm/documentation/ja-jp/material-mtoon/index.md +113 -0
  91. package/browser/addons/vrm/documentation/ja-jp/material-pbr/index.md +90 -0
  92. package/browser/addons/vrm/documentation/ja-jp/scripting-api/index.md +389 -0
  93. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrm/index.md +55 -0
  94. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrma/index.md +19 -0
  95. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrm/index.md +56 -0
  96. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrma/index.md +14 -0
  97. package/browser/addons/vrm/editor/__init__.py +1 -0
  98. package/browser/addons/vrm/editor/extension.py +425 -0
  99. package/browser/addons/vrm/editor/extension_accessor.py +75 -0
  100. package/browser/addons/vrm/editor/handler.py +84 -0
  101. package/browser/addons/vrm/editor/khr_character/__init__.py +1 -0
  102. package/browser/addons/vrm/editor/khr_character/panel.py +69 -0
  103. package/browser/addons/vrm/editor/khr_character/property_group.py +27 -0
  104. package/browser/addons/vrm/editor/khr_xmp_json_ld/__init__.py +1 -0
  105. package/browser/addons/vrm/editor/khr_xmp_json_ld/ops.py +464 -0
  106. package/browser/addons/vrm/editor/khr_xmp_json_ld/panel.py +136 -0
  107. package/browser/addons/vrm/editor/khr_xmp_json_ld/property_group.py +83 -0
  108. package/browser/addons/vrm/editor/khr_xmp_json_ld/ui_list.py +198 -0
  109. package/browser/addons/vrm/editor/make_armature.py +709 -0
  110. package/browser/addons/vrm/editor/menu.py +147 -0
  111. package/browser/addons/vrm/editor/migration.py +297 -0
  112. package/browser/addons/vrm/editor/mtoon1/__init__.py +1 -0
  113. package/browser/addons/vrm/editor/mtoon1/handler.py +20 -0
  114. package/browser/addons/vrm/editor/mtoon1/migration.py +536 -0
  115. package/browser/addons/vrm/editor/mtoon1/ops.py +304 -0
  116. package/browser/addons/vrm/editor/mtoon1/panel.py +442 -0
  117. package/browser/addons/vrm/editor/mtoon1/property_group.py +4977 -0
  118. package/browser/addons/vrm/editor/mtoon1/scene_watcher.py +381 -0
  119. package/browser/addons/vrm/editor/node_constraint1/__init__.py +1 -0
  120. package/browser/addons/vrm/editor/node_constraint1/panel.py +317 -0
  121. package/browser/addons/vrm/editor/node_constraint1/property_group.py +25 -0
  122. package/browser/addons/vrm/editor/ops.py +471 -0
  123. package/browser/addons/vrm/editor/panel.py +315 -0
  124. package/browser/addons/vrm/editor/property_group.py +888 -0
  125. package/browser/addons/vrm/editor/search.py +682 -0
  126. package/browser/addons/vrm/editor/spring_bone1/__init__.py +1 -0
  127. package/browser/addons/vrm/editor/spring_bone1/handler.py +994 -0
  128. package/browser/addons/vrm/editor/spring_bone1/menu.py +246 -0
  129. package/browser/addons/vrm/editor/spring_bone1/migration.py +86 -0
  130. package/browser/addons/vrm/editor/spring_bone1/ops.py +1679 -0
  131. package/browser/addons/vrm/editor/spring_bone1/panel.py +605 -0
  132. package/browser/addons/vrm/editor/spring_bone1/property_group.py +1457 -0
  133. package/browser/addons/vrm/editor/spring_bone1/ui_list.py +408 -0
  134. package/browser/addons/vrm/editor/subscription.py +123 -0
  135. package/browser/addons/vrm/editor/t_pose.py +713 -0
  136. package/browser/addons/vrm/editor/validation.py +1271 -0
  137. package/browser/addons/vrm/editor/vrm0/__init__.py +1 -0
  138. package/browser/addons/vrm/editor/vrm0/gizmo_group.py +63 -0
  139. package/browser/addons/vrm/editor/vrm0/handler.py +23 -0
  140. package/browser/addons/vrm/editor/vrm0/menu.py +145 -0
  141. package/browser/addons/vrm/editor/vrm0/migration.py +761 -0
  142. package/browser/addons/vrm/editor/vrm0/ops.py +2145 -0
  143. package/browser/addons/vrm/editor/vrm0/panel.py +1333 -0
  144. package/browser/addons/vrm/editor/vrm0/property_group.py +1818 -0
  145. package/browser/addons/vrm/editor/vrm0/ui_list.py +688 -0
  146. package/browser/addons/vrm/editor/vrm1/__init__.py +1 -0
  147. package/browser/addons/vrm/editor/vrm1/handler.py +28 -0
  148. package/browser/addons/vrm/editor/vrm1/menu.py +76 -0
  149. package/browser/addons/vrm/editor/vrm1/migration.py +321 -0
  150. package/browser/addons/vrm/editor/vrm1/ops.py +2679 -0
  151. package/browser/addons/vrm/editor/vrm1/panel.py +1243 -0
  152. package/browser/addons/vrm/editor/vrm1/property_group.py +2087 -0
  153. package/browser/addons/vrm/editor/vrm1/scene_watcher.py +90 -0
  154. package/browser/addons/vrm/editor/vrm1/ui_list.py +533 -0
  155. package/browser/addons/vrm/exporter/__init__.py +1 -0
  156. package/browser/addons/vrm/exporter/abstract_base_vrm_exporter.py +628 -0
  157. package/browser/addons/vrm/exporter/export_scene.py +930 -0
  158. package/browser/addons/vrm/exporter/gltf2_export_user_extension.py +45 -0
  159. package/browser/addons/vrm/exporter/khr_character_exporter.py +34 -0
  160. package/browser/addons/vrm/exporter/vrm0_exporter.py +4020 -0
  161. package/browser/addons/vrm/exporter/vrm1_exporter.py +3682 -0
  162. package/browser/addons/vrm/exporter/vrm_animation_exporter.py +1035 -0
  163. package/browser/addons/vrm/external/__init__.py +1 -0
  164. package/browser/addons/vrm/external/auto_rig_pro_support.py +3 -0
  165. package/browser/addons/vrm/external/io_scene_gltf2_support.py +418 -0
  166. package/browser/addons/vrm/external/rigify_support.py +1 -0
  167. package/browser/addons/vrm/importer/__init__.py +1 -0
  168. package/browser/addons/vrm/importer/abstract_base_vrm_importer.py +1548 -0
  169. package/browser/addons/vrm/importer/file_handler.py +34 -0
  170. package/browser/addons/vrm/importer/gltf2_import_user_extension.py +268 -0
  171. package/browser/addons/vrm/importer/import_scene.py +646 -0
  172. package/browser/addons/vrm/importer/license_validation.py +198 -0
  173. package/browser/addons/vrm/importer/vrm0_importer.py +1723 -0
  174. package/browser/addons/vrm/importer/vrm1_importer.py +2014 -0
  175. package/browser/addons/vrm/importer/vrm_animation_importer.py +763 -0
  176. package/browser/addons/vrm/importer/vrm_diff.py +316 -0
  177. package/browser/addons/vrm/locale/__init__.py +1 -0
  178. package/browser/addons/vrm/locale/ja_jp.py +826 -0
  179. package/browser/addons/vrm/locale/ruff.toml +8 -0
  180. package/browser/addons/vrm/locale/translation_dictionary.py +10 -0
  181. package/browser/addons/vrm/locale/zh_hans.py +928 -0
  182. package/browser/addons/vrm/registration.py +670 -0
  183. package/browser/addons/vrm.json +18 -0
  184. package/browser/blender-emscripten-engine.mts +66 -129
  185. package/browser/blender-engine.mts +20 -186
  186. package/browser/blender-wali-engine.mts +37 -81
  187. package/browser/describe-thrown.mts +3 -6
  188. package/browser/document-chunks.mts +4 -16
  189. package/browser/gltf_export.py +3161 -0
  190. package/browser/heap-growth.mts +23 -0
  191. package/browser/index.ts +3 -0
  192. package/browser/protocol.ts +130 -43
  193. package/browser/pull-job.mts +2 -10
  194. package/browser/rna.ts +190 -73
  195. package/browser/runtime.ts +271 -106
  196. package/browser/session-addons.mts +33 -0
  197. package/browser/session-frame.mts +5 -24
  198. package/browser/session.py +1389 -1446
  199. package/browser/three/attach-presenter.ts +11 -39
  200. package/browser/three/blender-base64.ts +1 -36
  201. package/browser/three/blender-corner-normals.ts +1 -23
  202. package/browser/three/blender-display-shaders.json +1 -1
  203. package/browser/three/blender-display-shaders.lut +0 -0
  204. package/browser/three/blender-display-transform.ts +2 -1
  205. package/browser/three/blender-frame-columns.ts +5 -13
  206. package/browser/three/blender-graph-material.ts +18 -3
  207. package/browser/three/blender-node-graph.ts +10 -34
  208. package/browser/three/blender-physical-material.ts +2 -31
  209. package/browser/three/blender-runtime-armature.ts +7 -60
  210. package/browser/three/blender-runtime-frame.ts +9 -23
  211. package/browser/three/blender-runtime-geometry.ts +22 -26
  212. package/browser/three/blender-runtime-lighting.ts +48 -178
  213. package/browser/three/blender-runtime-shadows.ts +187 -1
  214. package/browser/three/blender-runtime-skeleton.ts +53 -1
  215. package/browser/three/blender-runtime-view.ts +492 -306
  216. package/browser/three/blender-runtime-weights.ts +9 -72
  217. package/browser/three/blender-sky.ts +13 -33
  218. package/browser/three/blender-triangulate.ts +7 -35
  219. package/browser/three/blender-viewport-sampling.ts +235 -0
  220. package/browser/three/blender-workbench-material.ts +25 -29
  221. package/browser/three/blender-workbench-outline.ts +199 -0
  222. package/browser/three/blender-world-volume.ts +62 -10
  223. package/browser/three/presenter.ts +10 -26
  224. package/browser/three/release.ts +5 -21
  225. package/browser/three/sky-precompute-worker.ts +1 -18
  226. package/browser/three/sky-worker.ts +5 -23
  227. package/browser/three/world-field-sampler.ts +12 -26
  228. package/browser/volter_three.py +9 -105
  229. package/browser/worker.ts +195 -180
  230. package/package.json +5 -2
  231. package/wasm/BUNDLE.json +17 -17
  232. package/wasm/DEPENDENCY-LICENSES.txt +14 -0
  233. package/wasm/blender_browser.data.br +0 -0
  234. package/wasm/blender_browser.js +1 -1
  235. package/wasm/blender_browser.wasm.br +0 -0
  236. package/browser/frame-transfer.mts +0 -19
  237. package/browser/three/agx-base-srgb.lut +0 -0
  238. package/browser/three/agx-look-medium-high-contrast.lut +0 -0
  239. package/browser/three/agx-look-punchy.lut +0 -0
  240. package/browser/three/blender-agx.ts +0 -235
  241. package/browser/three/blender-display-lut.ts +0 -145
  242. package/browser/three/blender-filmic.ts +0 -49
  243. package/browser/three/blender-standard.ts +0 -68
  244. package/browser/three/blender-world-visibility.ts +0 -278
  245. package/browser/three/filmic-srgb.lut +0 -0
@@ -0,0 +1,888 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+ import uuid
3
+ from collections.abc import Iterable, Iterator, Mapping, Sequence, ValuesView
4
+ from dataclasses import dataclass
5
+ from enum import Enum
6
+ from typing import (
7
+ TYPE_CHECKING,
8
+ ClassVar,
9
+ Final,
10
+ Optional,
11
+ Protocol,
12
+ TypeVar,
13
+ Union,
14
+ overload,
15
+ )
16
+
17
+ import bpy
18
+ from bpy.app.translations import pgettext
19
+ from bpy.props import FloatProperty, PointerProperty, StringProperty
20
+ from bpy.types import Armature, Bone, Context, Material, Object, PropertyGroup, UILayout
21
+ from mathutils import Vector
22
+
23
+ from ..common import shader
24
+ from ..common.logger import get_logger
25
+ from ..common.vrm0 import human_bone as vrm0_human_bone
26
+ from ..common.vrm1 import human_bone as vrm1_human_bone
27
+ from .extension_accessor import (
28
+ get_armature_extension,
29
+ get_bone_extension,
30
+ get_material_extension,
31
+ )
32
+
33
+ HumanBoneSpecification = TypeVar(
34
+ "HumanBoneSpecification",
35
+ vrm0_human_bone.HumanBoneSpecification,
36
+ vrm1_human_bone.HumanBoneSpecification,
37
+ )
38
+
39
+ _logger = get_logger(__name__)
40
+
41
+
42
+ # https://docs.blender.org/api/2.93/bpy.types.EnumPropertyItem.html#bpy.types.EnumPropertyItem
43
+ @dataclass(frozen=True)
44
+ class PropertyGroupEnumItem:
45
+ identifier: str
46
+ name: str
47
+ description: str
48
+ icon: str
49
+ value: int
50
+
51
+ @staticmethod
52
+ def from_enum_property_items(
53
+ items: tuple[tuple[str, str, str, str, int], ...],
54
+ ) -> tuple[tuple[str, ...], tuple[int, ...], tuple["PropertyGroupEnumItem", ...]]:
55
+ enum_items = tuple(
56
+ PropertyGroupEnumItem(
57
+ identifier=identifier,
58
+ name=name,
59
+ description=description,
60
+ icon=icon,
61
+ value=value,
62
+ )
63
+ for identifier, name, description, icon, value in items
64
+ )
65
+ identifiers = tuple(enum_item.identifier for enum_item in enum_items)
66
+ values = tuple(enum_item.value for enum_item in enum_items)
67
+ return identifiers, values, enum_items
68
+
69
+
70
+ class PropertyGroupEnum:
71
+ def __init__(self, enum_items: tuple[tuple[str, str, str, str, int], ...]) -> None:
72
+ self.enum_items = enum_items
73
+
74
+ def items(self) -> tuple[tuple[str, str, str, str, int], ...]:
75
+ return self.enum_items
76
+
77
+ def value_to_identifier(self, value: int, default: str) -> str:
78
+ return next(
79
+ (enum.identifier for enum in self if enum.value == value),
80
+ default,
81
+ )
82
+
83
+ def identifier_to_value(self, identifier: str, default: int) -> int:
84
+ return next(
85
+ (enum.value for enum in self if enum.identifier == identifier),
86
+ default,
87
+ )
88
+
89
+ def identifiers(self) -> tuple[str, ...]:
90
+ return tuple(enum.identifier for enum in self)
91
+
92
+ def values(self) -> tuple[int, ...]:
93
+ return tuple(enum.value for enum in self)
94
+
95
+ def __iter__(self) -> Iterator[PropertyGroupEnumItem]:
96
+ return (
97
+ PropertyGroupEnumItem(
98
+ identifier=identifier,
99
+ name=name,
100
+ description=description,
101
+ icon=icon,
102
+ value=value,
103
+ )
104
+ for identifier, name, description, icon, value in self.items()
105
+ )
106
+
107
+
108
+ def property_group_enum(
109
+ *items: tuple[str, str, str, str, int],
110
+ ) -> tuple[PropertyGroupEnum, Iterator[PropertyGroupEnumItem]]:
111
+ enum = PropertyGroupEnum(items)
112
+ return enum, enum.__iter__()
113
+
114
+
115
+ class StringPropertyGroup(PropertyGroup):
116
+ def _get_value(self) -> str:
117
+ value = self.get("value")
118
+ if isinstance(value, str):
119
+ return value
120
+ return str(value)
121
+
122
+ def _set_value(self, value: str) -> None:
123
+ self.name = value
124
+ self["value"] = value
125
+
126
+ value: StringProperty( # type: ignore[valid-type]
127
+ name="String Value",
128
+ get=_get_value,
129
+ set=_set_value,
130
+ )
131
+
132
+ if TYPE_CHECKING:
133
+ # This code is auto generated.
134
+ # To regenerate, run the `uv run tools/property_typing.py` command.
135
+ value: str # type: ignore[no-redef]
136
+
137
+
138
+ class FloatPropertyGroup(PropertyGroup):
139
+ def _get_value(self) -> float:
140
+ value = self.get("value")
141
+ if isinstance(value, (float, int)):
142
+ return float(value)
143
+ return 0.0
144
+
145
+ def _set_value(self, value: float) -> None:
146
+ self.name = str(value)
147
+ self["value"] = value
148
+
149
+ value: FloatProperty( # type: ignore[valid-type]
150
+ name="Float Value",
151
+ get=_get_value,
152
+ set=_set_value,
153
+ )
154
+
155
+ if TYPE_CHECKING:
156
+ # This code is auto generated.
157
+ # To regenerate, run the `uv run tools/property_typing.py` command.
158
+ value: float # type: ignore[no-redef]
159
+
160
+
161
+ class MeshObjectPropertyGroup(PropertyGroup):
162
+ def _get_mesh_object_name(self) -> str:
163
+ bpy_object = self.bpy_object
164
+ if not bpy_object or not bpy_object.name or bpy_object.type != "MESH":
165
+ return ""
166
+ return str(bpy_object.name)
167
+
168
+ def _set_mesh_object_name(self, value: object) -> None:
169
+ context = bpy.context
170
+
171
+ if (
172
+ not isinstance(value, str)
173
+ or not (obj := context.blend_data.objects.get(value))
174
+ or obj.type != "MESH"
175
+ ):
176
+ if self.bpy_object:
177
+ self.bpy_object = None
178
+ return
179
+
180
+ if self.bpy_object != obj:
181
+ self.bpy_object = obj
182
+
183
+ mesh_object_name: StringProperty( # type: ignore[valid-type]
184
+ get=_get_mesh_object_name, set=_set_mesh_object_name
185
+ )
186
+
187
+ saved_mesh_object_name_to_restore: StringProperty() # type: ignore[valid-type]
188
+
189
+ def _poll_bpy_object(self, obj: object) -> bool:
190
+ return isinstance(obj, Object) and obj.type == "MESH"
191
+
192
+ def _update_bpy_object(self, _context: Context) -> None:
193
+ bpy_object = self.bpy_object
194
+ self.saved_mesh_object_name_to_restore = bpy_object.name if bpy_object else ""
195
+
196
+ bpy_object: PointerProperty( # type: ignore[valid-type]
197
+ type=Object,
198
+ poll=_poll_bpy_object,
199
+ update=_update_bpy_object,
200
+ )
201
+
202
+ def restore_object_assignment(self, context: Context) -> None:
203
+ if self.bpy_object:
204
+ return
205
+ obj = context.blend_data.objects.get(self.saved_mesh_object_name_to_restore)
206
+ if not obj:
207
+ return
208
+ self._set_mesh_object_name(obj.name)
209
+
210
+ if TYPE_CHECKING:
211
+ # This code is auto generated.
212
+ # To regenerate, run the `uv run tools/property_typing.py` command.
213
+ mesh_object_name: str # type: ignore[no-redef]
214
+ saved_mesh_object_name_to_restore: str # type: ignore[no-redef]
215
+ bpy_object: Optional[Object] # type: ignore[no-redef]
216
+
217
+
218
+ class MaterialPropertyGroup(PropertyGroup):
219
+ material: PointerProperty( # type: ignore[valid-type]
220
+ type=Material,
221
+ )
222
+
223
+ if TYPE_CHECKING:
224
+ # This code is auto generated.
225
+ # To regenerate, run the `uv run tools/property_typing.py` command.
226
+ material: Optional[Material] # type: ignore[no-redef]
227
+
228
+
229
+ class BonePropertyGroupType(Enum):
230
+ VRM0_FIRST_PERSON = 1
231
+ VRM0_HUMAN = 2
232
+ VRM0_COLLIDER_GROUP = 3
233
+ VRM0_BONE_GROUP_CENTER = 4
234
+ VRM0_BONE_GROUP = 5
235
+ VRM1_HUMAN = 6
236
+ SPRING_BONE1_COLLIDER = 7
237
+ SPRING_BONE1_SPRING_CENTER = 8
238
+ SPRING_BONE1_SPRING_JOINT = 9
239
+
240
+ @staticmethod
241
+ def is_vrm0(bone_property_group_type: "BonePropertyGroupType") -> bool:
242
+ return bone_property_group_type in {
243
+ BonePropertyGroupType.VRM0_FIRST_PERSON,
244
+ BonePropertyGroupType.VRM0_HUMAN,
245
+ BonePropertyGroupType.VRM0_COLLIDER_GROUP,
246
+ BonePropertyGroupType.VRM0_BONE_GROUP_CENTER,
247
+ BonePropertyGroupType.VRM0_BONE_GROUP,
248
+ }
249
+
250
+ @staticmethod
251
+ def is_vrm1(bone_property_group_type: "BonePropertyGroupType") -> bool:
252
+ return bone_property_group_type in {
253
+ BonePropertyGroupType.VRM1_HUMAN,
254
+ BonePropertyGroupType.SPRING_BONE1_COLLIDER,
255
+ BonePropertyGroupType.SPRING_BONE1_SPRING_CENTER,
256
+ BonePropertyGroupType.SPRING_BONE1_SPRING_JOINT,
257
+ }
258
+
259
+
260
+ class BonePropertyGroup(PropertyGroup):
261
+ @staticmethod
262
+ def get_all_bone_property_groups(
263
+ armature: Union[Object, Armature],
264
+ ) -> Iterator[tuple["BonePropertyGroup", BonePropertyGroupType]]:
265
+ """Return (bone: BonePropertyGroup, is_vrm0: bool, is_vrm1: bool)."""
266
+ if isinstance(armature, Object):
267
+ armature_data = armature.data
268
+ if not isinstance(armature_data, Armature):
269
+ return
270
+ else:
271
+ armature_data = armature
272
+
273
+ ext = get_armature_extension(armature_data)
274
+ yield (
275
+ ext.vrm0.first_person.first_person_bone,
276
+ BonePropertyGroupType.VRM0_FIRST_PERSON,
277
+ )
278
+ for human_bone in ext.vrm0.humanoid.human_bones:
279
+ yield human_bone.node, BonePropertyGroupType.VRM0_HUMAN
280
+ for collider_group in ext.vrm0.secondary_animation.collider_groups:
281
+ yield collider_group.node, BonePropertyGroupType.VRM0_COLLIDER_GROUP
282
+ for bone_group in ext.vrm0.secondary_animation.bone_groups:
283
+ yield bone_group.center, BonePropertyGroupType.VRM0_BONE_GROUP_CENTER
284
+ yield from (
285
+ (bone, BonePropertyGroupType.VRM0_BONE_GROUP)
286
+ for bone in bone_group.bones
287
+ )
288
+ for (
289
+ human_bone
290
+ ) in ext.vrm1.humanoid.human_bones.human_bone_name_to_human_bone().values():
291
+ yield human_bone.node, BonePropertyGroupType.VRM1_HUMAN
292
+ for collider in ext.spring_bone1.colliders:
293
+ yield collider.node, BonePropertyGroupType.SPRING_BONE1_COLLIDER
294
+ for spring in ext.spring_bone1.springs:
295
+ yield spring.center, BonePropertyGroupType.SPRING_BONE1_SPRING_CENTER
296
+ for joint in spring.joints:
297
+ yield joint.node, BonePropertyGroupType.SPRING_BONE1_SPRING_JOINT
298
+
299
+ armature_data_name_and_bone_uuid_to_bone_name_cache: ClassVar[
300
+ dict[tuple[str, str], str]
301
+ ] = {}
302
+
303
+ def _get_bone_name(self) -> str:
304
+ if not self.bone_uuid:
305
+ return ""
306
+
307
+ armature_data = self.find_armature()
308
+
309
+ # Use cache to speed up this function since profiling showed it was slow
310
+ cache_key = (armature_data.name, self.bone_uuid)
311
+ cached_bone_name = self.armature_data_name_and_bone_uuid_to_bone_name_cache.get(
312
+ cache_key
313
+ )
314
+ if cached_bone_name is not None:
315
+ if (
316
+ cached_bone := armature_data.bones.get(cached_bone_name)
317
+ ) and get_bone_extension(cached_bone).uuid == self.bone_uuid:
318
+ return cached_bone_name
319
+ # If there's even one old value in the cache, clear everything for safety
320
+ self.armature_data_name_and_bone_uuid_to_bone_name_cache.clear()
321
+
322
+ for bone in armature_data.bones:
323
+ if get_bone_extension(bone).uuid == self.bone_uuid:
324
+ self.armature_data_name_and_bone_uuid_to_bone_name_cache[cache_key] = (
325
+ bone.name
326
+ )
327
+ return bone.name
328
+
329
+ return ""
330
+
331
+ def find_armature(self) -> Armature:
332
+ id_data = self.id_data
333
+ if isinstance(id_data, Armature):
334
+ return id_data
335
+
336
+ message = (
337
+ f"{type(self)}/{self}.id_data is not a {Armature}"
338
+ + f" but {type(id_data)}/{id_data}"
339
+ )
340
+ raise AssertionError(message)
341
+
342
+ def get_bone_property_group_type(self) -> BonePropertyGroupType:
343
+ armature_data = self.find_armature()
344
+ for (
345
+ bone_property_group,
346
+ bone_property_group_type,
347
+ ) in self.get_all_bone_property_groups(armature_data):
348
+ if bone_property_group == self:
349
+ return bone_property_group_type
350
+
351
+ message = (
352
+ f"{type(self)}/{self} is not associated with "
353
+ + "BonePropertyGroupType.get_all_bone_property_groups"
354
+ )
355
+ raise AssertionError(message)
356
+
357
+ def _set_bone_name(self, value: str) -> None:
358
+ context = bpy.context
359
+
360
+ armature_data = self.find_armature()
361
+ armature_objects = [
362
+ obj for obj in context.blend_data.objects if obj.data == armature_data
363
+ ]
364
+ bone_property_group_type = self.get_bone_property_group_type()
365
+
366
+ # Assign UUIDs and regenerate it if duplication exist
367
+ found_uuids: set[str] = set()
368
+ for bone in armature_data.bones:
369
+ bone_extension = get_bone_extension(bone)
370
+ found_uuid = bone_extension.uuid
371
+ if not found_uuid or found_uuid in found_uuids:
372
+ bone_extension.uuid = uuid.uuid4().hex
373
+ self.armature_data_name_and_bone_uuid_to_bone_name_cache.clear()
374
+ found_uuids.add(bone_extension.uuid)
375
+
376
+ if not value or not (bone := armature_data.bones.get(value)):
377
+ if not self.bone_uuid:
378
+ # Not changed
379
+ return
380
+ self.bone_uuid = ""
381
+ elif self.bone_uuid and self.bone_uuid == get_bone_extension(bone).uuid:
382
+ # Not changed
383
+ return
384
+ else:
385
+ self.bone_uuid = get_bone_extension(bone).uuid
386
+
387
+ ext = get_armature_extension(armature_data)
388
+
389
+ if bone_property_group_type in (
390
+ BonePropertyGroupType.VRM0_COLLIDER_GROUP,
391
+ BonePropertyGroupType.VRM0_BONE_GROUP,
392
+ ):
393
+ for collider_group in ext.vrm0.secondary_animation.collider_groups:
394
+ for armature_object in armature_objects:
395
+ collider_group.fixup(armature_object)
396
+
397
+ if bone_property_group_type == BonePropertyGroupType.SPRING_BONE1_COLLIDER:
398
+ for collider in ext.spring_bone1.colliders:
399
+ for armature_object in armature_objects:
400
+ collider.reset_bpy_object(context, armature_object)
401
+
402
+ if bone_property_group_type == BonePropertyGroupType.VRM0_HUMAN:
403
+ HumanoidStructureBonePropertyGroup.update_all_vrm0_bone_name_candidates(
404
+ armature_data
405
+ )
406
+ if bone_property_group_type == BonePropertyGroupType.VRM1_HUMAN:
407
+ HumanoidStructureBonePropertyGroup.update_all_vrm1_bone_name_candidates(
408
+ armature_data
409
+ )
410
+
411
+ bone_name: StringProperty( # type: ignore[valid-type]
412
+ name="Bone",
413
+ get=_get_bone_name,
414
+ set=_set_bone_name,
415
+ )
416
+
417
+ def filter_bone_names(self, bone_names: Iterable[str]) -> Sequence[str]:
418
+ return list(bone_names)
419
+
420
+ bone_uuid: StringProperty() # type: ignore[valid-type]
421
+
422
+ if TYPE_CHECKING:
423
+ # This code is auto generated.
424
+ # To regenerate, run the `uv run tools/property_typing.py` command.
425
+ bone_name: str # type: ignore[no-redef]
426
+ bone_uuid: str # type: ignore[no-redef]
427
+
428
+
429
+ class HumanoidStructureBonePropertyGroup(BonePropertyGroup):
430
+ pointer_to_bone_name_candidates: ClassVar[dict[int, set[str]]] = {}
431
+
432
+ @classmethod
433
+ def clear_bone_name_candidates_cache(
434
+ cls, humanoid_structure_bones: Iterable["HumanoidStructureBonePropertyGroup"]
435
+ ) -> None:
436
+ for humanoid_structure_bone in humanoid_structure_bones:
437
+ cls.pointer_to_bone_name_candidates.pop(
438
+ humanoid_structure_bone.as_pointer(), None
439
+ )
440
+
441
+ @property
442
+ def bone_name_candidates_or_none(self) -> Optional[set[str]]:
443
+ pointer_key = self.as_pointer()
444
+ return self.pointer_to_bone_name_candidates.get(pointer_key)
445
+
446
+ @property
447
+ def bone_name_candidates(self) -> set[str]:
448
+ pointer_key = self.as_pointer()
449
+ bone_name_candidates = self.pointer_to_bone_name_candidates.get(pointer_key)
450
+ if bone_name_candidates is None:
451
+ bone_name_candidates = set[str]()
452
+ self.pointer_to_bone_name_candidates[pointer_key] = bone_name_candidates
453
+ armature_data = self.find_armature()
454
+ bone_property_group_type = self.get_bone_property_group_type()
455
+ if bone_property_group_type == BonePropertyGroupType.VRM0_HUMAN:
456
+ HumanoidStructureBonePropertyGroup.update_all_vrm0_bone_name_candidates(
457
+ armature_data
458
+ )
459
+ elif bone_property_group_type == BonePropertyGroupType.VRM1_HUMAN:
460
+ HumanoidStructureBonePropertyGroup.update_all_vrm1_bone_name_candidates(
461
+ armature_data
462
+ )
463
+ return bone_name_candidates
464
+
465
+ def filter_bone_names(self, bone_names: Iterable[str]) -> Sequence[str]:
466
+ bone_name_candidates = self.bone_name_candidates
467
+ return [
468
+ bone_name for bone_name in bone_names if bone_name in bone_name_candidates
469
+ ]
470
+
471
+ @staticmethod
472
+ def find_bone_candidates(
473
+ armature_data: Armature,
474
+ target: HumanBoneSpecification,
475
+ bpy_bone_name_to_human_bone_specification: Mapping[str, HumanBoneSpecification],
476
+ error_bpy_bone_names: Sequence[str],
477
+ diagnostics_layout: Optional[UILayout] = None,
478
+ ) -> set[str]:
479
+ bones = armature_data.bones
480
+ human_bone_name_to_bpy_bone_name = {
481
+ value.name: key
482
+ for key, value in bpy_bone_name_to_human_bone_specification.items()
483
+ }
484
+
485
+ search_conditions: list[str] = []
486
+
487
+ # If the target's ancestor has a Human Bone assignment, use that as the
488
+ # search start bone
489
+ searching_bones: Optional[list[Bone]] = None
490
+ ancestor: Optional[HumanBoneSpecification] = target.parent
491
+ while ancestor:
492
+ ancestor_bpy_bone_name = human_bone_name_to_bpy_bone_name.get(ancestor.name)
493
+ if not ancestor_bpy_bone_name or not (
494
+ ancestor_bpy_bone := bones.get(ancestor_bpy_bone_name)
495
+ ):
496
+ # If there's no Human Bone assignment, traverse to the parent
497
+ ancestor = ancestor.parent
498
+ continue
499
+
500
+ if ancestor_bpy_bone.name in error_bpy_bone_names:
501
+ # If there's an error in the Human Bone assignment, return empty result
502
+ if diagnostics_layout:
503
+ diagnostics_message = pgettext(
504
+ 'The bone assigned to the VRM Human Bone "{human_bone}" must'
505
+ + " be descendants of the bones assigned \nto the VRM human"
506
+ + ' bone "{parent_human_bone}". However, it cannot retrieve'
507
+ + " bone candidates because there\nis an error in the"
508
+ + ' assignment of the VRM Human Bone "{parent_human_bone}".'
509
+ + " Please resolve the error in the\nassignment of the VRM"
510
+ + ' Human Bone "{parent_human_bone}" first.'
511
+ ).format(
512
+ human_bone=target.title,
513
+ parent_human_bone=ancestor.title,
514
+ )
515
+ diagnostics_column = diagnostics_layout.column(align=True)
516
+ for i, line in enumerate(diagnostics_message.splitlines()):
517
+ diagnostics_column.label(
518
+ text=line,
519
+ translate=False,
520
+ icon="ERROR" if i == 0 else "BLANK1",
521
+ )
522
+ return set()
523
+
524
+ # Use the child bones of the found ancestor bone as the search start bones
525
+ searching_bones = list(ancestor_bpy_bone.children)
526
+ if diagnostics_layout:
527
+ search_conditions.append(
528
+ pgettext(
529
+ 'Being a descendant of the bone "{bpy_bone}" assigned'
530
+ + ' to the VRM Human Bone "{human_bone}"'
531
+ ).format(
532
+ human_bone=ancestor.title,
533
+ bpy_bone=ancestor_bpy_bone_name,
534
+ )
535
+ )
536
+ break
537
+
538
+ root_bones: Final[Sequence[Bone]] = [
539
+ bone for bone in bones.values() if not bone.parent
540
+ ]
541
+
542
+ # If no ancestor bone is found, use the root bone as the search start bone
543
+ if searching_bones is None and len(root_bones) > 1:
544
+ # If there are multiple root bones,
545
+ # select the root bone of the already assigned bone
546
+ human_bone_specification = None
547
+ for (
548
+ bpy_bone_name,
549
+ human_bone_specification,
550
+ ) in bpy_bone_name_to_human_bone_specification.items():
551
+ if not bpy_bone_name:
552
+ continue
553
+ if bpy_bone_name in error_bpy_bone_names:
554
+ continue
555
+ bpy_bone = bones.get(bpy_bone_name)
556
+ if not bpy_bone:
557
+ continue
558
+
559
+ main_root_bone: Optional[Bone] = None
560
+ parent: Optional[Bone] = bpy_bone
561
+ while parent:
562
+ main_root_bone = parent
563
+ parent = parent.parent
564
+ if not main_root_bone:
565
+ continue
566
+
567
+ searching_bones = [main_root_bone]
568
+ if diagnostics_layout:
569
+ search_conditions.append(
570
+ pgettext(
571
+ 'Sharing the root bone with the bone "{bpy_bone}" assigned'
572
+ + ' to the VRM Human Bone "{human_bone}"'
573
+ ).format(
574
+ human_bone=human_bone_specification.title,
575
+ bpy_bone=bpy_bone_name,
576
+ )
577
+ )
578
+ break
579
+ if searching_bones is None:
580
+ searching_bones = list(root_bones)
581
+
582
+ # Bone candidates
583
+ bone_candidates: set[Bone] = set(searching_bones)
584
+
585
+ # First, register all descendant bones as candidates
586
+ filling_bones = searching_bones.copy()
587
+ while filling_bones:
588
+ filling_bone = filling_bones.pop()
589
+ bone_candidates.update(filling_bone.children)
590
+ filling_bones.extend(filling_bone.children)
591
+
592
+ removing_bone_tree = set[Bone]()
593
+
594
+ # Traverse descendant bones and when we encounter an already assigned bone,
595
+ # examine its relationship and exclude unnecessary candidates.
596
+ while searching_bones:
597
+ searching_bone = searching_bones.pop()
598
+ human_bone_specification = bpy_bone_name_to_human_bone_specification.get(
599
+ searching_bone.name
600
+ )
601
+
602
+ # If not assigned to a Human Bone or if it's the target bone,
603
+ # recursively traverse child bones
604
+ if (
605
+ human_bone_specification is None
606
+ or human_bone_specification == target
607
+ or searching_bone.name in error_bpy_bone_names
608
+ ):
609
+ searching_bones.extend(searching_bone.children)
610
+ continue
611
+
612
+ if human_bone_specification.is_ancestor_of(target):
613
+ # If an ancestor bone has an assignment
614
+ # This case shouldn't exist since we start from the nearest
615
+ # ancestor bone
616
+ continue
617
+
618
+ if target.is_ancestor_of(human_bone_specification):
619
+ # If a descendant bone has an assignment:
620
+ # - Exclude that bone and its descendants
621
+ # - Exclude branches when traversing from that bone to the root bone
622
+ removing_bone_tree.add(searching_bone)
623
+
624
+ parent = searching_bone
625
+ while parent:
626
+ grand_parent = parent.parent
627
+ if grand_parent is None:
628
+ # If parent is a root bone,
629
+ # exclude other root bones except parent
630
+ removing_bone_tree.update(
631
+ root_bone for root_bone in root_bones if root_bone != parent
632
+ )
633
+ break
634
+ # Exclude sibling bones of parent
635
+ removing_bone_tree.update(
636
+ parent_sibling
637
+ for parent_sibling in grand_parent.children
638
+ if parent_sibling != parent
639
+ )
640
+ parent = grand_parent
641
+
642
+ if diagnostics_layout:
643
+ search_conditions.append(
644
+ pgettext(
645
+ 'Being an ancestor of the bone "{bpy_bone}" assigned'
646
+ + ' to the VRM Human Bone "{human_bone}"'
647
+ ).format(
648
+ human_bone=human_bone_specification.title,
649
+ bpy_bone=searching_bone.name,
650
+ )
651
+ )
652
+ else:
653
+ # If a bone that is neither ancestor nor descendant has an assignment:
654
+ # - Exclude that bone and its descendants
655
+ # - Exclude that bone and its ancestors
656
+ removing_bone_tree.add(searching_bone)
657
+
658
+ parent = searching_bone
659
+ while parent:
660
+ bone_candidates.discard(parent)
661
+ parent = parent.parent
662
+ if diagnostics_layout:
663
+ search_conditions.append(
664
+ pgettext(
665
+ 'Not being an ancestor of the bone "{bpy_bone}" assigned'
666
+ + ' to the VRM Human Bone "{human_bone}"'
667
+ ).format(
668
+ human_bone=human_bone_specification.title,
669
+ bpy_bone=searching_bone.name,
670
+ )
671
+ )
672
+
673
+ bone_candidates.difference_update(removing_bone_tree)
674
+ while removing_bone_tree:
675
+ removing_bone = removing_bone_tree.pop()
676
+ bone_candidates.difference_update(removing_bone.children)
677
+ removing_bone_tree.update(removing_bone.children)
678
+
679
+ if diagnostics_layout and search_conditions:
680
+ diagnostics_layout.label(
681
+ text=pgettext(
682
+ "Bones that meet all of the following conditions will be "
683
+ + "candidates for assignment:"
684
+ ),
685
+ translate=False,
686
+ icon="INFO",
687
+ )
688
+ for search_condition in sorted(search_conditions):
689
+ diagnostics_layout.label(
690
+ text=search_condition,
691
+ translate=False,
692
+ icon="DOT",
693
+ )
694
+
695
+ return {bone_cancidate.name for bone_cancidate in bone_candidates}
696
+
697
+ @staticmethod
698
+ def update_all_vrm0_bone_name_candidates(armature_data: Armature) -> None:
699
+ ext = get_armature_extension(armature_data)
700
+
701
+ bpy_bone_name_to_human_bone_specification: dict[
702
+ str, vrm0_human_bone.HumanBoneSpecification
703
+ ] = {}
704
+ for human_bone in ext.vrm0.humanoid.human_bones:
705
+ if not human_bone.node.bone_name:
706
+ continue
707
+ human_bone_name = vrm0_human_bone.HumanBoneName.from_str(human_bone.bone)
708
+ if human_bone_name is None:
709
+ continue
710
+ bpy_bone_name_to_human_bone_specification[human_bone.node.bone_name] = (
711
+ vrm0_human_bone.HumanBoneSpecifications.get(human_bone_name)
712
+ )
713
+
714
+ # Set from parent to child since child nodes will always have errors
715
+ # if parent node has errors
716
+ traversing_human_bone_specifications = [
717
+ vrm0_human_bone.HumanBoneSpecifications.HIPS
718
+ ]
719
+ error_bpy_bone_names = []
720
+ bone_name_candidates_updated = True
721
+ while traversing_human_bone_specifications:
722
+ traversing_human_bone_specification = (
723
+ traversing_human_bone_specifications.pop()
724
+ )
725
+
726
+ if bone_name_candidates_updated:
727
+ error_bpy_bone_names = [
728
+ error_human_bone.node.bone_name
729
+ for error_human_bone in ext.vrm0.humanoid.human_bones
730
+ if (bone_name := error_human_bone.node.bone_name)
731
+ and (
732
+ bone_name_candidates
733
+ := error_human_bone.node.bone_name_candidates_or_none
734
+ )
735
+ is not None
736
+ and bone_name not in bone_name_candidates
737
+ ]
738
+
739
+ human_bone, human_bone_name = next(
740
+ (
741
+ (human_bone, human_bone_name)
742
+ for human_bone in ext.vrm0.humanoid.human_bones
743
+ if (
744
+ human_bone_name := vrm0_human_bone.HumanBoneName.from_str(
745
+ human_bone.bone
746
+ )
747
+ )
748
+ == human_bone_name
749
+ == traversing_human_bone_specification.name
750
+ ),
751
+ (None, None),
752
+ )
753
+ if human_bone and human_bone_name:
754
+ bone_name_candidates_updated = (
755
+ human_bone.node.update_bone_name_candidates(
756
+ armature_data,
757
+ vrm0_human_bone.HumanBoneSpecifications.get(human_bone_name),
758
+ bpy_bone_name_to_human_bone_specification,
759
+ error_bpy_bone_names,
760
+ )
761
+ )
762
+
763
+ traversing_human_bone_specifications.extend(
764
+ traversing_human_bone_specification.children
765
+ )
766
+
767
+ @staticmethod
768
+ def update_all_vrm1_bone_name_candidates(armature_data: Armature) -> None:
769
+ ext = get_armature_extension(armature_data)
770
+
771
+ human_bone_name_to_human_bone = (
772
+ ext.vrm1.humanoid.human_bones.human_bone_name_to_human_bone()
773
+ )
774
+ bpy_bone_name_to_human_bone_specification: dict[
775
+ str, vrm1_human_bone.HumanBoneSpecification
776
+ ] = {}
777
+ for human_bone_name, human_bone in human_bone_name_to_human_bone.items():
778
+ if not human_bone.node.bone_name:
779
+ continue
780
+ bpy_bone_name_to_human_bone_specification[human_bone.node.bone_name] = (
781
+ vrm1_human_bone.HumanBoneSpecifications.get(human_bone_name)
782
+ )
783
+
784
+ # Set from parent to child since child nodes will always have errors
785
+ # if parent node has errors
786
+ traversing_human_bone_specifications = [
787
+ vrm1_human_bone.HumanBoneSpecifications.HIPS
788
+ ]
789
+ error_bpy_bone_names = []
790
+ bone_name_candidates_updated = True
791
+ while traversing_human_bone_specifications:
792
+ traversing_human_bone_specification = (
793
+ traversing_human_bone_specifications.pop()
794
+ )
795
+
796
+ if bone_name_candidates_updated:
797
+ error_bpy_bone_names = [
798
+ error_human_bone.node.bone_name
799
+ for error_human_bone in human_bone_name_to_human_bone.values()
800
+ if (bone_name := error_human_bone.node.bone_name)
801
+ and (
802
+ bone_name_candidates
803
+ := error_human_bone.node.bone_name_candidates_or_none
804
+ )
805
+ is not None
806
+ and bone_name not in bone_name_candidates
807
+ ]
808
+
809
+ human_bone = human_bone_name_to_human_bone[
810
+ traversing_human_bone_specification.name
811
+ ]
812
+ bone_name_candidates_updated = human_bone.node.update_bone_name_candidates(
813
+ armature_data,
814
+ traversing_human_bone_specification,
815
+ bpy_bone_name_to_human_bone_specification,
816
+ error_bpy_bone_names,
817
+ )
818
+
819
+ traversing_human_bone_specifications.extend(
820
+ traversing_human_bone_specification.children
821
+ )
822
+
823
+
824
+ def clear_expression_material_binds(context: Context) -> None:
825
+ for material in context.blend_data.materials:
826
+ mtoon1 = get_material_extension(material).mtoon1
827
+ if not mtoon1.enabled:
828
+ continue
829
+ for texture_info in mtoon1.all_texture_info():
830
+ khr_texture_transform = texture_info.extensions.khr_texture_transform
831
+ khr_texture_transform.set_texture_uv(
832
+ shader.UV_GROUP_EXPRESSION_UV_OFFSET_BIND_LABEL,
833
+ Vector((0, 0)),
834
+ )
835
+ khr_texture_transform.set_texture_uv(
836
+ shader.UV_GROUP_EXPRESSION_UV_SCALE_BIND_LABEL,
837
+ Vector((0, 0)),
838
+ )
839
+
840
+ mtoon1.set_value(
841
+ shader.OUTPUT_GROUP_NAME,
842
+ shader.OUTPUT_GROUP_EXPRESSION_COLOR_ALPHA_BIND_LABEL,
843
+ 0,
844
+ )
845
+ for label in (
846
+ shader.OUTPUT_GROUP_EXPRESSION_COLOR_BIND_LABEL,
847
+ shader.OUTPUT_GROUP_EXPRESSION_EMISSION_COLOR_BIND_LABEL,
848
+ shader.OUTPUT_GROUP_EXPRESSION_SHADE_COLOR_BIND_LABEL,
849
+ shader.OUTPUT_GROUP_EXPRESSION_MATCAP_COLOR_BIND_LABEL,
850
+ shader.OUTPUT_GROUP_EXPRESSION_RIM_COLOR_BIND_LABEL,
851
+ shader.OUTPUT_GROUP_EXPRESSION_OUTLINE_COLOR_BIND_LABEL,
852
+ ):
853
+ mtoon1.set_vector3(shader.OUTPUT_GROUP_NAME, label, Vector((0, 0, 0)))
854
+
855
+
856
+ T_co = TypeVar("T_co", covariant=True)
857
+
858
+
859
+ # The actual type does not take type arguments.
860
+ class CollectionPropertyProtocol(Protocol[T_co]):
861
+ def add(self) -> T_co: ...
862
+
863
+ def __len__(self) -> int: ...
864
+
865
+ def __iter__(self) -> Iterator[T_co]: ...
866
+
867
+ def clear(self) -> None: ...
868
+
869
+ @overload
870
+ def __getitem__(self, index: int) -> T_co: ...
871
+
872
+ @overload
873
+ def __getitem__(
874
+ self, index: "slice[Optional[int], Optional[int], Optional[int]]"
875
+ ) -> tuple[T_co, ...]: ...
876
+
877
+ def remove(self, index: int) -> None: ...
878
+
879
+ def values(self) -> ValuesView[T_co]: ...
880
+
881
+ def __contains__(self, value: str) -> bool: ...
882
+
883
+ def move(self, from_index: int, to_index: int) -> None: ...
884
+
885
+
886
+ def clear_global_variables() -> None:
887
+ BonePropertyGroup.armature_data_name_and_bone_uuid_to_bone_name_cache.clear()
888
+ HumanoidStructureBonePropertyGroup.pointer_to_bone_name_candidates.clear()