5 A-Frame Concepts

5.1 Questions

  • How are VR scenes described using A-Frame?
  • How do I navigate the A-Frame Documentation?

5.2 Overview

  • Teaching: 30 Min
  • Exercises: 20 Min

5.3 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.

5.3.1 Open an A-Frame scene on glitch.com

  1. Open this link in your browser: https://glitch.com/edit/#!/pricey-kitten
  2. Click “Remix to Edit” to create a copy of the project in your Glitch account
  3. 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.

5.3.2 The header

  <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.

5.3.3 The scene

Everything within the a-scene tag defines the items in the scene. There are two zones:

5.3.3.1 The assets block

<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.

5.3.3.2 The entities

<!-- 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.

5.4 Config Conventions

5.4.1 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”

5.4.2 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.

5.4.3 Applying Rotation

The green floor has a rotation of -90 0 0.

  1. Locate it in the entity configuration.
  2. Try subbing in large and small, positive and negative values for -90 and viewing the results.
  3. Which axis is the rotation around?
  4. Where is this axis of rotation on the floor entity?

5.4.4 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.

5.4.5 Tweaking a scene

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.
  2. Alter the yellow cylinder so that it is lying down on it’s side on the floor.
  3. Remove the mirror effect from the sphere in the back.
  4. Reverse the spin direction of the cube.

5.5 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

5.5.1 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.

5.5.2 Switching to long form

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

5.6 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.

5.7 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.

5.7.1 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.

5.7.2 Lighting it up

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.
  2. Show the live scene.
  3. The scene contains only a ambient light. Try various intensity settings and observe the effect on the scene.
  4. 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.
  2. 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>"

5.7.3 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.

5.7.4 Learn to fly

Still in the context of our moonlit night scene:

  1. Examine the documentation for wasd-controls
  2. 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.

5.8 Summary

  • VR conventions
  • Composing entities from components
  • Configuring components
  • Navigating the A-Frame documentation
  • Lights
  • Camera
  • Controls