@volter/blender-engine 0.1.148 → 0.1.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/LICENSE +22 -5
  2. package/README.md +4 -11
  3. package/browser/addons/vrm/LICENSE_(OPTION1)_MIT.txt +22 -0
  4. package/browser/addons/vrm/LICENSE_(OPTION2)_GPL-3_0.txt +674 -0
  5. package/browser/addons/vrm/LICENSE_MAIN.txt +1 -0
  6. package/browser/addons/vrm/README.txt +3 -0
  7. package/browser/addons/vrm/__init__.py +41 -0
  8. package/browser/addons/vrm/blender_manifest.toml +16 -0
  9. package/browser/addons/vrm/common/__init__.py +1 -0
  10. package/browser/addons/vrm/common/animation.py +58 -0
  11. package/browser/addons/vrm/common/blender_manifest.py +82 -0
  12. package/browser/addons/vrm/common/char.py +16 -0
  13. package/browser/addons/vrm/common/convert.py +287 -0
  14. package/browser/addons/vrm/common/convert_any.py +48 -0
  15. package/browser/addons/vrm/common/debug.py +40 -0
  16. package/browser/addons/vrm/common/deep.py +162 -0
  17. package/browser/addons/vrm/common/error_dialog.py +274 -0
  18. package/browser/addons/vrm/common/fs.py +71 -0
  19. package/browser/addons/vrm/common/gl.py +20 -0
  20. package/browser/addons/vrm/common/gltf.py +1149 -0
  21. package/browser/addons/vrm/common/human_bone_mapper/__init__.py +1 -0
  22. package/browser/addons/vrm/common/human_bone_mapper/biped_mapping.py +84 -0
  23. package/browser/addons/vrm/common/human_bone_mapper/cats_blender_plugin_fix_model_mapping.py +63 -0
  24. package/browser/addons/vrm/common/human_bone_mapper/human_bone_mapper.py +203 -0
  25. package/browser/addons/vrm/common/human_bone_mapper/microsoft_rocketbox_mapping.py +69 -0
  26. package/browser/addons/vrm/common/human_bone_mapper/mixamo_mapping.py +62 -0
  27. package/browser/addons/vrm/common/human_bone_mapper/mmd_mapping.py +115 -0
  28. package/browser/addons/vrm/common/human_bone_mapper/mpfb_mapping.py +120 -0
  29. package/browser/addons/vrm/common/human_bone_mapper/ready_player_me_mapping.py +65 -0
  30. package/browser/addons/vrm/common/human_bone_mapper/reallusion_mapping.py +94 -0
  31. package/browser/addons/vrm/common/human_bone_mapper/rigify_meta_rig_mapping.py +65 -0
  32. package/browser/addons/vrm/common/human_bone_mapper/structure_based_mapping.py +891 -0
  33. package/browser/addons/vrm/common/human_bone_mapper/unreal_mapping.py +62 -0
  34. package/browser/addons/vrm/common/human_bone_mapper/vrm_addon_mapping.py +112 -0
  35. package/browser/addons/vrm/common/human_bone_mapper/vroid_mapping.py +89 -0
  36. package/browser/addons/vrm/common/legacy_gltf.py +16 -0
  37. package/browser/addons/vrm/common/logger.py +84 -0
  38. package/browser/addons/vrm/common/mtoon0.blend +0 -0
  39. package/browser/addons/vrm/common/mtoon1.blend +0 -0
  40. package/browser/addons/vrm/common/mtoon1_outline.blend +0 -0
  41. package/browser/addons/vrm/common/mtoon_auto_setup.blend +0 -0
  42. package/browser/addons/vrm/common/mtoon_unversioned.py +62 -0
  43. package/browser/addons/vrm/common/ops/__init__.py +10 -0
  44. package/browser/addons/vrm/common/ops/export_scene.py +67 -0
  45. package/browser/addons/vrm/common/ops/icyp.py +53 -0
  46. package/browser/addons/vrm/common/ops/import_scene.py +57 -0
  47. package/browser/addons/vrm/common/ops/vrm.py +2380 -0
  48. package/browser/addons/vrm/common/ops/wm.py +167 -0
  49. package/browser/addons/vrm/common/preferences.py +362 -0
  50. package/browser/addons/vrm/common/progress.py +87 -0
  51. package/browser/addons/vrm/common/rotation.py +89 -0
  52. package/browser/addons/vrm/common/safe_removal.py +46 -0
  53. package/browser/addons/vrm/common/scene_watcher.py +230 -0
  54. package/browser/addons/vrm/common/shader.py +2243 -0
  55. package/browser/addons/vrm/common/shape_key_mapper/__init__.py +1 -0
  56. package/browser/addons/vrm/common/shape_key_mapper/arkit_mapping.py +168 -0
  57. package/browser/addons/vrm/common/shape_key_mapper/mmd_mapping.py +62 -0
  58. package/browser/addons/vrm/common/shape_key_mapper/ready_player_me_mapping.py +52 -0
  59. package/browser/addons/vrm/common/shape_key_mapper/vrchat_mapping.py +17 -0
  60. package/browser/addons/vrm/common/third_party_user_extension.py +214 -0
  61. package/browser/addons/vrm/common/transparent_z_write.blend +0 -0
  62. package/browser/addons/vrm/common/version.py +161 -0
  63. package/browser/addons/vrm/common/vrm0/__init__.py +1 -0
  64. package/browser/addons/vrm/common/vrm0/human_bone.py +662 -0
  65. package/browser/addons/vrm/common/vrm0/material_property.py +346 -0
  66. package/browser/addons/vrm/common/vrm1/__init__.py +1 -0
  67. package/browser/addons/vrm/common/vrm1/expression_preset.py +207 -0
  68. package/browser/addons/vrm/common/vrm1/human_bone.py +822 -0
  69. package/browser/addons/vrm/common/workspace.py +227 -0
  70. package/browser/addons/vrm/common/writable_context.py +77 -0
  71. package/browser/addons/vrm/documentation/en-us/animation/index.md +63 -0
  72. package/browser/addons/vrm/documentation/en-us/create-humanoid-vrm-from-scratch/index.md +131 -0
  73. package/browser/addons/vrm/documentation/en-us/create-simple-vrm-from-scratch/index.md +30 -0
  74. package/browser/addons/vrm/documentation/en-us/development/index.md +136 -0
  75. package/browser/addons/vrm/documentation/en-us/index.md +41 -0
  76. package/browser/addons/vrm/documentation/en-us/installation/index.md +152 -0
  77. package/browser/addons/vrm/documentation/en-us/material-mtoon/index.md +122 -0
  78. package/browser/addons/vrm/documentation/en-us/material-pbr/index.md +94 -0
  79. package/browser/addons/vrm/documentation/en-us/scripting-api/index.md +391 -0
  80. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrm/index.md +57 -0
  81. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrma/index.md +17 -0
  82. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrm/index.md +61 -0
  83. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrma/index.md +13 -0
  84. package/browser/addons/vrm/documentation/ja-jp/animation/index.md +57 -0
  85. package/browser/addons/vrm/documentation/ja-jp/create-humanoid-vrm-from-scratch/index.md +129 -0
  86. package/browser/addons/vrm/documentation/ja-jp/create-simple-vrm-from-scratch/index.md +29 -0
  87. package/browser/addons/vrm/documentation/ja-jp/development/index.md +137 -0
  88. package/browser/addons/vrm/documentation/ja-jp/index.md +37 -0
  89. package/browser/addons/vrm/documentation/ja-jp/installation/index.md +150 -0
  90. package/browser/addons/vrm/documentation/ja-jp/material-mtoon/index.md +113 -0
  91. package/browser/addons/vrm/documentation/ja-jp/material-pbr/index.md +90 -0
  92. package/browser/addons/vrm/documentation/ja-jp/scripting-api/index.md +389 -0
  93. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrm/index.md +55 -0
  94. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrma/index.md +19 -0
  95. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrm/index.md +56 -0
  96. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrma/index.md +14 -0
  97. package/browser/addons/vrm/editor/__init__.py +1 -0
  98. package/browser/addons/vrm/editor/extension.py +425 -0
  99. package/browser/addons/vrm/editor/extension_accessor.py +75 -0
  100. package/browser/addons/vrm/editor/handler.py +84 -0
  101. package/browser/addons/vrm/editor/khr_character/__init__.py +1 -0
  102. package/browser/addons/vrm/editor/khr_character/panel.py +69 -0
  103. package/browser/addons/vrm/editor/khr_character/property_group.py +27 -0
  104. package/browser/addons/vrm/editor/khr_xmp_json_ld/__init__.py +1 -0
  105. package/browser/addons/vrm/editor/khr_xmp_json_ld/ops.py +464 -0
  106. package/browser/addons/vrm/editor/khr_xmp_json_ld/panel.py +136 -0
  107. package/browser/addons/vrm/editor/khr_xmp_json_ld/property_group.py +83 -0
  108. package/browser/addons/vrm/editor/khr_xmp_json_ld/ui_list.py +198 -0
  109. package/browser/addons/vrm/editor/make_armature.py +709 -0
  110. package/browser/addons/vrm/editor/menu.py +147 -0
  111. package/browser/addons/vrm/editor/migration.py +297 -0
  112. package/browser/addons/vrm/editor/mtoon1/__init__.py +1 -0
  113. package/browser/addons/vrm/editor/mtoon1/handler.py +20 -0
  114. package/browser/addons/vrm/editor/mtoon1/migration.py +536 -0
  115. package/browser/addons/vrm/editor/mtoon1/ops.py +304 -0
  116. package/browser/addons/vrm/editor/mtoon1/panel.py +442 -0
  117. package/browser/addons/vrm/editor/mtoon1/property_group.py +4977 -0
  118. package/browser/addons/vrm/editor/mtoon1/scene_watcher.py +381 -0
  119. package/browser/addons/vrm/editor/node_constraint1/__init__.py +1 -0
  120. package/browser/addons/vrm/editor/node_constraint1/panel.py +317 -0
  121. package/browser/addons/vrm/editor/node_constraint1/property_group.py +25 -0
  122. package/browser/addons/vrm/editor/ops.py +471 -0
  123. package/browser/addons/vrm/editor/panel.py +315 -0
  124. package/browser/addons/vrm/editor/property_group.py +888 -0
  125. package/browser/addons/vrm/editor/search.py +682 -0
  126. package/browser/addons/vrm/editor/spring_bone1/__init__.py +1 -0
  127. package/browser/addons/vrm/editor/spring_bone1/handler.py +994 -0
  128. package/browser/addons/vrm/editor/spring_bone1/menu.py +246 -0
  129. package/browser/addons/vrm/editor/spring_bone1/migration.py +86 -0
  130. package/browser/addons/vrm/editor/spring_bone1/ops.py +1679 -0
  131. package/browser/addons/vrm/editor/spring_bone1/panel.py +605 -0
  132. package/browser/addons/vrm/editor/spring_bone1/property_group.py +1457 -0
  133. package/browser/addons/vrm/editor/spring_bone1/ui_list.py +408 -0
  134. package/browser/addons/vrm/editor/subscription.py +123 -0
  135. package/browser/addons/vrm/editor/t_pose.py +713 -0
  136. package/browser/addons/vrm/editor/validation.py +1271 -0
  137. package/browser/addons/vrm/editor/vrm0/__init__.py +1 -0
  138. package/browser/addons/vrm/editor/vrm0/gizmo_group.py +63 -0
  139. package/browser/addons/vrm/editor/vrm0/handler.py +23 -0
  140. package/browser/addons/vrm/editor/vrm0/menu.py +145 -0
  141. package/browser/addons/vrm/editor/vrm0/migration.py +761 -0
  142. package/browser/addons/vrm/editor/vrm0/ops.py +2145 -0
  143. package/browser/addons/vrm/editor/vrm0/panel.py +1333 -0
  144. package/browser/addons/vrm/editor/vrm0/property_group.py +1818 -0
  145. package/browser/addons/vrm/editor/vrm0/ui_list.py +688 -0
  146. package/browser/addons/vrm/editor/vrm1/__init__.py +1 -0
  147. package/browser/addons/vrm/editor/vrm1/handler.py +28 -0
  148. package/browser/addons/vrm/editor/vrm1/menu.py +76 -0
  149. package/browser/addons/vrm/editor/vrm1/migration.py +321 -0
  150. package/browser/addons/vrm/editor/vrm1/ops.py +2679 -0
  151. package/browser/addons/vrm/editor/vrm1/panel.py +1243 -0
  152. package/browser/addons/vrm/editor/vrm1/property_group.py +2087 -0
  153. package/browser/addons/vrm/editor/vrm1/scene_watcher.py +90 -0
  154. package/browser/addons/vrm/editor/vrm1/ui_list.py +533 -0
  155. package/browser/addons/vrm/exporter/__init__.py +1 -0
  156. package/browser/addons/vrm/exporter/abstract_base_vrm_exporter.py +628 -0
  157. package/browser/addons/vrm/exporter/export_scene.py +930 -0
  158. package/browser/addons/vrm/exporter/gltf2_export_user_extension.py +45 -0
  159. package/browser/addons/vrm/exporter/khr_character_exporter.py +34 -0
  160. package/browser/addons/vrm/exporter/vrm0_exporter.py +4020 -0
  161. package/browser/addons/vrm/exporter/vrm1_exporter.py +3682 -0
  162. package/browser/addons/vrm/exporter/vrm_animation_exporter.py +1035 -0
  163. package/browser/addons/vrm/external/__init__.py +1 -0
  164. package/browser/addons/vrm/external/auto_rig_pro_support.py +3 -0
  165. package/browser/addons/vrm/external/io_scene_gltf2_support.py +418 -0
  166. package/browser/addons/vrm/external/rigify_support.py +1 -0
  167. package/browser/addons/vrm/importer/__init__.py +1 -0
  168. package/browser/addons/vrm/importer/abstract_base_vrm_importer.py +1548 -0
  169. package/browser/addons/vrm/importer/file_handler.py +34 -0
  170. package/browser/addons/vrm/importer/gltf2_import_user_extension.py +268 -0
  171. package/browser/addons/vrm/importer/import_scene.py +646 -0
  172. package/browser/addons/vrm/importer/license_validation.py +198 -0
  173. package/browser/addons/vrm/importer/vrm0_importer.py +1723 -0
  174. package/browser/addons/vrm/importer/vrm1_importer.py +2014 -0
  175. package/browser/addons/vrm/importer/vrm_animation_importer.py +763 -0
  176. package/browser/addons/vrm/importer/vrm_diff.py +316 -0
  177. package/browser/addons/vrm/locale/__init__.py +1 -0
  178. package/browser/addons/vrm/locale/ja_jp.py +826 -0
  179. package/browser/addons/vrm/locale/ruff.toml +8 -0
  180. package/browser/addons/vrm/locale/translation_dictionary.py +10 -0
  181. package/browser/addons/vrm/locale/zh_hans.py +928 -0
  182. package/browser/addons/vrm/registration.py +670 -0
  183. package/browser/addons/vrm.json +18 -0
  184. package/browser/blender-emscripten-engine.mts +66 -129
  185. package/browser/blender-engine.mts +20 -186
  186. package/browser/blender-wali-engine.mts +37 -81
  187. package/browser/describe-thrown.mts +3 -6
  188. package/browser/document-chunks.mts +4 -16
  189. package/browser/gltf_export.py +3161 -0
  190. package/browser/heap-growth.mts +23 -0
  191. package/browser/index.ts +3 -0
  192. package/browser/protocol.ts +130 -43
  193. package/browser/pull-job.mts +2 -10
  194. package/browser/rna.ts +190 -73
  195. package/browser/runtime.ts +271 -106
  196. package/browser/session-addons.mts +33 -0
  197. package/browser/session-frame.mts +5 -24
  198. package/browser/session.py +1389 -1446
  199. package/browser/three/attach-presenter.ts +11 -39
  200. package/browser/three/blender-base64.ts +1 -36
  201. package/browser/three/blender-corner-normals.ts +1 -23
  202. package/browser/three/blender-display-shaders.json +1 -1
  203. package/browser/three/blender-display-shaders.lut +0 -0
  204. package/browser/three/blender-display-transform.ts +2 -1
  205. package/browser/three/blender-frame-columns.ts +5 -13
  206. package/browser/three/blender-graph-material.ts +18 -3
  207. package/browser/three/blender-node-graph.ts +10 -34
  208. package/browser/three/blender-physical-material.ts +2 -31
  209. package/browser/three/blender-runtime-armature.ts +7 -60
  210. package/browser/three/blender-runtime-frame.ts +9 -23
  211. package/browser/three/blender-runtime-geometry.ts +22 -26
  212. package/browser/three/blender-runtime-lighting.ts +48 -178
  213. package/browser/three/blender-runtime-shadows.ts +187 -1
  214. package/browser/three/blender-runtime-skeleton.ts +53 -1
  215. package/browser/three/blender-runtime-view.ts +492 -306
  216. package/browser/three/blender-runtime-weights.ts +9 -72
  217. package/browser/three/blender-sky.ts +13 -33
  218. package/browser/three/blender-triangulate.ts +7 -35
  219. package/browser/three/blender-viewport-sampling.ts +235 -0
  220. package/browser/three/blender-workbench-material.ts +25 -29
  221. package/browser/three/blender-workbench-outline.ts +199 -0
  222. package/browser/three/blender-world-volume.ts +62 -10
  223. package/browser/three/presenter.ts +10 -26
  224. package/browser/three/release.ts +5 -21
  225. package/browser/three/sky-precompute-worker.ts +1 -18
  226. package/browser/three/sky-worker.ts +5 -23
  227. package/browser/three/world-field-sampler.ts +12 -26
  228. package/browser/volter_three.py +9 -105
  229. package/browser/worker.ts +195 -180
  230. package/package.json +5 -2
  231. package/wasm/BUNDLE.json +17 -17
  232. package/wasm/DEPENDENCY-LICENSES.txt +14 -0
  233. package/wasm/blender_browser.data.br +0 -0
  234. package/wasm/blender_browser.js +1 -1
  235. package/wasm/blender_browser.wasm.br +0 -0
  236. package/browser/frame-transfer.mts +0 -19
  237. package/browser/three/agx-base-srgb.lut +0 -0
  238. package/browser/three/agx-look-medium-high-contrast.lut +0 -0
  239. package/browser/three/agx-look-punchy.lut +0 -0
  240. package/browser/three/blender-agx.ts +0 -235
  241. package/browser/three/blender-display-lut.ts +0 -145
  242. package/browser/three/blender-filmic.ts +0 -49
  243. package/browser/three/blender-standard.ts +0 -68
  244. package/browser/three/blender-world-visibility.ts +0 -278
  245. package/browser/three/filmic-srgb.lut +0 -0
