@zephyr3d/scene 0.9.25 → 0.9.26

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 (262) hide show
  1. package/dist/animation/hair/gpu_hair_simulation.js +1090 -0
  2. package/dist/animation/hair/gpu_hair_simulation.js.map +1 -0
  3. package/dist/animation/joint_dynamics/controller.js +7 -5
  4. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  5. package/dist/animation/joint_dynamics/joint_dynamics_system.js +81 -5
  6. package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
  7. package/dist/animation/morphtrack.js +3 -4
  8. package/dist/animation/morphtrack.js.map +1 -1
  9. package/dist/animation/skeleton.js +58 -24
  10. package/dist/animation/skeleton.js.map +1 -1
  11. package/dist/animation/spring/multi_chain_spring_system.js +577 -179
  12. package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
  13. package/dist/animation/spring/spring_collider.js +4 -3
  14. package/dist/animation/spring/spring_collider.js.map +1 -1
  15. package/dist/animation/spring/spring_node_pose_tracker.js +40 -0
  16. package/dist/animation/spring/spring_node_pose_tracker.js.map +1 -0
  17. package/dist/animation/spring/spring_particle.js +2 -0
  18. package/dist/animation/spring/spring_particle.js.map +1 -1
  19. package/dist/animation/spring/spring_system.js +11 -3
  20. package/dist/animation/spring/spring_system.js.map +1 -1
  21. package/dist/animation/spring_modifier.js +10 -0
  22. package/dist/animation/spring_modifier.js.map +1 -1
  23. package/dist/app/engine.js +53 -43
  24. package/dist/app/engine.js.map +1 -1
  25. package/dist/app/scriptingsystem.js +119 -6
  26. package/dist/app/scriptingsystem.js.map +1 -1
  27. package/dist/app/scriptregistry.js +3 -2
  28. package/dist/app/scriptregistry.js.map +1 -1
  29. package/dist/asset/assetmanager.js +284 -67
  30. package/dist/asset/assetmanager.js.map +1 -1
  31. package/dist/asset/loaders/zhair/zhair_format.js +288 -0
  32. package/dist/asset/loaders/zhair/zhair_format.js.map +1 -0
  33. package/dist/asset/loaders/zhair/zhair_loader.js +221 -0
  34. package/dist/asset/loaders/zhair/zhair_loader.js.map +1 -0
  35. package/dist/asset/model.js +178 -67
  36. package/dist/asset/model.js.map +1 -1
  37. package/dist/camera/camera.js +193 -21
  38. package/dist/camera/camera.js.map +1 -1
  39. package/dist/camera/perspectivecamera.js +3 -1
  40. package/dist/camera/perspectivecamera.js.map +1 -1
  41. package/dist/index.d.ts +4019 -1278
  42. package/dist/index.js +15 -5
  43. package/dist/index.js.map +1 -1
  44. package/dist/material/eye.js +932 -0
  45. package/dist/material/eye.js.map +1 -0
  46. package/dist/material/hair.js +917 -0
  47. package/dist/material/hair.js.map +1 -0
  48. package/dist/material/hairstrand.js +842 -0
  49. package/dist/material/hairstrand.js.map +1 -0
  50. package/dist/material/hairstrand_data.js +162 -0
  51. package/dist/material/hairstrand_data.js.map +1 -0
  52. package/dist/material/lambert.js +5 -2
  53. package/dist/material/lambert.js.map +1 -1
  54. package/dist/material/material.js +338 -300
  55. package/dist/material/material.js.map +1 -1
  56. package/dist/material/meshmaterial.js +120 -19
  57. package/dist/material/meshmaterial.js.map +1 -1
  58. package/dist/material/mixins/albedocolor.js +1 -1
  59. package/dist/material/mixins/albedocolor.js.map +1 -1
  60. package/dist/material/mixins/lightmodel/blinnphong.js +5 -3
  61. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  62. package/dist/material/mixins/lightmodel/lambert.js +5 -4
  63. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  64. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +3 -3
  65. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  66. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +5 -5
  67. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  68. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +3 -3
  69. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  70. package/dist/material/mixins/lit.js +73 -18
  71. package/dist/material/mixins/lit.js.map +1 -1
  72. package/dist/material/mixins/pbr/common.js +4 -4
  73. package/dist/material/mixins/pbr/common.js.map +1 -1
  74. package/dist/material/mixins/texture.js +48 -11
  75. package/dist/material/mixins/texture.js.map +1 -1
  76. package/dist/material/mtoon.js +6 -5
  77. package/dist/material/mtoon.js.map +1 -1
  78. package/dist/material/pbrblueprint.js +146 -28
  79. package/dist/material/pbrblueprint.js.map +1 -1
  80. package/dist/material/pbrblueprint_instance.js +501 -0
  81. package/dist/material/pbrblueprint_instance.js.map +1 -0
  82. package/dist/material/pbrmr.js +15 -16
  83. package/dist/material/pbrmr.js.map +1 -1
  84. package/dist/material/shader/helper.js +330 -20
  85. package/dist/material/shader/helper.js.map +1 -1
  86. package/dist/material/shader/terrain_blend.js +55 -0
  87. package/dist/material/shader/terrain_blend.js.map +1 -0
  88. package/dist/material/skin.js +192 -32
  89. package/dist/material/skin.js.map +1 -1
  90. package/dist/material/spriteblueprint.js +16 -1
  91. package/dist/material/spriteblueprint.js.map +1 -1
  92. package/dist/material/subsurfaceprofile.js +86 -23
  93. package/dist/material/subsurfaceprofile.js.map +1 -1
  94. package/dist/material/water.js +3 -1
  95. package/dist/material/water.js.map +1 -1
  96. package/dist/posteffect/bloom.js +167 -7
  97. package/dist/posteffect/bloom.js.map +1 -1
  98. package/dist/posteffect/coloradjust.js +2 -1
  99. package/dist/posteffect/coloradjust.js.map +1 -1
  100. package/dist/posteffect/compositor.js.map +1 -1
  101. package/dist/posteffect/fxaa.js +2 -1
  102. package/dist/posteffect/fxaa.js.map +1 -1
  103. package/dist/posteffect/grayscale.js +3 -1
  104. package/dist/posteffect/grayscale.js.map +1 -1
  105. package/dist/posteffect/motionblur.js +4 -1
  106. package/dist/posteffect/motionblur.js.map +1 -1
  107. package/dist/posteffect/posteffect.js.map +1 -1
  108. package/dist/posteffect/skinsss.js +368 -69
  109. package/dist/posteffect/skinsss.js.map +1 -1
  110. package/dist/posteffect/ssgi.js +16 -9
  111. package/dist/posteffect/ssgi.js.map +1 -1
  112. package/dist/posteffect/ssr.js +3 -0
  113. package/dist/posteffect/ssr.js.map +1 -1
  114. package/dist/posteffect/sss.js +91 -34
  115. package/dist/posteffect/sss.js.map +1 -1
  116. package/dist/posteffect/taa.js.map +1 -1
  117. package/dist/posteffect/tonemap.js +44 -1
  118. package/dist/posteffect/tonemap.js.map +1 -1
  119. package/dist/render/abuffer_oit.js +45 -39
  120. package/dist/render/abuffer_oit.js.map +1 -1
  121. package/dist/render/cull_visitor.js +19 -0
  122. package/dist/render/cull_visitor.js.map +1 -1
  123. package/dist/render/depthpass.js +36 -2
  124. package/dist/render/depthpass.js.map +1 -1
  125. package/dist/render/drawable_mixin.js +26 -1
  126. package/dist/render/drawable_mixin.js.map +1 -1
  127. package/dist/render/dualdepthpeeling_oit.js +52 -51
  128. package/dist/render/dualdepthpeeling_oit.js.map +1 -1
  129. package/dist/render/envlight.js +1 -1
  130. package/dist/render/envlight.js.map +1 -1
  131. package/dist/render/fbm_wavegenerator.js +3 -0
  132. package/dist/render/fbm_wavegenerator.js.map +1 -1
  133. package/dist/render/gerstner_wavegenerator.js +3 -0
  134. package/dist/render/gerstner_wavegenerator.js.map +1 -1
  135. package/dist/render/globalbindgroup_allocator.js +3 -0
  136. package/dist/render/globalbindgroup_allocator.js.map +1 -1
  137. package/dist/render/oit.js +29 -0
  138. package/dist/render/oit.js.map +1 -0
  139. package/dist/render/render_queue.js +3 -0
  140. package/dist/render/render_queue.js.map +1 -1
  141. package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
  142. package/dist/render/rendergraph/executor.js +2 -0
  143. package/dist/render/rendergraph/executor.js.map +1 -1
  144. package/dist/render/rendergraph/forward_plus_builder.js +61 -1
  145. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  146. package/dist/render/rendergraph/rendergraph.js.map +1 -1
  147. package/dist/render/rendergraph/texture_affinity_cache.js +1 -1
  148. package/dist/render/rendergraph/texture_affinity_cache.js.map +1 -1
  149. package/dist/render/rendergraph/types.js.map +1 -1
  150. package/dist/render/shadow_mask_pass.js +73 -8
  151. package/dist/render/shadow_mask_pass.js.map +1 -1
  152. package/dist/render/sky.js +166 -126
  153. package/dist/render/sky.js.map +1 -1
  154. package/dist/render/weightedblended_oit.js +36 -35
  155. package/dist/render/weightedblended_oit.js.map +1 -1
  156. package/dist/scene/basesprite.js +8 -0
  157. package/dist/scene/basesprite.js.map +1 -1
  158. package/dist/scene/batchgroup.js +3 -0
  159. package/dist/scene/batchgroup.js.map +1 -1
  160. package/dist/scene/environment.js +4 -1
  161. package/dist/scene/environment.js.map +1 -1
  162. package/dist/scene/hair.js +963 -0
  163. package/dist/scene/hair.js.map +1 -0
  164. package/dist/scene/light.js +5 -1
  165. package/dist/scene/light.js.map +1 -1
  166. package/dist/scene/mesh.js +481 -47
  167. package/dist/scene/mesh.js.map +1 -1
  168. package/dist/scene/meshdrawable.js +6 -0
  169. package/dist/scene/meshdrawable.js.map +1 -1
  170. package/dist/scene/msdftext.js +3 -0
  171. package/dist/scene/msdftext.js.map +1 -1
  172. package/dist/scene/msdftextsprite.js +3 -0
  173. package/dist/scene/msdftextsprite.js.map +1 -1
  174. package/dist/scene/particlesys.js +6 -0
  175. package/dist/scene/particlesys.js.map +1 -1
  176. package/dist/scene/scene.js +3 -0
  177. package/dist/scene/scene.js.map +1 -1
  178. package/dist/scene/scene_node.js +6 -1
  179. package/dist/scene/scene_node.js.map +1 -1
  180. package/dist/scene/terrain-cm/grass.js +3 -0
  181. package/dist/scene/terrain-cm/grass.js.map +1 -1
  182. package/dist/scene/terrain-cm/grassmaterial.js +3 -0
  183. package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
  184. package/dist/scene/terrain-cm/terrain-cm.js +6 -0
  185. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  186. package/dist/scene/terrain-cm/texture_cache.js +309 -0
  187. package/dist/scene/terrain-cm/texture_cache.js.map +1 -0
  188. package/dist/scene/water.js +6 -0
  189. package/dist/scene/water.js.map +1 -1
  190. package/dist/shaders/atmosphere.js.map +1 -1
  191. package/dist/shaders/diffusion.js +54 -0
  192. package/dist/shaders/diffusion.js.map +1 -0
  193. package/dist/shaders/shadow.js +33 -21
  194. package/dist/shaders/shadow.js.map +1 -1
  195. package/dist/shaders/temporal.js +71 -33
  196. package/dist/shaders/temporal.js.map +1 -1
  197. package/dist/shadow/dom.js +546 -0
  198. package/dist/shadow/dom.js.map +1 -0
  199. package/dist/shadow/pcf_opt.js +3 -5
  200. package/dist/shadow/pcf_opt.js.map +1 -1
  201. package/dist/shadow/pcf_pd.js +1 -1
  202. package/dist/shadow/pcf_pd.js.map +1 -1
  203. package/dist/shadow/receiver_bias.js +41 -0
  204. package/dist/shadow/receiver_bias.js.map +1 -0
  205. package/dist/shadow/shader.js +20 -60
  206. package/dist/shadow/shader.js.map +1 -1
  207. package/dist/shadow/shadow_impl.js +89 -0
  208. package/dist/shadow/shadow_impl.js.map +1 -1
  209. package/dist/shadow/shadow_region.js +50 -50
  210. package/dist/shadow/shadow_region.js.map +1 -1
  211. package/dist/shadow/shadowmapper.js +150 -37
  212. package/dist/shadow/shadowmapper.js.map +1 -1
  213. package/dist/shapes/shape.js +11 -2
  214. package/dist/shapes/shape.js.map +1 -1
  215. package/dist/shapes/sphere.js +50 -9
  216. package/dist/shapes/sphere.js.map +1 -1
  217. package/dist/utility/blueprint/common/constants.js +112 -2
  218. package/dist/utility/blueprint/common/constants.js.map +1 -1
  219. package/dist/utility/blueprint/material/func.js +142 -49
  220. package/dist/utility/blueprint/material/func.js.map +1 -1
  221. package/dist/utility/blueprint/material/ir.js +490 -25
  222. package/dist/utility/blueprint/material/ir.js.map +1 -1
  223. package/dist/utility/blueprint/material/texture.js +898 -4
  224. package/dist/utility/blueprint/material/texture.js.map +1 -1
  225. package/dist/utility/serialization/manager.js +431 -100
  226. package/dist/utility/serialization/manager.js.map +1 -1
  227. package/dist/utility/serialization/scene/animation.js +370 -3
  228. package/dist/utility/serialization/scene/animation.js.map +1 -1
  229. package/dist/utility/serialization/scene/batch.js +4 -0
  230. package/dist/utility/serialization/scene/batch.js.map +1 -1
  231. package/dist/utility/serialization/scene/camera.js +133 -1
  232. package/dist/utility/serialization/scene/camera.js.map +1 -1
  233. package/dist/utility/serialization/scene/common.js +26 -5
  234. package/dist/utility/serialization/scene/common.js.map +1 -1
  235. package/dist/utility/serialization/scene/hair.js +1141 -0
  236. package/dist/utility/serialization/scene/hair.js.map +1 -0
  237. package/dist/utility/serialization/scene/light.js +84 -4
  238. package/dist/utility/serialization/scene/light.js.map +1 -1
  239. package/dist/utility/serialization/scene/material.js +1867 -166
  240. package/dist/utility/serialization/scene/material.js.map +1 -1
  241. package/dist/utility/serialization/scene/mesh.js +231 -14
  242. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  243. package/dist/utility/serialization/scene/node.js +141 -7
  244. package/dist/utility/serialization/scene/node.js.map +1 -1
  245. package/dist/utility/serialization/scene/particle.js +4 -0
  246. package/dist/utility/serialization/scene/particle.js.map +1 -1
  247. package/dist/utility/serialization/scene/primitive.js +18 -0
  248. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  249. package/dist/utility/serialization/scene/sprite.js +4 -0
  250. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  251. package/dist/utility/serialization/scene/terrain.js +4 -0
  252. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  253. package/dist/utility/serialization/scene/text.js +4 -0
  254. package/dist/utility/serialization/scene/text.js.map +1 -1
  255. package/dist/utility/serialization/scene/water.js +4 -0
  256. package/dist/utility/serialization/scene/water.js.map +1 -1
  257. package/dist/utility/serialization/types.js.map +1 -1
  258. package/dist/utility/shprojector.js +96 -95
  259. package/dist/utility/shprojector.js.map +1 -1
  260. package/dist/values.js +49 -2
  261. package/dist/values.js.map +1 -1
  262. package/package.json +3 -3
