@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,34 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+
3
+ from bpy.types import Context, FileHandler
4
+
5
+ from .import_scene import (
6
+ VRM_OT_import_vrm_via_file_handler,
7
+ VRM_OT_import_vrma_via_file_handler,
8
+ )
9
+
10
+
11
+ class VRM_FH_vrm_import(FileHandler):
12
+ bl_idname = "VRM_FH_vrm_import"
13
+ bl_label = "Import VRM"
14
+ bl_import_operator = VRM_OT_import_vrm_via_file_handler.bl_idname
15
+ bl_export_operator = "export_scene.vrm"
16
+ bl_file_extensions = ".vrm"
17
+
18
+ @classmethod
19
+ def poll_drop(cls, context: Context) -> bool:
20
+ _ = context
21
+ return True
22
+
23
+
24
+ class VRM_FH_vrma_import(FileHandler):
25
+ bl_idname = "VRM_FH_vrma_import"
26
+ bl_label = "Import VRMA"
27
+ bl_import_operator = VRM_OT_import_vrma_via_file_handler.bl_idname
28
+ bl_export_operator = "export_scene.vrma"
29
+ bl_file_extensions = ".vrma"
30
+
31
+ @classmethod
32
+ def poll_drop(cls, context: Context) -> bool:
33
+ _ = context
34
+ return True
@@ -0,0 +1,268 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+ import secrets
3
+ import string
4
+ from collections.abc import Mapping
5
+ from typing import ClassVar, Final, Optional
6
+
7
+ import bpy
8
+ from bpy.types import Armature, Image, Object, Scene
9
+ from io_scene_gltf2.io.com import gltf2_io
10
+ from io_scene_gltf2.io.imp.gltf2_io_gltf import glTFImporter
11
+
12
+ from ..common.deep import Json, make_json
13
+ from ..common.logger import get_logger
14
+ from ..editor.extension import (
15
+ VrmAddonArmatureExtensionPropertyGroup,
16
+ )
17
+ from ..editor.extension_accessor import get_armature_extension
18
+ from ..editor.khr_xmp_json_ld.property_group import (
19
+ KhrXmpJsonLdKhrCharacterPacketPropertyGroup,
20
+ )
21
+
22
+ if bpy.app.version >= (4, 3):
23
+ from io_scene_gltf2.blender.imp.vnode import VNode
24
+ else:
25
+ from io_scene_gltf2.blender.imp.gltf2_blender_vnode import VNode
26
+
27
+ KHR_CHARACTER_SUPPORTED: Final[bool] = bpy.app.version >= (100000,)
28
+
29
+ _logger = get_logger(__name__)
30
+
31
+
32
+ def _get_list_from_json_ld(v: Json) -> list[str]:
33
+ """Extract a list of strings from a JSON-LD @list value or plain list."""
34
+ if isinstance(v, dict):
35
+ items = v.get("@list")
36
+ if isinstance(items, list):
37
+ return [s for s in items if isinstance(s, str)]
38
+ if isinstance(v, list):
39
+ return [s for s in v if isinstance(s, str)]
40
+ return []
41
+
42
+
43
+ def _get_string_from_json_ld_value(v: Json) -> str:
44
+ """Return a string from a plain string or localized JSON-LD object.
45
+
46
+ A localized value looks like ``{"en": "hello", "und": "hello"}``.
47
+ The first string value found is returned. An empty string is returned
48
+ when no string value can be extracted.
49
+ """
50
+ if isinstance(v, str):
51
+ return v
52
+ if isinstance(v, dict):
53
+ for item in v.values():
54
+ if isinstance(item, str):
55
+ return item
56
+ return ""
57
+
58
+
59
+ class Gltf2ImportUserExtensionVrm:
60
+ _current_import_id: ClassVar[Optional[str]] = None
61
+
62
+ @classmethod
63
+ def update_current_import_id(cls) -> str:
64
+ import_id = "BlenderVrmAddonImport" + (
65
+ "".join(secrets.choice(string.digits) for _ in range(15))
66
+ )
67
+ cls._current_import_id = import_id
68
+ return import_id
69
+
70
+ @classmethod
71
+ def clear_current_import_id(cls) -> None:
72
+ cls._current_import_id = None
73
+
74
+ # https://github.com/KhronosGroup/glTF-Blender-IO/blob/6f9d0d9fc1bb30e2b0bb019342ffe86bd67358fc/addons/io_scene_gltf2/blender/imp/gltf2_blender_image.py#L51
75
+ def gather_import_image_after_hook(
76
+ self,
77
+ gltf_image: gltf2_io.Image,
78
+ blender_image: Image,
79
+ gltf: glTFImporter,
80
+ ) -> None:
81
+ current_import_id = self._current_import_id
82
+ if current_import_id is None:
83
+ return
84
+
85
+ if not isinstance(gltf_data := getattr(gltf, "data", None), gltf2_io.Gltf):
86
+ return
87
+
88
+ images = gltf_data.images
89
+ if not images:
90
+ return
91
+
92
+ if gltf_image not in images:
93
+ return
94
+
95
+ image_index = images.index(gltf_image)
96
+ blender_image[current_import_id] = image_index
97
+
98
+
99
+ class Gltf2ImportUserExtensionVrmKhrCharacter(Gltf2ImportUserExtensionVrm):
100
+ def __init__(self) -> None:
101
+ self.image_index_to_blender_image: dict[int, Image] = {}
102
+ self.armature_objects: list[Object] = []
103
+
104
+ def gather_import_image_after_hook(
105
+ self,
106
+ gltf_image: gltf2_io.Image,
107
+ blender_image: Image,
108
+ gltf: glTFImporter,
109
+ ) -> None:
110
+ super().gather_import_image_after_hook(gltf_image, blender_image, gltf)
111
+
112
+ if not isinstance(gltf_data := getattr(gltf, "data", None), gltf2_io.Gltf):
113
+ return
114
+
115
+ images = gltf_data.images
116
+ if not images:
117
+ return
118
+ if gltf_image not in images:
119
+ return
120
+ image_index = images.index(gltf_image)
121
+ self.image_index_to_blender_image[image_index] = blender_image
122
+
123
+ def gather_import_node_after_hook(
124
+ self,
125
+ _vnode: VNode,
126
+ _gltf_node: gltf2_io.Node,
127
+ blender_object: Object,
128
+ _gltf: glTFImporter,
129
+ ) -> None:
130
+ """Track armature objects created during import for KHR_character processing."""
131
+ if blender_object.type == "ARMATURE":
132
+ self.armature_objects.append(blender_object)
133
+
134
+ def gather_import_scene_after_nodes_hook(
135
+ self,
136
+ _gltf_scene: gltf2_io.Scene,
137
+ _blender_scene: Scene,
138
+ gltf: glTFImporter,
139
+ ) -> None:
140
+ """Read KHR_character/KHR_xmp_json_ld and fill armature custom properties."""
141
+ if not isinstance(gltf_data := getattr(gltf, "data", None), gltf2_io.Gltf):
142
+ return
143
+
144
+ extensions_used = gltf_data.extensions_used
145
+ if not extensions_used:
146
+ return
147
+
148
+ if "KHR_character" not in extensions_used:
149
+ return
150
+
151
+ extensions = gltf_data.extensions
152
+ if not extensions:
153
+ return
154
+
155
+ khr_character_dict = extensions.get("KHR_character")
156
+ if not isinstance(khr_character_dict, dict):
157
+ return
158
+
159
+ packet_dict = None
160
+ if (
161
+ isinstance(khr_xmp_json_ld_dict := extensions.get("KHR_xmp_json_ld"), dict)
162
+ and isinstance(
163
+ packet_dicts := make_json(khr_xmp_json_ld_dict.get("packets")), list
164
+ )
165
+ and isinstance(asset_extensions := gltf_data.asset.extensions, dict)
166
+ and isinstance(
167
+ asset_khr_xmp_dict := asset_extensions.get("KHR_xmp_json_ld"), dict
168
+ )
169
+ and isinstance(packet_index := asset_khr_xmp_dict.get("packet"), int)
170
+ and 0 <= packet_index < len(packet_dicts)
171
+ ):
172
+ packet_dict = packet_dicts[packet_index]
173
+
174
+ if not isinstance(packet_dict, dict):
175
+ return
176
+
177
+ # Find armature objects: prefer tracked ones, fall back to vnodes
178
+ armature_objects = self.armature_objects
179
+ if not armature_objects:
180
+ _logger.warning(
181
+ "gather_import_scene_after_nodes_hook:"
182
+ " no armature found for KHR_character import"
183
+ )
184
+ return
185
+
186
+ for armature_object in armature_objects:
187
+ armature_data = armature_object.data
188
+ if not isinstance(armature_data, Armature):
189
+ continue
190
+ ext = get_armature_extension(armature_data)
191
+ if "VRMC_vrm" not in extensions_used and "VRM" not in extensions_used:
192
+ ext.spec_version = (
193
+ VrmAddonArmatureExtensionPropertyGroup.SPEC_VERSION_KHR_CHARACTER
194
+ )
195
+ self.fill_khr_character_xmp_packet(
196
+ ext.khr_character.khr_xmp_json_ld_packet, packet_dict
197
+ )
198
+
199
+ def fill_khr_character_xmp_packet(
200
+ self,
201
+ xmp: KhrXmpJsonLdKhrCharacterPacketPropertyGroup,
202
+ packet_dict: Mapping[str, Json],
203
+ ) -> None:
204
+ """Populate KhrXmpJsonLdKhrCharacterPacketPropertyGroup from XMP packet."""
205
+ # dc:title - plain string or localized {"lang": "value"}
206
+ dc_title = _get_string_from_json_ld_value(packet_dict.get("dc:title"))
207
+ if dc_title:
208
+ xmp.dc_title = dc_title
209
+
210
+ # dc:creator - {"@list": [...]}
211
+ for creator in _get_list_from_json_ld(packet_dict.get("dc:creator")):
212
+ item = xmp.dc_creator.add()
213
+ item.value = creator
214
+
215
+ # dc:license - {"@list": [...]}
216
+ for license_url in _get_list_from_json_ld(packet_dict.get("dc:license")):
217
+ item = xmp.dc_license.add()
218
+ item.value = license_url
219
+
220
+ # dc:created - plain string
221
+ dc_created = packet_dict.get("dc:created")
222
+ if isinstance(dc_created, str):
223
+ xmp.dc_created = dc_created
224
+
225
+ # dc:rights - plain string or localized
226
+ dc_rights = _get_string_from_json_ld_value(packet_dict.get("dc:rights"))
227
+ if dc_rights:
228
+ xmp.dc_rights = dc_rights
229
+
230
+ # dc:publisher - plain string
231
+ dc_publisher = packet_dict.get("dc:publisher")
232
+ if isinstance(dc_publisher, str):
233
+ xmp.dc_publisher = dc_publisher
234
+
235
+ # dc:description - plain string or localized
236
+ dc_description = _get_string_from_json_ld_value(
237
+ packet_dict.get("dc:description")
238
+ )
239
+ if dc_description:
240
+ xmp.dc_description = dc_description
241
+
242
+ # dc:subject - {"@list": [...]}
243
+ for subject in _get_list_from_json_ld(packet_dict.get("dc:subject")):
244
+ item = xmp.dc_subject.add()
245
+ item.value = subject
246
+
247
+ # dc:source - plain string
248
+ dc_source = packet_dict.get("dc:source")
249
+ if isinstance(dc_source, str):
250
+ xmp.dc_source = dc_source
251
+
252
+ # khr:version - plain string
253
+ khr_version = packet_dict.get("khr:version")
254
+ if isinstance(khr_version, str):
255
+ xmp.khr_version = khr_version
256
+
257
+ # khr:thumbnailImage - integer index into the glTF images array
258
+ thumbnail_index = packet_dict.get("khr:thumbnailImage")
259
+ if isinstance(thumbnail_index, int):
260
+ bpy_image = self.image_index_to_blender_image.get(thumbnail_index)
261
+ if isinstance(bpy_image, Image):
262
+ xmp.khr_thumbnail_image = bpy_image
263
+
264
+
265
+ if KHR_CHARACTER_SUPPORTED:
266
+ glTF2ImportUserExtension = Gltf2ImportUserExtensionVrmKhrCharacter
267
+ else:
268
+ glTF2ImportUserExtension = Gltf2ImportUserExtensionVrm