|
@@ -1,78 +1,15 @@
|
1
|
|
-window.addEventListener('load', () => {
|
2
|
|
-
|
3
|
|
- const my = { };
|
4
|
|
-
|
5
|
|
- // initialize the virtual scene
|
6
|
|
- async function init(ar)
|
7
|
|
- {
|
8
|
|
- // add lights
|
9
|
|
- const ambientLight = new THREE.AmbientLight(0xffffff);
|
10
|
|
- ar.scene.add(ambientLight);
|
11
|
|
-
|
12
|
|
- const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
|
13
|
|
- directionalLight.position.set(0, 1, 0);
|
14
|
|
- ar.root.add(directionalLight);
|
15
|
|
-
|
16
|
|
- //const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 0.5);
|
17
|
|
- //ar.scene.add(directionalLightHelper);
|
18
|
|
-
|
19
|
|
- // create a group as a child of ar.root, which is aligned to the physical scene
|
20
|
|
- const group = createMainGroup(true);
|
21
|
|
- group.position.set(0, -0.5, 0);
|
22
|
|
- group.scale.set(0.7, 0.7, 0.7);
|
23
|
|
- ar.root.add(group);
|
24
|
|
-
|
25
|
|
- // create the magic circle
|
26
|
|
- const magicCircle = createPlane('../assets/magic-circle.png');
|
27
|
|
- magicCircle.material.transparent = true;
|
28
|
|
- magicCircle.material.opacity = 0.85;
|
29
|
|
- magicCircle.material.color = new THREE.Color(0xbeefff);
|
30
|
|
- magicCircle.scale.set(6, 6, 1);
|
31
|
|
- group.add(magicCircle);
|
32
|
|
-
|
33
|
|
- // load the mage
|
34
|
|
- const gltf = await loadGLTF('../assets/mage.glb');
|
35
|
|
- const mage = gltf.scene;
|
36
|
|
- group.add(mage);
|
37
|
|
-
|
38
|
|
- // prepare the animation of the mage
|
39
|
|
- const animationAction = createAnimationAction(gltf, 'Idle');
|
40
|
|
- animationAction.loop = THREE.LoopRepeat;
|
41
|
|
- animationAction.play();
|
42
|
|
-
|
43
|
|
- // export objects
|
44
|
|
- my.group = group;
|
45
|
|
- my.magicCircle = magicCircle;
|
46
|
|
- my.mage = mage;
|
47
|
|
- my.animationAction = animationAction;
|
48
|
|
- }
|
49
|
|
-
|
50
|
|
- // animate the virtual scene
|
51
|
|
- function animate(ar, deltaSeconds)
|
52
|
|
- {
|
53
|
|
- const TWO_PI = 2.0 * Math.PI;
|
54
|
|
- const ROTATIONS_PER_SECOND = 0.25;
|
55
|
|
-
|
56
|
|
- // animate the mage
|
57
|
|
- const mixer = my.animationAction.getMixer();
|
58
|
|
- mixer.update(deltaSeconds);
|
59
|
|
-
|
60
|
|
- // animate the magic circle
|
61
|
|
- my.magicCircle.rotateZ(TWO_PI * ROTATIONS_PER_SECOND * deltaSeconds);
|
62
|
|
- }
|
63
|
|
-
|
64
|
|
- function createMainGroup(frontView = false)
|
65
|
|
- {
|
66
|
|
- const group = new THREE.Group();
|
67
|
|
-
|
68
|
|
- // top view is the default
|
69
|
|
- if(frontView)
|
70
|
|
- group.rotateX(-Math.PI / 2);
|
71
|
|
-
|
72
|
|
- return group;
|
73
|
|
- }
|
74
|
|
-
|
75
|
|
- async function loadGLTF(filepath, yAxisIsUp = true)
|
|
1
|
+/**
|
|
2
|
+ * Augmented Reality demo with three.js and encantar.js
|
|
3
|
+ */
|
|
4
|
+
|
|
5
|
+(function() {
|
|
6
|
+
|
|
7
|
+/**
|
|
8
|
+ * Utilities for the Demo scene
|
|
9
|
+ */
|
|
10
|
+class DemoUtils
|
|
11
|
+{
|
|
12
|
+ async loadGLTF(filepath, yAxisIsUp = true)
|
76
|
13
|
{
|
77
|
14
|
const loader = new THREE.GLTFLoader();
|
78
|
15
|
const gltf = await loader.loadAsync(filepath);
|
|
@@ -84,7 +21,13 @@ window.addEventListener('load', () => {
|
84
|
21
|
return gltf;
|
85
|
22
|
}
|
86
|
23
|
|
87
|
|
- function createAnimationAction(gltf, name = null)
|
|
24
|
+ switchToFrontView(root)
|
|
25
|
+ {
|
|
26
|
+ // top view is the default
|
|
27
|
+ root.rotateX(-Math.PI / 2);
|
|
28
|
+ }
|
|
29
|
+
|
|
30
|
+ createAnimationAction(gltf, name = null)
|
88
|
31
|
{
|
89
|
32
|
const mixer = new THREE.AnimationMixer(gltf.scene);
|
90
|
33
|
const clips = gltf.animations;
|
|
@@ -98,7 +41,7 @@ window.addEventListener('load', () => {
|
98
|
41
|
return action;
|
99
|
42
|
}
|
100
|
43
|
|
101
|
|
- function createPlane(imagepath)
|
|
44
|
+ createImagePlane(imagepath)
|
102
|
45
|
{
|
103
|
46
|
const texture = new THREE.TextureLoader().load(imagepath);
|
104
|
47
|
const geometry = new THREE.PlaneGeometry(1, 1);
|
|
@@ -111,7 +54,47 @@ window.addEventListener('load', () => {
|
111
|
54
|
return mesh;
|
112
|
55
|
}
|
113
|
56
|
|
114
|
|
- async function startARSession()
|
|
57
|
+ referenceImage(ar)
|
|
58
|
+ {
|
|
59
|
+ if(ar.frame === null)
|
|
60
|
+ return null;
|
|
61
|
+
|
|
62
|
+ for(const result of ar.frame.results) {
|
|
63
|
+ if(result.tracker.type == 'image-tracker') {
|
|
64
|
+ if(result.trackables.length > 0) {
|
|
65
|
+ const trackable = result.trackables[0];
|
|
66
|
+ return trackable.referenceImage;
|
|
67
|
+ }
|
|
68
|
+ }
|
|
69
|
+ }
|
|
70
|
+
|
|
71
|
+ return null;
|
|
72
|
+ }
|
|
73
|
+}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+/**
|
|
78
|
+ * Demo scene
|
|
79
|
+ */
|
|
80
|
+class DemoScene extends ARScene
|
|
81
|
+{
|
|
82
|
+ /**
|
|
83
|
+ * Constructor
|
|
84
|
+ */
|
|
85
|
+ constructor()
|
|
86
|
+ {
|
|
87
|
+ super();
|
|
88
|
+
|
|
89
|
+ this._utils = new DemoUtils();
|
|
90
|
+ this._objects = { };
|
|
91
|
+ }
|
|
92
|
+
|
|
93
|
+ /**
|
|
94
|
+ * Start the AR session
|
|
95
|
+ * @returns {Promise<Session>}
|
|
96
|
+ */
|
|
97
|
+ async startSession()
|
115
|
98
|
{
|
116
|
99
|
if(!AR.isSupported()) {
|
117
|
100
|
throw new Error(
|
|
@@ -165,7 +148,95 @@ window.addEventListener('load', () => {
|
165
|
148
|
return session;
|
166
|
149
|
}
|
167
|
150
|
|
168
|
|
- // enchant!
|
169
|
|
- encantar(startARSession, animate, init);
|
|
151
|
+ /**
|
|
152
|
+ * Initialize the augmented scene
|
|
153
|
+ * @param {ARPluginSystem} ar
|
|
154
|
+ * @returns {Promise<void>}
|
|
155
|
+ */
|
|
156
|
+ async init(ar)
|
|
157
|
+ {
|
|
158
|
+ // Change the point of view. All virtual objects are descendants of
|
|
159
|
+ // ar.root, a node that is automatically aligned to the physical scene.
|
|
160
|
+ // Adjusting ar.root will adjust all virtual objects.
|
|
161
|
+ this._utils.switchToFrontView(ar.root);
|
|
162
|
+ ar.root.position.set(0, -0.5, 0);
|
|
163
|
+ ar.root.scale.set(0.7, 0.7, 0.7);
|
|
164
|
+
|
|
165
|
+ // add lights
|
|
166
|
+ const ambientLight = new THREE.AmbientLight(0xffffff);
|
|
167
|
+ ar.scene.add(ambientLight);
|
|
168
|
+
|
|
169
|
+ const directionalLight = new THREE.DirectionalLight(0xffffff);
|
|
170
|
+ directionalLight.position.set(0, 0, 3);
|
|
171
|
+ ar.root.add(directionalLight);
|
|
172
|
+
|
|
173
|
+ // create the magic circle
|
|
174
|
+ const magicCircle = this._utils.createImagePlane('../assets/magic-circle.png');
|
|
175
|
+ magicCircle.material.transparent = true;
|
|
176
|
+ magicCircle.material.opacity = 0.85;
|
|
177
|
+ magicCircle.material.color = new THREE.Color(0xbeefff);
|
|
178
|
+ magicCircle.scale.set(6, 6, 1);
|
|
179
|
+ ar.root.add(magicCircle);
|
|
180
|
+
|
|
181
|
+ // load the mage
|
|
182
|
+ const gltf = await this._utils.loadGLTF('../assets/mage.glb');
|
|
183
|
+ const mage = gltf.scene;
|
|
184
|
+ ar.root.add(mage);
|
|
185
|
+
|
|
186
|
+ // prepare the animation of the mage
|
|
187
|
+ const animationAction = this._utils.createAnimationAction(gltf, 'Idle');
|
|
188
|
+ animationAction.loop = THREE.LoopRepeat;
|
|
189
|
+ animationAction.play();
|
|
190
|
+
|
|
191
|
+ // save objects
|
|
192
|
+ this._objects.mage = mage;
|
|
193
|
+ this._objects.magicCircle = magicCircle;
|
|
194
|
+ this._objects.animationAction = animationAction;
|
|
195
|
+ }
|
|
196
|
+
|
|
197
|
+ /**
|
|
198
|
+ * Update / animate the augmented scene
|
|
199
|
+ * @param {ARPluginSystem} ar
|
|
200
|
+ * @returns {void}
|
|
201
|
+ */
|
|
202
|
+ update(ar)
|
|
203
|
+ {
|
|
204
|
+ const TWO_PI = 2.0 * Math.PI;
|
|
205
|
+ const ROTATIONS_PER_SECOND = 0.25;
|
|
206
|
+ const delta = ar.session.time.delta; // given in seconds
|
|
207
|
+
|
|
208
|
+ // animate the mage
|
|
209
|
+ const animationAction = this._objects.animationAction;
|
|
210
|
+ const mixer = animationAction.getMixer();
|
|
211
|
+ mixer.update(delta);
|
|
212
|
+
|
|
213
|
+ // animate the magic circle
|
|
214
|
+ const magicCircle = this._objects.magicCircle;
|
|
215
|
+ magicCircle.rotateZ(TWO_PI * ROTATIONS_PER_SECOND * delta);
|
|
216
|
+ }
|
|
217
|
+
|
|
218
|
+ /**
|
|
219
|
+ * Release the augmented scene
|
|
220
|
+ * @param {ARPluginSystem} ar
|
|
221
|
+ * @returns {void}
|
|
222
|
+ */
|
|
223
|
+ release(ar)
|
|
224
|
+ {
|
|
225
|
+ // nothing to do
|
|
226
|
+ }
|
|
227
|
+}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+/**
|
|
232
|
+ * Enchant the Demo scene
|
|
233
|
+ */
|
|
234
|
+window.addEventListener('load', () => {
|
|
235
|
+
|
|
236
|
+ const scene = new DemoScene();
|
|
237
|
+
|
|
238
|
+ encantar(scene);
|
170
|
239
|
|
171
|
240
|
});
|
|
241
|
+
|
|
242
|
+})();
|