@@ -18,7 +18,7 @@ import '../animation/joint_dynamics/collision.js';
18
18
  import '../animation/joint_dynamics/solver.js';
19
19
  import { createTransformAccess, JointDynamicsSystem } from '../animation/joint_dynamics/joint_dynamics_system.js';
20
20
  import { JointDynamicsModifier } from '../animation/joint_dynamics_modifier.js';
21
- import { MAX_MORPH_TARGETS, MAX_MORPH_ATTRIBUTES } from '../values.js';
21
+ import { MAX_MORPH_ATTRIBUTES, MAX_MORPH_TARGETS, getMorphTargetLimit, MAX_SKIN_INFLUENCES } from '../values.js';
22
22
  import { Primitive } from '../render/primitive.js';
23
23
  import { UnlitMaterial } from '../material/unlit.js';
24
24
  import { PBRSpecularGlossinessMaterial } from '../material/pbrsg.js';
@@ -37,6 +37,30 @@ import { MToonMaterial } from '../material/mtoon.js';
37
37
  this.name = name;
38
38
  }
39
39
  }
40
+ function normalizeAssetNodePath(path) {
41
+ return path.replace(/\\/g, '/').split('/').filter(Boolean).join('/');
42
+ }
43
+ function getSkinBindingKey(rig, joints, inverseBindMatrices) {
44
+ const matrixKey = inverseBindMatrices.map((matrix)=>{
45
+ const elements = [];
46
+ for(let i = 0; i < 16; i++){
47
+ elements.push(matrix[i]);
48
+ }
49
+ return elements.join(',');
50
+ }).join('|');
51
+ return `${rig.persistentId}|${joints.map((joint)=>joint.persistentId).join('|')}|${matrixKey}`;
52
+ }
53
+ function getAssetNodePath(node) {
54
+ const segments = [];
55
+ let current = node;
56
+ while(current){
57
+ if (current.name) {
58
+ segments.push(current.name);
59
+ }
60
+ current = current.parent;
61
+ }
62
+ return normalizeAssetNodePath(segments.reverse().join('/'));
63
+ }
40
64
  /**
41
65
  * Heirarchical node interface for model loading
42
66
  * @public
@@ -665,18 +689,25 @@ import { MToonMaterial } from '../material/mtoon.js';
665
689
  ASSERT(!!ext, `Unknown image mime type: ${mimeType}`);
666
690
  const baseName = this.sanitizeResourceName(this.getImageBaseName(img, i, destName), `${destName}_texture_${i}`);
667
691
  const path = await this.tryReuseExactResourcePath(dstVFS, destPath, baseName, ext, usedPaths, `${destName}_texture_${i}`) ?? this.consumeReusableResourcePath(reusableResourcePools, baseName, ext, usedPaths) ?? await this.createUniqueResourcePath(dstVFS, destPath, baseName, ext, usedPaths, `${destName}_texture_${i}`);
668
- if (img.uri) {
669
- img.data = new Uint8Array(await srcVFS.readFile(img.uri, {
670
- encoding: 'binary'
671
- }));
692
+ try {
693
+ if (img.uri) {
694
+ img.data = new Uint8Array(await srcVFS.readFile(img.uri, {
695
+ encoding: 'binary'
696
+ }));
697
+ }
698
+ await dstVFS.writeFile(path, img.data.buffer.slice(img.data.byteOffset, img.data.byteOffset + img.data.byteLength), {
699
+ encoding: 'binary',
700
+ create: true
701
+ });
702
+ img.uri = path;
703
+ img.data = undefined;
704
+ img.mimeType = '';
705
+ } catch (err) {
706
+ console.warn(`Skip missing or unreadable texture during import: ${img.uri || img.name || `${destName}_texture_${i}`}: ${String(err)}`);
707
+ img.uri = undefined;
708
+ img.data = undefined;
709
+ img.mimeType = '';
672
710
  }
673
- await dstVFS.writeFile(path, img.data.buffer.slice(img.data.byteOffset, img.data.byteOffset + img.data.byteLength), {
674
- encoding: 'binary',
675
- create: true
676
- });
677
- img.uri = path;
678
- img.data = undefined;
679
- img.mimeType = '';
680
711
  }
681
712
  }
682
713
  const materialKeys = Object.keys(this._materialList);
@@ -900,6 +931,7 @@ import { MToonMaterial } from '../material/mtoon.js';
900
931
  }
901
932
  }
902
933
  const rigMap = new Map();
934
+ const bindingMap = new Map();
903
935
  for (const v of skeletonMeshMap){
904
936
  const sk = v[0];
905
937
  const joints = sk.joints.map((val)=>{
@@ -923,7 +955,13 @@ import { MToonMaterial } from '../material/mtoon.js';
923
955
  rigMap.set(rigKey, rig);
924
956
  group.animationSet.rigs.push(new DRef(rig));
925
957
  }
926
- const binding = new SkinBinding(rig, sk.inverseBindMatrices, joints);
958
+ const bindingKey = getSkinBindingKey(rig, joints, sk.inverseBindMatrices);
959
+ let binding = bindingMap.get(bindingKey);
960
+ if (!binding) {
961
+ binding = new SkinBinding(rig, sk.inverseBindMatrices, joints);
962
+ bindingMap.set(bindingKey, binding);
963
+ group.animationSet.skeletons.push(new DRef(binding));
964
+ }
927
965
  const nodes = skeletonMeshMap.get(sk);
928
966
  if (nodes) {
929
967
  if (!nodes.binding) {
@@ -933,14 +971,14 @@ import { MToonMaterial } from '../material/mtoon.js';
933
971
  const v = {
934
972
  positions: nodes.bounding[i].rawPositions,
935
973
  blendIndices: nodes.bounding[i].rawBlendIndices,
936
- weights: nodes.bounding[i].rawJointWeights
974
+ weights: nodes.bounding[i].rawJointWeights,
975
+ influenceCount: nodes.bounding[i].rawSkinInfluenceCount ?? 4
937
976
  };
938
977
  mesh.setSkinnedBoundingInfo(nodes.binding.getBoundingInfo(v));
939
978
  mesh.skeletonName = nodes.binding.persistentId;
940
979
  }
941
980
  }
942
981
  }
943
- group.animationSet.skeletons.push(new DRef(nodes.binding));
944
982
  }
945
983
  }
946
984
  if (saveAnimations) {
@@ -979,8 +1017,9 @@ import { MToonMaterial } from '../material/mtoon.js';
979
1017
  } else if (track.type === 'weights') {
980
1018
  for (const m of track.node.mesh.subMeshes){
981
1019
  const mesh = meshMap.get(m);
982
- if (track.interpolator.stride > MAX_MORPH_TARGETS) {
983
- console.error(`Morph target too large: ${track.interpolator.stride}, the maximum is ${MAX_MORPH_TARGETS}`);
1020
+ const morphTargetLimit = getMorphTargetLimit();
1021
+ if (track.interpolator.stride > morphTargetLimit) {
1022
+ console.error(`Morph target too large: ${track.interpolator.stride}, the project limit is ${morphTargetLimit}`);
984
1023
  } else {
985
1024
  const morphTrack = new MorphTargetTrack(track.interpolator, track.defaultMorphWeights, m.targetBox, mesh.getBoundingVolume().toAABB(), true);
986
1025
  animation.addTrack(mesh, morphTrack);
@@ -1214,6 +1253,7 @@ import { MToonMaterial } from '../material/mtoon.js';
1214
1253
  node.rotation.set(assetNode.rotation);
1215
1254
  node.scale.set(assetNode.scaling);
1216
1255
  if (saveMeshes && assetNode.mesh) {
1256
+ const sourceMorphReferenceAssetPath = this._preprocessOptions?.sourceMorphReferenceAssetPath ?? null;
1217
1257
  const meshData = assetNode.mesh;
1218
1258
  const skeleton = saveSkeletons ? assetNode.skeleton : null;
1219
1259
  for (const subMesh of meshData.subMeshes){
@@ -1229,7 +1269,7 @@ import { MToonMaterial } from '../material/mtoon.js';
1229
1269
  meshNode.position = instance.t;
1230
1270
  meshNode.scale = instance.s;
1231
1271
  meshNode.rotation = instance.r;
1232
- meshNode.name = subMesh.name;
1272
+ meshNode.name = subMesh.primitive?.name?.trim() || subMesh.name;
1233
1273
  meshNode.clipTestEnabled = true;
1234
1274
  meshNode.showState = 'inherit';
1235
1275
  if (!this._primitiveMap.get(subMesh.primitive)) {
@@ -1250,7 +1290,20 @@ import { MToonMaterial } from '../material/mtoon.js';
1250
1290
  mesh: meshData,
1251
1291
  subMesh
1252
1292
  });
1253
- processMorphData(subMesh, meshNode, assetNode.weights ?? meshData.morphWeights, meshData.morphNames);
1293
+ const morphSource = sourceMorphReferenceAssetPath && subMesh.numTargets > 0 ? (()=>{
1294
+ const nodePath = getAssetNodePath(assetNode);
1295
+ const subMeshName = subMesh.name;
1296
+ if (!nodePath || !subMeshName) {
1297
+ return null;
1298
+ }
1299
+ return {
1300
+ sourcePath: sourceMorphReferenceAssetPath,
1301
+ nodePath,
1302
+ subMeshName
1303
+ };
1304
+ })() : null;
1305
+ processMorphData(subMesh, meshNode, assetNode.weights ?? meshData.morphWeights, meshData.morphNames, morphSource);
1306
+ applyMeshSkinInfluenceData(subMesh, meshNode);
1254
1307
  if (skeleton) {
1255
1308
  if (!skeletonMeshMap.has(skeleton)) {
1256
1309
  skeletonMeshMap.set(skeleton, {
@@ -1762,30 +1815,28 @@ import { MToonMaterial } from '../material/mtoon.js';
1762
1815
  return null;
1763
1816
  }
1764
1817
  }
1765
- /** @internal */ function processMorphData(subMesh, mesh, morphWeights, morphNames) {
1766
- const device = getDevice();
1818
+ function applyMeshMorphMetadata(subMesh, mesh, morphWeights, morphNames) {
1767
1819
  const numTargets = subMesh.numTargets;
1768
- if (numTargets === 0) {
1820
+ if (numTargets === 0 || !subMesh.targets || !subMesh.targetBox) {
1769
1821
  return;
1770
1822
  }
1823
+ const supportedNumTargets = Math.min(numTargets, getMorphTargetLimit());
1824
+ if (supportedNumTargets !== numTargets) {
1825
+ console.warn(`Morph target count truncated from ${numTargets} to ${supportedNumTargets} for mesh "${subMesh.name ?? mesh.name ?? ''}"`);
1826
+ }
1771
1827
  const attributes = Object.getOwnPropertyNames(subMesh.targets);
1772
1828
  const positionInfo = subMesh.primitive.vertices['position'];
1773
1829
  const numVertices = positionInfo ? positionInfo.data.length / getVertexFormatComponentCount(positionInfo.format) >> 0 : 0;
1774
1830
  const weightsAndOffsets = new Float32Array(4 + MAX_MORPH_TARGETS + MAX_MORPH_ATTRIBUTES);
1775
- for(let i = 0; i < numTargets; i++){
1831
+ for(let i = 0; i < supportedNumTargets; i++){
1776
1832
  weightsAndOffsets[4 + i] = morphWeights?.[i] ?? 0;
1777
1833
  }
1778
1834
  const textureSize = Math.ceil(Math.sqrt(numVertices * attributes.length * numTargets));
1779
- if (textureSize > device.getDeviceCaps().textureCaps.maxTextureSize) {
1780
- // TODO: reduce morph attributes
1781
- throw new Error(`Morph target data too large`);
1782
- }
1783
1835
  weightsAndOffsets[0] = textureSize;
1784
1836
  weightsAndOffsets[1] = textureSize;
1785
1837
  weightsAndOffsets[2] = numVertices;
1786
- weightsAndOffsets[3] = numTargets;
1838
+ weightsAndOffsets[3] = supportedNumTargets;
1787
1839
  let offset = 0;
1788
- const textureData = new Float32Array(textureSize * textureSize * 4);
1789
1840
  for(let attrib = 0; attrib < MAX_MORPH_ATTRIBUTES; attrib++){
1790
1841
  const index = attributes.indexOf(String(attrib));
1791
1842
  if (index < 0) {
@@ -1798,64 +1849,124 @@ import { MToonMaterial } from '../material/mtoon.js';
1798
1849
  console.error(`Invalid morph target data`);
1799
1850
  return;
1800
1851
  }
1801
- for(let t = 0; t < numTargets; t++){
1802
- const data = info.data[t];
1803
- for(let i = 0; i < numVertices; i++){
1804
- for(let j = 0; j < 4; j++){
1805
- textureData[offset++] = j < info.numComponents ? data[i * info.numComponents + j] : 1;
1806
- }
1807
- }
1808
- }
1852
+ offset += numVertices * 4 * numTargets;
1809
1853
  }
1810
- const morphBoundingBox = new BoundingBox();
1811
- calculateMorphBoundingBox(morphBoundingBox, subMesh.targetBox, weightsAndOffsets.subarray(4, 4 + MAX_MORPH_TARGETS), numTargets);
1812
- const meshAABB = mesh.getBoundingVolume().toAABB();
1813
- morphBoundingBox.minPoint.addBy(meshAABB.minPoint);
1814
- morphBoundingBox.maxPoint.addBy(meshAABB.maxPoint);
1815
1854
  const names = {};
1816
- for(let i = 0; i < numTargets; i++){
1855
+ for(let i = 0; i < supportedNumTargets; i++){
1817
1856
  const name = morphNames?.[i] ?? `Target${i}`;
1818
1857
  names[name] = i;
1819
1858
  }
1820
- mesh.setMorphData({
1821
- width: textureSize,
1822
- height: textureSize,
1823
- data: textureData
1824
- });
1825
1859
  mesh.setMorphInfo({
1826
1860
  data: weightsAndOffsets,
1827
1861
  names
1828
1862
  });
1829
1863
  mesh.setMorphBoundingInfo({
1830
- targetBoxes: subMesh.targetBox,
1831
- originBox: new BoundingBox(meshAABB)
1864
+ targetBoxes: subMesh.targetBox.slice(0, supportedNumTargets),
1865
+ originBox: new BoundingBox(mesh.getBoundingVolume().toAABB())
1832
1866
  });
1833
- mesh.setAnimatedBoundingBox(morphBoundingBox);
1867
+ }
1868
+ function createMorphSourceDataFromSubMesh(subMesh) {
1869
+ const numTargets = Math.min(subMesh.numTargets, getMorphTargetLimit());
1870
+ if (numTargets === 0 || !subMesh.targets) {
1871
+ return null;
1872
+ }
1873
+ const positionInfo = subMesh.primitive.vertices['position'];
1874
+ const numVertices = positionInfo ? positionInfo.data.length / getVertexFormatComponentCount(positionInfo.format) >> 0 : 0;
1875
+ const targets = {};
1876
+ for (const [attribKey, info] of Object.entries(subMesh.targets)){
1877
+ const attrib = Number(attribKey);
1878
+ if (!info || !Number.isInteger(attrib) || attrib < 0) {
1879
+ continue;
1880
+ }
1881
+ if (info.data.length < numTargets) {
1882
+ console.error(`Invalid morph target data`);
1883
+ return null;
1884
+ }
1885
+ targets[attrib] = {
1886
+ numComponents: info.numComponents,
1887
+ data: info.data.slice(0, numTargets),
1888
+ indices: info.indices?.slice(0, numTargets)
1889
+ };
1890
+ }
1891
+ return {
1892
+ numTargets,
1893
+ numVertices,
1894
+ targets
1895
+ };
1896
+ }
1897
+ function applyMeshMorphData(subMesh, mesh) {
1898
+ const sourceData = createMorphSourceDataFromSubMesh(subMesh);
1899
+ if (!sourceData) {
1900
+ mesh.setMorphData(null);
1901
+ mesh.setMorphSourceData(null);
1902
+ return;
1903
+ }
1904
+ mesh.setMorphSourceData(sourceData);
1905
+ }
1906
+ function createSkinInfluenceDataFromSubMesh(subMesh) {
1907
+ // Preserve the influence count captured at import time so runtime settings do not silently
1908
+ // degrade already-imported assets when a project lowers the import limit later on.
1909
+ const influenceCount = Math.max(0, Math.min(subMesh.rawSkinInfluenceCount ?? 4, MAX_SKIN_INFLUENCES, Math.floor((subMesh.rawJointWeights?.length ?? 0) / Math.max(1, (subMesh.rawPositions?.length ?? 0) / 3))));
1910
+ if (influenceCount <= 4 || !subMesh.rawPositions || !subMesh.rawBlendIndices || !subMesh.rawJointWeights || subMesh.rawPositions.length < 3) {
1911
+ return null;
1912
+ }
1913
+ const numVertices = Math.floor(subMesh.rawPositions.length / 3);
1914
+ if (numVertices <= 0) {
1915
+ return null;
1916
+ }
1917
+ const extraInfluenceCount = influenceCount - 4;
1918
+ const pairCount = Math.ceil(extraInfluenceCount / 2);
1919
+ const textureSize = Math.ceil(Math.sqrt(numVertices * pairCount));
1920
+ const textureData = new Float32Array(textureSize * textureSize * 4);
1921
+ for(let vertexIndex = 0; vertexIndex < numVertices; vertexIndex++){
1922
+ const baseOffset = vertexIndex * influenceCount + 4;
1923
+ for(let pairIndex = 0; pairIndex < pairCount; pairIndex++){
1924
+ const influenceIndex = 4 + pairIndex * 2;
1925
+ const sourceIndex = baseOffset + pairIndex * 2;
1926
+ const texelOffset = (vertexIndex * pairCount + pairIndex) * 4;
1927
+ textureData[texelOffset] = Number(subMesh.rawBlendIndices[sourceIndex] ?? 0);
1928
+ textureData[texelOffset + 1] = Number(subMesh.rawJointWeights[sourceIndex] ?? 0);
1929
+ // Odd influence counts leave the second half of the final texel empty.
1930
+ // Do not read it from the next vertex's first influence.
1931
+ if (influenceIndex + 1 < influenceCount) {
1932
+ textureData[texelOffset + 2] = Number(subMesh.rawBlendIndices[sourceIndex + 1] ?? 0);
1933
+ textureData[texelOffset + 3] = Number(subMesh.rawJointWeights[sourceIndex + 1] ?? 0);
1934
+ }
1935
+ }
1936
+ }
1937
+ return {
1938
+ width: textureSize,
1939
+ height: textureSize,
1940
+ influenceCount,
1941
+ data: textureData
1942
+ };
1943
+ }
1944
+ function applyMeshSkinInfluenceData(subMesh, mesh) {
1945
+ mesh.setSkinInfluenceData(createSkinInfluenceDataFromSubMesh(subMesh));
1946
+ }
1947
+ /** @internal */ function processMorphData(subMesh, mesh, morphWeights, morphNames, morphSource) {
1948
+ if (subMesh.numTargets === 0) {
1949
+ return;
1950
+ }
1951
+ applyMeshMorphMetadata(subMesh, mesh, morphWeights, morphNames);
1952
+ mesh.setMorphSource(morphSource ?? null);
1953
+ if (morphSource) {
1954
+ mesh.setMorphSourceData(null);
1955
+ mesh.setMorphData(null);
1956
+ } else {
1957
+ applyMeshMorphData(subMesh, mesh);
1958
+ }
1834
1959
  }
1835
1960
  /** @internal */ function getAssetMeshMorphTargetCount(mesh) {
1836
1961
  let count = 0;
1837
1962
  for (const subMesh of mesh.subMeshes){
1838
1963
  count = Math.max(count, subMesh.numTargets);
1839
1964
  }
1840
- return count;
1965
+ return Math.min(count, getMorphTargetLimit());
1841
1966
  }
1842
1967
  /** @internal */ function getAssetMeshMorphTargetName(mesh, index) {
1843
1968
  return mesh.morphNames?.[index] ?? `Target${index}`;
1844
1969
  }
1845
- /** @internal */ function calculateMorphBoundingBox(morphBoundingBox, keyframeBoundingBox, weights, numTargets) {
1846
- morphBoundingBox.minPoint.setXYZ(0, 0, 0);
1847
- morphBoundingBox.maxPoint.setXYZ(0, 0, 0);
1848
- for(let i = 0; i < numTargets; i++){
1849
- const weight = weights[i];
1850
- const keyframeBox = keyframeBoundingBox[i];
1851
- morphBoundingBox.minPoint.x += keyframeBox.minPoint.x * weight;
1852
- morphBoundingBox.minPoint.y += keyframeBox.minPoint.y * weight;
1853
- morphBoundingBox.minPoint.z += keyframeBox.minPoint.z * weight;
1854
- morphBoundingBox.maxPoint.x += keyframeBox.maxPoint.x * weight;
1855
- morphBoundingBox.maxPoint.y += keyframeBox.maxPoint.y * weight;
1856
- morphBoundingBox.maxPoint.z += keyframeBox.maxPoint.z * weight;
1857
- }
1858
- }
1859
1970
 
1860
- export { AssetHierarchyNode, AssetScene, AssetSkeleton, NamedObject, SharedModel };
1971
+ export { AssetHierarchyNode, AssetScene, AssetSkeleton, NamedObject, SharedModel, applyMeshMorphData, applyMeshMorphMetadata, applyMeshSkinInfluenceData, createMorphSourceDataFromSubMesh };
1861
1972
  //# sourceMappingURL=model.js.map