@@ -0,0 +1,227 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+ import sys
3
+ from collections.abc import Generator
4
+ from contextlib import contextmanager
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Optional
8
+
9
+ import bpy
10
+ from bpy.types import Context, Object
11
+ from mathutils import Matrix
12
+
13
+ from .logger import get_logger
14
+
15
+ _logger = get_logger(__name__)
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class SavedWorkspace:
20
+ # Be careful not to include objects that might disappear before and after yield
21
+ cursor_matrix: Matrix
22
+ previous_object_name: Optional[str]
23
+ previous_object_mode: Optional[str]
24
+ active_object_name: Optional[str]
25
+ active_object_hide_viewport: bool
26
+
27
+
28
+ def _enter_save_workspace(
29
+ context: Context, obj: Optional[Object] = None, *, mode: str = "OBJECT"
30
+ ) -> SavedWorkspace:
31
+ # Save the position of the 3D cursor
32
+ cursor_matrix = context.scene.cursor.matrix.copy()
33
+
34
+ previous_object_name = None
35
+ previous_object_mode = None
36
+ previous_object = context.view_layer.objects.active
37
+ if previous_object:
38
+ # previous_object may disappear after yield.
39
+ # We intern it just in case, but it might not be necessary.
40
+ previous_object_name = sys.intern(previous_object.name)
41
+ previous_object_mode = sys.intern(previous_object.mode)
42
+
43
+ # If an obj argument is passed, set the mode to "OBJECT". If the mode
44
+ # stays as is, it may not be possible to change the active object
45
+ if previous_object != obj and previous_object_mode != "OBJECT":
46
+ previous_object_hide_viewport = previous_object.hide_viewport
47
+ if previous_object_hide_viewport:
48
+ # If hide_viewport is True, mode_set may fail if left as is
49
+ previous_object.hide_viewport = False
50
+ bpy.ops.object.mode_set(mode="OBJECT")
51
+ if previous_object.hide_viewport != previous_object_hide_viewport:
52
+ previous_object.hide_viewport = previous_object_hide_viewport
53
+
54
+ # If an object is passed, make it active
55
+ if obj is not None:
56
+ context.view_layer.objects.active = obj
57
+ context.view_layer.update()
58
+
59
+ active_object_name = None
60
+ active_object_hide_viewport = False
61
+ # Change the mode of the active object
62
+ active_object = context.view_layer.objects.active
63
+ if active_object:
64
+ # active_object may disappear after yield.
65
+ # We intern it just in case, but it might not be necessary.
66
+ active_object_name = sys.intern(active_object.name)
67
+ active_object_hide_viewport = active_object.hide_viewport
68
+ # If hide_viewport is True, mode_set may fail if left as is
69
+ # Currently we force it to be visible even when not changing mode,
70
+ # but this may be inappropriate
71
+ if active_object_hide_viewport:
72
+ active_object.hide_viewport = False
73
+ if active_object.mode != mode:
74
+ bpy.ops.object.mode_set(mode=mode)
75
+
76
+ return SavedWorkspace(
77
+ cursor_matrix=cursor_matrix,
78
+ previous_object_name=previous_object_name,
79
+ previous_object_mode=previous_object_mode,
80
+ active_object_name=active_object_name,
81
+ active_object_hide_viewport=active_object_hide_viewport,
82
+ )
83
+
84
+
85
+ def _exit_save_workspace(context: Context, saved_workspace: SavedWorkspace) -> None:
86
+ cursor_matrix = saved_workspace.cursor_matrix
87
+ previous_object_name = saved_workspace.previous_object_name
88
+ previous_object_mode = saved_workspace.previous_object_mode
89
+ active_object_name = saved_workspace.active_object_name
90
+ active_object_hide_viewport = saved_workspace.active_object_hide_viewport
91
+
92
+ previous_object = None
93
+ if previous_object_name is not None:
94
+ previous_object = context.blend_data.objects.get(previous_object_name)
95
+
96
+ current_active_object = context.view_layer.objects.active
97
+
98
+ # Set the mode of the currently active object to "OBJECT". If the mode stays as is,
99
+ # it may not be possible to change the active object
100
+ if (
101
+ current_active_object
102
+ and current_active_object != previous_object
103
+ and current_active_object.mode != "OBJECT"
104
+ ):
105
+ current_active_object_hide_viewport = current_active_object.hide_viewport
106
+ if current_active_object.hide_viewport:
107
+ current_active_object.hide_viewport = False
108
+ bpy.ops.object.mode_set(mode="OBJECT")
109
+ if current_active_object.hide_viewport != current_active_object_hide_viewport:
110
+ current_active_object.hide_viewport = current_active_object_hide_viewport
111
+
112
+ # Restore the hide_viewport of the activated object
113
+ if active_object_name is not None:
114
+ active_object = context.blend_data.objects.get(active_object_name)
115
+ if active_object and active_object.hide_viewport != active_object_hide_viewport:
116
+ active_object.hide_viewport = active_object_hide_viewport
117
+
118
+ # Return to the originally active object
119
+ previous_object = None
120
+ if previous_object_name is not None:
121
+ previous_object = context.blend_data.objects.get(previous_object_name)
122
+
123
+ if context.view_layer.objects.active != previous_object:
124
+ context.view_layer.objects.active = previous_object
125
+ context.view_layer.update()
126
+
127
+ # Restore the mode of the originally active object
128
+ if (
129
+ previous_object
130
+ and previous_object_mode is not None
131
+ and previous_object_mode != previous_object.mode
132
+ ):
133
+ # If hide_viewport is True, mode_set may fail if left as is
134
+ # Restore hide_viewport after mode_set is completed
135
+ previous_object_hide_viewport = previous_object.hide_viewport
136
+ if previous_object_hide_viewport:
137
+ previous_object.hide_viewport = False
138
+ bpy.ops.object.mode_set(mode=previous_object_mode)
139
+ if previous_object.hide_viewport != previous_object_hide_viewport:
140
+ previous_object.hide_viewport = previous_object_hide_viewport
141
+
142
+ # Restore the 3D cursor position
143
+ context.scene.cursor.matrix = cursor_matrix
144
+
145
+
146
+ @contextmanager
147
+ def save_workspace(
148
+ context: Context, obj: Optional[Object] = None, *, mode: str = "OBJECT"
149
+ ) -> Generator[None]:
150
+ saved_workspace = _enter_save_workspace(context, obj, mode=mode)
151
+ try:
152
+ yield
153
+ # After yield, bpy native objects may be deleted or become invalid
154
+ # as frames advance. Accessing them in this state can cause crashes,
155
+ # so be careful not to access potentially invalid native objects
156
+ # after yield
157
+ finally:
158
+ _exit_save_workspace(context, saved_workspace)
159
+
160
+
161
+ def wm_append_without_library(
162
+ context: Context,
163
+ blend_path: Path,
164
+ *,
165
+ append_filepath: str,
166
+ append_filename: str,
167
+ append_directory: str,
168
+ ) -> set[str]:
169
+ """Call wm.append and remove the added libraries.
170
+
171
+ Used to work around the issue where wm.append adding libraries causes
172
+ asset library addition to fail.
173
+ https://github.com/saturday06/VRM-Addon-for-Blender/issues/631
174
+ https://github.com/saturday06/VRM-Addon-for-Blender/issues/646
175
+ """
176
+ # https://projects.blender.org/blender/blender/src/tag/v2.93.18/source/blender/windowmanager/intern/wm_files_link.c#L85-L90
177
+ with save_workspace(context):
178
+ # List of pointers for library addition detection.
179
+ # Used only for addition detection. Be careful not to dereference,
180
+ # as it is dangerous.
181
+ existing_library_pointers: list[int] = [
182
+ library.as_pointer() for library in context.blend_data.libraries
183
+ ]
184
+
185
+ result = bpy.ops.wm.append(
186
+ filepath=append_filepath,
187
+ filename=append_filename,
188
+ directory=append_directory,
189
+ link=False,
190
+ )
191
+ if result != {"FINISHED"}:
192
+ return result
193
+
194
+ # Remove one added library.
195
+ # Reverse order to handle recursive calls, but effectiveness is unconfirmed.
196
+ for library in reversed(list(context.blend_data.libraries)):
197
+ try:
198
+ library_path = Path(bpy.path.abspath(library.filepath))
199
+ if not library_path.exists() or not blend_path.samefile(library_path):
200
+ continue
201
+ except OSError:
202
+ message = f'Failed to access library path for "{library.name}"'
203
+ _logger.warning(message)
204
+ continue
205
+
206
+ if library.as_pointer() in existing_library_pointers:
207
+ continue
208
+
209
+ if bpy.app.version >= (3, 2) and library.use_extra_user:
210
+ library.use_extra_user = False
211
+ if library.users:
212
+ if bpy.app.version >= (3, 2):
213
+ _logger.warning(
214
+ 'Failed to remove "%s" with %d users'
215
+ " while appending blend file:"
216
+ ' filepath="%s" filename="%s" directory="%s"',
217
+ library.name,
218
+ library.users,
219
+ append_filepath,
220
+ append_filename,
221
+ append_directory,
222
+ )
223
+ else:
224
+ context.blend_data.libraries.remove(library)
225
+
226
+ break
227
+ return result
@@ -0,0 +1,77 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Final, Optional, Protocol
5
+
6
+ import bpy
7
+ from bpy.app.handlers import persistent
8
+ from bpy.types import Context
9
+
10
+
11
+ class WritableContextBecomesAvailableOnceHandler(Protocol):
12
+ def __call__(self, context: Context, *, load_post: bool) -> None: ...
13
+
14
+
15
+ @dataclass
16
+ class State:
17
+ registered_handlers: Final[list[WritableContextBecomesAvailableOnceHandler]] = (
18
+ field(default_factory=list[WritableContextBecomesAvailableOnceHandler])
19
+ )
20
+ pending_handlers: Final[list[WritableContextBecomesAvailableOnceHandler]] = field(
21
+ default_factory=list[WritableContextBecomesAvailableOnceHandler]
22
+ )
23
+
24
+
25
+ _state: Final = State()
26
+
27
+
28
+ def register_writable_context_becomes_available_once_handler(
29
+ handler: WritableContextBecomesAvailableOnceHandler,
30
+ ) -> None:
31
+ if handler not in _state.registered_handlers:
32
+ _state.registered_handlers.append(handler)
33
+ if handler not in _state.pending_handlers:
34
+ _state.pending_handlers.append(handler)
35
+
36
+ if not bpy.app.timers.is_registered(
37
+ _writable_context_becomes_available_timer_callback
38
+ ):
39
+ bpy.app.timers.register(_writable_context_becomes_available_timer_callback)
40
+
41
+
42
+ def _writable_context_becomes_available_timer_callback() -> Optional[float]:
43
+ context = bpy.context
44
+ trigger_writable_context_becomes_available_once_handlers(context, load_post=False)
45
+
46
+
47
+ def trigger_writable_context_becomes_available_once_handlers(
48
+ context: Context, *, load_post: bool
49
+ ) -> None:
50
+ try:
51
+ while _state.pending_handlers:
52
+ handler = _state.pending_handlers.pop()
53
+ handler(context, load_post=load_post)
54
+ finally:
55
+ _state.pending_handlers.clear()
56
+
57
+
58
+ @persistent
59
+ def load_post(_unused: object) -> None:
60
+ context = bpy.context
61
+ for handler in _state.registered_handlers:
62
+ if handler not in _state.pending_handlers:
63
+ _state.pending_handlers.append(handler)
64
+ trigger_writable_context_becomes_available_once_handlers(context, load_post=True)
65
+
66
+
67
+ @persistent
68
+ def depsgraph_update_pre(_unused: object) -> None:
69
+ context = bpy.context
70
+ trigger_writable_context_becomes_available_once_handlers(context, load_post=False)
71
+
72
+
73
+ def clear_writable_context_becomes_available_once_handlers() -> None:
74
+ _state.registered_handlers.clear()
75
+ _state.pending_handlers.clear()
76
+ if bpy.app.timers.is_registered(_writable_context_becomes_available_timer_callback):
77
+ bpy.app.timers.unregister(_writable_context_becomes_available_timer_callback)
@@ -0,0 +1,63 @@
1
+ ---
2
+ title: "VRM Animation"
3
+ description: "How to import and export VRM Animation files."
4
+ ---
5
+
6
+ This section explains how to import and export VRM Animation files.
7
+
8
+ ![](/assets/images/animation.gif)
9
+
10
+ An English tutorial is currently being written.
11
+
12
+ ---
13
+
14
+ VRM Animationのインポートとエクスポートの解説です。
15
+
16
+ ## VRM Animationファイルのエクスポート
17
+
18
+ VRM Animationのエクスポートには、VRM
19
+ 1.0のアーマチュアが必要です。エクスポートされるアニメーションは次の通りです
20
+
21
+ - Humanoidボーンの回転値
22
+ - Humanoid Hipsボーンの移動値
23
+ - Expressionのプレビュー値 (Look At値のエクスポートは現在未対応)
24
+
25
+ 最低限のアニメーションをエクスポートしてみます。
26
+
27
+ ![](1.png)
28
+
29
+ ![](2.png)
30
+
31
+ ![](3.png)
32
+
33
+ ![](4.png)
34
+
35
+ ![](5.png)
36
+
37
+ ![](6.png)
38
+
39
+ ![](7.png)
40
+
41
+ ![](8.png)
42
+
43
+ ![](9.png)
44
+
45
+ ![](10.png)
46
+
47
+ ![](11.png)
48
+
49
+ ![](12.png)
50
+
51
+ ![](13.png)
52
+
53
+ ![](14.png)
54
+
55
+ ![](15.png)
56
+
57
+ ## VRM Animationファイルのインポート
58
+
59
+ ![](16.png)
60
+
61
+ ![](17.png)
62
+
63
+ ![](18.png)
@@ -0,0 +1,131 @@
1
+ ---
2
+ title: "Create Humanoid VRM"
3
+ description: "We will create a simple Humanoid VRM model."
4
+ ---
5
+
6
+ We will create a simple Humanoid VRM model.
7
+
8
+ ![](/assets/images/humanoid.gif)
9
+
10
+ After starting Blender, place the mouse cursor on the 3D Viewport and press the
11
+ `n` key.
12
+
13
+ ![](1.png)
14
+
15
+ This will open a Sidebar from the right side. Select the `VRM` tab and click the
16
+ `Create VRM Model` button.
17
+
18
+ ![](2.png)
19
+
20
+ Then an armature suitable for VRM output will be created automatically. An
21
+ armature represents the bone structure of a 3D model. This add-on uses armature
22
+ to represent the skeletal structure of the human figure in VRM.
23
+
24
+ ![](3.png)
25
+
26
+ We will use the default Cube as a torso.
27
+
28
+ Select the Cube in the 3D Viewport, select the tab with the
29
+ "![](/assets/images/object_property_tab_icon.png)" icon in the lower right
30
+ corner, go to `Transform` > `Scale`, and set all values to `0.2` to make it
31
+ small enough to be used as a torso.
32
+
33
+ ![](4.png)
34
+
35
+ We associate the torso with the bones of the armature. Go to `Relations`, and
36
+ set `Parent` to `Armature`, `Parent Type` to `Bone`, and `Parent Bone` to
37
+ `spine`. The torso will move to the spine of the 3D model.
38
+
39
+ ![](5.png)
40
+
41
+ The next step is to create the head, press `Shift + a` in the 3D viewport to
42
+ bring up an additional menu, select `Mesh` -> `UV Sphere`.
43
+
44
+ ![](6.png)
45
+
46
+ A `Sphere` will be added.
47
+
48
+ ![](7.png)
49
+
50
+ It is too big so we will shrink it.
51
+
52
+ Select the tab with the "![](/assets/images/object_property_tab_icon.png)" icon
53
+ in the lower right corner, go to `Transform` > `Scale`, and set all values to
54
+ `0.25`.
55
+
56
+ ![](8.png)
57
+
58
+ Associate this sphere with the armature's bone. Go to `Relations`, and set
59
+ `Parent` to `Armature`, `Parent Type` to `Bone`, and `Parent Bone` to `head`.
60
+ The sphere will move to the head of the 3D model.
61
+
62
+ ![](9.png)
63
+
64
+ Next, we will add the limbs: in the 3D viewport, press `Shift + a` to bring up
65
+ the Add menu, and select `Mesh` -> `Ico Sphere`.
66
+
67
+ ![](10.png)
68
+
69
+ The `Icosphere` will be added, and at the same time, you will see
70
+ `> Add Ico Sphere` in the lower-left corner of the 3D viewport. Click on this
71
+ message.
72
+
73
+ ![](11.png)
74
+
75
+ You can then set up the new Ico Sphere to be added. We feel that the radius is
76
+ too large so we will change the radius value to `0.1 m`.
77
+
78
+ ![](12.png)
79
+
80
+ Select the tab with the "![](/assets/images/object_property_tab_icon.png)" icon
81
+ in the lower right corner, go to `Relations`, set `Parent` to `Armature`, set
82
+ `Parent Type` to `Bone`, and set `Parent Bone` to `upper_arm.L`. The sphere will
83
+ move to the left upper arm of the 3D model.
84
+
85
+ ![](13.png)
86
+
87
+ Add the Ico sphere as before, and now associate it with the `hand.L` bone. The
88
+ Ico sphere will move to the left hand.
89
+
90
+ ![](14.png)
91
+
92
+ Similarly, we will associate it with the `upper_arm.R` bone.
93
+
94
+ ![](15.png)
95
+
96
+ Associate with the `hand.R` bone.
97
+
98
+ ![](16.png)
99
+
100
+ Associate with the `upper_leg.L` bone.
101
+
102
+ ![](17.png)
103
+
104
+ Associate with the `lower_leg.L` bone.
105
+
106
+ ![](18.png)
107
+
108
+ Associate with the `upper_leg.R` bone.
109
+
110
+ ![](19.png)
111
+
112
+ Finally, associate it with the `lower_leg.R` bone.
113
+
114
+ ![](20.png)
115
+
116
+ Save this model as a VRM. Select `File` → `Export` → `VRM (.vrm)` from the menu.
117
+
118
+ ![](21.png)
119
+
120
+ Enter the filename and destination when the File View window appears and press
121
+ `Export VRM`.
122
+
123
+ ![](22.png)
124
+
125
+ If successful, the VRM file will be saved to the specified location.
126
+
127
+ ![](/assets/images/humanoid.gif)
128
+
129
+ You can check the operation on this page.
130
+
131
+ - https://hub.vroid.com/en/characters/6595382014094436897/models/1372267393572384142
@@ -0,0 +1,30 @@
1
+ ---
2
+ title: "Create Simple VRM"
3
+ description: "Convert the cube displayed from the beginning when you start Blender to a VRM model."
4
+ ---
5
+
6
+ Convert the cube displayed from the beginning when you start Blender to a VRM
7
+ model.
8
+
9
+ ![](/assets/images/simple.gif)
10
+
11
+ First, start Blender and make sure that the cube is displayed.
12
+
13
+ ![](1.png)
14
+
15
+ Next, select `File` → `Export` → `VRM (.vrm)` from the menu.
16
+
17
+ ![](2.png)
18
+
19
+ Enter the filename and destination when the File View window appears and press
20
+ `Export VRM`.
21
+
22
+ ![](3.png)
23
+
24
+ If successful, the VRM file will be saved to the specified location.
25
+
26
+ ![](/assets/images/simple.gif)
27
+
28
+ You can check the operation on this page.
29
+
30
+ - https://hub.vroid.com/en/characters/2535511199028537879/models/127230567429676411
@@ -0,0 +1,136 @@
1
+ ---
2
+ title: "Development How-To"
3
+ description: "Set up the development environment for VRM Add-on for Blender."
4
+ ---
5
+
6
+ Instructions for setting up the add-on development environment.
7
+
8
+ ![](/assets/images/development.gif)
9
+
10
+ [The repository](https://github.com/saturday06/VRM-Addon-for-Blender) contains
11
+ source code, code formatting settings, code type checking settings, and software
12
+ testing settings. These are strongly dependent on the tool
13
+ [astral-sh/uv](https://docs.astral.sh/uv/), so you will need to install that
14
+ first. Alternatively, you can use [Dev Container](https://containers.dev/) to
15
+ set them up automatically.
16
+
17
+ ## Link the repository to the add-on folder
18
+
19
+ The
20
+ [src/io_scene_vrm](https://github.com/saturday06/VRM-Addon-for-Blender/tree/main/src/io_scene_vrm)
21
+ folder contains the main add-on code. By creating a symbolic link to this folder
22
+ in Blender's `user_default` or `addons` directory, you can install the
23
+ development source code as an add-on in Blender, making it easy to test changes
24
+ efficiently.
25
+
26
+ ### How to create a development link for Blender 4.2 or later
27
+
28
+ #### Linux
29
+
30
+ ```sh
31
+ blender_version=4.5
32
+ mkdir -p "$HOME/.config/blender/$blender_version/extensions/user_default"
33
+ ln -Ts "$PWD/src/io_scene_vrm" "$HOME/.config/blender/$blender_version/extensions/user_default/vrm"
34
+ ```
35
+
36
+ #### macOS
37
+
38
+ ```sh
39
+ blender_version=4.5
40
+ mkdir -p "$HOME/Library/Application Support/Blender/$blender_version/extensions/user_default"
41
+ ln -s "$PWD/src/io_scene_vrm" "$HOME/Library/Application Support/Blender/$blender_version/extensions/user_default/vrm"
42
+ ```
43
+
44
+ #### Windows PowerShell
45
+
46
+ ```powershell
47
+ $blenderVersion = "4.5"
48
+ New-Item -ItemType Directory -Path "$Env:APPDATA\Blender Foundation\Blender\$blenderVersion\extensions\user_default" -Force
49
+ New-Item -ItemType Junction -Path "$Env:APPDATA\Blender Foundation\Blender\$blenderVersion\extensions\user_default\vrm" -Value "$(Get-Location)\src\io_scene_vrm"
50
+ ```
51
+
52
+ ### How to create a development link for Blender 4.1.1 or earlier
53
+
54
+ #### Linux
55
+
56
+ ```sh
57
+ blender_version=3.6
58
+ mkdir -p "$HOME/.config/blender/$blender_version/scripts/addons"
59
+ ln -Ts "$PWD/src/io_scene_vrm" "$HOME/.config/blender/$blender_version/scripts/addons/io_scene_vrm"
60
+ ```
61
+
62
+ #### macOS
63
+
64
+ ```sh
65
+ blender_version=3.6
66
+ mkdir -p "$HOME/Library/Application Support/Blender/$blender_version/scripts/addons"
67
+ ln -s "$PWD/src/io_scene_vrm" "$HOME/Library/Application Support/Blender/$blender_version/scripts/addons/io_scene_vrm"
68
+ ```
69
+
70
+ #### Windows PowerShell
71
+
72
+ ```powershell
73
+ $blenderVersion = "3.6"
74
+ New-Item -ItemType Directory -Path "$Env:APPDATA\Blender Foundation\Blender\$blenderVersion\scripts\addons" -Force
75
+ New-Item -ItemType Junction -Path "$Env:APPDATA\Blender Foundation\Blender\$blenderVersion\scripts\addons\io_scene_vrm" -Value "$(Get-Location)\src\io_scene_vrm"
76
+ ```
77
+
78
+ ## To format the code, follow these steps
79
+
80
+ 1. Install [astral-sh/uv](https://docs.astral.sh/uv/).
81
+ 2. Double-click `tools\format.bat` in the repository to run it.
82
+
83
+ ## To format the code in Visual Studio Code, follow these steps
84
+
85
+ 1. Install the `Ruff` extension in Visual Studio Code.
86
+ 2. Run Visual Studio Code's `Format Document`.
87
+
88
+ ## To run type checking of the code, follow these steps
89
+
90
+ 1. Install [astral-sh/uv](https://docs.astral.sh/uv/).
91
+ 2. Double-click `tools\lint.bat` in the repository and run it.
92
+
93
+ ## To run type checking of the code in Visual Studio Code, follow these steps
94
+
95
+ 1. Install the `Pyright` extension in Visual Studio Code.
96
+ 2. Open the Python file you want to type check.
97
+
98
+ ## To run the software tests of the code, follow these steps
99
+
100
+ 1. Install [astral-sh/uv](https://docs.astral.sh/uv/).
101
+ 2. Double-click `tools\test.bat` in the repository and run it.
102
+
103
+ ## To run the software tests of the code in Visual Studio Code, follow these steps
104
+
105
+ 1. Install [astral-sh/uv](https://docs.astral.sh/uv/).
106
+ 2. In the Visual Studio Code terminal, run the `uv sync` command.
107
+ 3. Select `Testing` from the left icon in Visual Studio Code.
108
+ 4. Select `Configure Python Tests`.
109
+ 5. Select `unittests` as the test library.
110
+ 6. Select `Root Directory` as the test folder.
111
+ 7. Select `test_*` as the test file pattern.
112
+ 8. Press `Run Tests`.
113
+
114
+ ## How to create a distribution build
115
+
116
+ You can create a distribution build on Ubuntu Linux LTS.
117
+
118
+ 1. Run the `sudo ./tools/install_ubuntu_packages.sh` command to install the
119
+ required packages.
120
+ 2. Run the `./tools/build_release.sh` command.
121
+ 3. If you see the following output, the build was successful:
122
+
123
+ ```text
124
+ |
125
+ | Release Build Completed
126
+ |
127
+ | - Blender 4.2 or later:
128
+ | /workspace/release_output/VRM_Addon_for_Blender-Extension-0_0_0.zip
129
+ |
130
+ | - Blender 2.93 - 4.1:
131
+ | /workspace/release_output/VRM_Addon_for_Blender-0_0_0.zip
132
+ |
133
+ ```
134
+
135
+ For more details, refer to the GitHub Actions code at
136
+ https://github.com/saturday06/VRM-Addon-for-Blender/blob/v3.11.5/.github/workflows/release-please.yml#L51-L54.