@volter/blender-engine 0.1.148 → 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.
Files changed (245) hide show
  1. package/LICENSE +16 -0
  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 +60 -128
  185. package/browser/blender-engine.mts +20 -186
  186. package/browser/blender-wali-engine.mts +35 -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 +2 -0
  192. package/browser/protocol.ts +119 -35
  193. package/browser/pull-job.mts +2 -10
  194. package/browser/rna.ts +190 -73
  195. package/browser/runtime.ts +197 -82
  196. package/browser/session-addons.mts +33 -0
  197. package/browser/session-frame.mts +5 -24
  198. package/browser/session.py +1338 -1427
  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 +505 -283
  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 +156 -151
  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,1818 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+ import uuid
3
+ from collections.abc import Sequence
4
+ from sys import float_info
5
+ from typing import TYPE_CHECKING, ClassVar, Optional
6
+
7
+ import bpy
8
+ from bpy.app.translations import pgettext
9
+ from bpy.props import (
10
+ BoolProperty,
11
+ CollectionProperty,
12
+ EnumProperty,
13
+ FloatProperty,
14
+ FloatVectorProperty,
15
+ IntProperty,
16
+ PointerProperty,
17
+ StringProperty,
18
+ )
19
+ from bpy.types import (
20
+ Action,
21
+ Armature,
22
+ Context,
23
+ Image,
24
+ Material,
25
+ Mesh,
26
+ Object,
27
+ PropertyGroup,
28
+ )
29
+ from mathutils import Vector
30
+
31
+ from ...common import convert, shader
32
+ from ...common.animation import defer_shape_key_update
33
+ from ...common.logger import get_logger
34
+ from ...common.shader import LegacyAddonMaterial
35
+ from ...common.vrm0.human_bone import (
36
+ HumanBoneName,
37
+ HumanBoneSpecification,
38
+ HumanBoneSpecifications,
39
+ )
40
+ from ...common.vrm0.material_property import (
41
+ GLTF_PROPERTIES,
42
+ MTOON0_PROPERTIES,
43
+ MaterialPropertyTarget,
44
+ MaterialPropertyType,
45
+ )
46
+ from ...common.vrm1.expression_preset import (
47
+ VRM0_PRESET_UNKNOWN,
48
+ ExpressionPresets,
49
+ )
50
+ from ..extension_accessor import get_armature_extension, get_material_extension
51
+ from ..mtoon1.property_group import (
52
+ Mtoon1MaterialPropertyGroup,
53
+ Mtoon1TextureInfoPropertyGroup,
54
+ )
55
+ from ..property_group import (
56
+ BonePropertyGroup,
57
+ FloatPropertyGroup,
58
+ HumanoidStructureBonePropertyGroup,
59
+ MeshObjectPropertyGroup,
60
+ clear_expression_material_binds,
61
+ property_group_enum,
62
+ )
63
+ from ..vrm1.property_group import Vrm1HumanoidPropertyGroup
64
+
65
+ if TYPE_CHECKING:
66
+ from ..property_group import CollectionPropertyProtocol
67
+
68
+
69
+ _logger = get_logger(__name__)
70
+
71
+
72
+ class Vrm0HumanoidBoneNodePropertyGroup(HumanoidStructureBonePropertyGroup):
73
+ def update_bone_name_candidates(
74
+ self,
75
+ armature_data: Armature,
76
+ target: HumanBoneSpecification,
77
+ bpy_bone_name_to_human_bone_specification: dict[str, HumanBoneSpecification],
78
+ error_bpy_bone_names: Sequence[str],
79
+ ) -> bool:
80
+ new_candidates = HumanoidStructureBonePropertyGroup.find_bone_candidates(
81
+ armature_data,
82
+ target,
83
+ bpy_bone_name_to_human_bone_specification,
84
+ error_bpy_bone_names,
85
+ )
86
+
87
+ bone_name_candidates = self.bone_name_candidates
88
+ if bone_name_candidates == new_candidates:
89
+ return False
90
+
91
+ bone_name_candidates.clear()
92
+ bone_name_candidates.update(new_candidates)
93
+ return True
94
+
95
+
96
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_Humanoid.cs#L70-L164
97
+ class Vrm0HumanoidBonePropertyGroup(PropertyGroup):
98
+ bone: StringProperty( # type: ignore[valid-type]
99
+ name="VRM Humanoid Bone Name"
100
+ )
101
+ node: PointerProperty( # type: ignore[valid-type]
102
+ name="Bone Name",
103
+ type=Vrm0HumanoidBoneNodePropertyGroup,
104
+ )
105
+ use_default_values: BoolProperty( # type: ignore[valid-type]
106
+ name="Unity's HumanLimit.useDefaultValues",
107
+ default=True,
108
+ )
109
+ min: FloatVectorProperty( # type: ignore[valid-type]
110
+ size=3,
111
+ name="Unity's HumanLimit.min",
112
+ )
113
+ max: FloatVectorProperty( # type: ignore[valid-type]
114
+ size=3,
115
+ name="Unity's HumanLimit.max",
116
+ )
117
+ center: FloatVectorProperty( # type: ignore[valid-type]
118
+ size=3,
119
+ name="Unity's HumanLimit.center",
120
+ )
121
+ axis_length: FloatProperty( # type: ignore[valid-type]
122
+ name="Unity's HumanLimit.axisLength"
123
+ )
124
+
125
+ def specification(self) -> HumanBoneSpecification:
126
+ name = HumanBoneName.from_str(self.bone)
127
+ if name is None:
128
+ message = f'HumanBone "{self.bone}" is invalid'
129
+ raise ValueError(message)
130
+ return HumanBoneSpecifications.get(name)
131
+
132
+ if TYPE_CHECKING:
133
+ # This code is auto generated.
134
+ # To regenerate, run the `uv run tools/property_typing.py` command.
135
+ bone: str # type: ignore[no-redef]
136
+ node: Vrm0HumanoidBoneNodePropertyGroup # type: ignore[no-redef]
137
+ use_default_values: bool # type: ignore[no-redef]
138
+ min: Sequence[float] # type: ignore[no-redef]
139
+ max: Sequence[float] # type: ignore[no-redef]
140
+ center: Sequence[float] # type: ignore[no-redef]
141
+ axis_length: float # type: ignore[no-redef]
142
+
143
+
144
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_Humanoid.cs#L166-L195
145
+ class Vrm0HumanoidPropertyGroup(PropertyGroup):
146
+ human_bones: CollectionProperty( # type: ignore[valid-type]
147
+ name="Human Bones",
148
+ type=Vrm0HumanoidBonePropertyGroup,
149
+ )
150
+ arm_stretch: FloatProperty( # type: ignore[valid-type]
151
+ name="Arm Stretch",
152
+ default=0.05,
153
+ )
154
+ leg_stretch: FloatProperty( # type: ignore[valid-type]
155
+ name="Leg Stretch",
156
+ default=0.05,
157
+ )
158
+ upper_arm_twist: FloatProperty( # type: ignore[valid-type]
159
+ name="Upper Arm Twist",
160
+ default=0.5,
161
+ )
162
+ lower_arm_twist: FloatProperty( # type: ignore[valid-type]
163
+ name="Lower Arm Twist",
164
+ default=0.5,
165
+ )
166
+ upper_leg_twist: FloatProperty( # type: ignore[valid-type]
167
+ name="Upper Leg Twist",
168
+ default=0.5,
169
+ )
170
+ lower_leg_twist: FloatProperty( # type: ignore[valid-type]
171
+ name="Lower Leg Twist",
172
+ default=0.5,
173
+ )
174
+ feet_spacing: FloatProperty( # type: ignore[valid-type]
175
+ name="Feet Spacing",
176
+ default=0,
177
+ )
178
+ has_translation_dof: BoolProperty( # type: ignore[valid-type]
179
+ name="Has Translation DoF",
180
+ default=False,
181
+ )
182
+
183
+ POSE_AUTO_POSE = Vrm1HumanoidPropertyGroup.POSE_AUTO_POSE
184
+ POSE_REST_POSITION_POSE = Vrm1HumanoidPropertyGroup.POSE_REST_POSITION_POSE
185
+ POSE_CURRENT_POSE = Vrm1HumanoidPropertyGroup.POSE_CURRENT_POSE
186
+ POSE_CUSTOM_POSE = Vrm1HumanoidPropertyGroup.POSE_CUSTOM_POSE
187
+
188
+ pose: bpy.props.EnumProperty( # type: ignore[valid-type]
189
+ items=Vrm1HumanoidPropertyGroup.pose_enum.items(),
190
+ name="T-Pose",
191
+ description="T-Pose",
192
+ default=POSE_AUTO_POSE.identifier,
193
+ )
194
+
195
+ # for T-Pose
196
+ def _update_pose_library(self, _context: Context) -> None:
197
+ self.pose_marker_name = ""
198
+
199
+ pose_library: PointerProperty( # type: ignore[valid-type]
200
+ type=Action,
201
+ name="Pose Library",
202
+ description="Pose library for T Pose",
203
+ update=_update_pose_library,
204
+ )
205
+ pose_marker_name: StringProperty() # type: ignore[valid-type]
206
+
207
+ # for UI
208
+ pointer_to_last_bone_names_str: ClassVar[dict[int, str]] = {}
209
+ initial_automatic_bone_assignment: BoolProperty( # type: ignore[valid-type]
210
+ default=True
211
+ )
212
+
213
+ def _update_filter_by_human_bone_hierarchy(self, _context: Context) -> None:
214
+ if not isinstance(armature_data := self.id_data, Armature):
215
+ return
216
+ HumanoidStructureBonePropertyGroup.clear_bone_name_candidates_cache(
217
+ human_bone.node for human_bone in self.human_bones
218
+ )
219
+ HumanoidStructureBonePropertyGroup.update_all_vrm0_bone_name_candidates(
220
+ armature_data
221
+ )
222
+
223
+ filter_by_human_bone_hierarchy: BoolProperty( # type: ignore[valid-type]
224
+ name="Filter by VRM Human Bone Hierarchy",
225
+ description="Restrict selectable bones by VRM humanoid hierarchy",
226
+ default=True,
227
+ update=_update_filter_by_human_bone_hierarchy,
228
+ )
229
+
230
+ def human_bone_duplication_error_messages(self) -> list[tuple[str, str]]:
231
+ messages: list[tuple[str, str]] = []
232
+ bone_name_to_human_bone_names: dict[str, list[str]] = {}
233
+ for human_bone in self.human_bones:
234
+ bone_name = human_bone.node.bone_name
235
+ if not bone_name:
236
+ continue
237
+
238
+ human_bone_names = bone_name_to_human_bone_names.get(bone_name)
239
+ if human_bone_names is None:
240
+ human_bone_names = []
241
+ bone_name_to_human_bone_names[bone_name] = human_bone_names
242
+
243
+ human_bone_name = HumanBoneName.from_str(human_bone.bone)
244
+ if human_bone_name is None:
245
+ human_bone_names.append(human_bone.bone)
246
+ continue
247
+ human_bone_names.append(HumanBoneSpecifications.get(human_bone_name).title)
248
+
249
+ for bone_name, human_bone_names in bone_name_to_human_bone_names.items():
250
+ if len(human_bone_names) < 2:
251
+ continue
252
+ messages.append(
253
+ (
254
+ bone_name,
255
+ pgettext(
256
+ 'Bone "{bone_name}" is assigned to multiple VRM Human Bones:'
257
+ + " {human_bone_names}."
258
+ ).format(
259
+ bone_name=bone_name,
260
+ human_bone_names=", ".join(human_bone_names),
261
+ ),
262
+ )
263
+ )
264
+ return messages
265
+
266
+ def error_messages(self) -> Sequence[str]:
267
+ messages = [
268
+ message for _, message in self.human_bone_duplication_error_messages()
269
+ ]
270
+
271
+ for human_bone_name, human_bone in (
272
+ (human_bone_name, human_bone)
273
+ for human_bone in self.human_bones
274
+ for name in HumanBoneSpecifications.required_names
275
+ if human_bone.bone == name
276
+ and (human_bone_name := HumanBoneName.from_str(name))
277
+ ):
278
+ specification = HumanBoneSpecifications.get(human_bone_name)
279
+ bone_name = human_bone.node.bone_name
280
+ if not bone_name:
281
+ if specification.requirement:
282
+ messages.append(
283
+ pgettext(
284
+ 'Please assign Required VRM Human Bone "{human_bone_name}".'
285
+ ).format(human_bone_name=specification.title)
286
+ )
287
+ continue
288
+ if (
289
+ self.filter_by_human_bone_hierarchy
290
+ and bone_name not in human_bone.node.bone_name_candidates
291
+ ):
292
+ messages.append(
293
+ pgettext(
294
+ 'Couldn\'t assign "{bone_name}" bone'
295
+ + ' to VRM Human Bone "{human_bone_name}". '
296
+ ).format(bone_name=bone_name, human_bone_name=specification.title)
297
+ )
298
+
299
+ return messages
300
+
301
+ def bones_are_correctly_assigned(self) -> bool:
302
+ return len(self.error_messages()) == 0
303
+
304
+ @staticmethod
305
+ def update_all_bone_name_candidates(
306
+ context: Context,
307
+ armature_data_name: str,
308
+ *,
309
+ force: bool = False,
310
+ ) -> None:
311
+ armature_data = context.blend_data.armatures.get(armature_data_name)
312
+ if not armature_data:
313
+ return
314
+
315
+ ext = get_armature_extension(armature_data)
316
+ if not ext.is_vrm0():
317
+ return
318
+
319
+ bone_names_str = "\n".join(
320
+ sorted(
321
+ bone.name + "\n" + (parent.name if (parent := bone.parent) else "")
322
+ for bone in armature_data.bones.values()
323
+ )
324
+ )
325
+ humanoid = ext.vrm0.humanoid
326
+ pointer_key = humanoid.as_pointer()
327
+ pointer_to_last_bone_names_str = humanoid.pointer_to_last_bone_names_str
328
+ last_bone_names_str = pointer_to_last_bone_names_str.get(pointer_key)
329
+ if not force and last_bone_names_str == bone_names_str:
330
+ return
331
+ pointer_to_last_bone_names_str[pointer_key] = bone_names_str
332
+
333
+ HumanoidStructureBonePropertyGroup.update_all_vrm0_bone_name_candidates(
334
+ armature_data
335
+ )
336
+
337
+ @staticmethod
338
+ def fixup_human_bones(obj: Object) -> None:
339
+ armature_data = obj.data
340
+ if not isinstance(armature_data, Armature):
341
+ return
342
+
343
+ humanoid = get_armature_extension(armature_data).vrm0.humanoid
344
+
345
+ # Add bone maps that don't exist
346
+ refresh = False
347
+ for human_bone_name in HumanBoneSpecifications.all_names:
348
+ if any(
349
+ human_bone.bone == human_bone_name
350
+ for human_bone in humanoid.human_bones
351
+ ):
352
+ continue
353
+ human_bone = humanoid.human_bones.add()
354
+ human_bone.bone = human_bone_name
355
+ refresh = True
356
+
357
+ # Remove duplicate bone maps
358
+ fixup = True
359
+ while fixup:
360
+ fixup = False
361
+ found_bones: list[str] = []
362
+ for i, human_bone in enumerate(list(humanoid.human_bones)):
363
+ if (
364
+ human_bone.bone in HumanBoneSpecifications.all_names
365
+ and human_bone.bone not in found_bones
366
+ ):
367
+ found_bones.append(human_bone.bone)
368
+ continue
369
+ humanoid.human_bones.remove(i)
370
+ refresh = True
371
+ fixup = True
372
+ break
373
+
374
+ # If multiple bone maps have the same Blender bone assigned, remove one of them
375
+ fixup = True
376
+ while fixup:
377
+ fixup = False
378
+ found_node_bone_names: list[str] = []
379
+ for human_bone in humanoid.human_bones:
380
+ if not human_bone.node.bone_name:
381
+ continue
382
+ if human_bone.node.bone_name not in found_node_bone_names:
383
+ found_node_bone_names.append(human_bone.node.bone_name)
384
+ continue
385
+ human_bone.node.bone_name = ""
386
+ refresh = True
387
+ fixup = True
388
+ break
389
+
390
+ if not refresh:
391
+ return
392
+
393
+ secondary_animation = get_armature_extension(
394
+ armature_data
395
+ ).vrm0.secondary_animation
396
+ secondary_animation.fixup(obj)
397
+
398
+ if TYPE_CHECKING:
399
+ # This code is auto generated.
400
+ # To regenerate, run the `uv run tools/property_typing.py` command.
401
+ human_bones: CollectionPropertyProtocol[ # type: ignore[no-redef]
402
+ Vrm0HumanoidBonePropertyGroup
403
+ ]
404
+ arm_stretch: float # type: ignore[no-redef]
405
+ leg_stretch: float # type: ignore[no-redef]
406
+ upper_arm_twist: float # type: ignore[no-redef]
407
+ lower_arm_twist: float # type: ignore[no-redef]
408
+ upper_leg_twist: float # type: ignore[no-redef]
409
+ lower_leg_twist: float # type: ignore[no-redef]
410
+ feet_spacing: float # type: ignore[no-redef]
411
+ has_translation_dof: bool # type: ignore[no-redef]
412
+ pose: str # type: ignore[no-redef]
413
+ pose_library: Optional[Action] # type: ignore[no-redef]
414
+ pose_marker_name: str # type: ignore[no-redef]
415
+ initial_automatic_bone_assignment: bool # type: ignore[no-redef]
416
+ filter_by_human_bone_hierarchy: bool # type: ignore[no-redef]
417
+
418
+
419
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_FirstPerson.cs#L10-L22
420
+ class Vrm0DegreeMapPropertyGroup(PropertyGroup):
421
+ curve: FloatVectorProperty( # type: ignore[valid-type]
422
+ size=8,
423
+ name="Curve",
424
+ default=(0, 0, 0, 1, 1, 1, 1, 0),
425
+ )
426
+ x_range: FloatProperty( # type: ignore[valid-type]
427
+ name="X Range",
428
+ default=90,
429
+ )
430
+ y_range: FloatProperty( # type: ignore[valid-type]
431
+ name="Y Range",
432
+ default=10,
433
+ )
434
+
435
+ if TYPE_CHECKING:
436
+ # This code is auto generated.
437
+ # To regenerate, run the `uv run tools/property_typing.py` command.
438
+ curve: Sequence[float] # type: ignore[no-redef]
439
+ x_range: float # type: ignore[no-redef]
440
+ y_range: float # type: ignore[no-redef]
441
+
442
+
443
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_FirstPerson.cs#L32-L41
444
+ class Vrm0MeshAnnotationPropertyGroup(PropertyGroup):
445
+ mesh: PointerProperty( # type: ignore[valid-type]
446
+ name="Mesh",
447
+ type=MeshObjectPropertyGroup,
448
+ description="Mesh on restrict render in the first person camera",
449
+ )
450
+
451
+ first_person_flag_enum, *__first_person_flags = property_group_enum(
452
+ ("Auto", "Auto", "Auto restrict render", "NONE", 0),
453
+ (
454
+ "FirstPersonOnly",
455
+ "First-Person Only",
456
+ "(Maybe needless) Restrict render in the third person camera",
457
+ "NONE",
458
+ 1,
459
+ ),
460
+ (
461
+ "ThirdPersonOnly",
462
+ "Third-Person Only",
463
+ "Restrict render in the first person camera for face, hairs or hat",
464
+ "NONE",
465
+ 2,
466
+ ),
467
+ ("Both", "Both", "No restrict render for body, arms or legs", "NONE", 3),
468
+ )
469
+
470
+ first_person_flag: EnumProperty( # type: ignore[valid-type]
471
+ items=first_person_flag_enum.items(),
472
+ name="First Person Flag",
473
+ description="Restrict render in the first person camera",
474
+ )
475
+
476
+ if TYPE_CHECKING:
477
+ # This code is auto generated.
478
+ # To regenerate, run the `uv run tools/property_typing.py` command.
479
+ mesh: MeshObjectPropertyGroup # type: ignore[no-redef]
480
+ first_person_flag: str # type: ignore[no-redef]
481
+
482
+
483
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_FirstPerson.cs#L50-L91
484
+ class Vrm0FirstPersonPropertyGroup(PropertyGroup):
485
+ first_person_bone: PointerProperty( # type: ignore[valid-type]
486
+ name="Bone",
487
+ type=BonePropertyGroup,
488
+ description="Bone to follow the first person camera",
489
+ )
490
+ first_person_bone_offset: FloatVectorProperty( # type: ignore[valid-type]
491
+ size=3,
492
+ name="Bone Offset",
493
+ description=(
494
+ "Offset from the first person bone to follow the first person camera"
495
+ ),
496
+ subtype="TRANSLATION",
497
+ unit="LENGTH",
498
+ default=(0, 0, 0),
499
+ )
500
+ mesh_annotations: CollectionProperty( # type: ignore[valid-type]
501
+ name="Mesh Annotations",
502
+ type=Vrm0MeshAnnotationPropertyGroup,
503
+ )
504
+ look_at_type_name_enum, *__look_at_types = property_group_enum(
505
+ ("Bone", "Bone", "Use bones to eye movement", "BONE_DATA", 0),
506
+ (
507
+ "BlendShape",
508
+ "Blend Shape",
509
+ "Use blend Shapes of VRM Blend Shape Proxy to eye movement.",
510
+ "SHAPEKEY_DATA",
511
+ 1,
512
+ ),
513
+ )
514
+ look_at_type_name: EnumProperty( # type: ignore[valid-type]
515
+ items=look_at_type_name_enum.items(),
516
+ name="Look At Type",
517
+ description="How to eye movement",
518
+ )
519
+ look_at_horizontal_inner: PointerProperty( # type: ignore[valid-type]
520
+ type=Vrm0DegreeMapPropertyGroup,
521
+ name="Look At Horizontal Inner",
522
+ )
523
+ look_at_horizontal_outer: PointerProperty( # type: ignore[valid-type]
524
+ type=Vrm0DegreeMapPropertyGroup,
525
+ name="Look At Horizontal Outer",
526
+ )
527
+ look_at_vertical_down: PointerProperty( # type: ignore[valid-type]
528
+ type=Vrm0DegreeMapPropertyGroup,
529
+ name="Look At Vertical Down",
530
+ )
531
+ look_at_vertical_up: PointerProperty( # type: ignore[valid-type]
532
+ type=Vrm0DegreeMapPropertyGroup,
533
+ name="lookAt Vertical Up",
534
+ )
535
+
536
+ # for UI
537
+ active_mesh_annotation_index: IntProperty(min=0) # type: ignore[valid-type]
538
+
539
+ if TYPE_CHECKING:
540
+ # This code is auto generated.
541
+ # To regenerate, run the `uv run tools/property_typing.py` command.
542
+ first_person_bone: BonePropertyGroup # type: ignore[no-redef]
543
+ first_person_bone_offset: Sequence[float] # type: ignore[no-redef]
544
+ mesh_annotations: CollectionPropertyProtocol[ # type: ignore[no-redef]
545
+ Vrm0MeshAnnotationPropertyGroup
546
+ ]
547
+ look_at_type_name: str # type: ignore[no-redef]
548
+ look_at_horizontal_inner: Vrm0DegreeMapPropertyGroup # type: ignore[no-redef]
549
+ look_at_horizontal_outer: Vrm0DegreeMapPropertyGroup # type: ignore[no-redef]
550
+ look_at_vertical_down: Vrm0DegreeMapPropertyGroup # type: ignore[no-redef]
551
+ look_at_vertical_up: Vrm0DegreeMapPropertyGroup # type: ignore[no-redef]
552
+ active_mesh_annotation_index: int # type: ignore[no-redef]
553
+
554
+
555
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_BlendShape.cs#L18-L30
556
+ class Vrm0BlendShapeBindPropertyGroup(PropertyGroup):
557
+ def _update_preview(self, context: Context) -> None:
558
+ if not isinstance(armature_data := self.id_data, Armature):
559
+ return
560
+ Vrm0BlendShapeGroupPropertyGroup.apply_previews(context, armature_data)
561
+
562
+ mesh: PointerProperty( # type: ignore[valid-type]
563
+ name="Mesh",
564
+ type=MeshObjectPropertyGroup,
565
+ update=_update_preview,
566
+ )
567
+ index: StringProperty( # type: ignore[valid-type]
568
+ name="Index",
569
+ update=_update_preview,
570
+ )
571
+ weight: FloatProperty( # type: ignore[valid-type]
572
+ name="Weight",
573
+ min=0,
574
+ default=1,
575
+ max=1,
576
+ subtype="FACTOR",
577
+ update=_update_preview,
578
+ )
579
+
580
+ if TYPE_CHECKING:
581
+ # This code is auto generated.
582
+ # To regenerate, run the `uv run tools/property_typing.py` command.
583
+ mesh: MeshObjectPropertyGroup # type: ignore[no-redef]
584
+ index: str # type: ignore[no-redef]
585
+ weight: float # type: ignore[no-redef]
586
+
587
+
588
+ def reset_blend_shape_material_value_binds(context: Context) -> None:
589
+ clear_expression_material_binds(context)
590
+ for armature_data in context.blend_data.armatures:
591
+ Vrm0BlendShapeGroupPropertyGroup.apply_previews(context, armature_data)
592
+
593
+
594
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_BlendShape.cs#L9-L16
595
+ class Vrm0MaterialValueBindPropertyGroup(PropertyGroup):
596
+ material: PointerProperty( # type: ignore[valid-type]
597
+ name="Material",
598
+ type=Material,
599
+ update=lambda _, context: reset_blend_shape_material_value_binds(context),
600
+ )
601
+
602
+ # Use StringProperty instead of EnumProperty for property_name.
603
+ # This is necessary to allow arbitrary values to be entered.
604
+ property_name: StringProperty( # type: ignore[valid-type]
605
+ name="Property Name",
606
+ update=lambda _, context: reset_blend_shape_material_value_binds(context),
607
+ )
608
+
609
+ target_value: CollectionProperty( # type: ignore[valid-type]
610
+ name="Target Value",
611
+ type=FloatPropertyGroup,
612
+ )
613
+
614
+ def _get_target_value_as_rgb(self) -> tuple[float, float, float]:
615
+ r, g, b, _a = self.read_target_value_as_float4()
616
+ return (
617
+ r,
618
+ g,
619
+ b,
620
+ )
621
+
622
+ def _set_target_value_as_rgb(self, value: Sequence[float]) -> None:
623
+ if len(value) < 3:
624
+ return
625
+ r, g, b = value[:3]
626
+ while len(self.target_value) < 4:
627
+ self.target_value.add()
628
+ while len(self.target_value) > 4:
629
+ self.target_value.remove(len(self.target_value) - 1)
630
+ self.target_value[0].value = r
631
+ self.target_value[1].value = g
632
+ self.target_value[2].value = b
633
+ self.target_value[3].value = 1.0
634
+
635
+ target_value_as_rgb: FloatVectorProperty( # type: ignore[valid-type]
636
+ name="Color",
637
+ size=3,
638
+ subtype="COLOR",
639
+ get=_get_target_value_as_rgb,
640
+ set=_set_target_value_as_rgb,
641
+ )
642
+
643
+ def _get_target_value_as_rgba(self) -> tuple[float, float, float, float]:
644
+ return self.read_target_value_as_float4()
645
+
646
+ def _set_target_value_as_rgba(self, value: Sequence[float]) -> None:
647
+ if len(value) < 4:
648
+ return
649
+ r, g, b, a = value[:4]
650
+ while len(self.target_value) < 4:
651
+ self.target_value.add()
652
+ while len(self.target_value) > 4:
653
+ self.target_value.remove(len(self.target_value) - 1)
654
+ self.target_value[0].value = r
655
+ self.target_value[1].value = g
656
+ self.target_value[2].value = b
657
+ self.target_value[3].value = a
658
+
659
+ target_value_as_rgba: FloatVectorProperty( # type: ignore[valid-type]
660
+ name="Color",
661
+ size=4,
662
+ subtype="COLOR",
663
+ get=_get_target_value_as_rgba,
664
+ set=_set_target_value_as_rgba,
665
+ )
666
+
667
+ def _set_target_value_uv(self, index: int, value: float) -> None:
668
+ u_scale, v_scale, u_offset, v_offset = self.read_target_value_as_float4()
669
+ values = [u_scale, v_scale, u_offset, v_offset]
670
+ values[index] = value
671
+ while len(self.target_value) < 4:
672
+ self.target_value.add()
673
+ while len(self.target_value) > 4:
674
+ self.target_value.remove(len(self.target_value) - 1)
675
+ for i, v in enumerate(values):
676
+ self.target_value[i].value = v
677
+
678
+ def _get_target_value_tiling_s(self) -> float:
679
+ return self.read_target_value_as_float4()[0]
680
+
681
+ def _set_target_value_tiling_s(self, value: float) -> None:
682
+ self._set_target_value_uv(0, value)
683
+
684
+ target_value_tiling_s: FloatProperty( # type: ignore[valid-type]
685
+ name="Tiling X",
686
+ get=_get_target_value_tiling_s,
687
+ set=_set_target_value_tiling_s,
688
+ )
689
+
690
+ def _get_target_value_tiling_t(self) -> float:
691
+ return self.read_target_value_as_float4()[1]
692
+
693
+ def _set_target_value_tiling_t(self, value: float) -> None:
694
+ self._set_target_value_uv(1, value)
695
+
696
+ target_value_tiling_t: FloatProperty( # type: ignore[valid-type]
697
+ name="Tiling Y",
698
+ get=_get_target_value_tiling_t,
699
+ set=_set_target_value_tiling_t,
700
+ )
701
+
702
+ def _get_target_value_offset_s(self) -> float:
703
+ return self.read_target_value_as_float4()[2]
704
+
705
+ def _set_target_value_offset_s(self, value: float) -> None:
706
+ self._set_target_value_uv(2, value)
707
+
708
+ target_value_offset_s: FloatProperty( # type: ignore[valid-type]
709
+ name="Offset X",
710
+ get=_get_target_value_offset_s,
711
+ set=_set_target_value_offset_s,
712
+ )
713
+
714
+ def _get_target_value_offset_t(self) -> float:
715
+ return self.read_target_value_as_float4()[3]
716
+
717
+ def _set_target_value_offset_t(self, value: float) -> None:
718
+ self._set_target_value_uv(3, value)
719
+
720
+ target_value_offset_t: FloatProperty( # type: ignore[valid-type]
721
+ name="Offset Y",
722
+ get=_get_target_value_offset_t,
723
+ set=_set_target_value_offset_t,
724
+ )
725
+
726
+ def read_default_target_value(self) -> Optional[tuple[float, float, float, float]]:
727
+ material = self.material
728
+ is_mtoon = material and (
729
+ get_material_extension(material).mtoon1.enabled
730
+ or (
731
+ (legacy_addon_material := LegacyAddonMaterial.try_parse(material))
732
+ and legacy_addon_material.shader_name == "MToon_unversioned"
733
+ )
734
+ )
735
+
736
+ for material_property in (
737
+ list(MTOON0_PROPERTIES.values()) + list(GLTF_PROPERTIES.values())
738
+ if is_mtoon
739
+ else list(GLTF_PROPERTIES.values()) + list(MTOON0_PROPERTIES.values())
740
+ ):
741
+ if material_property.name != self.property_name:
742
+ continue
743
+ if material_property.type in {
744
+ MaterialPropertyType.RGB,
745
+ MaterialPropertyType.RGBA,
746
+ }:
747
+ return (1.0, 1.0, 1.0, 1.0)
748
+ if material_property.type in {
749
+ MaterialPropertyType.UV,
750
+ MaterialPropertyType.UV_S,
751
+ MaterialPropertyType.UV_T,
752
+ }:
753
+ return (1.0, 1.0, 0.0, 0.0)
754
+ return None
755
+
756
+ def read_target_value_as_float4(self) -> tuple[float, float, float, float]:
757
+ default_target_value = self.read_default_target_value()
758
+ if default_target_value is None:
759
+ default_target_value = (0.0, 0.0, 0.0, 0.0)
760
+ target_value = self.target_value
761
+ return (
762
+ target_value[0].value if len(target_value) > 0 else default_target_value[0],
763
+ target_value[1].value if len(target_value) > 1 else default_target_value[1],
764
+ target_value[2].value if len(target_value) > 2 else default_target_value[2],
765
+ target_value[3].value if len(target_value) > 3 else default_target_value[3],
766
+ )
767
+
768
+ def read_target_value_as_float_list(self) -> list[float]:
769
+ target_value = self.target_value
770
+ default_target_value = self.read_default_target_value()
771
+ if default_target_value is None:
772
+ return [value.value for value in target_value]
773
+ return [
774
+ target_value[i].value if i < len(target_value) else default_target_value[i]
775
+ for i in range(len(default_target_value))
776
+ ]
777
+
778
+ if TYPE_CHECKING:
779
+ # This code is auto generated.
780
+ # To regenerate, run the `uv run tools/property_typing.py` command.
781
+ material: Optional[Material] # type: ignore[no-redef]
782
+ property_name: str # type: ignore[no-redef]
783
+ target_value: CollectionPropertyProtocol[ # type: ignore[no-redef]
784
+ FloatPropertyGroup
785
+ ]
786
+ target_value_as_rgb: Sequence[float] # type: ignore[no-redef]
787
+ target_value_as_rgba: Sequence[float] # type: ignore[no-redef]
788
+ target_value_tiling_s: float # type: ignore[no-redef]
789
+ target_value_tiling_t: float # type: ignore[no-redef]
790
+ target_value_offset_s: float # type: ignore[no-redef]
791
+ target_value_offset_t: float # type: ignore[no-redef]
792
+
793
+
794
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_BlendShape.cs#L62-L99
795
+ class Vrm0BlendShapeGroupPropertyGroup(PropertyGroup):
796
+ name: StringProperty( # type: ignore[valid-type]
797
+ name="Name",
798
+ description="Name of the blendshape group",
799
+ )
800
+
801
+ preset_name_enum, (PRESET_NAME_UNKNOWN, *__preset_names) = property_group_enum(
802
+ (VRM0_PRESET_UNKNOWN, "Unknown", "", "SHAPEKEY_DATA", 0),
803
+ (ExpressionPresets.NEUTRAL.vrm0_preset, "Neutral", "", "VIEW_ORTHO", 1),
804
+ (ExpressionPresets.AA.vrm0_preset, "A", "", "EVENT_A", 2),
805
+ (ExpressionPresets.IH.vrm0_preset, "I", "", "EVENT_I", 3),
806
+ (ExpressionPresets.OU.vrm0_preset, "U", "", "EVENT_U", 4),
807
+ (ExpressionPresets.EE.vrm0_preset, "E", "", "EVENT_E", 5),
808
+ (ExpressionPresets.OH.vrm0_preset, "O", "", "EVENT_O", 6),
809
+ (ExpressionPresets.BLINK.vrm0_preset, "Blink", "", "HIDE_ON", 7),
810
+ (ExpressionPresets.HAPPY.vrm0_preset, "Joy", "", "HEART", 8),
811
+ (ExpressionPresets.ANGRY.vrm0_preset, "Angry", "", "ORPHAN_DATA", 9),
812
+ (ExpressionPresets.SAD.vrm0_preset, "Sorrow", "", "MOD_FLUIDSIM", 10),
813
+ (ExpressionPresets.RELAXED.vrm0_preset, "Fun", "", "LIGHT_SUN", 11),
814
+ (ExpressionPresets.LOOK_UP.vrm0_preset, "Look Up", "", "ANCHOR_TOP", 12),
815
+ (ExpressionPresets.LOOK_DOWN.vrm0_preset, "Look Down", "", "ANCHOR_BOTTOM", 13),
816
+ (ExpressionPresets.LOOK_LEFT.vrm0_preset, "Look Left", "", "ANCHOR_RIGHT", 14),
817
+ (ExpressionPresets.LOOK_RIGHT.vrm0_preset, "Look Right", "", "ANCHOR_LEFT", 15),
818
+ (ExpressionPresets.BLINK_LEFT.vrm0_preset, "Blink_L", "", "HIDE_ON", 16),
819
+ (ExpressionPresets.BLINK_RIGHT.vrm0_preset, "Blink_R", "", "HIDE_ON", 17),
820
+ )
821
+
822
+ preset_name: EnumProperty( # type: ignore[valid-type]
823
+ items=preset_name_enum.items(),
824
+ name="Preset",
825
+ description="Preset name in VRM avatar",
826
+ )
827
+ binds: CollectionProperty( # type: ignore[valid-type]
828
+ type=Vrm0BlendShapeBindPropertyGroup,
829
+ name="Binds",
830
+ )
831
+ material_values: CollectionProperty( # type: ignore[valid-type]
832
+ type=Vrm0MaterialValueBindPropertyGroup,
833
+ name="Material Values",
834
+ )
835
+
836
+ # for UI
837
+ active_bind_index: IntProperty(min=0) # type: ignore[valid-type]
838
+ active_material_value_index: IntProperty(min=0) # type: ignore[valid-type]
839
+
840
+ def _get_preview(self) -> float:
841
+ value = self.get("preview")
842
+ if isinstance(value, (float, int)):
843
+ return float(value)
844
+ return 0.0
845
+
846
+ def _set_preview(self, value_obj: object) -> None:
847
+ context = bpy.context
848
+
849
+ value = convert.float_or_none(value_obj)
850
+ if value is None:
851
+ return
852
+
853
+ current_value = convert.float_or_none(self.get("preview"))
854
+ if (
855
+ current_value is not None
856
+ and abs(current_value - value) < float_info.epsilon
857
+ ):
858
+ return
859
+
860
+ self["preview"] = value
861
+
862
+ self._update_preview(context)
863
+
864
+ pending_preview_update_armature_data_names: ClassVar[list[str]] = []
865
+
866
+ def _update_preview(self, context: Context) -> None:
867
+ armature_data = self.id_data
868
+ if not isinstance(armature_data, Armature):
869
+ return
870
+
871
+ if defer_shape_key_update(context):
872
+ if (
873
+ armature_data.name
874
+ not in self.pending_preview_update_armature_data_names
875
+ ):
876
+ self.pending_preview_update_armature_data_names.append(
877
+ armature_data.name
878
+ )
879
+ return
880
+
881
+ self.apply_previews(context, armature_data)
882
+
883
+ @classmethod
884
+ def apply_pending_preview_update_to_armatures(cls, context: Context) -> None:
885
+ for armature_data_name in cls.pending_preview_update_armature_data_names:
886
+ armature_data = context.blend_data.armatures.get(armature_data_name)
887
+ if not armature_data:
888
+ continue
889
+ cls.apply_previews(context, armature_data)
890
+ cls.pending_preview_update_armature_data_names.clear()
891
+
892
+ @classmethod
893
+ def get_texture_info(
894
+ cls,
895
+ gltf: Mtoon1MaterialPropertyGroup,
896
+ target: MaterialPropertyTarget,
897
+ ) -> Optional[Mtoon1TextureInfoPropertyGroup]:
898
+ mtoon = gltf.extensions.vrmc_materials_mtoon
899
+ if target == MaterialPropertyTarget.MAIN_TEX:
900
+ return gltf.pbr_metallic_roughness.base_color_texture
901
+ if target == MaterialPropertyTarget.SHADE_TEXTURE:
902
+ return mtoon.shade_multiply_texture
903
+ if target == MaterialPropertyTarget.BUMP_MAP:
904
+ return gltf.normal_texture
905
+ if target == MaterialPropertyTarget.RIM_TEXTURE:
906
+ return mtoon.rim_multiply_texture
907
+ if target == MaterialPropertyTarget.SPHERE_ADD:
908
+ return mtoon.matcap_texture
909
+ if target == MaterialPropertyTarget.EMISSION_MAP:
910
+ return gltf.emissive_texture
911
+ if target == MaterialPropertyTarget.OUTLINE_WIDTH_TEXTURE:
912
+ return mtoon.outline_width_multiply_texture
913
+ if target == MaterialPropertyTarget.UV_ANIM_MASK_TEXTURE:
914
+ return mtoon.uv_animation_mask_texture
915
+ return None
916
+
917
+ @classmethod
918
+ def get_material_property_vector(
919
+ cls, material: Material, material_value: Vrm0MaterialValueBindPropertyGroup
920
+ ) -> Optional[
921
+ tuple[tuple[float, float, float, float], tuple[float, float, float, float]]
922
+ ]:
923
+ gltf = get_material_extension(material).mtoon1
924
+ if not gltf.enabled:
925
+ return None
926
+ mtoon = gltf.extensions.vrmc_materials_mtoon
927
+ target_vector = material_value.read_target_value_as_float_list()
928
+ property_name = material_value.property_name
929
+ if not property_name:
930
+ return None
931
+ material_property = MTOON0_PROPERTIES.get(property_name)
932
+ if not material_property:
933
+ return None
934
+
935
+ if len(target_vector) != 4:
936
+ return None
937
+ target_vector = (
938
+ target_vector[0],
939
+ target_vector[1],
940
+ target_vector[2],
941
+ target_vector[3],
942
+ )
943
+
944
+ target = material_property.target
945
+ if target is None:
946
+ return None
947
+
948
+ if target == MaterialPropertyTarget.COLOR:
949
+ default_vector = convert.float4_or(
950
+ gltf.pbr_metallic_roughness.base_color_factor,
951
+ (
952
+ *shader.OUTPUT_GROUP_BASE_COLOR_FACTOR_COLOR_DEFAULT,
953
+ shader.OUTPUT_GROUP_BASE_COLOR_FACTOR_ALPHA_DEFAULT,
954
+ ),
955
+ )
956
+ return (target_vector, default_vector)
957
+ if target == MaterialPropertyTarget.SHADE_COLOR:
958
+ default_vector = (
959
+ *convert.float3_or(
960
+ mtoon.shade_color_factor,
961
+ shader.OUTPUT_GROUP_SHADE_COLOR_FACTOR_DEFAULT,
962
+ ),
963
+ 1.0,
964
+ )
965
+ return (target_vector, default_vector)
966
+ if target == MaterialPropertyTarget.RIM_COLOR:
967
+ default_vector = (
968
+ *convert.float3_or(
969
+ mtoon.parametric_rim_color_factor,
970
+ shader.OUTPUT_GROUP_PARAMETRIC_RIM_COLOR_FACTOR_DEFAULT,
971
+ ),
972
+ 1.0,
973
+ )
974
+ return (target_vector, default_vector)
975
+ if target == MaterialPropertyTarget.EMISSION_COLOR:
976
+ default_vector = (
977
+ *convert.float3_or(
978
+ gltf.emissive_factor,
979
+ shader.OUTPUT_GROUP_EMISSIVE_FACTOR_DEFAULT,
980
+ ),
981
+ 1.0,
982
+ )
983
+ return (target_vector, default_vector)
984
+ if target == MaterialPropertyTarget.OUTLINE_COLOR:
985
+ default_vector = (
986
+ *convert.float3_or(
987
+ mtoon.outline_color_factor,
988
+ shader.OUTPUT_GROUP_OUTLINE_COLOR_FACTOR_DEFAULT,
989
+ ),
990
+ 1.0,
991
+ )
992
+ return (target_vector, default_vector)
993
+
994
+ texture_info = cls.get_texture_info(gltf, target)
995
+ if not texture_info:
996
+ return None
997
+ khr_texture_transform = texture_info.extensions.khr_texture_transform
998
+ khr_scale_u = khr_texture_transform.scale[0]
999
+ khr_scale_v = khr_texture_transform.scale[1]
1000
+ khr_offset_u = khr_texture_transform.offset[0]
1001
+ khr_offset_v = khr_texture_transform.offset[1]
1002
+ if material_property.type == MaterialPropertyType.UV:
1003
+ unity_scale_u, unity_scale_v, unity_offset_u, unity_offset_v = target_vector
1004
+ target_vector = (
1005
+ unity_scale_u,
1006
+ unity_scale_v,
1007
+ unity_offset_u,
1008
+ # https://github.com/vrm-c/UniVRM/issues/930
1009
+ 1 - unity_offset_v - unity_scale_v,
1010
+ )
1011
+ elif material_property.type == MaterialPropertyType.UV_S:
1012
+ unity_scale_u, _, unity_offset_u, _ = target_vector
1013
+ target_vector = (
1014
+ unity_scale_u,
1015
+ khr_scale_v,
1016
+ unity_offset_u,
1017
+ khr_offset_v, # No need to change offset
1018
+ )
1019
+ elif material_property.type == MaterialPropertyType.UV_T:
1020
+ _, unity_scale_v, _, unity_offset_v = target_vector
1021
+ target_vector = (
1022
+ khr_scale_u,
1023
+ unity_scale_v,
1024
+ khr_offset_u,
1025
+ # https://github.com/vrm-c/UniVRM/issues/930
1026
+ 1 - unity_offset_v - unity_scale_v,
1027
+ )
1028
+ else:
1029
+ return None
1030
+
1031
+ return (
1032
+ target_vector,
1033
+ (
1034
+ khr_scale_u,
1035
+ khr_scale_v,
1036
+ khr_offset_u,
1037
+ khr_offset_v,
1038
+ ),
1039
+ )
1040
+
1041
+ @classmethod
1042
+ def set_material_property_vector_to_expression(
1043
+ cls,
1044
+ material: Material,
1045
+ target: MaterialPropertyTarget,
1046
+ vector: Vector,
1047
+ ) -> None:
1048
+ mtoon1 = get_material_extension(material).mtoon1
1049
+
1050
+ if target == MaterialPropertyTarget.COLOR:
1051
+ mtoon1.set_vector3(
1052
+ shader.OUTPUT_GROUP_NAME,
1053
+ shader.OUTPUT_GROUP_EXPRESSION_COLOR_BIND_LABEL,
1054
+ vector.xyz,
1055
+ )
1056
+ mtoon1.set_value(
1057
+ shader.OUTPUT_GROUP_NAME,
1058
+ shader.OUTPUT_GROUP_EXPRESSION_COLOR_ALPHA_BIND_LABEL,
1059
+ vector.w,
1060
+ )
1061
+ return
1062
+ if target == MaterialPropertyTarget.SHADE_COLOR:
1063
+ mtoon1.set_vector3(
1064
+ shader.OUTPUT_GROUP_NAME,
1065
+ shader.OUTPUT_GROUP_EXPRESSION_SHADE_COLOR_BIND_LABEL,
1066
+ vector.xyz,
1067
+ )
1068
+ return
1069
+ if target == MaterialPropertyTarget.RIM_COLOR:
1070
+ mtoon1.set_vector3(
1071
+ shader.OUTPUT_GROUP_NAME,
1072
+ shader.OUTPUT_GROUP_EXPRESSION_RIM_COLOR_BIND_LABEL,
1073
+ vector.xyz,
1074
+ )
1075
+ return
1076
+ if target == MaterialPropertyTarget.EMISSION_COLOR:
1077
+ mtoon1.set_vector3(
1078
+ shader.OUTPUT_GROUP_NAME,
1079
+ shader.OUTPUT_GROUP_EXPRESSION_EMISSION_COLOR_BIND_LABEL,
1080
+ vector.xyz,
1081
+ )
1082
+ return
1083
+ if target == MaterialPropertyTarget.OUTLINE_COLOR:
1084
+ mtoon1.set_vector3(
1085
+ shader.OUTPUT_GROUP_NAME,
1086
+ shader.OUTPUT_GROUP_EXPRESSION_OUTLINE_COLOR_BIND_LABEL,
1087
+ vector.xyz,
1088
+ )
1089
+ return
1090
+
1091
+ texture_info = cls.get_texture_info(mtoon1, target)
1092
+ if not texture_info:
1093
+ return
1094
+ khr_texture_transform = texture_info.extensions.khr_texture_transform
1095
+ khr_texture_transform.set_texture_uv(
1096
+ shader.UV_GROUP_EXPRESSION_UV_SCALE_BIND_LABEL,
1097
+ vector.xy,
1098
+ )
1099
+ khr_texture_transform.set_texture_uv(
1100
+ shader.UV_GROUP_EXPRESSION_UV_OFFSET_BIND_LABEL,
1101
+ vector.zw,
1102
+ )
1103
+
1104
+ @classmethod
1105
+ def apply_previews(cls, context: Context, armature_data: Armature) -> None:
1106
+ mesh_object_name_to_key_block_name_to_value: dict[str, dict[str, float]] = {}
1107
+ blend_shape_groups = get_armature_extension(
1108
+ armature_data
1109
+ ).vrm0.blend_shape_master.blend_shape_groups
1110
+ material_name_to_target_to_vector: dict[
1111
+ str, dict[MaterialPropertyTarget, Vector]
1112
+ ] = {}
1113
+ for blend_shape_group in blend_shape_groups:
1114
+ if blend_shape_group.is_binary:
1115
+ # https://github.com/vrm-c/UniVRM/blob/a4711bbf8c4d10659d3e5568c2e3d7d595005e51/Packages/VRM/Runtime/BlendShape/BlendShapeMerger.cs#L89-L92
1116
+ # https://docs.unity3d.com/6000.3/Documentation/ScriptReference/Mathf.Round.html
1117
+ preview = round(blend_shape_group.preview)
1118
+ else:
1119
+ preview = blend_shape_group.preview
1120
+
1121
+ for material_value in blend_shape_group.material_values:
1122
+ material = material_value.material
1123
+ if not material:
1124
+ continue
1125
+ vectors = cls.get_material_property_vector(material, material_value)
1126
+ if not vectors:
1127
+ continue
1128
+ property_name = material_value.property_name
1129
+ if not property_name:
1130
+ continue
1131
+ material_property = MTOON0_PROPERTIES.get(property_name)
1132
+ if not material_property:
1133
+ continue
1134
+ target = material_property.target
1135
+ if not target:
1136
+ continue
1137
+ target_vector, default_vector = vectors
1138
+ target_to_vector = material_name_to_target_to_vector.get(material.name)
1139
+ if target_to_vector is None:
1140
+ target_to_vector = {}
1141
+ material_name_to_target_to_vector[material.name] = target_to_vector
1142
+ current_vector = target_to_vector.get(target)
1143
+ if current_vector is None:
1144
+ current_vector = (
1145
+ Vector(target_vector) - Vector(default_vector)
1146
+ ) * preview
1147
+ else:
1148
+ current_vector = (
1149
+ current_vector
1150
+ + (Vector(target_vector) - Vector(default_vector)) * preview
1151
+ )
1152
+ target_to_vector[target] = current_vector
1153
+
1154
+ for bind in blend_shape_group.binds:
1155
+ mesh_object_name = bind.mesh.mesh_object_name
1156
+ key_block_name = bind.index
1157
+ value = bind.weight * preview # Lerp 0.0 * (1 - a) + weight * a
1158
+ key_block_name_to_value = (
1159
+ mesh_object_name_to_key_block_name_to_value.get(mesh_object_name)
1160
+ )
1161
+ if not key_block_name_to_value:
1162
+ mesh_object_name_to_key_block_name_to_value[mesh_object_name] = {
1163
+ key_block_name: value
1164
+ }
1165
+ continue
1166
+ key_block_name_to_value[key_block_name] = (
1167
+ key_block_name_to_value.get(key_block_name, 0) + value
1168
+ )
1169
+
1170
+ for (
1171
+ material_name,
1172
+ target_to_vector,
1173
+ ) in material_name_to_target_to_vector.items():
1174
+ material = context.blend_data.materials.get(material_name)
1175
+ if not material:
1176
+ continue
1177
+ for target, vector in target_to_vector.items():
1178
+ cls.set_material_property_vector_to_expression(material, target, vector)
1179
+
1180
+ mesh_data_name_to_key_block_name_to_total_value: dict[
1181
+ str, dict[str, float]
1182
+ ] = {}
1183
+ for (
1184
+ mesh_object_name,
1185
+ key_block_name_to_value,
1186
+ ) in mesh_object_name_to_key_block_name_to_value.items():
1187
+ mesh_object = context.blend_data.objects.get(mesh_object_name)
1188
+ if not mesh_object:
1189
+ continue
1190
+ mesh_data = mesh_object.data
1191
+ if not isinstance(mesh_data, Mesh):
1192
+ continue
1193
+ key_block_name_to_total_value = (
1194
+ mesh_data_name_to_key_block_name_to_total_value.get(mesh_data.name)
1195
+ )
1196
+ if not key_block_name_to_total_value:
1197
+ mesh_data_name_to_key_block_name_to_total_value[mesh_data.name] = (
1198
+ key_block_name_to_value
1199
+ )
1200
+ continue
1201
+ for key_block_name, value in key_block_name_to_value.items():
1202
+ key_block_name_to_total_value[key_block_name] = (
1203
+ key_block_name_to_total_value.get(key_block_name, 0) + value
1204
+ )
1205
+
1206
+ for (
1207
+ mesh_data_name,
1208
+ key_block_name_to_value,
1209
+ ) in mesh_data_name_to_key_block_name_to_total_value.items():
1210
+ mesh_data = context.blend_data.meshes.get(mesh_data_name)
1211
+ if not mesh_data:
1212
+ continue
1213
+ shape_keys = mesh_data.shape_keys
1214
+ if not shape_keys:
1215
+ continue
1216
+ key_blocks = shape_keys.key_blocks
1217
+ if not key_blocks:
1218
+ continue
1219
+ for key_block_name, value in key_block_name_to_value.items():
1220
+ key_block = key_blocks.get(key_block_name)
1221
+ if not key_block:
1222
+ continue
1223
+ if abs(key_block.value - value) < float_info.epsilon:
1224
+ continue
1225
+ key_block.value = value
1226
+
1227
+ preview: FloatProperty( # type: ignore[valid-type]
1228
+ name="Blend Shape Proxy",
1229
+ min=0,
1230
+ max=1,
1231
+ subtype="FACTOR",
1232
+ get=_get_preview,
1233
+ set=_set_preview,
1234
+ )
1235
+
1236
+ is_binary: BoolProperty( # type: ignore[valid-type]
1237
+ name="Is Binary",
1238
+ description="Use binary change in the blendshape group",
1239
+ update=_update_preview,
1240
+ )
1241
+
1242
+ if TYPE_CHECKING:
1243
+ # This code is auto generated.
1244
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1245
+ name: str # type: ignore[no-redef]
1246
+ preset_name: str # type: ignore[no-redef]
1247
+ binds: CollectionPropertyProtocol[ # type: ignore[no-redef]
1248
+ Vrm0BlendShapeBindPropertyGroup
1249
+ ]
1250
+ material_values: CollectionPropertyProtocol[ # type: ignore[no-redef]
1251
+ Vrm0MaterialValueBindPropertyGroup
1252
+ ]
1253
+ active_bind_index: int # type: ignore[no-redef]
1254
+ active_material_value_index: int # type: ignore[no-redef]
1255
+ preview: float # type: ignore[no-redef]
1256
+ is_binary: bool # type: ignore[no-redef]
1257
+
1258
+
1259
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_SecondaryAnimation.cs#L10-L18
1260
+ class Vrm0SecondaryAnimationColliderPropertyGroup(PropertyGroup):
1261
+ bpy_object: PointerProperty( # type: ignore[valid-type]
1262
+ type=Object
1263
+ )
1264
+
1265
+ def fixup(self, armature: Optional[Object], bone_name: str) -> None:
1266
+ bpy_object = self.bpy_object
1267
+ if not bpy_object or not bpy_object.name:
1268
+ return
1269
+
1270
+ if armature and bpy_object.parent != armature:
1271
+ _logger.warning(
1272
+ "Collider %s is not parented to the armature."
1273
+ " Parenting to the armature %s.",
1274
+ self.path_from_id(),
1275
+ armature.name,
1276
+ )
1277
+ bpy_object.parent = armature
1278
+
1279
+ if bpy_object.empty_display_type != "SPHERE":
1280
+ _logger.warning(
1281
+ "Collider %s has empty display type %s. Setting to SPHERE.",
1282
+ self.path_from_id(),
1283
+ bpy_object.empty_display_type,
1284
+ )
1285
+ bpy_object.empty_display_type = "SPHERE"
1286
+
1287
+ parent_obj = bpy_object.parent
1288
+ if not parent_obj:
1289
+ return
1290
+
1291
+ if parent_obj.type != "ARMATURE" or not bone_name:
1292
+ if bpy_object.parent_type != "OBJECT":
1293
+ _logger.warning(
1294
+ "Collider %s is parented to a bone but no bone is assigned."
1295
+ " Changing to object parenting.",
1296
+ self.path_from_id(),
1297
+ )
1298
+ bpy_object.parent_type = "OBJECT"
1299
+ if bpy_object.parent_bone:
1300
+ _logger.warning(
1301
+ "Collider %s has a stale parent bone %s while using object"
1302
+ " parenting. Clearing the parent bone.",
1303
+ self.path_from_id(),
1304
+ bpy_object.parent_bone,
1305
+ )
1306
+ bpy_object.parent_bone = ""
1307
+ return
1308
+
1309
+ if bpy_object.parent_type != "BONE":
1310
+ _logger.warning(
1311
+ "Collider %s is not parented to a bone. Parenting to the bone %s.",
1312
+ self.path_from_id(),
1313
+ bone_name,
1314
+ )
1315
+ bpy_object.parent_type = "BONE"
1316
+
1317
+ if bpy_object.parent_bone != bone_name:
1318
+ _logger.warning(
1319
+ "Collider %s is parented to a different bone %s."
1320
+ " Changing to the bone %s.",
1321
+ self.path_from_id(),
1322
+ bpy_object.parent_bone,
1323
+ bone_name,
1324
+ )
1325
+ bpy_object.parent_bone = bone_name
1326
+
1327
+ if TYPE_CHECKING:
1328
+ # This code is auto generated.
1329
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1330
+ bpy_object: Optional[Object] # type: ignore[no-redef]
1331
+
1332
+
1333
+ # https://github.com/vrm-c/vrm-specification/blob/f2d8f158297fc883aef9c3071ca68fbe46b03f45/specification/0.0/schema/vrm.secondaryanimation.collidergroup.schema.json
1334
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_SecondaryAnimation.cs#L21-L29
1335
+ class Vrm0SecondaryAnimationColliderGroupPropertyGroup(PropertyGroup):
1336
+ node: PointerProperty( # type: ignore[valid-type]
1337
+ name="Bone",
1338
+ type=BonePropertyGroup,
1339
+ )
1340
+ # Use the collider's own data for offset and radius
1341
+ colliders: CollectionProperty( # type: ignore[valid-type]
1342
+ name="Colliders",
1343
+ type=Vrm0SecondaryAnimationColliderPropertyGroup,
1344
+ )
1345
+
1346
+ @property
1347
+ def display_name(self) -> str:
1348
+ if not self.uuid:
1349
+ return ""
1350
+ return f"{self.node.bone_name}#{self.uuid}"
1351
+
1352
+ def fixup(self, armature: Optional[Object]) -> None:
1353
+ if not self.uuid:
1354
+ new_uuid = uuid.uuid4().hex
1355
+ _logger.error(
1356
+ "Collider group %s has no UUID. Assigning a new UUID %s.",
1357
+ self.path_from_id(),
1358
+ new_uuid,
1359
+ )
1360
+ self.uuid = new_uuid
1361
+
1362
+ for index, collider in reversed(
1363
+ tuple((index, collider) for index, collider in enumerate(self.colliders))
1364
+ ):
1365
+ if not collider.bpy_object or not collider.bpy_object.name:
1366
+ _logger.warning(
1367
+ "Collider %s in group %s has no valid object. Removing.",
1368
+ collider.path_from_id(),
1369
+ self.display_name,
1370
+ )
1371
+ self.colliders.remove(index)
1372
+ else:
1373
+ collider.fixup(armature, self.node.bone_name)
1374
+
1375
+ armature_data = self.id_data
1376
+ if not isinstance(armature_data, Armature):
1377
+ return
1378
+
1379
+ vrm0 = get_armature_extension(armature_data).vrm0
1380
+ for bone_group in vrm0.secondary_animation.bone_groups:
1381
+ bone_group.fixup()
1382
+
1383
+ # for UI
1384
+ show_expanded: BoolProperty() # type: ignore[valid-type]
1385
+
1386
+ active_collider_index: IntProperty(min=0) # type: ignore[valid-type]
1387
+
1388
+ # for reference from Vrm0SecondaryAnimationGroupPropertyGroup
1389
+ uuid: StringProperty() # type: ignore[valid-type]
1390
+
1391
+ if TYPE_CHECKING:
1392
+ # This code is auto generated.
1393
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1394
+ node: BonePropertyGroup # type: ignore[no-redef]
1395
+ colliders: CollectionPropertyProtocol[ # type: ignore[no-redef]
1396
+ Vrm0SecondaryAnimationColliderPropertyGroup
1397
+ ]
1398
+ show_expanded: bool # type: ignore[no-redef]
1399
+ active_collider_index: int # type: ignore[no-redef]
1400
+ uuid: str # type: ignore[no-redef]
1401
+
1402
+
1403
+ class Vrm0SecondaryAnimationColliderGroupReferencePropertyGroup(PropertyGroup):
1404
+ @property
1405
+ def collider_group_display_name(self) -> str:
1406
+ armature_data = self.id_data
1407
+ if not isinstance(armature_data, Armature):
1408
+ return ""
1409
+ if not self.collider_group_uuid:
1410
+ return ""
1411
+
1412
+ secondary_animation = get_armature_extension(
1413
+ armature_data
1414
+ ).vrm0.secondary_animation
1415
+ for collider_group in secondary_animation.collider_groups:
1416
+ if collider_group.uuid == self.collider_group_uuid:
1417
+ return collider_group.display_name
1418
+ return ""
1419
+
1420
+ def _update_collider_group_uuid(self, _context: Context) -> None:
1421
+ if not self.collider_group_uuid:
1422
+ return
1423
+
1424
+ armature_data = self.id_data
1425
+ if not isinstance(armature_data, Armature):
1426
+ return
1427
+
1428
+ vrm0 = get_armature_extension(armature_data).vrm0
1429
+ secondary_animation = vrm0.secondary_animation
1430
+ for collider_group in secondary_animation.collider_groups:
1431
+ if self.collider_group_uuid == collider_group.uuid:
1432
+ return
1433
+
1434
+ self.collider_group_uuid = ""
1435
+
1436
+ collider_group_uuid: StringProperty(update=_update_collider_group_uuid) # type: ignore[valid-type]
1437
+
1438
+ if TYPE_CHECKING:
1439
+ # This code is auto generated.
1440
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1441
+ collider_group_uuid: str # type: ignore[no-redef]
1442
+
1443
+
1444
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_SecondaryAnimation.cs#L32-L67
1445
+ class Vrm0SecondaryAnimationGroupPropertyGroup(PropertyGroup):
1446
+ comment: StringProperty( # type: ignore[valid-type]
1447
+ name="Comment",
1448
+ description="Comment about the purpose of springs",
1449
+ )
1450
+
1451
+ # typo in VRM 0.0 specification
1452
+ # https://github.com/vrm-c/vrm-specification/blob/1723a45abfb4f12ac5d3635a3f66dc45e2f93c83/specification/0.0/schema/vrm.secondaryanimation.spring.schema.json#L9-L12
1453
+ stiffiness: FloatProperty( # type: ignore[valid-type]
1454
+ name="Stiffness",
1455
+ min=0.0,
1456
+ soft_max=4.0,
1457
+ subtype="FACTOR",
1458
+ description="Stiffness of springs",
1459
+ )
1460
+
1461
+ gravity_power: FloatProperty( # type: ignore[valid-type]
1462
+ name="Gravity Power",
1463
+ min=0.0,
1464
+ soft_max=2.0,
1465
+ subtype="FACTOR",
1466
+ description="Gravity power of springs",
1467
+ )
1468
+
1469
+ def _update_gravity_dir(self, _context: Context) -> None:
1470
+ gravity_dir = Vector(self.gravity_dir)
1471
+ normalized_gravity_dir = gravity_dir.normalized()
1472
+ if (gravity_dir - normalized_gravity_dir).length > 0.0001:
1473
+ self.gravity_dir = normalized_gravity_dir
1474
+
1475
+ gravity_dir: FloatVectorProperty( # type: ignore[valid-type]
1476
+ size=3,
1477
+ min=-1,
1478
+ max=1,
1479
+ subtype="XYZ",
1480
+ name="Gravity Direction",
1481
+ description="Gravity direction of springs",
1482
+ update=_update_gravity_dir,
1483
+ )
1484
+ drag_force: FloatProperty( # type: ignore[valid-type]
1485
+ name="Drag Force",
1486
+ min=0.0,
1487
+ max=1.0,
1488
+ subtype="FACTOR",
1489
+ description="Drag Force of springs",
1490
+ )
1491
+ center: PointerProperty( # type: ignore[valid-type]
1492
+ name="Center",
1493
+ type=BonePropertyGroup,
1494
+ description="Origin of Physics simulation to stop springs on moving",
1495
+ )
1496
+ hit_radius: FloatProperty( # type: ignore[valid-type]
1497
+ name="Hit Radius",
1498
+ min=0.0,
1499
+ soft_max=0.5,
1500
+ subtype="DISTANCE",
1501
+ description="Hit Radius of springs",
1502
+ )
1503
+ bones: CollectionProperty( # type: ignore[valid-type]
1504
+ name="Bones",
1505
+ type=BonePropertyGroup,
1506
+ description="Bones of the spring roots",
1507
+ )
1508
+ collider_groups: CollectionProperty( # type: ignore[valid-type]
1509
+ name="Collider Group",
1510
+ type=Vrm0SecondaryAnimationColliderGroupReferencePropertyGroup,
1511
+ description="Enabled collider Groups of springs",
1512
+ )
1513
+
1514
+ # for UI
1515
+ show_expanded: BoolProperty() # type: ignore[valid-type]
1516
+ show_expanded_bones: BoolProperty( # type: ignore[valid-type]
1517
+ name="Bones"
1518
+ )
1519
+ show_expanded_collider_groups: BoolProperty( # type: ignore[valid-type]
1520
+ name="Collider Groups"
1521
+ )
1522
+
1523
+ active_bone_index: IntProperty(min=0) # type: ignore[valid-type]
1524
+ active_collider_group_index: IntProperty(min=0) # type: ignore[valid-type]
1525
+
1526
+ def fixup(self) -> None:
1527
+ armature_data = self.id_data
1528
+ if not isinstance(armature_data, Armature):
1529
+ return
1530
+ ext = get_armature_extension(armature_data)
1531
+ collider_group_uuids = {
1532
+ collider_group.uuid
1533
+ for collider_group in ext.vrm0.secondary_animation.collider_groups
1534
+ }
1535
+ for collider_group_reference in self.collider_groups:
1536
+ collider_group_uuid = collider_group_reference.collider_group_uuid
1537
+ if not collider_group_uuid:
1538
+ continue
1539
+ if collider_group_uuid in collider_group_uuids:
1540
+ collider_group_uuids.remove(collider_group_uuid)
1541
+ continue
1542
+ _logger.error(
1543
+ 'Collider group with uuid "%s" not found or duplicated for'
1544
+ ' "%s". Clearing UUID.',
1545
+ collider_group_uuid,
1546
+ collider_group_reference.path_from_id(),
1547
+ )
1548
+ collider_group_reference.collider_group_uuid = ""
1549
+
1550
+ if TYPE_CHECKING:
1551
+ # This code is auto generated.
1552
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1553
+ comment: str # type: ignore[no-redef]
1554
+ stiffiness: float # type: ignore[no-redef]
1555
+ gravity_power: float # type: ignore[no-redef]
1556
+ gravity_dir: Sequence[float] # type: ignore[no-redef]
1557
+ drag_force: float # type: ignore[no-redef]
1558
+ center: BonePropertyGroup # type: ignore[no-redef]
1559
+ hit_radius: float # type: ignore[no-redef]
1560
+ bones: CollectionPropertyProtocol[ # type: ignore[no-redef]
1561
+ BonePropertyGroup
1562
+ ]
1563
+ collider_groups: CollectionPropertyProtocol[ # type: ignore[no-redef]
1564
+ Vrm0SecondaryAnimationColliderGroupReferencePropertyGroup
1565
+ ]
1566
+ show_expanded: bool # type: ignore[no-redef]
1567
+ show_expanded_bones: bool # type: ignore[no-redef]
1568
+ show_expanded_collider_groups: bool # type: ignore[no-redef]
1569
+ active_bone_index: int # type: ignore[no-redef]
1570
+ active_collider_group_index: int # type: ignore[no-redef]
1571
+
1572
+
1573
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_Meta.cs#L33-L149
1574
+ class Vrm0MetaPropertyGroup(PropertyGroup):
1575
+ allowed_user_name_enum, __allowed_user_names = property_group_enum(
1576
+ ("OnlyAuthor", "Only Author", "", "NONE", 0),
1577
+ ("ExplicitlyLicensedPerson", "Explicitly Licensed Person", "", "NONE", 1),
1578
+ ("Everyone", "Everyone", "", "NONE", 2),
1579
+ )
1580
+
1581
+ violent_ussage_name_enum, __violent_ussage_names = property_group_enum(
1582
+ ("Disallow", "Disallow", "", "NONE", 0),
1583
+ ("Allow", "Allow", "", "NONE", 1),
1584
+ )
1585
+
1586
+ sexual_ussage_name_enum, __sexual_ussage_names = property_group_enum(
1587
+ ("Disallow", "Disallow", "", "NONE", 0),
1588
+ ("Allow", "Allow", "", "NONE", 1),
1589
+ )
1590
+
1591
+ commercial_ussage_name_enum, __commercial_ussage_names = property_group_enum(
1592
+ ("Disallow", "Disallow", "", "NONE", 0),
1593
+ ("Allow", "Allow", "", "NONE", 1),
1594
+ )
1595
+
1596
+ (
1597
+ license_name_enum,
1598
+ (
1599
+ LICENSE_NAME_REDISTRIBUTION_PROHIBITED,
1600
+ LICENSE_NAME_CC0,
1601
+ LICENSE_NAME_CC_BY,
1602
+ LICENSE_NAME_CC_BY_NC,
1603
+ LICENSE_NAME_CC_BY_SA,
1604
+ LICENSE_NAME_CC_BY_NC_SA,
1605
+ LICENSE_NAME_CC_BY_ND,
1606
+ LICENSE_NAME_CC_BY_NC_ND,
1607
+ LICENSE_NAME_OTHER,
1608
+ ),
1609
+ ) = property_group_enum(
1610
+ ("Redistribution_Prohibited", "Redistribution Prohibited", "", "NONE", 0),
1611
+ ("CC0", "CC0", "", "NONE", 1),
1612
+ ("CC_BY", "CC BY", "", "NONE", 2),
1613
+ ("CC_BY_NC", "CC BY NC", "", "NONE", 3),
1614
+ ("CC_BY_SA", "CC BY SA", "", "NONE", 4),
1615
+ ("CC_BY_NC_SA", "CC BY NC SA", "", "NONE", 5),
1616
+ ("CC_BY_ND", "CC BY ND", "", "NONE", 6), # codespell:ignore nd
1617
+ ("CC_BY_NC_ND", "CC BY NC ND", "", "NONE", 7), # codespell:ignore nd
1618
+ ("Other", "Other", "", "NONE", 8),
1619
+ )
1620
+
1621
+ title: StringProperty( # type: ignore[valid-type]
1622
+ name="Title",
1623
+ description="Title of the avatar",
1624
+ )
1625
+ version: StringProperty( # type: ignore[valid-type]
1626
+ name="Version",
1627
+ description="Version of the avatar",
1628
+ )
1629
+ author: StringProperty( # type: ignore[valid-type]
1630
+ name="Author",
1631
+ description="Author of the avatar",
1632
+ )
1633
+ contact_information: StringProperty( # type: ignore[valid-type]
1634
+ name="Contact Information",
1635
+ description="Contact Information about the avatar",
1636
+ )
1637
+ reference: StringProperty( # type: ignore[valid-type]
1638
+ name="Reference",
1639
+ description="Referenced works about the avatar",
1640
+ )
1641
+ allowed_user_name: EnumProperty( # type: ignore[valid-type]
1642
+ items=allowed_user_name_enum.items(),
1643
+ name="Allowed User",
1644
+ description="Allowed user of the avatar",
1645
+ )
1646
+ violent_ussage_name: EnumProperty( # type: ignore[valid-type]
1647
+ items=violent_ussage_name_enum.items(),
1648
+ name="Violent Usage",
1649
+ description="Violent usage of the avatar",
1650
+ )
1651
+ sexual_ussage_name: EnumProperty( # type: ignore[valid-type]
1652
+ items=sexual_ussage_name_enum.items(),
1653
+ name="Sexual Usage",
1654
+ description="Sexual Usage of the avatar",
1655
+ )
1656
+ commercial_ussage_name: EnumProperty( # type: ignore[valid-type]
1657
+ items=commercial_ussage_name_enum.items(),
1658
+ name="Commercial Usage",
1659
+ description="Commercial Usage of the avatar",
1660
+ )
1661
+ other_permission_url: StringProperty( # type: ignore[valid-type]
1662
+ name="Other Permission URL",
1663
+ description="URL about other permissions of the avatar",
1664
+ )
1665
+ license_name: EnumProperty( # type: ignore[valid-type]
1666
+ items=license_name_enum.items(),
1667
+ name="License",
1668
+ description="License of the avatar",
1669
+ )
1670
+ other_license_url: StringProperty( # type: ignore[valid-type]
1671
+ name="Other License URL",
1672
+ description="URL about other License of the avatar",
1673
+ )
1674
+ texture: PointerProperty( # type: ignore[valid-type]
1675
+ name="Thumbnail",
1676
+ type=Image,
1677
+ description="Thumbnail of the avatar",
1678
+ )
1679
+
1680
+ if TYPE_CHECKING:
1681
+ # This code is auto generated.
1682
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1683
+ title: str # type: ignore[no-redef]
1684
+ version: str # type: ignore[no-redef]
1685
+ author: str # type: ignore[no-redef]
1686
+ contact_information: str # type: ignore[no-redef]
1687
+ reference: str # type: ignore[no-redef]
1688
+ allowed_user_name: str # type: ignore[no-redef]
1689
+ violent_ussage_name: str # type: ignore[no-redef]
1690
+ sexual_ussage_name: str # type: ignore[no-redef]
1691
+ commercial_ussage_name: str # type: ignore[no-redef]
1692
+ other_permission_url: str # type: ignore[no-redef]
1693
+ license_name: str # type: ignore[no-redef]
1694
+ other_license_url: str # type: ignore[no-redef]
1695
+ texture: Optional[Image] # type: ignore[no-redef]
1696
+
1697
+
1698
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_BlendShape.cs#L101-L106
1699
+ class Vrm0BlendShapeMasterPropertyGroup(PropertyGroup):
1700
+ blend_shape_groups: CollectionProperty( # type: ignore[valid-type]
1701
+ name="Blend Shape Group",
1702
+ type=Vrm0BlendShapeGroupPropertyGroup,
1703
+ )
1704
+
1705
+ def restore_blend_shape_group_bind_object_assignments(
1706
+ self, context: Context
1707
+ ) -> None:
1708
+ for blend_shape_group in self.blend_shape_groups:
1709
+ for bind in blend_shape_group.binds:
1710
+ bind.mesh.restore_object_assignment(context)
1711
+
1712
+ # for UI
1713
+ active_blend_shape_group_index: IntProperty(min=0) # type: ignore[valid-type]
1714
+
1715
+ if TYPE_CHECKING:
1716
+ # This code is auto generated.
1717
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1718
+ blend_shape_groups: CollectionPropertyProtocol[ # type: ignore[no-redef]
1719
+ Vrm0BlendShapeGroupPropertyGroup
1720
+ ]
1721
+ active_blend_shape_group_index: int # type: ignore[no-redef]
1722
+
1723
+
1724
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_SecondaryAnimation.cs#L69-L78
1725
+ class Vrm0SecondaryAnimationPropertyGroup(PropertyGroup):
1726
+ bone_groups: CollectionProperty( # type: ignore[valid-type]
1727
+ name="Secondary Animation Groups",
1728
+ type=Vrm0SecondaryAnimationGroupPropertyGroup,
1729
+ )
1730
+ collider_groups: CollectionProperty( # type: ignore[valid-type]
1731
+ name="Collider Groups",
1732
+ type=Vrm0SecondaryAnimationColliderGroupPropertyGroup,
1733
+ )
1734
+
1735
+ # for UI
1736
+ show_expanded_bone_groups: BoolProperty( # type: ignore[valid-type]
1737
+ name="Spring Bone Groups",
1738
+ )
1739
+ show_expanded_collider_groups: BoolProperty( # type: ignore[valid-type]
1740
+ name="Collider Groups",
1741
+ )
1742
+
1743
+ active_bone_group_index: IntProperty(min=0) # type: ignore[valid-type]
1744
+ active_collider_group_index: IntProperty(min=0) # type: ignore[valid-type]
1745
+
1746
+ def fixup(self, armature_object: Optional[Object]) -> None:
1747
+ found_uuids = set[str]()
1748
+ for collider_group in self.collider_groups:
1749
+ if collider_group.uuid and collider_group.uuid not in found_uuids:
1750
+ found_uuids.add(collider_group.uuid)
1751
+ continue
1752
+ new_uuid = uuid.uuid4().hex
1753
+ _logger.error(
1754
+ "Collider group %s in secondary animation has no UUID or duplicated"
1755
+ " UUID. Assigning a new UUID %s.",
1756
+ collider_group.path_from_id(),
1757
+ new_uuid,
1758
+ )
1759
+ collider_group.uuid = new_uuid
1760
+
1761
+ for collider_group in self.collider_groups:
1762
+ collider_group.fixup(armature_object)
1763
+
1764
+ for bone_group in self.bone_groups:
1765
+ bone_group.fixup()
1766
+
1767
+ if TYPE_CHECKING:
1768
+ # This code is auto generated.
1769
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1770
+ bone_groups: CollectionPropertyProtocol[ # type: ignore[no-redef]
1771
+ Vrm0SecondaryAnimationGroupPropertyGroup
1772
+ ]
1773
+ collider_groups: CollectionPropertyProtocol[ # type: ignore[no-redef]
1774
+ Vrm0SecondaryAnimationColliderGroupPropertyGroup
1775
+ ]
1776
+ show_expanded_bone_groups: bool # type: ignore[no-redef]
1777
+ show_expanded_collider_groups: bool # type: ignore[no-redef]
1778
+ active_bone_group_index: int # type: ignore[no-redef]
1779
+ active_collider_group_index: int # type: ignore[no-redef]
1780
+
1781
+
1782
+ # https://github.com/vrm-c/UniVRM/blob/v0.91.1/Assets/VRM/Runtime/Format/glTF_VRM_extensions.cs#L8-L48
1783
+ class Vrm0PropertyGroup(PropertyGroup):
1784
+ meta: PointerProperty( # type: ignore[valid-type]
1785
+ name="VRM Meta",
1786
+ type=Vrm0MetaPropertyGroup,
1787
+ )
1788
+ humanoid: PointerProperty( # type: ignore[valid-type]
1789
+ name="VRM Humanoid",
1790
+ type=Vrm0HumanoidPropertyGroup,
1791
+ )
1792
+ first_person: PointerProperty( # type: ignore[valid-type]
1793
+ name="VRM First Person",
1794
+ type=Vrm0FirstPersonPropertyGroup,
1795
+ )
1796
+ blend_shape_master: PointerProperty( # type: ignore[valid-type]
1797
+ name="VRM Blend Shape Master",
1798
+ type=Vrm0BlendShapeMasterPropertyGroup,
1799
+ )
1800
+ secondary_animation: PointerProperty( # type: ignore[valid-type]
1801
+ name="VRM Secondary Animation",
1802
+ type=Vrm0SecondaryAnimationPropertyGroup,
1803
+ )
1804
+ if TYPE_CHECKING:
1805
+ # This code is auto generated.
1806
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1807
+ meta: Vrm0MetaPropertyGroup # type: ignore[no-redef]
1808
+ humanoid: Vrm0HumanoidPropertyGroup # type: ignore[no-redef]
1809
+ first_person: Vrm0FirstPersonPropertyGroup # type: ignore[no-redef]
1810
+ blend_shape_master: Vrm0BlendShapeMasterPropertyGroup # type: ignore[no-redef]
1811
+ secondary_animation: ( # type: ignore[no-redef]
1812
+ Vrm0SecondaryAnimationPropertyGroup
1813
+ )
1814
+
1815
+
1816
+ def clear_global_variables() -> None:
1817
+ Vrm0HumanoidPropertyGroup.pointer_to_last_bone_names_str.clear()
1818
+ Vrm0BlendShapeGroupPropertyGroup.pending_preview_update_armature_data_names.clear()