Categories
A-Frame Intermediate JavaScript Project Rainbow WebXR

Introduction to Web-based XR – Part I

One of the easiest ways to create an enjoy Virtual Reality (VR) experiences is on the Web. And the most popular and versatile way to built VR experiences for the Web is to use A-Frame and WebXR.

We will look into how we can built a basic VR scene, that you can experience via your Web browser. We will then convert it in Augmented Reality (AR), in a future activity.

These activities relate to our Web Technologies modules (UG/PG), as well as our XReality module (PG).

WebXR

WebXR (and its predecessor WebVR, which is still around) is an open specification that makes it possible to experience VR in your browser. WebXR allows everyone to get into VR experiences, no matter what device they have. More importantly, WebVR/WebXR is used by various popular frameworks that provide tools for building VR – and AR as we are going to see later – experiences. You can find some information on WebXR on the W3C website, as well as on Youtube here.

A-Frame

A-Frame, an entity-component framework built upon the popular JavaScript 3D library, Three.js. A-Frame works along WebXR and together they are the easiest way to create Web-based VR. These experiences can be viewed with the most popular Head-Mounted Displays, such as the HTC Vive, Oculus Quest, Gear VR, as well as desktops and smartphones.

A-Frame is at the centre of this activity which start in VR and continue in AR. Out goal is to create a simple VR scene, with a rainbow arch, as shown below

See the Pen Simple A-Frane Rainbow Scene by Panagiotis D. Ritsos (@ritsosp) on CodePen.

Putting things together

Lets look at how we can built this and review the code. We first need an HTML page, within which A-Frame will display our scene.

Using your favourite editor (Visual Studio Code is a good choice) create a file, named index.html. Create a basic Web page by adding the code below:

<html>
  <head>
    <meta charset="utf-8">
    <title>VR Rainbow</title>
    <meta name="keywords" content="HTML, CSS, JavaScript,  A-Frame">
    <meta name="description" content="A Rainbow in VR">
    <script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
  </head>
  <body>
    <a-scene id="rainbowScene" background="color: #FAFAFA">
    </a-scene>
  </body>
</html>

Notice, it is a good practice to add a meaningful title and some appropriate meta tags.

In addition, we need a link to the A-Frame library (line 7). Lines 10 and 11 include the A-Frame element <a-scene> where our VR scene will display.

To see your index.html file in a browser, it is advisable to run a local web server, and add it into that. Here is one of the ways you can do that with Python. From this point onwards we assume you have the code in your editor, and the webpage in a browser. Refreshing the page will display any changes. You can also use the console to debug your JavaScript. Here is some info, how to do that in Chrome.

Although it is a good idea to add any JavaScript to a separate file, in this case we will embed all our additional code inindex.html. Within a <script> tag, right before the </body> tag, add the following code:

var zStartPosition = 4;    // Sceme placement
var color = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"];       // The Rainbow colours of the arch
var zIncrement = 0.5;      // The step where each Torus is placed
var arc = 180;             // The arc of the Tori
var radius = 4;            // The radius of the Tori
var radiusTubular = 0.125; // The radius of the Tori's 'tube' 

These are variables we will be using to built our scene. Once the scene is completed, you can tweak these and change different parts of the scene.

We will itterate over the color array and use it as a spine for our arch. For that we will use a For loop:

for (i = 0; i<color.length; i++){
}

Within the loop we will add statements to create each Torus, and add attributes to them, using our aforementioned variables.

var torus = document.createElement("a-torus"); 
 torus.setAttribute("id", "torus_" + i);
 torus.setAttribute("color", color[i]);
 torus.setAttribute("arc", arc); 
 torus.setAttribute("radius", radius);
 torus.setAttribute("radius-tubular", radiusTubular);

The first line of this block creates the torus element in A-Frame (<a-torus>). We also use the name torus followed by an underscore and the index of the for loop, to create an ID for each torus. Finally, by using the for loop index, we iterate over our colour array. This way each of our colours are assigned to each torus sequentialy.

However, when it comes to positioning each torus in our scene, we need to follow a different approach. Because rendering 3D graphics is costly (in processing power) placement of objects is done at a lower level. A-Frame recommends, for performance and ergonomics, to update position directly via the Three.js Object3D.position Vector3, instead of using .setAttribute.

We therefore place the first torus in the position (x:0, y:0, z:-zStartPosition). Then for each for loop iteration, z gets incremented.

// Set position using Three.js for performance
torus.object3D.position.set(0, 0 , -zStartPosition);
zStartPosition += zIncrement;

// Place newly created torus in scene 
document.getElementsByTagName("a-scene")[0].appendChild(torus);

This effectively pushed the position of subsequent tori further from the camera/starting position. A-Frame uses a right-handed coordinate system. With the default camera direction: positive X-axis extends right, positive Y-axis extends up, and the positive Z-axis extends out of the screen towards us (see below). In this case we are pushing the Tori towards the screen.

righthandimage
Image from A-Frame

Then next line gets a reference to the <a-scene> element and appends each torus in sequence. Notice the statement refers to the document which is our webpage, and then refers to all the elements in the document that have a tag name <a-scene>.

// Place newly created torus in scene 
document.getElementsByTagName("a-scene")[0].appendChild(torus);

As this in principle can be many, this statement returns an array, the elements of which are accessed via an index. [0] is the first element of the array and in this case the only instance of <a-scene>.

Adding a ground plane

The next block works in a similar way to the tori placement, to place one plane as base in our scene. In this case we have hardcoded width, heigh, colour, shadows and rotation. Placement works in a similar way to the placement of the tori. Finally, we add the plane as a child element, in our <a-scene>.

var ground = document.createElement("a-plane");
ground.setAttribute("id", "ground");
ground.setAttribute("width", 9);
ground.setAttribute("height", 5);
ground.setAttribute("color", "#7BC8A4");
ground.setAttribute("shadow", "receive: true");
ground.setAttribute("rotation", "-90, 0, 0");

// Set rotation using Three.js for performance
ground.object3D.position.set(0, 0 , -zStartPosition + 1.5);
ground.object3D.rotation.set.x = -90;

document.getElementsByTagName("a-scene")[0].appendChild(ground);

If all is well, refreshing the page should display the scene below (repeated for convenience).

See the Pen Simple A-Frane Rainbow Scene by Panagiotis D. Ritsos (@ritsosp) on CodePen.

By Panos Ritsos

Panos (Panagiotis) is a Lecturer in Visualization, at Bangor University - His research is on Mixed and Virtual Reality, Immersive Analytics, Data Visualization and Human-Computer Interaction | Scale Modeller and Mountainbiker

Leave a Reply to Anonymous Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

en_GBEnglish (UK)
cyCymraeg en_GBEnglish (UK)