-
Notifications
You must be signed in to change notification settings - Fork 3
/
03_building_vr_with_aframe.Rmd
335 lines (242 loc) · 13.1 KB
/
03_building_vr_with_aframe.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# A-Frame Concepts
## Questions
* How are VR scenes described using A-Frame?
* How do I navigate the A-Frame Documentation?
## Overview
* Teaching: 30 Min
* Exercises: 20 Min
## Anatomy of an A-Frame Scene
Let's have a look at an example to get a feel for how an A-Frame scene hangs
together.
### Open an A-Frame scene on glitch.com {.exercise}
1. Open this link in your browser: https://glitch.com/edit/#!/pricey-kitten
1. Click "Remix to Edit" to create a copy of the project in your Glitch account
1. Click "Show Live" to see what the scene looks like.
- Explore the scene briefly. You can use the WASD or arrow keys to move and mouse to change the camera angle.
1. In the left hand file pane click "index.html" to open the app source.
*What is glitch.com? Glitch is a social coding site that makes is easy to
write and host JS web apps from within your browser. A lot of A-Frame
introductory examples are hosted there.*
Ignoring the *solutions* directory, we see that the scene is primary composed of
a single `index.html` file. There is one associated JavaScript file `spin.js`,
the purpose of which will become clear soon.
### The header
```html
<head>
<title>Hello, WebVR! - A-Frame</title>
<meta name="description" content="Hello, WebVR! - A-Frame">
<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
<script src="spin.js"></script>
<script src="https://unpkg.com/aframe-mirror-component/dist/aframe-mirror-component.min.js"></script>
</head>
```
The header of an A-Frame scene is like a normal html web page. Within it we can
define the scene title and metadata. Typically an A-Frame scene will have many
script calls that load JS files. In this case:
* `"https://aframe.io/releases/0.8.0/aframe.min.js"` is the A-Frame framework. Without it there is no VR
* `"spin.js"` is a local JS file that contains a component called `spin`
* `"https://unpkg.com/aframe-mirror-component/dist/aframe-mirror-component.min.js"` is a 3rd party component included from a repository.
So this is roughly analogous to declaring all your R packages with
`library()` calls at the beginning of your script.
### The scene
Everything within the `a-scene` tag defines the items in the scene. There are two zones:
#### The assets block
```html
<a-assets>
<img crossorigin="anonymous" id="hadz" src="https://cdn.glitch.com/aaf7e3b8-f72b-405d-a6dd-b5ba91c32622%2FJT_R_code.gif?1542275718299"></img>
</a-assets>
```
The assets block is where media files are defined that need to be pre-loaded before the scene will be rendered. Each media file in the assets block is assigned an `id` that can be used to reference the asset as many times as required throughout the scene.
#### The entities
```html
<!-- hadley box -->
<a-box id = "important" position="-1 0.5 -3" rotation="0 45 0" shadow
spin = "axis: y; speed: 1.6" scale="1 1 1" src="#hadz">
</a-box>
<!-- mirrored sphere -->
<a-sphere position="0 1.0 -4.75" radius="1.25" color="#EF2D5E" shadow
mirror="resolution: 64; interval: 150; distance: 5000; repeat: true"></a-sphere>
<!-- plain ol' yellow cylinder -->
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D" shadow></a-cylinder>
<!-- floor -->
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" shadow></a-plane>
<!-- backboard -->
<a-plane position="0 2 -6" rotation="0 0 0" width="4" height="4" color="#7BC8A4" shadow></a-plane>
<!-- the background colour -->
<a-sky color="#ECECEC"></a-sky>
```
The objects that comprise the scene are called **entities**. Here they are
defined by the tags `a-box`, `a-sphere`, `a-plane` etc. Within the entity tags,
the attributes define configuration for components. This configuration is
enclosed in quotes and can contain multiple **properties** e.g.: ` spin = "axis: y; speed: 1.6`.
## Config Conventions
### Coordinate system
To fully comprehend the scene configuration you need to know the coordinate
system. In VR, The standard unit is meters, which are scaled in VR space to
look like meters in real space.
In the coordinate system X points "right", Y points "up", and Z points toward the camera. Like so:
```
| Y +
|
|_ _ X +
/
/
Z +
```
This can be confusing when using spatial data since the spatial convention is
typically to have Z pointing "up from the table" and Y pointing "up the page"
### Vectors
Vectors of X,Y,Z are written as space delimited triples like so:
* `position="-1 0.5 -4"`
* `rotation="-90 0 0"`
In the case of rotation the each vector component specifies degrees rotation clockwise about an entity's axis.
### Applying Rotation {.exercise}
The green floor has a rotation of `-90 0 0`.
1. Locate it in the entity configuration.
1. Try subbing in large and small, positive and negative values for `-90` and viewing the results.
1. Which axis is the rotation around?
1. Where is this axis of rotation on the floor entity?
### Camera Position
Unless otherwise specified the camera as placed at the origin, at a height of 1.6m, looking in the
negative direction on the Z axis.
Camera position and angle can be configured by adding an `a-camera` entity to
the scene.
### Tweaking a scene {.exercise}
We'll dive deeper into entity configuration soon, but for now let's see what we
can do intuitively based on what's in front of us in the scene HTML. Make the following tweaks:
1. Insert a new `a-camera` entity. Place it at the origin, at roughly your eye height by setting its `position`.
1. Alter the yellow cylinder so that it is lying down on it's side on the floor.
1. Remove the mirror effect from the sphere in the back.
1. Reverse the spin direction of the cube.
## Entity component configuration
An A-Frame scene is made up completely of entities that may reference assets. It
the configuration we have seen so far it looks like entities have many types:
'box', 'sphere', 'cylinder', 'plane' etc - But this is actually an illusion. The
'type' or nature of all entities is completely determined by their components.
But what are their components?!
There a couple of ways to write entities and what we have seen so far was short
hand to save typing. The shorthand is convenient but it can make seeing how the
entity is composed from components less clear.
Consider the yellow cylinder in it's initial position and orientation:
```
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D" shadow></a-cylinder>
```
That definition is a shorthand for this:
```
<a-entity position="1 0.75 -3"
geometry="primitive: cylinder; height: 1.5; radius: 0.5"
material="color: #FFC65D"
shadow></a-entity>
```
Where each component has been placed on a new line for emphasis. Now it is clear
that the cylinder we see is an entity with four components:
* a position component that places it in spaces
* a geometry component that determines its shape
* a material component that sets the colour and reflective properties of its surfaces
* a shadow component that lets the entity cast shadows and have shadows casted on it.
Notice how component properties are configured as string of key value pairs, delimited by `:` and separated by `;`.
We can consult the A-Frame documentation entry for `a-cylinder` to see how its
attributes map to properties of the underlying components:
https://aframe.io/docs/0.8.0/primitives/a-cylinder.html
### The `id`
One useful attribute that is not a component is `id`. It can be applied to any
entity or asset as a means to refer to them in the configuration of other
entities. In our example we referred to an asset with `id` 'hadz' in the `src`
attribute of the box, to use the image as a texture. When referring to ids they
are prefixed with a `#`, eg `#hadz`.
### Switching to long form {.exercise}
Still in the same demo scene, replace `a-box` with an `a-entity` that defines
all components explicitly. To this you will need to know that:
* position is a component
* rotation is a component
* shadow is a component
* spin is a component
* scale is a component
* src is NOT a component, it is an attribute.
The A-Frame documentation entry for `a-box` may help:
https://aframe.io/docs/0.8.0/primitives/a-box.html
## A-Frame Documentation
We've mentioned the A-Frame documentation now a couple of times and it is worth
quickly becoming familiar with how to navigate it, because it is an extensive
and well put together resource. The documentation can be found at:
https://aframe.io/docs
Now let's use the documentation to fix a problem with our scene: If you walk
around the back of the objects you will notice that the 'backboard' turns
invisible. This is because by default A-Frame only renders the 'front' side of a
3D model or geometry. For closed shapes this is fine, but for open shapes this disconcerting disappearing effect will occur.
If we type 'material' into the search box in the top left of the docs website we
will get a list of suggestions, choose the first one. If we look though the
properties of the material component, we will find one that can address this
issue: `side: double`.
The documentation also has some vignette style content through the 'Guides' link.
## Lights, Camera, Actions (controls)
We've covered entities and components, but there are a couple special components that really make things 'work':
* The camera: The user's viewport
* Lights: illumination for the scene. Lighting can have a huge effect on scene mood and perceived realism.
* Controls: The control scheme affects how the user can interact with the your VR creation.
### Lighting
If no entities with light components are configured, the framework will
automatically inject two lights: an ambient light source and a point light
source.
* A point light source emits light outward in all directions. It can cast shadows.
* An ambient light source increases the brightness of all surfaces in the scene. It has no origin or direction and so cannot cast shadows.
These two together make a reasonable approximation of an outdoor lighting model. The
point source models the sun (or moon), and the ambient source models indirect
light reflected light from various sources.
### Lighting it up {.exercise}
Here's a little example to showcase how light sources combined create mood and a
realistic look. We have a drab night-time scene with only ambient lighting at:
https://glitch.com/edit/#!/giddy-taxi
1. Open the link and click the 'Remix to Edit' button.
1. Show the live scene.
1. The scene contains only a ambient light. Try various `intensity` settings and observe the effect on the scene.
1. Add a new light source to represent the Moon.
- Position it 40 meters high, 30 meters in front the viewer.
- Make the `type` 'point'
- Set `castShadow` 'true'
- set the `intensity` to 0.5 (50%)
1. Review the scene. Tweak the intensity settings of the two lights until it feels right.
1. Add a geometry component and a material component to the 'Moon' so it becomes visible.
- use a sphere with `radius` '2'.
- set the `color` to 'white'.
- Add this config to the material component: `shader: flat` - This will stop
it dimming with distance.
1. Review your light intensity settings now you have a bright full Moon in the sky and set appropriately.
The documentation entries for 'light' and 'geometry > sphere' may assist you.
**Bonus!** For fun try animating the moon using a third party library. Here's a
template of the component config:
```
animation="property: position; to: <END_POSITION>; dir: alternate; loop: true; dur: <ANIMATION_DURATION_ms>"
```
### Cameras and Controls
Camera and control components tend to be used together. As mentioned the scene gets a default camera if none is configured. The config for that camera looks roughly like this:
```
<a-entity camera wasd-controls look-controls></a-entity>
```
It has two control components that allow inputs to rotate and move the camera:
* `wasd-controls` listens for keyboard input and moves the camera accordingly
* `look-controls` listens for movement from a phone or headset accelerometer, or
a mouse. It can also respond to swipes on a touch screen as per a mouse.
Components for hand controllers are also attached to the camera entity for
interactivity. The most general way to do interactivity is to have entities
things that react to being looked at, this way even mobile users can interact
with the scene. This can control is added with the `cursor` component. We'll
consider an example that does this later in the session.
Like other components, controls have properties that alter how they work.
### Learn to fly {.exercise}
Still in the context of our moonlit night scene:
1. Examine the documentation for `wasd-controls`
1. Add a `camera` entity to the scene with `look-controls`, and `wasd-controls` configured to:
- move the camera twice as fast as the default
- allow the camera to 'fly', instead of being locked into a single plane.
Notice how when moving fast clicking and dragging to turn becomes infeasible. It
is possible to configure the mouse to control the camera 'First Person Shooter'
style with community components.
## Summary
* VR conventions
* Composing entities from components
* Configuring components
* Navigating the A-Frame documentation
* Lights
* Camera
* Controls