@volter/blender-engine 0.1.147 → 0.1.149

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,761 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+ import contextlib
3
+ import json
4
+ import uuid
5
+ from typing import Optional
6
+
7
+ from bpy.types import ID, Armature, Context, Mesh, Object, Text
8
+
9
+ from ...common import convert
10
+ from ...common.convert import Json
11
+ from ...common.deep import make_json
12
+ from ...common.vrm0.human_bone import HumanBoneSpecifications
13
+ from ..extension_accessor import get_armature_extension, get_bone_extension
14
+ from ..property_group import BonePropertyGroup
15
+ from .ops import assign_vrm0_humanoid_human_bones_automatically
16
+ from .property_group import (
17
+ Vrm0BlendShapeMasterPropertyGroup,
18
+ Vrm0FirstPersonPropertyGroup,
19
+ Vrm0HumanoidPropertyGroup,
20
+ Vrm0MeshAnnotationPropertyGroup,
21
+ Vrm0MetaPropertyGroup,
22
+ Vrm0PropertyGroup,
23
+ Vrm0SecondaryAnimationPropertyGroup,
24
+ )
25
+
26
+
27
+ def _read_textblock_json(context: Context, armature: Object, armature_key: str) -> Json:
28
+ text_key = armature.get(armature_key)
29
+ if isinstance(text_key, Text):
30
+ textblock: Optional[Text] = text_key
31
+ elif not isinstance(text_key, str):
32
+ return None
33
+ else:
34
+ textblock = context.blend_data.texts.get(text_key)
35
+ if not isinstance(textblock, Text):
36
+ return None
37
+ textblock_str = "".join(line.body for line in textblock.lines)
38
+ with contextlib.suppress(json.JSONDecodeError):
39
+ return make_json(json.loads(textblock_str))
40
+ return None
41
+
42
+
43
+ def _migrate_vrm0_meta(
44
+ context: Context, meta: Vrm0MetaPropertyGroup, armature: Object
45
+ ) -> None:
46
+ allowed_user_name = armature.get("allowedUserName")
47
+ if (
48
+ isinstance(allowed_user_name, str)
49
+ and allowed_user_name
50
+ in Vrm0MetaPropertyGroup.allowed_user_name_enum.identifiers()
51
+ ):
52
+ meta.allowed_user_name = allowed_user_name
53
+
54
+ author = armature.get("author")
55
+ if isinstance(author, str):
56
+ meta.author = author
57
+
58
+ commercial_ussage_name = armature.get("commercialUssageName")
59
+ if (
60
+ isinstance(commercial_ussage_name, str)
61
+ and commercial_ussage_name
62
+ in Vrm0MetaPropertyGroup.commercial_ussage_name_enum.identifiers()
63
+ ):
64
+ meta.commercial_ussage_name = commercial_ussage_name
65
+
66
+ contact_information = armature.get("contactInformation")
67
+ if isinstance(contact_information, str):
68
+ meta.contact_information = contact_information
69
+
70
+ license_name = armature.get("licenseName")
71
+ if (
72
+ isinstance(license_name, str)
73
+ and license_name in Vrm0MetaPropertyGroup.license_name_enum.identifiers()
74
+ ):
75
+ meta.license_name = license_name
76
+
77
+ other_license_url = armature.get("otherLicenseUrl")
78
+ if isinstance(other_license_url, str):
79
+ meta.other_license_url = other_license_url
80
+
81
+ other_permission_url = armature.get("otherPermissionUrl")
82
+ if isinstance(other_permission_url, str):
83
+ meta.other_permission_url = other_permission_url
84
+
85
+ reference = armature.get("reference")
86
+ if isinstance(reference, str):
87
+ meta.reference = reference
88
+
89
+ sexual_ussage_name = armature.get("sexualUssageName")
90
+ if (
91
+ isinstance(sexual_ussage_name, str)
92
+ and sexual_ussage_name
93
+ in Vrm0MetaPropertyGroup.sexual_ussage_name_enum.identifiers()
94
+ ):
95
+ meta.sexual_ussage_name = sexual_ussage_name
96
+
97
+ title = armature.get("title")
98
+ if isinstance(title, str):
99
+ meta.title = title
100
+
101
+ version = armature.get("version")
102
+ if isinstance(version, str):
103
+ meta.version = version
104
+
105
+ violent_ussage_name = armature.get("violentUssageName")
106
+ if (
107
+ isinstance(violent_ussage_name, str)
108
+ and violent_ussage_name
109
+ in Vrm0MetaPropertyGroup.violent_ussage_name_enum.identifiers()
110
+ ):
111
+ meta.violent_ussage_name = violent_ussage_name
112
+
113
+ texture = armature.get("texture")
114
+ if isinstance(texture, str):
115
+ texture_image = context.blend_data.images.get(texture)
116
+ if texture_image:
117
+ meta.texture = texture_image
118
+
119
+
120
+ def _migrate_vrm0_humanoid(
121
+ humanoid: Vrm0HumanoidPropertyGroup, humanoid_dict: Json
122
+ ) -> None:
123
+ if not isinstance(humanoid_dict, dict):
124
+ return
125
+
126
+ arm_stretch = convert.float_or_none(humanoid_dict.get("armStretch"))
127
+ if arm_stretch is not None:
128
+ humanoid.arm_stretch = arm_stretch
129
+
130
+ leg_stretch = convert.float_or_none(humanoid_dict.get("legStretch"))
131
+ if leg_stretch is not None:
132
+ humanoid.leg_stretch = leg_stretch
133
+
134
+ upper_arm_twist = convert.float_or_none(humanoid_dict.get("upperArmTwist"))
135
+ if upper_arm_twist is not None:
136
+ humanoid.upper_arm_twist = upper_arm_twist
137
+
138
+ lower_arm_twist = convert.float_or_none(humanoid_dict.get("lowerArmTwist"))
139
+ if lower_arm_twist is not None:
140
+ humanoid.lower_arm_twist = lower_arm_twist
141
+
142
+ upper_leg_twist = convert.float_or_none(humanoid_dict.get("upperLegTwist"))
143
+ if upper_leg_twist is not None:
144
+ humanoid.upper_leg_twist = upper_leg_twist
145
+
146
+ lower_leg_twist = convert.float_or_none(humanoid_dict.get("lowerLegTwist"))
147
+ if lower_leg_twist is not None:
148
+ humanoid.lower_leg_twist = lower_leg_twist
149
+
150
+ feet_spacing = convert.float_or_none(humanoid_dict.get("feetSpacing"))
151
+ if feet_spacing is not None:
152
+ humanoid.feet_spacing = feet_spacing
153
+
154
+ has_translation_dof = humanoid_dict.get("hasTranslationDoF")
155
+ if isinstance(has_translation_dof, bool):
156
+ humanoid.has_translation_dof = has_translation_dof
157
+
158
+
159
+ def _migrate_vrm0_first_person(
160
+ context: Context,
161
+ first_person: Vrm0FirstPersonPropertyGroup,
162
+ first_person_dict: Json,
163
+ ) -> None:
164
+ if not isinstance(first_person_dict, dict):
165
+ return
166
+
167
+ first_person_bone = first_person_dict.get("firstPersonBone")
168
+ if isinstance(first_person_bone, str):
169
+ first_person.first_person_bone.bone_name = first_person_bone
170
+
171
+ first_person_bone_offset = convert.vrm_json_vector3_to_tuple(
172
+ first_person_dict.get("firstPersonBoneOffset")
173
+ )
174
+ if first_person_bone_offset is not None:
175
+ # Perform a special axis transformation for VRM 0.0.
176
+ # https://github.com/vrm-c/vrm-specification/issues/205#issuecomment-753582597
177
+ (x, y, z) = first_person_bone_offset
178
+ first_person.first_person_bone_offset = (x, z, y)
179
+
180
+ mesh_annotation_dicts = first_person_dict.get("meshAnnotations")
181
+ if isinstance(mesh_annotation_dicts, list):
182
+ for mesh_annotation_dict in mesh_annotation_dicts:
183
+ mesh_annotation = first_person.mesh_annotations.add()
184
+
185
+ if not isinstance(mesh_annotation_dict, dict):
186
+ continue
187
+
188
+ mesh = mesh_annotation_dict.get("mesh")
189
+ if isinstance(mesh, str):
190
+ if mesh in context.blend_data.meshes:
191
+ for obj in context.blend_data.objects:
192
+ if obj.data == context.blend_data.meshes[mesh]:
193
+ mesh_annotation.mesh.mesh_object_name = obj.name
194
+ break
195
+ elif (
196
+ mesh in context.blend_data.objects
197
+ and context.blend_data.objects[mesh].type == "MESH"
198
+ ):
199
+ mesh_annotation.mesh.mesh_object_name = context.blend_data.objects[
200
+ mesh
201
+ ].name
202
+
203
+ first_person_flag = mesh_annotation_dict.get("firstPersonFlag")
204
+ if (
205
+ isinstance(first_person_flag, str)
206
+ and first_person_flag
207
+ in Vrm0MeshAnnotationPropertyGroup.first_person_flag_enum.identifiers()
208
+ ):
209
+ mesh_annotation.first_person_flag = first_person_flag
210
+
211
+ look_at_type_name = first_person_dict.get("lookAtTypeName")
212
+ if (
213
+ isinstance(look_at_type_name, str)
214
+ and look_at_type_name in first_person.look_at_type_name_enum.identifiers()
215
+ ):
216
+ first_person.look_at_type_name = look_at_type_name
217
+
218
+ for look_at, look_at_dict in (
219
+ (
220
+ first_person.look_at_horizontal_inner,
221
+ first_person_dict.get("lookAtHorizontalInner"),
222
+ ),
223
+ (
224
+ first_person.look_at_horizontal_outer,
225
+ first_person_dict.get("lookAtHorizontalOuter"),
226
+ ),
227
+ (
228
+ first_person.look_at_vertical_down,
229
+ first_person_dict.get("lookAtVerticalDown"),
230
+ ),
231
+ (
232
+ first_person.look_at_vertical_up,
233
+ first_person_dict.get("lookAtVerticalUp"),
234
+ ),
235
+ ):
236
+ if not isinstance(look_at_dict, dict):
237
+ continue
238
+
239
+ curve = convert.vrm_json_curve_to_list(look_at_dict.get("curve"))
240
+ if curve is not None:
241
+ look_at.curve = curve
242
+
243
+ x_range = look_at_dict.get("xRange")
244
+ if isinstance(x_range, (float, int)):
245
+ look_at.x_range = x_range
246
+
247
+ y_range = look_at_dict.get("yRange")
248
+ if isinstance(y_range, (float, int)):
249
+ look_at.y_range = y_range
250
+
251
+
252
+ def _migrate_vrm0_blend_shape_groups(
253
+ context: Context,
254
+ blend_shape_master: Vrm0BlendShapeMasterPropertyGroup,
255
+ blend_shape_group_dicts: Json,
256
+ ) -> None:
257
+ if not isinstance(blend_shape_group_dicts, list):
258
+ return
259
+
260
+ for blend_shape_group_dict in blend_shape_group_dicts:
261
+ blend_shape_group = blend_shape_master.blend_shape_groups.add()
262
+ if not isinstance(blend_shape_group_dict, dict):
263
+ continue
264
+
265
+ name = blend_shape_group_dict.get("name")
266
+ if isinstance(name, str):
267
+ blend_shape_group.name = name
268
+
269
+ preset_name = blend_shape_group_dict.get("presetName")
270
+ if (
271
+ isinstance(preset_name, str)
272
+ and preset_name in blend_shape_group.preset_name_enum.identifiers()
273
+ ):
274
+ blend_shape_group.preset_name = preset_name
275
+
276
+ bind_dicts = blend_shape_group_dict.get("binds")
277
+ if isinstance(bind_dicts, list):
278
+ for bind_dict in bind_dicts:
279
+ bind = blend_shape_group.binds.add()
280
+
281
+ if not isinstance(bind_dict, dict):
282
+ continue
283
+
284
+ mesh_name = bind_dict.get("mesh")
285
+ if isinstance(mesh_name, str):
286
+ if mesh_name in context.blend_data.meshes:
287
+ mesh: Optional[ID] = context.blend_data.meshes[mesh_name]
288
+ for obj in context.blend_data.objects:
289
+ if obj.data == mesh:
290
+ bind.mesh.mesh_object_name = obj.name
291
+ break
292
+ elif (
293
+ mesh_name in context.blend_data.objects
294
+ and context.blend_data.objects[mesh_name].type == "MESH"
295
+ ):
296
+ obj = context.blend_data.objects[mesh_name]
297
+ bind.mesh.mesh_object_name = obj.name
298
+ mesh = obj.data
299
+ else:
300
+ mesh = None
301
+
302
+ if isinstance(mesh, Mesh):
303
+ index = bind_dict.get("index")
304
+ shape_keys = mesh.shape_keys
305
+ if (
306
+ isinstance(index, str)
307
+ and shape_keys
308
+ and index in shape_keys.key_blocks
309
+ ):
310
+ bind.index = index
311
+
312
+ weight = convert.float_or_none(bind_dict.get("weight"))
313
+ if weight is not None:
314
+ bind.weight = weight
315
+
316
+ material_value_dicts = blend_shape_group_dict.get("materialValues")
317
+ if isinstance(material_value_dicts, list):
318
+ for material_value_dict in material_value_dicts:
319
+ material_value = blend_shape_group.material_values.add()
320
+
321
+ if not isinstance(material_value_dict, dict):
322
+ continue
323
+
324
+ material_name = material_value_dict.get("materialName")
325
+ if (
326
+ isinstance(material_name, str)
327
+ and material_name in context.blend_data.materials
328
+ ):
329
+ material_value.material = context.blend_data.materials[
330
+ material_name
331
+ ]
332
+
333
+ property_name = material_value_dict.get("propertyName")
334
+ if isinstance(property_name, str):
335
+ material_value.property_name = property_name
336
+
337
+ target_value_vector = material_value_dict.get("targetValue")
338
+ if isinstance(target_value_vector, list):
339
+ for v in target_value_vector:
340
+ material_value.target_value.add().value = convert.float_or(
341
+ v, 0.0
342
+ )
343
+
344
+ is_binary = blend_shape_group_dict.get("isBinary")
345
+ if isinstance(is_binary, bool):
346
+ blend_shape_group.is_binary = is_binary
347
+
348
+
349
+ def _migrate_vrm0_secondary_animation(
350
+ secondary_animation: Vrm0SecondaryAnimationPropertyGroup,
351
+ bone_group_dicts: Json,
352
+ armature: Object,
353
+ armature_data: Armature,
354
+ ) -> None:
355
+ bone_name_to_collider_objects: dict[str, list[Object]] = {}
356
+ for collider_object in (
357
+ child
358
+ for child in armature.children
359
+ if child.type == "EMPTY"
360
+ and child.empty_display_type == "SPHERE"
361
+ and child.parent_type == "BONE"
362
+ and child.parent_bone in armature_data.bones
363
+ ):
364
+ if collider_object.parent_bone not in bone_name_to_collider_objects:
365
+ bone_name_to_collider_objects[collider_object.parent_bone] = []
366
+ bone_name_to_collider_objects[collider_object.parent_bone].append(
367
+ collider_object
368
+ )
369
+
370
+ for bone_name, collider_objects in bone_name_to_collider_objects.items():
371
+ collider_group = secondary_animation.collider_groups.add()
372
+ collider_group.uuid = uuid.uuid4().hex
373
+ collider_group.node.bone_name = bone_name
374
+ for collider_object in collider_objects:
375
+ collider_prop = collider_group.colliders.add()
376
+ collider_prop.bpy_object = collider_object
377
+
378
+ for collider_group in secondary_animation.collider_groups:
379
+ collider_group.fixup(armature)
380
+
381
+ if not isinstance(bone_group_dicts, list):
382
+ bone_group_dicts = []
383
+
384
+ for bone_group_dict in bone_group_dicts:
385
+ bone_group = secondary_animation.bone_groups.add()
386
+
387
+ if not isinstance(bone_group_dict, dict):
388
+ continue
389
+
390
+ comment = bone_group_dict.get("comment")
391
+ if isinstance(comment, str):
392
+ bone_group.comment = comment
393
+
394
+ stiffiness = convert.float_or_none(bone_group_dict.get("stiffiness"))
395
+ if stiffiness is not None:
396
+ bone_group.stiffiness = stiffiness
397
+
398
+ gravity_power = convert.float_or_none(bone_group_dict.get("gravityPower"))
399
+ if gravity_power is not None:
400
+ bone_group.gravity_power = gravity_power
401
+
402
+ gravity_dir = convert.vrm_json_vector3_to_tuple(
403
+ bone_group_dict.get("gravityDir")
404
+ )
405
+ if gravity_dir is not None:
406
+ # Perform a special axis transformation for VRM 0.0.
407
+ # https://github.com/vrm-c/vrm-specification/issues/205#issuecomment-753582597
408
+ (x, y, z) = gravity_dir
409
+ bone_group.gravity_dir = (x, z, y)
410
+
411
+ drag_force = convert.float_or_none(bone_group_dict.get("dragForce"))
412
+ if drag_force is not None:
413
+ bone_group.drag_force = drag_force
414
+
415
+ center = bone_group_dict.get("center")
416
+ if isinstance(center, str):
417
+ bone_group.center.bone_name = center
418
+
419
+ hit_radius = convert.float_or_none(bone_group_dict.get("hitRadius"))
420
+ if hit_radius is not None:
421
+ bone_group.hit_radius = hit_radius
422
+
423
+ bones = bone_group_dict.get("bones")
424
+ if isinstance(bones, list):
425
+ for bone in bones:
426
+ bone_prop = bone_group.bones.add()
427
+ if not isinstance(bone, str):
428
+ continue
429
+ bone_prop.bone_name = bone
430
+
431
+ collider_group_node_names = bone_group_dict.get("colliderGroups")
432
+ if not isinstance(collider_group_node_names, list):
433
+ continue
434
+
435
+ for collider_group_node_name in collider_group_node_names:
436
+ if not isinstance(collider_group_node_name, str):
437
+ continue
438
+ for collider_group in secondary_animation.collider_groups:
439
+ if collider_group.node.bone_name != collider_group_node_name:
440
+ continue
441
+ collider_group_reference = bone_group.collider_groups.add()
442
+ collider_group_reference.collider_group_uuid = collider_group.uuid
443
+ break
444
+
445
+ for bone_group in secondary_animation.bone_groups:
446
+ bone_group.fixup()
447
+
448
+
449
+ def _migrate_legacy_custom_properties(
450
+ context: Context, armature: Object, armature_data: Armature
451
+ ) -> None:
452
+ ext = get_armature_extension(armature_data)
453
+ if tuple(ext.addon_version) >= (2, 0, 1):
454
+ return
455
+
456
+ _migrate_vrm0_meta(context, ext.vrm0.meta, armature)
457
+ _migrate_vrm0_blend_shape_groups(
458
+ context,
459
+ ext.vrm0.blend_shape_master,
460
+ _read_textblock_json(context, armature, "blendshape_group"),
461
+ )
462
+ _migrate_vrm0_first_person(
463
+ context,
464
+ ext.vrm0.first_person,
465
+ _read_textblock_json(context, armature, "firstPerson_params"),
466
+ )
467
+ _migrate_vrm0_humanoid(
468
+ ext.vrm0.humanoid, _read_textblock_json(context, armature, "humanoid_params")
469
+ )
470
+ _migrate_vrm0_secondary_animation(
471
+ ext.vrm0.secondary_animation,
472
+ _read_textblock_json(context, armature, "spring_bone"),
473
+ armature,
474
+ armature_data,
475
+ )
476
+
477
+ assigned_bpy_bone_names: list[str] = []
478
+ for human_bone_name in HumanBoneSpecifications.all_names:
479
+ bpy_bone_name = armature_data.get(human_bone_name)
480
+ if (
481
+ not isinstance(bpy_bone_name, str)
482
+ or not bpy_bone_name
483
+ or bpy_bone_name in assigned_bpy_bone_names
484
+ ):
485
+ continue
486
+ assigned_bpy_bone_names.append(bpy_bone_name)
487
+
488
+ for human_bone in ext.vrm0.humanoid.human_bones:
489
+ if human_bone.bone == human_bone_name:
490
+ human_bone.node.bone_name = bpy_bone_name
491
+ break
492
+
493
+
494
+ def _migrate_blender_object(armature_data: Armature) -> None:
495
+ ext = get_armature_extension(armature_data)
496
+ if tuple(ext.addon_version) >= (2, 3, 27):
497
+ return
498
+
499
+ for collider_group in ext.vrm0.secondary_animation.collider_groups:
500
+ for collider in collider_group.colliders:
501
+ bpy_object = collider.pop("blender_object", None)
502
+ if isinstance(bpy_object, Object):
503
+ collider.bpy_object = bpy_object
504
+
505
+
506
+ def _migrate_link_to_bone_object(
507
+ context: Context, armature: Object, armature_data: Armature
508
+ ) -> None:
509
+ ext = get_armature_extension(armature_data)
510
+ if tuple(ext.addon_version) >= (2, 3, 27):
511
+ return
512
+
513
+ for (
514
+ bone_property_group,
515
+ _bone_property_group_type,
516
+ ) in BonePropertyGroup.get_all_bone_property_groups(armature):
517
+ link_to_bone = bone_property_group.get("link_to_bone")
518
+ if not isinstance(link_to_bone, Object) or not link_to_bone.parent_bone:
519
+ continue
520
+ parent = link_to_bone.parent
521
+ if not parent or not parent.name or parent.type != "ARMATURE":
522
+ continue
523
+ parent_data = parent.data
524
+ if not isinstance(parent_data, Armature):
525
+ continue
526
+ bone = parent_data.bones.get(link_to_bone.parent_bone)
527
+ if not bone:
528
+ continue
529
+ bone_extension = get_bone_extension(bone)
530
+ if not bone_extension.uuid:
531
+ bone_extension.uuid = uuid.uuid4().hex
532
+ bone_property_group.bone_uuid = bone_extension.uuid
533
+
534
+ for (
535
+ bone_property_group,
536
+ _bone_property_group_type,
537
+ ) in BonePropertyGroup.get_all_bone_property_groups(armature):
538
+ link_to_bone = bone_property_group.pop("link_to_bone", None)
539
+ if not isinstance(link_to_bone, Object):
540
+ continue
541
+ if link_to_bone.parent_type != "OBJECT":
542
+ link_to_bone.parent_type = "OBJECT"
543
+ if link_to_bone.parent_bone:
544
+ link_to_bone.parent_bone = ""
545
+ if link_to_bone.parent is not None:
546
+ link_to_bone.parent = None
547
+
548
+ Vrm0HumanoidPropertyGroup.update_all_bone_name_candidates(
549
+ context,
550
+ armature_data.name,
551
+ force=True,
552
+ )
553
+
554
+
555
+ def _migrate_link_to_mesh_object(armature_data: Armature) -> None:
556
+ ext = get_armature_extension(armature_data)
557
+ if tuple(ext.addon_version) >= (2, 3, 23):
558
+ return
559
+
560
+ meshes = [
561
+ mesh_annotation.mesh
562
+ for mesh_annotation in ext.vrm0.first_person.mesh_annotations
563
+ ] + [
564
+ bind.mesh
565
+ for blend_shape_group in ext.vrm0.blend_shape_master.blend_shape_groups
566
+ for bind in blend_shape_group.binds
567
+ ]
568
+
569
+ for mesh in meshes:
570
+ if not mesh:
571
+ continue
572
+ link_to_mesh = mesh.get("link_to_mesh")
573
+ if (
574
+ not isinstance(link_to_mesh, Object)
575
+ or not link_to_mesh.parent
576
+ or not link_to_mesh.parent.name
577
+ or link_to_mesh.parent.type != "MESH"
578
+ ):
579
+ continue
580
+ mesh.mesh_object_name = link_to_mesh.parent.name
581
+
582
+
583
+ def _remove_link_to_mesh_object(armature_data: Armature) -> None:
584
+ ext = get_armature_extension(armature_data)
585
+ if tuple(ext.addon_version) >= (2, 3, 27):
586
+ return
587
+
588
+ meshes = [
589
+ mesh_annotation.mesh
590
+ for mesh_annotation in ext.vrm0.first_person.mesh_annotations
591
+ ] + [
592
+ bind.mesh
593
+ for blend_shape_group in ext.vrm0.blend_shape_master.blend_shape_groups
594
+ for bind in blend_shape_group.binds
595
+ ]
596
+
597
+ for mesh in meshes:
598
+ if not mesh:
599
+ continue
600
+ link_to_mesh = mesh.pop("link_to_mesh", None)
601
+ if not isinstance(link_to_mesh, Object):
602
+ continue
603
+ if link_to_mesh.parent_type != "OBJECT":
604
+ link_to_mesh.parent_type = "OBJECT"
605
+ if link_to_mesh.parent_bone:
606
+ link_to_mesh.parent_bone = ""
607
+ if link_to_mesh.parent is not None:
608
+ link_to_mesh.parent = None
609
+
610
+
611
+ def _fixup_gravity_dir(armature_data: Armature) -> None:
612
+ ext = get_armature_extension(armature_data)
613
+ for bone_group in ext.vrm0.secondary_animation.bone_groups:
614
+ gravity_dir = list(bone_group.gravity_dir)
615
+ bone_group.gravity_dir = (gravity_dir[0] + 1, 0, 0) # Make a change
616
+ bone_group.gravity_dir = gravity_dir
617
+
618
+
619
+ def _fixup_humanoid_feet_spacing(armature_data: Armature) -> None:
620
+ ext = get_armature_extension(armature_data)
621
+ if tuple(ext.addon_version) >= (2, 18, 2):
622
+ return
623
+ humanoid = ext.vrm0.humanoid
624
+ feet_spacing = convert.float_or_none(humanoid.get("feet_spacing"))
625
+ if feet_spacing is not None:
626
+ humanoid.feet_spacing = float(feet_spacing)
627
+
628
+
629
+ def _migrate_pose(context: Context, _armature: Object, armature_data: Armature) -> None:
630
+ ext = get_armature_extension(armature_data)
631
+ if tuple(ext.addon_version) >= (2, 20, 34):
632
+ return
633
+
634
+ humanoid = ext.vrm0.humanoid
635
+ if isinstance(humanoid.get("pose"), int):
636
+ return
637
+
638
+ if tuple(ext.addon_version) == ext.UNMANAGED_ADDON_VERSION:
639
+ return
640
+
641
+ if tuple(ext.addon_version) <= (2, 0, 1):
642
+ humanoid.pose = humanoid.POSE_CURRENT_POSE.identifier
643
+ return
644
+
645
+ action = humanoid.pose_library
646
+ if action and action.name in context.blend_data.actions:
647
+ humanoid.pose = humanoid.POSE_CUSTOM_POSE.identifier
648
+ elif armature_data.pose_position == "REST":
649
+ humanoid.pose = humanoid.POSE_REST_POSITION_POSE.identifier
650
+ else:
651
+ humanoid.pose = humanoid.POSE_CURRENT_POSE.identifier
652
+
653
+
654
+ def _migrate_auto_pose(_context: Context, armature_data: Armature) -> None:
655
+ ext = get_armature_extension(armature_data)
656
+ if (
657
+ tuple(ext.addon_version) >= (2, 20, 81)
658
+ or tuple(ext.addon_version) == ext.UNMANAGED_ADDON_VERSION
659
+ ):
660
+ return
661
+
662
+ humanoid = ext.vrm0.humanoid
663
+ if not isinstance(humanoid.get("pose"), int):
664
+ humanoid.pose = humanoid.POSE_CURRENT_POSE.identifier
665
+
666
+
667
+ def _migrate_saved_mesh_object_name_to_restore(
668
+ _context: Context, armature_data: Armature
669
+ ) -> None:
670
+ ext = get_armature_extension(armature_data)
671
+ if (
672
+ tuple(ext.addon_version) >= (3, 9, 0)
673
+ or tuple(ext.addon_version) == ext.UNMANAGED_ADDON_VERSION
674
+ ):
675
+ return
676
+
677
+ for blend_shape_group in ext.vrm0.blend_shape_master.blend_shape_groups:
678
+ for bind in blend_shape_group.binds:
679
+ bind.mesh.saved_mesh_object_name_to_restore = bind.mesh.name
680
+
681
+
682
+ def _migrate_collider_group_references_to_uuid(
683
+ armature_data: Armature,
684
+ ) -> None:
685
+ ext = get_armature_extension(armature_data)
686
+ if tuple(ext.addon_version) > (3, 23, 0):
687
+ return
688
+ vrm0 = ext.vrm0
689
+ for bone_group in vrm0.secondary_animation.bone_groups:
690
+ collider_group_references = bone_group.collider_groups
691
+ for collider_group_reference in collider_group_references:
692
+ if collider_group_reference.collider_group_uuid:
693
+ continue
694
+ old_collider_group_name = collider_group_reference.pop("value", None)
695
+ if not isinstance(old_collider_group_name, str):
696
+ continue
697
+ collider_group_uuid = old_collider_group_name.split("#")[-1]
698
+ if not collider_group_uuid:
699
+ continue
700
+ collider_group_reference.collider_group_uuid = collider_group_uuid
701
+
702
+
703
+ def is_unnecessary(vrm0: Vrm0PropertyGroup, *, heavy_migration: bool) -> bool:
704
+ if heavy_migration and vrm0.humanoid.initial_automatic_bone_assignment:
705
+ return False
706
+ if vrm0.first_person.first_person_bone.bone_name:
707
+ return True
708
+ return all(
709
+ (human_bone.bone != "head" or not human_bone.node.bone_name)
710
+ for human_bone in vrm0.humanoid.human_bones
711
+ )
712
+
713
+
714
+ def migrate(
715
+ context: Context,
716
+ vrm0: Vrm0PropertyGroup,
717
+ armature: Object,
718
+ *,
719
+ heavy_migration: bool,
720
+ ) -> None:
721
+ armature_data = armature.data
722
+ if not isinstance(armature_data, Armature):
723
+ return
724
+
725
+ _migrate_blender_object(armature_data)
726
+ _migrate_link_to_bone_object(context, armature, armature_data)
727
+ Vrm0HumanoidPropertyGroup.fixup_human_bones(armature)
728
+
729
+ _migrate_collider_group_references_to_uuid(armature_data)
730
+ vrm0.secondary_animation.fixup(armature)
731
+
732
+ if not vrm0.first_person.first_person_bone.bone_name:
733
+ for human_bone in vrm0.humanoid.human_bones:
734
+ if human_bone.bone == "head":
735
+ vrm0.first_person.first_person_bone.bone_name = (
736
+ human_bone.node.bone_name
737
+ )
738
+ break
739
+
740
+ _migrate_legacy_custom_properties(context, armature, armature_data)
741
+ _migrate_link_to_mesh_object(armature_data)
742
+ _remove_link_to_mesh_object(armature_data)
743
+ _fixup_gravity_dir(armature_data)
744
+ _fixup_humanoid_feet_spacing(armature_data)
745
+ _migrate_pose(context, armature, armature_data)
746
+ _migrate_auto_pose(context, armature_data)
747
+ _migrate_saved_mesh_object_name_to_restore(context, armature_data)
748
+
749
+ if heavy_migration:
750
+ Vrm0HumanoidPropertyGroup.update_all_bone_name_candidates(
751
+ context,
752
+ armature_data.name,
753
+ force=True,
754
+ )
755
+
756
+ vrm0.humanoid.pop("last_bone_names", None)
757
+ vrm0.humanoid.pop("last_bone_names_str", None)
758
+ if heavy_migration and vrm0.humanoid.initial_automatic_bone_assignment:
759
+ vrm0.humanoid.initial_automatic_bone_assignment = False
760
+ if all(not b.node.bone_name for b in vrm0.humanoid.human_bones):
761
+ assign_vrm0_humanoid_human_bones_automatically(context, armature)