Richard Mat­tka

Learn how to cre­ate a WEBVR scene us­ing three.js

Web Designer - - Meta Contributors -

Richard is an award-win­ning In­ter­ac­tive di­rec­tor, de­signer and de­vel­oper. In this is­sue Richard demon­strates how you can cre­ate a WEBVR ex­pe­ri­ence, us­ing the pop­u­lar Javascript 3D li­brary three.js.

Vir­tual re­al­ity is a com­plex and rapidly evolv­ing tech­nol­ogy. It has come in and out fo­cus over many years, each time with var­ied lev­els of suc­cess, but it never gains enough mo­men­tum to re­main. There is a re­newed ef­fort to ad­dress this. A goal for de­vel­op­ers is to make it eas­ier for ev­ery­one to get into VR ex­pe­ri­ences – to re­move as many bar­ri­ers to en­try as pos­si­ble.

En­ter WEBVR, a Javascript API for re­al­is­ing 3D vir­tual re­al­ity ex­pe­ri­ences in the browser. This re­quires low la­tency, high frame rate and ex­cel­lent per­for­mance.

WEBGL en­ables de­vel­op­ers to cre­ate rich, con­sole-qual­ity ex­pe­ri­ences that ren­der in real time on mo­bile de­vices and desk­top browsers. Nearly univer­sal browser and de­vice sup­port makes it a per­fect ap­proach for web de­vel­op­ers want­ing to cre­ate in­cred­i­ble VR ex­pe­ri­ences.

A go-to re­source for 3D and VR on the web is the highly pop­u­lar three.js. You’ll be us­ing it in this tu­to­rial. It’s free and open source, lightweight and boasts count­less award-win­ning web­sites that have used it.

Other than hav­ing a Javascript back­ground, you can dive into this tu­to­rial with no prior knowl­edge and cre­ate your first WEBVR ex­pe­ri­ence. The goal of this tu­to­rial is to get you started and to get you in­spired to con­tinue to ex­plore and utilise this very ex­cit­ing tech­nol­ogy.

1. En­able WEBVR flag in Chrome

WEBVR is still an ex­per­i­men­tal tech­nol­ogy and re­quires HTTPS to run on your server, and won’t run on mo­bile de­vices with­out a poly­fill. im­mer­sive-web/webvr-poly­fill. How­ever, you can run con­tent lo­cally in Chrome for test­ing and build­ing. Be sure to en­able the Chrome WEBVR flag. Go to chrome://flags/#en­able-webvr, and then click en­able to ac­ti­vate it. You may need to restart Chrome as well.

2. In­stall the WEBVR API Em­u­la­tion plugin

In or­der to test lo­cally on your desk­top and avoid the need for a de­vice, there is a great plugin that you can use on Chrome by click­tore­lease. The plugin will em­u­late a head­set for you and al­low you to move and ro­tate the head­set vir­tu­ally. You can get it here:

3. Open de­vice tool­bar in de­vel­oper tools

To em­u­late a mo­bile de­vice or head­set, it works best to use the de­vice em­u­la­tion in Chrome tools. Open the de­vel­oper tools in Chrome, and tog­gle on the de­vice tool­bar to see mo­bile view, ro­tate to land­scape and se­lect favourite phone em­u­la­tion.

4. Cre­ate a ba­sic HTML file

Next, you need to set up a ba­sic HTML file. You can set up ex­ter­nal CSS and Javascript files or in­clude in­line for sim­plic­ity. Three.js’s ren­derer class will cre­ate a <can­vas> el­e­ment for you. Add the fol­low­ing code to your in­dex.html file:

<!DOCTYPE html>

<html lang=”en”>


<ti­tle>webvr Demo</ti­tle>

<meta charset=”utf-8”>

<meta name=”view­port” con­tent= ”width=de­vice-width, ini­tial-scale= 1.0, user-scal­able=no”>

<style> html, body { mar­gin: 0; pad­ding:0; over­flow: hid­den; }





// Code will go here




5. In­clude three.js classes

In­clude a link to the three.js li­brary in the head of your file – ei­ther hosted ex­ter­nally, or down­load it from the three.js repos­i­tory. You’ll also need the new WEBVR class and Box­li­ne­ge­om­e­try class for this tu­to­rial. You can find the li­brary and sup­port­ing classes at­doob/three.js. Note: the code in this tu­to­rial has been tested on the lat­est re­lease of three.js v99.

<script src=”libs/three.min.js”></script> <script src=”libs/webvr.js”></script> <script src=”libs/box­li­ne­ge­om­e­try.js”> </script>

6. Add global vari­ables

Be­tween the script tags for the code, add the fol­low­ing global vari­ables to glob­ally ac­cess the cam­era, scene, ren­ders, ob­jects and ray­caster. Also add a ‘HIT’ vari­able to keep track of ob­jects that are in­ter­sected by the gaze of the cam­era. This will demon­strate how to know what a user is look­ing at in VR.

var clock = new THREE.CLOCK(); var con­tainer, cam­era, scene, ren­derer, room, crosshair, HIT; var ob­jects=[]; // col­lec­tion of ob­jects var num=100; // num­ber of ob­jects var ray­caster = new Three.ray­caster();

