@zephyr3d/scene 0.4.0 → 0.6.0

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 (233) hide show
  1. package/dist/animation/animation.js +25 -117
  2. package/dist/animation/animation.js.map +1 -1
  3. package/dist/animation/animationset.js +191 -51
  4. package/dist/animation/animationset.js.map +1 -1
  5. package/dist/animation/animationtrack.js +6 -18
  6. package/dist/animation/animationtrack.js.map +1 -1
  7. package/dist/animation/eulerrotationtrack.js +16 -6
  8. package/dist/animation/eulerrotationtrack.js.map +1 -1
  9. package/dist/animation/morphtarget.js +104 -0
  10. package/dist/animation/morphtarget.js.map +1 -0
  11. package/dist/animation/morphtrack.js +70 -0
  12. package/dist/animation/morphtrack.js.map +1 -0
  13. package/dist/animation/rotationtrack.js +15 -7
  14. package/dist/animation/rotationtrack.js.map +1 -1
  15. package/dist/animation/scaletrack.js +15 -7
  16. package/dist/animation/scaletrack.js.map +1 -1
  17. package/dist/animation/skeleton.js +107 -5
  18. package/dist/animation/skeleton.js.map +1 -1
  19. package/dist/animation/translationtrack.js +15 -7
  20. package/dist/animation/translationtrack.js.map +1 -1
  21. package/dist/app.js +4 -26
  22. package/dist/app.js.map +1 -1
  23. package/dist/asset/assetmanager.js +60 -109
  24. package/dist/asset/assetmanager.js.map +1 -1
  25. package/dist/asset/loaders/dds/dds.js +77 -3
  26. package/dist/asset/loaders/dds/dds.js.map +1 -1
  27. package/dist/asset/loaders/dds/dds_loader.js +1 -1
  28. package/dist/asset/loaders/gltf/gltf_loader.js +287 -40
  29. package/dist/asset/loaders/gltf/gltf_loader.js.map +1 -1
  30. package/dist/asset/loaders/image/tga_Loader.js +1 -1
  31. package/dist/asset/loaders/image/webimage_loader.js +16 -0
  32. package/dist/asset/loaders/image/webimage_loader.js.map +1 -1
  33. package/dist/asset/model.js +16 -9
  34. package/dist/asset/model.js.map +1 -1
  35. package/dist/blitter/bilateralblur.js +222 -0
  36. package/dist/{render/temporalcache.js.map → blitter/bilateralblur.js.map} +1 -1
  37. package/dist/blitter/blitter.js +9 -3
  38. package/dist/blitter/blitter.js.map +1 -1
  39. package/dist/blitter/depthlimitedgaussion.js +96 -39
  40. package/dist/blitter/depthlimitedgaussion.js.map +1 -1
  41. package/dist/blitter/gaussianblur.js +21 -21
  42. package/dist/camera/camera.js +200 -4
  43. package/dist/camera/camera.js.map +1 -1
  44. package/dist/index.d.ts +6406 -5786
  45. package/dist/index.js +12 -10
  46. package/dist/index.js.map +1 -1
  47. package/dist/material/blinn.js +15 -4
  48. package/dist/material/blinn.js.map +1 -1
  49. package/dist/material/lambert.js +26 -17
  50. package/dist/material/lambert.js.map +1 -1
  51. package/dist/material/material.js +13 -2
  52. package/dist/material/material.js.map +1 -1
  53. package/dist/material/meshmaterial.js +103 -31
  54. package/dist/material/meshmaterial.js.map +1 -1
  55. package/dist/material/mixins/albedocolor.js +5 -4
  56. package/dist/material/mixins/albedocolor.js.map +1 -1
  57. package/dist/material/mixins/lightmodel/blinnphong.js +17 -7
  58. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  59. package/dist/material/mixins/lightmodel/lambert.js +5 -5
  60. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +16 -7
  61. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  62. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +16 -7
  63. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  64. package/dist/material/mixins/lit.js +2 -2
  65. package/dist/material/mixins/pbr/common.js +454 -19
  66. package/dist/material/mixins/pbr/common.js.map +1 -1
  67. package/dist/material/pbrmr.js +28 -6
  68. package/dist/material/pbrmr.js.map +1 -1
  69. package/dist/material/pbrsg.js +27 -9
  70. package/dist/material/pbrsg.js.map +1 -1
  71. package/dist/material/shader/helper.js +128 -23
  72. package/dist/material/shader/helper.js.map +1 -1
  73. package/dist/material/unlit.js +8 -4
  74. package/dist/material/unlit.js.map +1 -1
  75. package/dist/posteffect/bloom.js +34 -53
  76. package/dist/posteffect/bloom.js.map +1 -1
  77. package/dist/posteffect/compositor.js +48 -58
  78. package/dist/posteffect/compositor.js.map +1 -1
  79. package/dist/posteffect/fxaa.js +3 -11
  80. package/dist/posteffect/fxaa.js.map +1 -1
  81. package/dist/posteffect/grayscale.js +3 -11
  82. package/dist/posteffect/grayscale.js.map +1 -1
  83. package/dist/posteffect/posteffect.js +4 -0
  84. package/dist/posteffect/posteffect.js.map +1 -1
  85. package/dist/posteffect/sao.js +55 -48
  86. package/dist/posteffect/sao.js.map +1 -1
  87. package/dist/posteffect/ssr.js +536 -0
  88. package/dist/{material/lit.js.map → posteffect/ssr.js.map} +1 -1
  89. package/dist/posteffect/tonemap.js +3 -11
  90. package/dist/posteffect/tonemap.js.map +1 -1
  91. package/dist/posteffect/water.js +306 -340
  92. package/dist/posteffect/water.js.map +1 -1
  93. package/dist/render/abuffer_oit.js +2 -2
  94. package/dist/render/clipmap.js +16 -19
  95. package/dist/render/clipmap.js.map +1 -1
  96. package/dist/render/cull_visitor.js +8 -6
  97. package/dist/render/cull_visitor.js.map +1 -1
  98. package/dist/render/depthpass.js +30 -14
  99. package/dist/render/depthpass.js.map +1 -1
  100. package/dist/render/drawable_mixin.js +70 -22
  101. package/dist/render/drawable_mixin.js.map +1 -1
  102. package/dist/render/envlight.js +169 -33
  103. package/dist/render/envlight.js.map +1 -1
  104. package/dist/render/fft_wavegenerator.js +989 -0
  105. package/dist/{shaders/framework.js.map → render/fft_wavegenerator.js.map} +1 -1
  106. package/dist/render/gerstner_wavegenerator.js +265 -0
  107. package/dist/{material/standard.js.map → render/gerstner_wavegenerator.js.map} +1 -1
  108. package/dist/render/globalbindgroup_allocator.js +2 -1
  109. package/dist/render/globalbindgroup_allocator.js.map +1 -1
  110. package/dist/render/hzb.js +273 -0
  111. package/dist/{material/terrainlightmodel.js.map → render/hzb.js.map} +1 -1
  112. package/dist/render/lightpass.js +68 -28
  113. package/dist/render/lightpass.js.map +1 -1
  114. package/dist/render/objectcolorpass.js +51 -0
  115. package/dist/render/objectcolorpass.js.map +1 -0
  116. package/dist/render/render_queue.js +211 -158
  117. package/dist/render/render_queue.js.map +1 -1
  118. package/dist/render/renderbundle_wrapper.js +79 -0
  119. package/dist/render/renderbundle_wrapper.js.map +1 -1
  120. package/dist/render/renderer.js +151 -35
  121. package/dist/render/renderer.js.map +1 -1
  122. package/dist/render/renderpass.js +27 -20
  123. package/dist/render/renderpass.js.map +1 -1
  124. package/dist/render/shadowmap_pass.js +20 -14
  125. package/dist/render/shadowmap_pass.js.map +1 -1
  126. package/dist/render/sky.js +12 -13
  127. package/dist/render/sky.js.map +1 -1
  128. package/dist/render/watermesh.js +94 -828
  129. package/dist/render/watermesh.js.map +1 -1
  130. package/dist/render/wavegenerator.js +8 -0
  131. package/dist/render/wavegenerator.js.map +1 -0
  132. package/dist/render/weightedblended_oit.js +11 -28
  133. package/dist/render/weightedblended_oit.js.map +1 -1
  134. package/dist/scene/batchgroup.js +60 -14
  135. package/dist/scene/batchgroup.js.map +1 -1
  136. package/dist/scene/environment.js +24 -3
  137. package/dist/scene/environment.js.map +1 -1
  138. package/dist/scene/graph_node.js +0 -14
  139. package/dist/scene/graph_node.js.map +1 -1
  140. package/dist/scene/light.js +5 -5
  141. package/dist/scene/mesh.js +62 -15
  142. package/dist/scene/mesh.js.map +1 -1
  143. package/dist/scene/octree.js +5 -2
  144. package/dist/scene/octree.js.map +1 -1
  145. package/dist/scene/raycast_visitor.js +4 -2
  146. package/dist/scene/raycast_visitor.js.map +1 -1
  147. package/dist/scene/scene.js +6 -9
  148. package/dist/scene/scene.js.map +1 -1
  149. package/dist/scene/scene_node.js +11 -8
  150. package/dist/scene/scene_node.js.map +1 -1
  151. package/dist/scene/terrain/grass.js +10 -2
  152. package/dist/scene/terrain/grass.js.map +1 -1
  153. package/dist/scene/terrain/heightfield.js +135 -53
  154. package/dist/scene/terrain/heightfield.js.map +1 -1
  155. package/dist/scene/terrain/patch.js +10 -2
  156. package/dist/scene/terrain/patch.js.map +1 -1
  157. package/dist/scene/terrain/quadtree.js +2 -2
  158. package/dist/scene/terrain/terrain.js +1 -1
  159. package/dist/scene/xform.js +7 -9
  160. package/dist/scene/xform.js.map +1 -1
  161. package/dist/shaders/misc.js +10 -1
  162. package/dist/shaders/misc.js.map +1 -1
  163. package/dist/shaders/noise.js +81 -16
  164. package/dist/shaders/noise.js.map +1 -1
  165. package/dist/shaders/shadow.js +1 -9
  166. package/dist/shaders/shadow.js.map +1 -1
  167. package/dist/shaders/ssr.js +442 -0
  168. package/dist/{material/terrainmat.js.map → shaders/ssr.js.map} +1 -1
  169. package/dist/shaders/water.js +377 -250
  170. package/dist/shaders/water.js.map +1 -1
  171. package/dist/shadow/esm.js +4 -22
  172. package/dist/shadow/esm.js.map +1 -1
  173. package/dist/shadow/shadowmapper.js +56 -31
  174. package/dist/shadow/shadowmapper.js.map +1 -1
  175. package/dist/shadow/vsm.js +4 -24
  176. package/dist/shadow/vsm.js.map +1 -1
  177. package/dist/shapes/cylinder.js +6 -5
  178. package/dist/shapes/cylinder.js.map +1 -1
  179. package/dist/utility/bounding_volume.js +1 -53
  180. package/dist/utility/bounding_volume.js.map +1 -1
  181. package/dist/utility/draco/decoder.js +116 -0
  182. package/dist/utility/draco/decoder.js.map +1 -0
  183. package/dist/utility/misc.js +93 -0
  184. package/dist/utility/misc.js.map +1 -0
  185. package/dist/utility/shprojection.js +2 -7
  186. package/dist/utility/shprojection.js.map +1 -1
  187. package/dist/utility/textures/ggxlut.js +213 -0
  188. package/dist/utility/textures/ggxlut.js.map +1 -0
  189. package/dist/utility/textures/gradientnoise.js +61 -0
  190. package/dist/utility/textures/gradientnoise.js.map +1 -0
  191. package/dist/utility/textures/randomnoise.js +41 -0
  192. package/dist/utility/textures/randomnoise.js.map +1 -0
  193. package/dist/values.js +25 -1
  194. package/dist/values.js.map +1 -1
  195. package/package.json +5 -8
  196. package/dist/animation/usertrack.js +0 -47
  197. package/dist/animation/usertrack.js.map +0 -1
  198. package/dist/material/grassmat.js +0 -127
  199. package/dist/material/grassmat.js.map +0 -1
  200. package/dist/material/lightmodel.js +0 -2074
  201. package/dist/material/lightmodel.js.map +0 -1
  202. package/dist/material/lit.js +0 -578
  203. package/dist/material/mixins/pbr/metallicroughness.js +0 -126
  204. package/dist/material/mixins/pbr/metallicroughness.js.map +0 -1
  205. package/dist/material/mixins/pbr/specularglossness.js +0 -104
  206. package/dist/material/mixins/pbr/specularglossness.js.map +0 -1
  207. package/dist/material/pbr.js +0 -27
  208. package/dist/material/pbr.js.map +0 -1
  209. package/dist/material/standard.js +0 -282
  210. package/dist/material/terrainlightmodel.js +0 -259
  211. package/dist/material/terrainmat.js +0 -357
  212. package/dist/render/depth_pass.js +0 -47
  213. package/dist/render/depth_pass.js.map +0 -1
  214. package/dist/render/forward.js +0 -186
  215. package/dist/render/forward.js.map +0 -1
  216. package/dist/render/forward_pass.js +0 -137
  217. package/dist/render/forward_pass.js.map +0 -1
  218. package/dist/render/helper.js +0 -38
  219. package/dist/render/helper.js.map +0 -1
  220. package/dist/render/renderscheme.js +0 -61
  221. package/dist/render/renderscheme.js.map +0 -1
  222. package/dist/render/temporalcache.js +0 -222
  223. package/dist/scene/model.js +0 -111
  224. package/dist/scene/model.js.map +0 -1
  225. package/dist/scene/octree_update_visitor.js +0 -20
  226. package/dist/scene/octree_update_visitor.js.map +0 -1
  227. package/dist/shaders/builtins.js +0 -110
  228. package/dist/shaders/builtins.js.map +0 -1
  229. package/dist/shaders/framework.js +0 -723
  230. package/dist/shaders/lighting.js +0 -335
  231. package/dist/shaders/lighting.js.map +0 -1
  232. package/dist/utility/sheenlut.js +0 -196
  233. package/dist/utility/sheenlut.js.map +0 -1
