Преглед на файлове

Add gltf-anim component for A-Frame

customisations
alemart преди 11 месеца
родител
ревизия
24180803f9
променени са 1 файла, в които са добавени 148 реда и са изтрити 0 реда
  1. 148
    0
      plugins/extras/aframe-gltf-anim.js

+ 148
- 0
plugins/extras/aframe-gltf-anim.js Целия файл

@@ -0,0 +1,148 @@
1
+/**
2
+ * A minimalistic A-Frame component for animating 3D models
3
+ * @author Alexandre Martins <alemartf(at)gmail.com> (https://github.com/alemart)
4
+ * @license MIT
5
+ */
6
+
7
+AFRAME.registerComponent('gltf-anim', {
8
+
9
+    schema: {
10
+
11
+        /** the name of an animation clip */
12
+        'clip': { type: 'string', default: '' },
13
+
14
+        /** whether or not to loop the animation */
15
+        'loop': { type: 'boolean', default: true },
16
+
17
+        /** scaling factor for the playback speed */
18
+        'speed': { type: 'number', default: 1 },
19
+
20
+        /** duration in seconds of transitions between clips */
21
+        'transitionDuration': { type: 'number', default: 0 },
22
+
23
+    },
24
+
25
+    init()
26
+    {
27
+        const el = this.el;
28
+
29
+        this._model = null;
30
+        this._action = null;
31
+
32
+        el.addEventListener('model-loaded', event => {
33
+
34
+            if(event.target === el) {
35
+                this._model = event.detail.model;
36
+                this._refresh();
37
+            }
38
+
39
+        });
40
+
41
+        el.addEventListener('model-error', event => {
42
+
43
+            if(event.target === el) {
44
+                this._model = null;
45
+                this._refresh();
46
+            }
47
+
48
+        });
49
+
50
+    },
51
+
52
+    update(oldData)
53
+    {
54
+        if(!this._model)
55
+            return;
56
+
57
+        if(this.data.clip != oldData.clip)
58
+            this._switchClip();
59
+
60
+        if(!this._action)
61
+            return;
62
+
63
+        if(Math.abs(this.data.speed - oldData.speed) > 1e-5)
64
+            this._action.timeScale = this.data.speed;
65
+
66
+        if(this.data.loop != oldData.loop)
67
+            this._action.loop = this.data.loop ? THREE.LoopRepeat : THREE.LoopOnce;
68
+    },
69
+
70
+    remove()
71
+    {
72
+        if(this._action)
73
+            this._action.getMixer().stopAllAction();
74
+
75
+        this._action = null;
76
+        this._model = null;
77
+    },
78
+
79
+    tick(time, delta)
80
+    {
81
+        if(this._action) {
82
+            const mixer = this._action.getMixer();
83
+            mixer.update(delta * 0.001);
84
+        }
85
+    },
86
+
87
+    _refresh()
88
+    {
89
+        if(this._action) {
90
+            this._action.getMixer().stopAllAction();
91
+            this._action = null;
92
+        }
93
+
94
+        if(this._model) {
95
+            if((this._action = this._clipAction(null)))
96
+                this._action.play();
97
+        }
98
+    },
99
+
100
+    _switchClip()
101
+    {
102
+        const oldAction = this._action;
103
+        if(!oldAction) {
104
+            this._refresh();
105
+            return;
106
+        }
107
+
108
+        const newAction = this._clipAction(oldAction.getMixer());
109
+        if(!newAction) {
110
+            this._refresh();
111
+            return;
112
+        }
113
+        
114
+        this._action = newAction;
115
+        this._action.reset().play().crossFadeFrom(oldAction, Math.max(0, this.data.transitionDuration));
116
+    },
117
+
118
+    _clipAction(existingMixer)
119
+    {
120
+        if(!this._model)
121
+            return null;
122
+
123
+        const mixer = (existingMixer && existingMixer.getRoot() === this._model) ? existingMixer : new THREE.AnimationMixer(this._model);
124
+        const clips = this._model.animations;
125
+
126
+        if(!clips || clips.length == 0)
127
+            return null;
128
+
129
+        const name = (this.data.clip != '') ? this.data.clip : this._defaultClipName(clips);
130
+        const clip = THREE.AnimationClip.findByName(clips, name);
131
+
132
+        if(!clip)
133
+            return null;
134
+
135
+        const action = mixer.clipAction(clip);
136
+        action.loop = this.data.loop ? THREE.LoopRepeat : THREE.LoopOnce;
137
+        action.timeScale = this.data.speed;
138
+
139
+        return action;
140
+    },
141
+
142
+    _defaultClipName(clips)
143
+    {
144
+        const sortedNames = clips.map(clip => clip.name).sort();
145
+        return sortedNames[0];
146
+    },
147
+
148
+});

Loading…
Отказ
Запис