7. Cre­ate a 3D scene

You’re go­ing to add a ba­sic 3D scene, which will be the con­tainer for your ob­jects. The scene is the stage that will ren­der with the cam­era. All 3D pre­sen­ta­tions will have a scene or stage of some form. What is in that stage and in view of the cam­era is what the user will see. Add the fol­low­ing code to add a scene:

// cre­ate a scene ob­ject var scene = new THREE.SCENE();

8. Add a per­spec­tive cam­era

Next, you need to add a cam­era. You’ll use the per­spec­tive cam­era, meant for 3D scenes. The first at­tribute is the field of view of the cam­era. The sec­ond is the as­pect ra­tio (width / height). Then you can in­di­cate the near clip­ping plane and the far clip­ping plane dis­tances, which de­fine what is to be vis­i­ble to the cam­era.

// cre­ate cam­era cam­era = new Three.per­spec­tive­cam­era

( 70, win­­ner­width/win­­ner­height, 0.1, 1000 ); scene.add( cam­era );

9. Add a ren­derer and can­vas el­e­ment

The ren­derer han­dles the draw­ing of the ob­jects in your scene that are vis­i­ble to the cam­era. Set the an­tialias prop­erty to true to get smooth edges on the ob­ject. The ren­derer cre­ates a domele­ment, which is ac­tu­ally an HTML <can­vas> el­e­ment. You can then ap­pend to the body. Note the use of the new Vr-en­abled flag of the ren­derer.

ren­derer = new Three.we­bglren­derer( {an­tialias:true}); ren­derer.set­pix­el­ra­tio( win­dow. de­vi­cepix­el­ra­tio ); ren­derer.set­size( win­­ner­width, win­dow. in­ner­height ); ren­derer.vr.en­abled = true; doc­u­ment.body.ap­pend­child( ren­derer. domele­ment );

10. Add cam­era crosshair

To help users ori­ent to the cam­era’s point of fo­cus, it is good prac­tice to add a crosshair or tar­get­ing icon in front of the cam­era. You can add it di­rectly to the cam­era ob­ject so it’s al­ways where it should be.

crosshair = new THREE.MESH( new Three.ring­buffer­ge­om­e­try( 0.02, 0.04, 32 ), new Three.mesh­ba­sic­ma­te­rial( { color: 0xffffff, opac­ity: 0.5, trans­par­ent: true

} )

); crosshair.po­si­tion.z = - 2; cam­era.add( crosshair );

11. Cre­ate a VR room ob­ject (op­tional)

Next, cre­ate a sim­ple room ob­ject. This is nice to give the user a sense of ori­en­ta­tion in the VR world. It cre­ates a sim­ple room box with lines to in­di­cate the walls, floor and ceil­ing.

room = new Three.line­seg­ments( new­li­ne­ge­om­e­try( 6, 6, 6, 10, 10, 10 ), new Three.lineba­sic­ma­te­rial( { color:

0x808080 } )); room.po­si­tion.y = 2; scene.add( room );

12. Add lights to the scene

To light the scene, we’ll use a sim­ple hemi­sphere light and a di­rec­tional light. It’ll give a nice am­bi­ent vis­i­bil­ity and some re­al­is­tic shad­ing from a uni­form light source as well.

scene.add( new Three.hemi­sphere­light ( 0x806060, 0x404040 ) ); var light = new Three.di­rec­tion­al­light ( 0xffffff ); light.po­si­tion.set( 1, 1, 1 ).nor­mal­ize(); scene.add( light );

13. Cre­ate some ob­jects

You’re go­ing to fill the room with ob­jects next. Apply them ran­domly around the room. You will also set the ro­ta­tion and scale ran­domly for va­ri­ety. You can add a lit­tle bit more code in the next step, where it says ‘cre­ate or­bit at­tributes’ to en­able some cus­tom or­bit paths.