@@ -1,47 +1,22 @@
1
- import { Quaternion, Vector3, Matrix4x4 } from '@zephyr3d/base';
2
- import { BoundingBox } from '../utility/bounding_volume.js';
3
- import { Application } from '../app.js';
4
-
5
1
  /**
6
2
  * Animation that contains multiple tracks
7
3
  * @public
8
4
  */ class AnimationClip {
9
5
  /** @internal */ _name;
10
- /** @internal */ _model;
11
- /** @internal */ _repeat;
12
- /** @internal */ _speedRatio;
13
- /** @internal */ _repeatCounter;
14
6
  /** @internal */ _duration;
15
- /** @internal */ _isPlaying;
16
- /** @internal */ _lastUpdateFrame;
17
- /** @internal */ _currentPlayTime;
18
7
  /** @internal */ _tracks;
19
8
  /** @internal */ _skeletons;
20
- /** @internal */ _tmpPosition;
21
- /** @internal */ _tmpRotation;
22
- /** @internal */ _tmpScale;
23
9
  /**
24
10
  * Creates an animation instance
25
11
  * @param name - Name of the animation
26
12
  * @param model - Parent node if this is a skeleton animation
27
- */ constructor(name, model){
13
+ */ constructor(name){
28
14
  this._name = name;
29
- this._model = model ?? null;
30
15
  this._tracks = new Map();
31
16
  this._duration = 0;
32
- this._repeat = 0;
33
- this._repeatCounter = 0;
34
- this._speedRatio = 1;
35
- this._isPlaying = false;
36
- this._currentPlayTime = 0;
37
- this._lastUpdateFrame = 0;
38
- this._skeletons = new Map();
39
- this._tmpRotation = new Quaternion();
40
- this._tmpPosition = new Vector3();
41
- this._tmpScale = new Vector3();
17
+ this._skeletons = new Set();
42
18
  }
43
19
  /** Disposes self */ dispose() {
44
- this._model = null;
45
20
  this._tracks = null;
46
21
  this._skeletons?.forEach((val, key)=>key.dispose());
47
22
  this._skeletons = null;
@@ -52,6 +27,9 @@ import { Application } from '../app.js';
52
27
  /** Gets all the tracks of this animation */ get tracks() {
53
28
  return this._tracks;
54
29
  }
30
+ /** Gets all skeletons */ get skeletons() {
31
+ return this._skeletons;
32
+ }
55
33
  /** The duration of the animation */ get timeDuration() {
56
34
  return this._duration;
57
35
  }
@@ -60,19 +38,8 @@ import { Application } from '../app.js';
60
38
  * @param skeleton - The skeleton to be added
61
39
  * @param meshList - The meshes controlled by the skeleton
62
40
  * @param boundingBoxInfo - Bounding box information for the skeleton
63
- */ addSkeleton(skeleton, meshList, boundingBoxInfo) {
64
- let meshes = this._skeletons.get(skeleton);
65
- if (!meshes) {
66
- meshes = [];
67
- this._skeletons.set(skeleton, meshes);
68
- }
69
- for(let i = 0; i < meshList.length; i++){
70
- meshes.push({
71
- mesh: meshList[i],
72
- bounding: boundingBoxInfo[i],
73
- box: new BoundingBox()
74
- });
75
- }
41
+ */ addSkeleton(skeleton) {
42
+ this._skeletons.add(skeleton);
76
43
  }
77
44
  /**
78
45
  * Adds an animation track to the animation
@@ -83,90 +50,31 @@ import { Application } from '../app.js';
83
50
  if (!track) {
84
51
  return;
85
52
  }
53
+ if (track.animation) {
54
+ if (track.animation === this) {
55
+ return;
56
+ } else {
57
+ console.error('Track is already in another animation');
58
+ return;
59
+ }
60
+ }
61
+ const blendId = track.getBlendId();
62
+ const tracks = this._tracks.get(node);
63
+ if (tracks && tracks.findIndex((track)=>track.getBlendId() === blendId) >= 0) {
64
+ console.error('Tracks with same BlendId could not be added to same animation');
65
+ return;
66
+ }
67
+ track.animation = this;
86
68
  let trackInfo = this._tracks.get(node);
87
69
  if (!trackInfo) {
88
- trackInfo = {
89
- poseTranslation: new Vector3(node.position),
90
- poseRotation: new Quaternion(node.rotation),
91
- poseScaling: new Vector3(node.scale),
92
- tracks: []
93
- };
70
+ trackInfo = [];
94
71
  this._tracks.set(node, trackInfo);
95
72
  }
96
- trackInfo.tracks.push(track);
73
+ trackInfo.push(track);
97
74
  this._duration = Math.max(this._duration, track.interpolator.maxTime);
75
+ track.reset(node);
98
76
  return this;
99
77
  }
100
- /**
101
- * Check if the animation is playing
102
- * @returns true if the animation is playing, otherwise false
103
- */ isPlaying() {
104
- return this._isPlaying;
105
- }
106
- /**
107
- * Updates the animation state
108
- */ update() {
109
- const device = Application.instance.device;
110
- if (!this._isPlaying || this._lastUpdateFrame === device.frameInfo.frameCounter) {
111
- return;
112
- }
113
- this._lastUpdateFrame = device.frameInfo.frameCounter;
114
- this._tracks.forEach((trackInfo, node)=>{
115
- for (const track of trackInfo.tracks){
116
- track.apply(node, this._currentPlayTime, this._duration);
117
- }
118
- });
119
- this._skeletons.forEach((meshes, skeleton)=>{
120
- skeleton.computeJoints();
121
- for (const mesh of meshes){
122
- skeleton.computeBoundingBox(mesh.bounding, mesh.mesh.invWorldMatrix);
123
- mesh.mesh.setBoneMatrices(skeleton.jointTexture);
124
- mesh.mesh.setInvBindMatrix(mesh.mesh.invWorldMatrix);
125
- mesh.mesh.setAnimatedBoundingBox(mesh.bounding.boundingBox);
126
- }
127
- });
128
- const timeAdvance = device.frameInfo.elapsedFrame * 0.001 * this._speedRatio;
129
- this._currentPlayTime += timeAdvance;
130
- if (this._currentPlayTime > this._duration) {
131
- this._repeatCounter++;
132
- this._currentPlayTime = 0;
133
- } else if (this._currentPlayTime < 0) {
134
- this._repeatCounter++;
135
- this._currentPlayTime = this._duration;
136
- }
137
- if (this._repeat !== 0 && this._repeatCounter >= this._repeat) {
138
- this.stop();
139
- }
140
- }
141
- /**
142
- * Starts playing the animation
143
- */ play(repeat, speedRatio) {
144
- this._isPlaying = true;
145
- this._repeat = repeat;
146
- this._speedRatio = speedRatio;
147
- this._currentPlayTime = speedRatio < 0 ? this._duration : 0;
148
- this.update();
149
- }
150
- /**
151
- * Stops the animation
152
- */ stop() {
153
- this._isPlaying = false;
154
- this._skeletons.forEach((meshes, skeleton)=>{
155
- skeleton.computeBindPose();
156
- for (const mesh of meshes){
157
- const invWorldMatrix = Matrix4x4.multiply(mesh.mesh.invWorldMatrix, this._model.worldMatrix);
158
- skeleton.computeBoundingBox(mesh.bounding, invWorldMatrix);
159
- mesh.mesh.setBoneMatrices(skeleton.jointTexture);
160
- mesh.mesh.setInvBindMatrix(invWorldMatrix);
161
- mesh.mesh.setAnimatedBoundingBox(mesh.bounding.boundingBox);
162
- }
163
- });
164
- }
165
- /**
166
- * Rewind the animation to the first frame
167
- */ rewind() {
168
- this._currentPlayTime = 0;
169
- }
170
78
  }
171
79
 
172
80
  export { AnimationClip };
@@ -1 +1 @@
1
- {"version":3,"file":"animation.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"animation.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,84 +1,221 @@
1
- /**
2
- * Animation set
3
- * @public
1
+ import { weightedAverage } from '@zephyr3d/base';
2
+ import { Application } from '../app.js';
3
+
4
+ /**
5
+ * Animation set
6
+ * @public
4
7
  */ class AnimationSet {
8
+ /** @internal */ _model;
5
9
  /** @internal */ _animations;
6
10
  /** @internal */ _scene;
7
- /**
8
- * Creates an instance of AnimationSet
9
- * @param scene - The scene to which the animation set belongs
10
- */ constructor(scene){
11
+ /** @internal */ _activeTracks;
12
+ /** @internal */ _activeSkeletons;
13
+ /** @internal */ _activeAnimations;
14
+ /**
15
+ * Creates an instance of AnimationSet
16
+ * @param scene - The scene to which the animation set belongs
17
+ */ constructor(scene, model){
11
18
  this._scene = scene;
19
+ this._model = model;
12
20
  this._scene.animationSet.push(this);
13
21
  this._animations = {};
22
+ this._activeTracks = new Map();
23
+ this._activeSkeletons = new Map();
24
+ this._activeAnimations = new Map();
14
25
  }
15
- /**
16
- * How many animations in this set
26
+ /**
27
+ * How many animations in this set
17
28
  */ get numAnimations() {
18
29
  return Object.getOwnPropertyNames(this._animations).length;
19
30
  }
20
- /**
21
- * Gets an animation clip by name
22
- * @param name - name of the animation to get
31
+ /**
32
+ * Gets an animation clip by name
33
+ * @param name - name of the animation to get
23
34
  */ get(name) {
24
35
  return this._animations[name] ?? null;
25
36
  }
26
- /**
27
- * Adds an animation
37
+ /**
38
+ * Adds an animation
28
39
  */ add(animation) {
29
40
  this._animations[animation.name] = animation;
30
41
  }
31
- /**
32
- * Gets names of all the animations of the model
33
- * @returns An array of string that contains the animation names
42
+ /**
43
+ * Gets names of all the animations of the model
44
+ * @returns An array of string that contains the animation names
34
45
  */ getAnimationNames() {
35
46
  return Object.keys(this._animations);
36
47
  }
37
- /**
38
- * Updates all animations of the model
48
+ /**
49
+ * Updates all animations of the model
39
50
  */ update() {
40
- for(const k in this._animations){
41
- this._animations[k].update();
42
- }
51
+ this._activeAnimations.forEach((v, k)=>{
52
+ if (v.fadeOut > 0 && v.fadeOutStart < 0) {
53
+ v.fadeOutStart = v.animateTime;
54
+ }
55
+ // Update animation time
56
+ if (v.firstFrame) {
57
+ v.firstFrame = false;
58
+ } else {
59
+ const timeAdvance = Application.instance.device.frameInfo.elapsedFrame * 0.001 * v.speedRatio;
60
+ v.currentTime += timeAdvance;
61
+ v.animateTime += timeAdvance;
62
+ if (v.currentTime > k.timeDuration) {
63
+ v.repeatCounter++;
64
+ v.currentTime = 0;
65
+ } else if (v.currentTime < 0) {
66
+ v.repeatCounter++;
67
+ v.currentTime = k.timeDuration;
68
+ }
69
+ if (v.repeat !== 0 && v.repeatCounter >= v.repeat) {
70
+ this.stopAnimation(k.name);
71
+ } else if (v.fadeOut > 0) {
72
+ if (v.animateTime - v.fadeOutStart >= v.fadeOut) {
73
+ this.stopAnimation(k.name);
74
+ }
75
+ }
76
+ }
77
+ });
78
+ // Update tracks
79
+ this._activeTracks.forEach((v, k)=>{
80
+ v.forEach((tracks)=>{
81
+ if (tracks.length > 0) {
82
+ const weights = tracks.map((track)=>{
83
+ const info = this._activeAnimations.get(track.animation);
84
+ const weight = info.weight;
85
+ const fadeIn = info.fadeIn === 0 ? 1 : Math.min(1, info.animateTime / info.fadeIn);
86
+ let fadeOut = 1;
87
+ if (info.fadeOut !== 0) {
88
+ fadeOut = 1 - (info.animateTime - info.fadeOutStart) / info.fadeOut;
89
+ }
90
+ return weight * fadeIn * fadeOut;
91
+ });
92
+ const states = tracks.map((track)=>track.calculateState(this._activeAnimations.get(track.animation).currentTime));
93
+ const state = weightedAverage(weights, states, (a, b, t)=>{
94
+ return tracks[0].mixState(a, b, t);
95
+ });
96
+ tracks[0].applyState(k, state);
97
+ }
98
+ });
99
+ });
100
+ // Update skeletons
101
+ this._activeSkeletons.forEach((v, k)=>{
102
+ k.apply();
103
+ });
43
104
  }
44
- /**
45
- * Checks whether an animation is playing
46
- * @param name - Name of the animation to be checked
47
- * @returns true if the animation is playing, otherwise false
105
+ /**
106
+ * Checks whether an animation is playing
107
+ * @param name - Name of the animation to be checked
108
+ * @returns true if the animation is playing, otherwise false
48
109
  */ isPlayingAnimation(name) {
49
- if (name) {
50
- return this._animations[name]?.isPlaying();
110
+ return name ? this._activeAnimations.has(this._animations[name]) : this._activeAnimations.size > 0;
111
+ }
112
+ /**
113
+ * Gets the weight of specific animation which is currently playing
114
+ * @param name - Name of the animation
115
+ * @returns Weight of the animation or 0 if this animation is not playing
116
+ */ getAnimationWeight(name) {
117
+ const ani = this._animations[name];
118
+ const info = this._activeAnimations.get(ani);
119
+ return info?.weight ?? 0;
120
+ }
121
+ /**
122
+ * Sets the weight of specific animation which is currently playing
123
+ * @param name - Name of the animation
124
+ * @param weight - New weight value
125
+ */ setAnimationWeight(name, weight) {
126
+ const ani = this._animations[name];
127
+ const info = this._activeAnimations.get(ani);
128
+ if (info) {
129
+ info.weight = weight;
130
+ }
131
+ }
132
+ /**
133
+ * Starts playing an animation of the model
134
+ * @param name - Name of the animation to play
135
+ * @param options - Playing options
136
+ */ playAnimation(name, options) {
137
+ const ani = this._animations[name];
138
+ if (!ani) {
139
+ console.error(`Animation ${name} not exists`);
140
+ return;
141
+ }
142
+ const fadeIn = Math.max(options?.fadeIn ?? 0, 0);
143
+ const info = this._activeAnimations.get(ani);
144
+ if (info) {
145
+ info.fadeOut = 0;
146
+ info.fadeIn = fadeIn;
51
147
  } else {
52
- for(const k in this._animations){
53
- if (this._animations[k].isPlaying()) {
54
- return true;
148
+ const repeat = options?.repeat ?? 0;
149
+ const speedRatio = options?.speedRatio ?? 1;
150
+ const weight = options?.weight ?? 1;
151
+ this._activeAnimations.set(ani, {
152
+ repeat,
153
+ weight,
154
+ speedRatio,
155
+ fadeIn,
156
+ fadeOut: 0,
157
+ repeatCounter: 0,
158
+ currentTime: speedRatio < 0 ? ani.timeDuration : 0,
159
+ animateTime: 0,
160
+ fadeOutStart: 0,
161
+ firstFrame: true
162
+ });
163
+ ani.tracks?.forEach((v, k)=>{
164
+ let nodeTracks = this._activeTracks.get(k);
165
+ if (!nodeTracks) {
166
+ nodeTracks = new Map();
167
+ this._activeTracks.set(k, nodeTracks);
55
168
  }
56
- }
57
- return false;
169
+ for (const track of v){
170
+ const blendId = track.getBlendId();
171
+ let blendedTracks = nodeTracks.get(blendId);
172
+ if (!blendedTracks) {
173
+ blendedTracks = [];
174
+ nodeTracks.set(blendId, blendedTracks);
175
+ }
176
+ blendedTracks.push(track);
177
+ }
178
+ });
179
+ ani.skeletons?.forEach((v, k)=>{
180
+ const refcount = this._activeSkeletons.get(k);
181
+ if (refcount) {
182
+ this._activeSkeletons.set(k, refcount + 1);
183
+ } else {
184
+ this._activeSkeletons.set(k, 1);
185
+ }
186
+ });
58
187
  }
59
188
  }
60
- /**
61
- * Starts playing an animation of the model
62
- * @param name - Name of the animation to play
63
- * @param repeat - The repeat times, 0 for always repeating, default is 1
64
- * @param ratio - The speed ratio, default is 1. Use negative value to play backwards
65
- */ playAnimation(name, repeat = 0, speedRatio = 1) {
189
+ /**
190
+ * Stops playing an animation of the model
191
+ * @param name - Name of the animation to stop playing
192
+ */ stopAnimation(name, options) {
66
193
  const ani = this._animations[name];
67
- if (ani && !ani.isPlaying()) {
68
- for (const name of this.getAnimationNames()){
69
- if (this.isPlayingAnimation(name)) {
70
- this.stopAnimation(name);
71
- }
194
+ const info = this._activeAnimations.get(ani);
195
+ if (info) {
196
+ const fadeOut = Math.max(options?.fadeOut ?? 0, 0);
197
+ if (fadeOut !== 0) {
198
+ info.fadeOut = fadeOut;
199
+ info.fadeOutStart = -1;
200
+ } else {
201
+ this._activeAnimations.delete(ani);
202
+ this._activeTracks.forEach((v, k)=>{
203
+ v.forEach((tracks, id)=>{
204
+ v.set(id, tracks.filter((track)=>track.animation !== ani));
205
+ });
206
+ });
207
+ ani.skeletons?.forEach((v, k)=>{
208
+ const refcount = this._activeSkeletons.get(k);
209
+ if (refcount === 1) {
210
+ k.reset(this._model);
211
+ this._activeSkeletons.delete(k);
212
+ } else {
213
+ this._activeSkeletons.set(k, refcount - 1);
214
+ }
215
+ });
72
216
  }
73
- ani.play(repeat, speedRatio);
74
217
  }
75
218
  }
76
- /**
77
- * Stops playing an animation of the model
78
- * @param name - Name of the animation to stop playing
79
- */ stopAnimation(name) {
80
- this._animations[name]?.stop();
81
- }
82
219
  dispose() {
83
220
  const index = this._scene.animationSet.indexOf(this);
84
221
  if (index >= 0) {
@@ -88,6 +225,9 @@
88
225
  this._animations[k].dispose();
89
226
  }
90
227
  this._animations = {};
228
+ this._activeAnimations.clear();
229
+ this._activeSkeletons.clear();
230
+ this._activeTracks.clear();
91
231
  }
92
232
  }
93
233
 
@@ -1 +1 @@
1
- {"version":3,"file":"animationset.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"animationset.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -3,35 +3,23 @@
3
3
  * @public
4
4
  */ class AnimationTrack {
5
5
  /** @internal */ _interpolator;
6
- /** @internal */ _currentPlayTime;
7
- /** @internal */ _playing;
6
+ /** @internal */ _animation;
8
7
  /**
9
8
  * Creates a new animation track
10
9
  * @param interpolator - Interpolator for the track
11
10
  */ constructor(interpolator){
12
- this._currentPlayTime = 0;
13
- this._playing = false;
14
11
  this._interpolator = interpolator;
15
12
  }
16
13
  /** Gets the interpolator of the track */ get interpolator() {
17
14
  return this._interpolator;
18
15
  }
19
- /** Return true if the track is playing, otherwise false */ get playing() {
20
- return this._playing;
16
+ /** Animation this track belongs to */ get animation() {
17
+ return this._animation;
21
18
  }
22
- /** Starts playing the track */ start() {
23
- this._playing = true;
24
- }
25
- /** Stops playing the track */ stop() {
26
- this._playing = false;
27
- }
28
- /** Rewinds the track to the first frame */ rewind() {
29
- this._currentPlayTime = 0;
30
- }
31
- /** Stops playing the track and rewind to the first frame */ reset() {
32
- this.stop();
33
- this._currentPlayTime = 0;
19
+ set animation(ani) {
20
+ this._animation = ani;
34
21
  }
22
+ /** Stops playing the track and rewind to the first frame */ reset(node) {}
35
23
  }
36
24
 
37
25
  export { AnimationTrack };
@@ -1 +1 @@
1
- {"version":3,"file":"animationtrack.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"animationtrack.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,12 +1,12 @@
1
- import { Vector3, Quaternion, Interpolator } from '@zephyr3d/base';
1
+ import { Vector3, Interpolator, Quaternion } from '@zephyr3d/base';
2
2
  import { AnimationTrack } from './animationtrack.js';
3
3
 
4
4
  const tmpVec3 = new Vector3();
5
- const tmpQuat = new Quaternion();
6
5
  /**
7
6
  * Euler angle rotation animation track
8
7
  * @public
9
8
  */ class EulerRotationTrack extends AnimationTrack {
9
+ _state;
10
10
  /**
11
11
  * Create an instance of EulerRotationTrack from keyframe values
12
12
  * @param mode - The interpolation mode of keyframes
@@ -21,11 +21,21 @@ const tmpQuat = new Quaternion();
21
21
  }
22
22
  const interpolator = new Interpolator(mode, 'vec3', inputs, outputs);
23
23
  super(interpolator);
24
+ this._state = new Quaternion();
24
25
  }
25
- /** {@inheritDoc AnimationTrack.apply} */ apply(node, currentTime, duration) {
26
- this._interpolator.interpolate(currentTime, duration, tmpVec3);
27
- node.rotation.set(tmpQuat.fromEulerAngle(tmpVec3.x, tmpVec3.y, tmpVec3.z, 'ZYX'));
28
- return true;
26
+ calculateState(currentTime) {
27
+ this._interpolator.interpolate(currentTime, tmpVec3);
28
+ this._state.fromEulerAngle(tmpVec3.x, tmpVec3.y, tmpVec3.z, 'ZYX');
29
+ return this._state;
30
+ }
31
+ applyState(node, state) {
32
+ node.rotation.set(state);
33
+ }
34
+ mixState(a, b, t) {
35
+ return Quaternion.slerp(a, b, t);
36
+ }
37
+ getBlendId() {
38
+ return 'node-rotation';
29
39
  }
30
40
  }
31
41
 
@@ -1 +1 @@
1
- {"version":3,"file":"eulerrotationtrack.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"eulerrotationtrack.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,104 @@
1
+ import { PBStructTypeInfo, PBArrayTypeInfo, PBPrimitiveTypeInfo, PBPrimitiveType } from '@zephyr3d/device';
2
+ import { Application } from '../app.js';
3
+ import { MAX_MORPH_ATTRIBUTES, MAX_MORPH_TARGETS, MORPH_WEIGHTS_VECTOR_COUNT, MORPH_ATTRIBUTE_VECTOR_COUNT } from '../values.js';
4
+ import { ShaderHelper } from '../material/shader/helper.js';
5
+ import '../material/lambert.js';
6
+ import '../material/blinn.js';
7
+ import '../material/unlit.js';
8
+ import '../material/meshmaterial.js';
9
+ import '../material/grassmaterial.js';
10
+ import '../material/terrainmaterial.js';
11
+ import '../material/pbrmr.js';
12
+ import '../material/pbrsg.js';
13
+ import '@zephyr3d/base';
14
+ import '../utility/pmrem.js';
15
+ import '../utility/panorama.js';
16
+ import '../utility/shprojection.js';
17
+ import { BoundingBox } from '../utility/bounding_volume.js';
18
+
19
+ function processMorphData(subMesh, morphWeights) {
20
+ const numTargets = subMesh.numTargets;
21
+ if (numTargets === 0) {
22
+ return;
23
+ }
24
+ const attributes = Object.getOwnPropertyNames(subMesh.targets);
25
+ const numVertices = subMesh.primitive.getNumVertices();
26
+ const weightsAndOffsets = new Float32Array(4 + MAX_MORPH_TARGETS + MAX_MORPH_ATTRIBUTES);
27
+ for(let i = 0; i < numTargets; i++){
28
+ weightsAndOffsets[4 + i] = morphWeights?.[i] ?? 0;
29
+ }
30
+ const textureSize = Math.ceil(Math.sqrt(numVertices * attributes.length * numTargets));
31
+ if (textureSize > Application.instance.device.getDeviceCaps().textureCaps.maxTextureSize) {
32
+ // TODO: reduce morph attributes
33
+ throw new Error(`Morph target data too large`);
34
+ }
35
+ weightsAndOffsets[0] = textureSize;
36
+ weightsAndOffsets[1] = textureSize;
37
+ weightsAndOffsets[2] = numVertices;
38
+ weightsAndOffsets[3] = numTargets;
39
+ let offset = 0;
40
+ const textureData = new Float32Array(textureSize * textureSize * 4);
41
+ for(let attrib = 0; attrib < MAX_MORPH_ATTRIBUTES; attrib++){
42
+ const index = attributes.indexOf(String(attrib));
43
+ if (index < 0) {
44
+ weightsAndOffsets[4 + MAX_MORPH_TARGETS + attrib] = -1;
45
+ continue;
46
+ }
47
+ weightsAndOffsets[4 + MAX_MORPH_TARGETS + attrib] = offset >> 2;
48
+ const info = subMesh.targets[attrib];
49
+ if (info.data.length !== numTargets) {
50
+ console.error(`Invalid morph target data`);
51
+ return;
52
+ }
53
+ for(let t = 0; t < numTargets; t++){
54
+ const data = info.data[t];
55
+ for(let i = 0; i < numVertices; i++){
56
+ for(let j = 0; j < 4; j++){
57
+ textureData[offset++] = j < info.numComponents ? data[i * info.numComponents + j] : 1;
58
+ }
59
+ }
60
+ }
61
+ }
62
+ const morphTexture = Application.instance.device.createTexture2D('rgba32f', textureSize, textureSize, {
63
+ samplerOptions: {
64
+ minFilter: 'nearest',
65
+ magFilter: 'nearest',
66
+ mipFilter: 'none'
67
+ }
68
+ });
69
+ morphTexture.update(textureData, 0, 0, textureSize, textureSize);
70
+ const bufferType = new PBStructTypeInfo('dummy', 'std140', [
71
+ {
72
+ name: ShaderHelper.getMorphInfoUniformName(),
73
+ type: new PBArrayTypeInfo(new PBPrimitiveTypeInfo(PBPrimitiveType.F32VEC4), 1 + MORPH_WEIGHTS_VECTOR_COUNT + MORPH_ATTRIBUTE_VECTOR_COUNT)
74
+ }
75
+ ]);
76
+ const morphUniformBuffer = Application.instance.device.createStructuredBuffer(bufferType, {
77
+ usage: 'uniform'
78
+ }, weightsAndOffsets);
79
+ const morphBoundingBox = new BoundingBox();
80
+ calculateMorphBoundingBox(morphBoundingBox, subMesh.targetBox, weightsAndOffsets.subarray(4, 4 + MAX_MORPH_TARGETS), numTargets);
81
+ const meshAABB = subMesh.mesh.getBoundingVolume().toAABB();
82
+ morphBoundingBox.minPoint.addBy(meshAABB.minPoint);
83
+ morphBoundingBox.maxPoint.addBy(meshAABB.maxPoint);
84
+ subMesh.mesh.setMorphData(morphTexture);
85
+ subMesh.mesh.setMorphInfo(morphUniformBuffer);
86
+ subMesh.mesh.setAnimatedBoundingBox(morphBoundingBox);
87
+ }
88
+ /** @internal */ function calculateMorphBoundingBox(morphBoundingBox, keyframeBoundingBox, weights, numTargets) {
89
+ morphBoundingBox.minPoint.setXYZ(0, 0, 0);
90
+ morphBoundingBox.maxPoint.setXYZ(0, 0, 0);
91
+ for(let i = 0; i < numTargets; i++){
92
+ const weight = weights[i];
93
+ const keyframeBox = keyframeBoundingBox[i];
94
+ morphBoundingBox.minPoint.x += keyframeBox.minPoint.x * weight;
95
+ morphBoundingBox.minPoint.y += keyframeBox.minPoint.y * weight;
96
+ morphBoundingBox.minPoint.y += keyframeBox.minPoint.z * weight;
97
+ morphBoundingBox.maxPoint.x += keyframeBox.maxPoint.x * weight;
98
+ morphBoundingBox.maxPoint.y += keyframeBox.maxPoint.y * weight;
99
+ morphBoundingBox.maxPoint.y += keyframeBox.maxPoint.z * weight;
100
+ }
101
+ }
102
+
103
+ export { calculateMorphBoundingBox, processMorphData };
104
+ //# sourceMappingURL=morphtarget.js.map