@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,709 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+ from math import radians
3
+ from sys import float_info
4
+ from typing import TYPE_CHECKING, ClassVar, Optional
5
+
6
+ import bpy
7
+ from bpy.props import BoolProperty, FloatProperty, StringProperty
8
+ from bpy.types import Armature, Context, EditBone, Object, Operator
9
+ from mathutils import Matrix, Vector
10
+
11
+ from ..common.version import get_addon_version
12
+ from ..common.workspace import save_workspace
13
+ from . import migration
14
+ from .extension_accessor import get_armature_extension
15
+ from .vrm0.property_group import (
16
+ Vrm0BlendShapeGroupPropertyGroup,
17
+ Vrm0HumanoidPropertyGroup,
18
+ )
19
+
20
+ MIN_BONE_LENGTH = 0.00001 # 10μm
21
+ AUTO_BONE_CONNECTION_DISTANCE = 0.000001 # 1μm
22
+
23
+
24
+ class ICYP_OT_make_armature(Operator):
25
+ bl_idname = "icyp.make_basic_armature"
26
+ bl_label = "Add VRM Humanoid"
27
+ bl_description = "make armature and simple setup for VRM export"
28
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
29
+
30
+ skip_heavy_armature_setup: BoolProperty( # type: ignore[valid-type]
31
+ default=False,
32
+ options={"HIDDEN"},
33
+ )
34
+
35
+ wip_with_template_mesh: BoolProperty( # type: ignore[valid-type]
36
+ default=False
37
+ )
38
+
39
+ # Height in meters
40
+ tall: FloatProperty( # type: ignore[valid-type]
41
+ default=1.70,
42
+ min=0.3,
43
+ step=1,
44
+ name="Bone tall",
45
+ )
46
+
47
+ # Head-to-body ratio
48
+ head_ratio: FloatProperty( # type: ignore[valid-type]
49
+ default=8.0,
50
+ min=4,
51
+ step=5,
52
+ description="height per heads",
53
+ )
54
+
55
+ head_width_ratio: FloatProperty( # type: ignore[valid-type]
56
+ default=2 / 3,
57
+ min=0.3,
58
+ max=1.2,
59
+ step=5,
60
+ description="height per heads",
61
+ )
62
+
63
+ # Leg-to-torso ratio: 0: child-like, 1: adult-like (effective for low head count)
64
+ aging_ratio: FloatProperty( # type: ignore[valid-type]
65
+ default=0.5, min=0, max=1, step=10
66
+ )
67
+
68
+ # Eye depth
69
+ eye_depth: FloatProperty( # type: ignore[valid-type]
70
+ default=-0.03, min=-0.1, max=0, step=1
71
+ )
72
+
73
+ # Shoulder width
74
+ shoulder_in_width: FloatProperty( # type: ignore[valid-type]
75
+ default=0.05,
76
+ min=0.01,
77
+ step=1,
78
+ description="Inner shoulder position",
79
+ )
80
+
81
+ shoulder_width: FloatProperty( # type: ignore[valid-type]
82
+ default=0.08,
83
+ min=0.01,
84
+ step=1,
85
+ description="shoulder roll position",
86
+ )
87
+
88
+ # Arm length ratio
89
+ arm_length_ratio: FloatProperty( # type: ignore[valid-type]
90
+ default=1, min=0.5, step=1
91
+ )
92
+
93
+ # Hand
94
+ hand_ratio: FloatProperty( # type: ignore[valid-type]
95
+ default=1, min=0.5, max=2.0, step=5
96
+ )
97
+
98
+ finger_1_2_ratio: FloatProperty( # type: ignore[valid-type]
99
+ default=0.75,
100
+ min=0.5,
101
+ max=1,
102
+ step=1,
103
+ description="proximal / intermediate",
104
+ )
105
+
106
+ finger_2_3_ratio: FloatProperty( # type: ignore[valid-type]
107
+ default=0.75,
108
+ min=0.5,
109
+ max=1,
110
+ step=1,
111
+ description="intermediate / distal",
112
+ )
113
+
114
+ nail_bone: BoolProperty( # type: ignore[valid-type]
115
+ default=False,
116
+ description="may need for finger collider",
117
+ ) # Needed for fingertip collision detection
118
+
119
+ # Foot
120
+ leg_length_ratio: FloatProperty( # type: ignore[valid-type]
121
+ default=0.5,
122
+ min=0.3,
123
+ max=0.6,
124
+ step=1,
125
+ description="upper body/lower body",
126
+ )
127
+
128
+ leg_width_ratio: FloatProperty( # type: ignore[valid-type]
129
+ default=1, min=0.01, step=1
130
+ )
131
+
132
+ leg_size: FloatProperty( # type: ignore[valid-type]
133
+ default=0.26, min=0.05, step=1
134
+ )
135
+
136
+ custom_property_name: StringProperty( # type: ignore[valid-type]
137
+ options={"HIDDEN"}
138
+ )
139
+
140
+ armature_obj: Optional[Object] = None
141
+
142
+ def execute(self, context: Context) -> set[str]:
143
+ with save_workspace(context):
144
+ self.armature_obj, compare_dict = self._make_armature(context)
145
+ self._setup_as_vrm(context, self.armature_obj, compare_dict)
146
+ if self.custom_property_name:
147
+ self.armature_obj[self.custom_property_name] = True
148
+ context.view_layer.objects.active = self.armature_obj
149
+ return {"FINISHED"}
150
+
151
+ def _float_prop(self, name: str) -> float:
152
+ prop = getattr(self, name)
153
+ if not isinstance(prop, float):
154
+ message = f"prop {name} is not float"
155
+ raise TypeError(message)
156
+ return prop
157
+
158
+ def _head_size(self) -> float:
159
+ return self._float_prop("tall") / self._float_prop("head_ratio")
160
+
161
+ def _hand_size(self) -> float:
162
+ return self._head_size() * 0.75 * self._float_prop("hand_ratio")
163
+
164
+ def _make_armature(self, context: Context) -> tuple[Object, dict[str, str]]:
165
+ def bone_add(
166
+ armature_data: Armature,
167
+ name: str,
168
+ head_pos: Vector,
169
+ tail_pos: Vector,
170
+ parent_bone: Optional[EditBone] = None,
171
+ radius: float = 0.1,
172
+ roll: float = 0,
173
+ ) -> EditBone:
174
+ added_bone = armature_data.edit_bones.new(name)
175
+ added_bone.head = head_pos
176
+ added_bone.tail = tail_pos
177
+ added_bone.head_radius = radius
178
+ added_bone.tail_radius = radius
179
+ added_bone.envelope_distance = 0.01
180
+ added_bone.roll = radians(roll)
181
+ if parent_bone is not None:
182
+ added_bone.parent = parent_bone
183
+ bone_dict.update({name: added_bone})
184
+ return added_bone
185
+
186
+ def x_mirror_bones_add(
187
+ armature_data: Armature,
188
+ base_name: str,
189
+ right_head_pos: Vector,
190
+ right_tail_pos: Vector,
191
+ parent_bones: tuple[EditBone, EditBone],
192
+ radius: float = 0.1,
193
+ bone_type: str = "other",
194
+ ) -> tuple[EditBone, EditBone]:
195
+ right_roll = 0
196
+ left_roll = 0
197
+ if bone_type == "arm":
198
+ right_roll = 0
199
+ elif bone_type == "leg":
200
+ right_roll = 0
201
+ left_roll = 0
202
+ left_bone = bone_add(
203
+ armature_data,
204
+ base_name + ".L",
205
+ right_head_pos,
206
+ right_tail_pos,
207
+ parent_bones[0],
208
+ radius=radius,
209
+ roll=left_roll,
210
+ )
211
+
212
+ head_pos = [pos * axis for pos, axis in zip(right_head_pos, (-1, 1, 1))]
213
+ tail_pos = [pos * axis for pos, axis in zip(right_tail_pos, (-1, 1, 1))]
214
+ right_bone = bone_add(
215
+ armature_data,
216
+ base_name + ".R",
217
+ Vector((head_pos[0], head_pos[1], head_pos[2])),
218
+ Vector((tail_pos[0], tail_pos[1], tail_pos[2])),
219
+ parent_bones[1],
220
+ radius=radius,
221
+ roll=right_roll,
222
+ )
223
+
224
+ return left_bone, right_bone
225
+
226
+ def x_add(pos_a: Vector, add_x: float) -> Vector:
227
+ pos = [p_a + _add for p_a, _add in zip(pos_a, [add_x, 0, 0])]
228
+ return Vector((pos[0], pos[1], pos[2]))
229
+
230
+ def y_add(pos_a: Vector, add_y: float) -> Vector:
231
+ pos = [p_a + _add for p_a, _add in zip(pos_a, [0, add_y, 0])]
232
+ return Vector((pos[0], pos[1], pos[2]))
233
+
234
+ def z_add(pos_a: Vector, add_z: float) -> Vector:
235
+ pos = [p_a + _add for p_a, _add in zip(pos_a, [0, 0, add_z])]
236
+ return Vector((pos[0], pos[1], pos[2]))
237
+
238
+ def fingers(
239
+ armature_data: Armature,
240
+ finger_name: str,
241
+ proximal_pos: Vector,
242
+ finger_len_sum: float,
243
+ ) -> tuple[
244
+ tuple[EditBone, EditBone],
245
+ tuple[EditBone, EditBone],
246
+ tuple[EditBone, EditBone],
247
+ ]:
248
+ finger_normalize = 1 / (
249
+ self.finger_1_2_ratio * self.finger_2_3_ratio
250
+ + self.finger_1_2_ratio
251
+ + 1
252
+ )
253
+ proximal_finger_len = finger_len_sum * finger_normalize
254
+ intermediate_finger_len = (
255
+ finger_len_sum * finger_normalize * self.finger_1_2_ratio
256
+ )
257
+ distal_finger_len = (
258
+ finger_len_sum
259
+ * finger_normalize
260
+ * self.finger_1_2_ratio
261
+ * self.finger_2_3_ratio
262
+ )
263
+ proximal_bones = x_mirror_bones_add(
264
+ armature_data,
265
+ f"{finger_name}_proximal",
266
+ proximal_pos,
267
+ x_add(proximal_pos, proximal_finger_len),
268
+ hands,
269
+ self._hand_size() / 18,
270
+ bone_type="arm",
271
+ )
272
+ intermediate_bones = x_mirror_bones_add(
273
+ armature_data,
274
+ f"{finger_name}_intermediate",
275
+ proximal_bones[0].tail,
276
+ x_add(proximal_bones[0].tail, intermediate_finger_len),
277
+ proximal_bones,
278
+ self._hand_size() / 18,
279
+ bone_type="arm",
280
+ )
281
+ distal_bones = x_mirror_bones_add(
282
+ armature_data,
283
+ f"{finger_name}_distal",
284
+ intermediate_bones[0].tail,
285
+ x_add(intermediate_bones[0].tail, distal_finger_len),
286
+ intermediate_bones,
287
+ self._hand_size() / 18,
288
+ bone_type="arm",
289
+ )
290
+ if self.nail_bone:
291
+ x_mirror_bones_add(
292
+ armature_data,
293
+ f"{finger_name}_nail",
294
+ distal_bones[0].tail,
295
+ x_add(distal_bones[0].tail, distal_finger_len),
296
+ distal_bones,
297
+ self._hand_size() / 20,
298
+ bone_type="arm",
299
+ )
300
+ return proximal_bones, intermediate_bones, distal_bones
301
+
302
+ bpy.ops.object.add(type="ARMATURE", enter_editmode=True, location=(0, 0, 0))
303
+ armature = context.object
304
+ if not armature:
305
+ message = "armature is not created"
306
+ raise ValueError(message)
307
+ armature_data = armature.data
308
+ if not isinstance(armature_data, Armature):
309
+ message = "armature data is not an Armature"
310
+ raise TypeError(message)
311
+ get_armature_extension(armature_data).addon_version = get_addon_version()
312
+
313
+ bone_dict: dict[str, EditBone] = {}
314
+
315
+ # bone_type = "leg" or "arm" for roll setting
316
+
317
+ head_size = self._head_size()
318
+ # down side (previously the lower leg ratio of upper leg/lower leg for
319
+ # 8-head proportions, later linearly interpolated with age factor for
320
+ # 4-head proportions)(breaks if upper leg is too high)
321
+ eight_upside_ratio, four_upside_ratio = (
322
+ 1 - self.leg_length_ratio,
323
+ (2.5 / 4) * (1 - self.aging_ratio)
324
+ + (1 - self.leg_length_ratio) * self.aging_ratio,
325
+ )
326
+ hip_up_down_ratio = (
327
+ eight_upside_ratio * (1 - (8 - self.head_ratio) / 4)
328
+ + four_upside_ratio * (8 - self.head_ratio) / 4
329
+ )
330
+ # Torso
331
+ # Groin
332
+ body_separate = self.tall * (1 - hip_up_down_ratio)
333
+ # Neck length
334
+ neck_len = head_size * 2 / 3
335
+ # Sacrum (pelvic spine base)
336
+ hips_tall = body_separate + head_size * 3 / 4
337
+ # Thoracic spine total length # 1/3 of neck is hidden behind the jaw
338
+ backbone_len = self.tall - hips_tall - head_size - neck_len / 2
339
+ # TODO: Verify the ratio of thoracic spine to vertebrae
340
+ # Main flexion point located at the base of the spine, and another flexion
341
+ # point located at the base of the thoracic cage
342
+ # by Humanoid Doc
343
+ spine_len = backbone_len * 5 / 17
344
+
345
+ root = bone_add(armature_data, "root", Vector((0, 0, 0)), Vector((0, 0, 0.3)))
346
+ # Sacrum base
347
+ hips = bone_add(
348
+ armature_data,
349
+ "hips",
350
+ Vector((0, 0, body_separate)),
351
+ Vector((0, 0, hips_tall)),
352
+ root,
353
+ roll=0,
354
+ )
355
+ # Pelvic base -> Thoracic cage base
356
+ spine = bone_add(
357
+ armature_data, "spine", hips.tail, z_add(hips.tail, spine_len), hips, roll=0
358
+ )
359
+ # Thoracic cage base -> Neck base
360
+ chest = bone_add(
361
+ armature_data,
362
+ "chest",
363
+ spine.tail,
364
+ z_add(hips.tail, backbone_len),
365
+ spine,
366
+ roll=0,
367
+ )
368
+ neck = bone_add(
369
+ armature_data,
370
+ "neck",
371
+ Vector((0, 0, self.tall - head_size - neck_len / 2)),
372
+ Vector((0, 0, self.tall - head_size + neck_len / 2)),
373
+ chest,
374
+ roll=0,
375
+ )
376
+ # Half of the neck is hidden behind the jaw
377
+ head = bone_add(
378
+ armature_data,
379
+ "head",
380
+ Vector((0, 0, self.tall - head_size + neck_len / 2)),
381
+ Vector((0, 0, self.tall)),
382
+ neck,
383
+ roll=0,
384
+ )
385
+
386
+ # Eyes
387
+ eye_depth = self.eye_depth
388
+ eyes = x_mirror_bones_add(
389
+ armature_data,
390
+ "eye",
391
+ Vector(
392
+ (head_size * self.head_width_ratio / 5, 0, self.tall - head_size / 2)
393
+ ),
394
+ Vector(
395
+ (
396
+ head_size * self.head_width_ratio / 5,
397
+ eye_depth,
398
+ self.tall - head_size / 2,
399
+ )
400
+ ),
401
+ (head, head),
402
+ )
403
+ # Legs
404
+ leg_width = head_size / 4 * self.leg_width_ratio
405
+ leg_size = self.leg_size
406
+
407
+ leg_bone_length = (body_separate + head_size * 3 / 8 - self.tall * 0.05) / 2
408
+ upside_legs = x_mirror_bones_add(
409
+ armature_data,
410
+ "upper_leg",
411
+ x_add(Vector((0, 0, body_separate + head_size * 3 / 8)), leg_width),
412
+ x_add(
413
+ Vector(
414
+ z_add(
415
+ Vector((0, 0, body_separate + head_size * 3 / 8)),
416
+ -leg_bone_length,
417
+ )
418
+ ),
419
+ leg_width,
420
+ ),
421
+ (hips, hips),
422
+ radius=leg_width * 0.9,
423
+ bone_type="leg",
424
+ )
425
+ lower_legs = x_mirror_bones_add(
426
+ armature_data,
427
+ "lower_leg",
428
+ upside_legs[0].tail,
429
+ Vector((leg_width, 0, self.tall * 0.05)),
430
+ upside_legs,
431
+ radius=leg_width * 0.9,
432
+ bone_type="leg",
433
+ )
434
+ foots = x_mirror_bones_add(
435
+ armature_data,
436
+ "foot",
437
+ lower_legs[0].tail,
438
+ Vector((leg_width, -leg_size * (2 / 3), 0)),
439
+ lower_legs,
440
+ radius=leg_width * 0.9,
441
+ bone_type="leg",
442
+ )
443
+ toes = x_mirror_bones_add(
444
+ armature_data,
445
+ "toes",
446
+ foots[0].tail,
447
+ Vector((leg_width, -leg_size, 0)),
448
+ foots,
449
+ radius=leg_width * 0.5,
450
+ bone_type="leg",
451
+ )
452
+
453
+ # Shoulder to fingers
454
+ shoulder_in_pos = self.shoulder_in_width / 2
455
+
456
+ shoulder_parent = chest
457
+ shoulders = x_mirror_bones_add(
458
+ armature_data,
459
+ "shoulder",
460
+ x_add(shoulder_parent.tail, shoulder_in_pos),
461
+ x_add(shoulder_parent.tail, shoulder_in_pos + self.shoulder_width),
462
+ (shoulder_parent, shoulder_parent),
463
+ radius=self._hand_size() * 0.4,
464
+ bone_type="arm",
465
+ )
466
+
467
+ arm_length = (
468
+ head_size
469
+ * (1 * (1 - (self.head_ratio - 6) / 2) + 1.5 * ((self.head_ratio - 6) / 2))
470
+ * self.arm_length_ratio
471
+ )
472
+ arms = x_mirror_bones_add(
473
+ armature_data,
474
+ "upper_arm",
475
+ shoulders[0].tail,
476
+ x_add(shoulders[0].tail, arm_length),
477
+ shoulders,
478
+ radius=self._hand_size() * 0.4,
479
+ bone_type="arm",
480
+ )
481
+
482
+ # When making a fist, it becomes about half the size of an open palm.
483
+ # When making a fist, the length of the forearm including the hand
484
+ # is roughly the same as the length of the upper arm,
485
+ # but it breaks down if the hand is too big.
486
+ forearm_length = max(arm_length - self._hand_size() / 2, arm_length * 0.8)
487
+ forearms = x_mirror_bones_add(
488
+ armature_data,
489
+ "lower_arm",
490
+ arms[0].tail,
491
+ x_add(arms[0].tail, forearm_length),
492
+ arms,
493
+ radius=self._hand_size() * 0.4,
494
+ bone_type="arm",
495
+ )
496
+ hands = x_mirror_bones_add(
497
+ armature_data,
498
+ "hand",
499
+ forearms[0].tail,
500
+ x_add(forearms[0].tail, self._hand_size() / 2),
501
+ forearms,
502
+ radius=self._hand_size() / 4,
503
+ bone_type="arm",
504
+ )
505
+
506
+ finger_y_offset = -self._hand_size() / 16
507
+ thumbs = fingers(
508
+ armature_data,
509
+ "thumb",
510
+ y_add(hands[0].head, finger_y_offset * 3),
511
+ self._hand_size() / 2,
512
+ )
513
+
514
+ mats = tuple(
515
+ Matrix.Translation(vec)
516
+ for vec in (thumbs[0][i].matrix.translation for i in (0, 1))
517
+ )
518
+ for j in range(3):
519
+ for n, angle in enumerate((-45, 45)):
520
+ thumbs[j][n].transform(mats[n].inverted(), scale=False, roll=False)
521
+ thumbs[j][n].transform(Matrix.Rotation(radians(angle), 4, "Z"))
522
+ thumbs[j][n].transform(mats[n], scale=False, roll=False)
523
+ thumbs[j][n].roll = 0
524
+
525
+ index_fingers = fingers(
526
+ armature_data,
527
+ "index",
528
+ y_add(hands[0].tail, finger_y_offset * 3),
529
+ (self._hand_size() / 2) - (1 / 2.3125) * (self._hand_size() / 2) / 3,
530
+ )
531
+ middle_fingers = fingers(
532
+ armature_data,
533
+ "middle",
534
+ y_add(hands[0].tail, finger_y_offset),
535
+ self._hand_size() / 2,
536
+ )
537
+ ring_fingers = fingers(
538
+ armature_data,
539
+ "ring",
540
+ y_add(hands[0].tail, -finger_y_offset),
541
+ (self._hand_size() / 2) - (1 / 2.3125) * (self._hand_size() / 2) / 3,
542
+ )
543
+ little_fingers = fingers(
544
+ armature_data,
545
+ "little",
546
+ y_add(hands[0].tail, -finger_y_offset * 3),
547
+ ((self._hand_size() / 2) - (1 / 2.3125) * (self._hand_size() / 2) / 3)
548
+ * ((1 / 2.3125) + (1 / 2.3125) * 0.75),
549
+ )
550
+
551
+ body_dict = {
552
+ "hips": hips.name,
553
+ "spine": spine.name,
554
+ "chest": chest.name,
555
+ "neck": neck.name,
556
+ "head": head.name,
557
+ }
558
+
559
+ left_right_body_dict = {
560
+ f"{left_right}{bone_name}": bones[lr].name
561
+ for bone_name, bones in {
562
+ "Eye": eyes,
563
+ "UpperLeg": upside_legs,
564
+ "LowerLeg": lower_legs,
565
+ "Foot": foots,
566
+ "Toes": toes,
567
+ "Shoulder": shoulders,
568
+ "UpperArm": arms,
569
+ "LowerArm": forearms,
570
+ "Hand": hands,
571
+ }.items()
572
+ for lr, left_right in enumerate(["left", "right"])
573
+ }
574
+
575
+ # VRM finger like name key
576
+ fingers_dict = {
577
+ f"{left_right}{finger_name}{position}": finger[i][lr].name
578
+ for finger_name, finger in zip(
579
+ ["Thumb", "Index", "Middle", "Ring", "Little"],
580
+ [thumbs, index_fingers, middle_fingers, ring_fingers, little_fingers],
581
+ )
582
+ for i, position in enumerate(["Proximal", "Intermediate", "Distal"])
583
+ for lr, left_right in enumerate(["left", "right"])
584
+ }
585
+
586
+ # VRM bone name : blender bone name
587
+ bone_name_all_dict: dict[str, str] = {}
588
+ bone_name_all_dict.update(body_dict)
589
+ bone_name_all_dict.update(left_right_body_dict)
590
+ bone_name_all_dict.update(fingers_dict)
591
+
592
+ armature_data = armature.data
593
+ if isinstance(armature_data, Armature):
594
+ connect_parent_tail_and_child_head_if_very_close_position(armature_data)
595
+
596
+ context.scene.view_layers.update()
597
+ bpy.ops.object.mode_set(mode="OBJECT")
598
+ context.scene.view_layers.update()
599
+ return armature, bone_name_all_dict
600
+
601
+ def _setup_as_vrm(
602
+ self, context: Context, armature: Object, compare_dict: dict[str, str]
603
+ ) -> None:
604
+ armature_data = armature.data
605
+ if not isinstance(armature_data, Armature):
606
+ message = "armature data is not an Armature"
607
+ raise TypeError(message)
608
+ Vrm0HumanoidPropertyGroup.fixup_human_bones(armature)
609
+ ext = get_armature_extension(armature_data)
610
+ vrm0_humanoid = ext.vrm0.humanoid
611
+ vrm1_humanoid = ext.vrm1.humanoid
612
+ if not self.skip_heavy_armature_setup:
613
+ for vrm_bone_name, bpy_bone_name in compare_dict.items():
614
+ for human_bone in vrm0_humanoid.human_bones:
615
+ if human_bone.bone == vrm_bone_name:
616
+ human_bone.node.bone_name = bpy_bone_name
617
+ break
618
+ vrm0_humanoid.pose = vrm0_humanoid.POSE_REST_POSITION_POSE.identifier
619
+ vrm1_humanoid.pose = vrm1_humanoid.POSE_REST_POSITION_POSE.identifier
620
+ self._make_extension_setting_and_metas(
621
+ armature,
622
+ offset_from_head_bone=(-self.eye_depth, self._head_size() / 6, 0),
623
+ )
624
+ if not self.skip_heavy_armature_setup:
625
+ migration.migrate(context, armature.name, heavy_migration=True)
626
+
627
+ @classmethod
628
+ def _make_extension_setting_and_metas(
629
+ cls,
630
+ armature: Object,
631
+ offset_from_head_bone: tuple[float, float, float] = (0, 0, 0),
632
+ ) -> None:
633
+ armature_data = armature.data
634
+ if not isinstance(armature_data, Armature):
635
+ return
636
+ vrm0 = get_armature_extension(armature_data).vrm0
637
+ vrm1 = get_armature_extension(armature_data).vrm1
638
+ vrm0.first_person.first_person_bone.bone_name = "head"
639
+ vrm0.first_person.first_person_bone_offset = (0, 0, 0.06)
640
+ vrm1.look_at.offset_from_head_bone = offset_from_head_bone
641
+ vrm0.first_person.look_at_horizontal_inner.y_range = 8
642
+ vrm0.first_person.look_at_horizontal_outer.y_range = 12
643
+ vrm0.meta.author = "undefined"
644
+ vrm0.meta.contact_information = "undefined"
645
+ vrm0.meta.reference = "undefined"
646
+ vrm0.meta.title = "undefined"
647
+ vrm0.meta.version = "undefined"
648
+ for preset in Vrm0BlendShapeGroupPropertyGroup.preset_name_enum:
649
+ if (
650
+ preset.identifier
651
+ == Vrm0BlendShapeGroupPropertyGroup.PRESET_NAME_UNKNOWN.identifier
652
+ ):
653
+ continue
654
+ blend_shape_group = vrm0.blend_shape_master.blend_shape_groups.add()
655
+ blend_shape_group.name = preset.name.replace(" ", "")
656
+ blend_shape_group.preset_name = preset.identifier
657
+
658
+ if TYPE_CHECKING:
659
+ # This code is auto generated.
660
+ # To regenerate, run the `uv run tools/property_typing.py` command.
661
+ skip_heavy_armature_setup: bool # type: ignore[no-redef]
662
+ wip_with_template_mesh: bool # type: ignore[no-redef]
663
+ tall: float # type: ignore[no-redef]
664
+ head_ratio: float # type: ignore[no-redef]
665
+ head_width_ratio: float # type: ignore[no-redef]
666
+ aging_ratio: float # type: ignore[no-redef]
667
+ eye_depth: float # type: ignore[no-redef]
668
+ shoulder_in_width: float # type: ignore[no-redef]
669
+ shoulder_width: float # type: ignore[no-redef]
670
+ arm_length_ratio: float # type: ignore[no-redef]
671
+ hand_ratio: float # type: ignore[no-redef]
672
+ finger_1_2_ratio: float # type: ignore[no-redef]
673
+ finger_2_3_ratio: float # type: ignore[no-redef]
674
+ nail_bone: bool # type: ignore[no-redef]
675
+ leg_length_ratio: float # type: ignore[no-redef]
676
+ leg_width_ratio: float # type: ignore[no-redef]
677
+ leg_size: float # type: ignore[no-redef]
678
+ custom_property_name: str # type: ignore[no-redef]
679
+
680
+
681
+ def connect_parent_tail_and_child_head_if_very_close_position(
682
+ armature: Armature,
683
+ ) -> None:
684
+ bones = [bone for bone in armature.edit_bones if not bone.parent]
685
+ while bones:
686
+ bone = bones.pop()
687
+
688
+ children_by_distance = sorted(
689
+ bone.children,
690
+ key=lambda child: (
691
+ (child.parent.tail - child.head).length_squared if child.parent else 0.0
692
+ ),
693
+ )
694
+ for child in children_by_distance:
695
+ if (bone.tail - child.head).length < AUTO_BONE_CONNECTION_DISTANCE and (
696
+ bone.head - child.head
697
+ ).length >= MIN_BONE_LENGTH:
698
+ bone.tail = child.head
699
+ break
700
+
701
+ bones.extend(bone.children)
702
+
703
+ bones = [bone for bone in armature.edit_bones if not bone.parent]
704
+ while bones:
705
+ bone = bones.pop()
706
+ for child in bone.children:
707
+ if (bone.tail - child.head).length < float_info.epsilon:
708
+ child.use_connect = True
709
+ bones.append(child)