var ge­om­e­try = new Three.boxbuffer­ge­om­e­try ( 0.15, 0.15, 0.15 ); for (i=0;i<=num;i++){ var ma­te­rial =new Three.mesh­lam­bert­ma­te­rial ( { color: Math.ran­dom() * 0xffffff } ) ; var ob­ject = new THREE.MESH

( ge­om­e­try, ma­te­rial ); ob­ject.po­si­tion.set(math.ran­dom()*4.0 - 2.0,Math.ran­dom()*4.0 - 2.0,Math. ran­dom()*4.0 - 2.0 ); ob­ject.scale.set(math.ran­dom()+.5,math. ran­dom()+.5,math.ran­dom()+.5 ); ob­­ta­tion.set( Math.ran­dom() * 2 * Math.pi, Math.ran­dom() * 2 * Math.pi, Math. ran­dom() * 2 * Math.pi );

// cre­ate or­bit at­tributes }

14. Add or­bit at­tributes to ob­jects

To en­able some nice ran­dom or­bit­ing mo­tion, and to keep the ob­jects from ‘es­cap­ing the room’ we’ll as­sign some ini­tial an­gle data (in ra­di­ans) and a dis­tance. It en­ables a sim­ple way to an­i­mate the ob­jects in the ren­der loop af­ter.

// cre­ate or­bit at­tributes

// calc dis­tance as con­stant and as­sign to ob­ject var a = new THREE.VECTOR3( 0, 0, 0 ); var b = ob­ject.po­si­tion; var d = a.dis­tanceto( b ); ob­ject.dis­tance = d; ob­ject.ra­di­ans = Math.ran­dom()*360 * Math. PI/180; // ini­tial an­gle ob­ject.ra­di­ans2 = Math.ran­dom()*360 * Math. PI/180; // ini­tial an­gle ob­ject.ra­di­ans3 = Math.ran­dom()*360 * Math. PI/180; // ini­tial an­gle room.add( ob­ject ); ob­jects.push( ob­ject );

15. Add a win­dow re­size han­dler

As we test our WEBVR app, we’ll be re­siz­ing the screen, mov­ing it around, etc. It’s a good idea to have a han­dler that ad­justs the di­men­sions of the ren­der area and up­dates things to keep it filling the screen prop­erly and look­ing nice.

win­­de­ventlis­tener( ‘re­size’, on­win­dowre­size, false ); func­tion on­win­dowre­size() { cam­­pect = win­­ner­width / win­dow. in­ner­height; cam­era.up­datepro­jec­tion­ma­trix(); ren­derer.set­size( win­­ner­width, win­­ner­height ); }

16. Cre­ate the WEBVR but­ton

Three.js’s new WEBVR class in­cludes a WEBVR but­ton, which han­dles tog­gling in and out of VR mode for us. It also han­dles if the de­vice doesn’t sup­port VR mode. You can in­clude it with this sim­ple code:

// three.js webvr but­ton to en­ter/ exit vr mode doc­u­ment.body.ap­pend­child( Webvr.cre­ate­but­ton ( ren­derer ) );

17. Start the VR an­i­ma­tion loop

Typ­i­cally, you’d be us­ing the re­ques­tani­ma­tion­frame to han­dle the ren­der loop, but in VR you have to use a dif­fer­ent loop han­dler to en­sure ev­ery­thing is ready to ren­der and that you avoid la­tency and ren­der is­sues. In­stead, use the new se­tan­i­ma­tion­loop and pass in your ren­der func­tion.

// start the VR an­i­ma­tion loop ren­­tan­i­ma­tion­loop( ren­der );

18. Cre­ate the ren­der func­tion

Next, cre­ate a ren­der func­tion. If you didn’t want to an­i­mate your ob­jects or test for the cam­era/crosshair in­ter­sect­ing with ob­jects, you could just use the fol­low­ing code:

func­tion ren­der() {

// find in­ter­sec­tions // an­i­mate the ob­jects // ren­der the scene ren­­der( scene, cam­era ); }

19. Test for in­ter­sec­tions

To en­able test­ing for ob­jects in­ter­sect­ing the ray traced from the cam­era into Z space, add the fol­low­ing code to your ren­der loop where you com­mented it in the last step.: ray­caster.set­from­cam­era( { x: 0, y: 0 }, cam­era ); var in­ter­sects = ray­­ter­sec­to­b­jects ( room.chil­dren ); if ( in­ter­sects.length > 0 ) { if ( HIT != in­ter­sects[ 0 ].ob­ject ) { if ( HIT ) {­te­rial.emis­sive. sethex( Hit.cur­ren­thex ); }

HIT = in­ter­sects[ 0 ].ob­ject; Hit.cur­ren­thex =­te­rial.emis­sive. gethex();­te­rial.emis­sive.sethex( 0x00ff00 ); } } else { if ( HIT ){­te­rial.emis­sive.sethex ( Hit.cur­ren­thex ); }

HIT = un­de­fined; }

20. An­i­mate ob­jects along or­bits

Next, you can an­i­mate your ob­jects along their or­bit paths us­ing this code:

for (i=0;i<=num;i++){ var o = ob­jects[i];­ta­tion.y+=.01; if( i % 2 == 0) { o.ra­di­ans+=.004; o.ra­di­ans2+=.005; o.ra­di­ans3+=.008; } else { o.ra­di­ans-=.006; o.ra­di­ans2-=.005; o.ra­di­ans3-=.003; } o.po­si­tion.x = (Math.cos(o.ra­di­ans) * o.dis­tance); o.po­si­tion.z = (Math.sin(o.ra­di­ans3) * o.dis­tance); o.po­si­tion.y = (Math.sin(o.ra­di­ans2) * o.dis­tance*.5); }

21. Ren­der the WEBVR scene

Fi­nally, you can ren­der out your scene us­ing the us­ably ren­der func­tions. If you haven’t added this line al­ready, do it now. Once you’ve added this, you can test it all out and should see a WEBVR scene ren­der­ing in your browser. You can also check it out on your mo­bile de­vice or VR head­set.

// ren­der the scene ren­­der( scene, cam­era );

Newspapers in English

Newspapers from UK

© PressReader. All rights reserved.