Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Getting Started with WebVR Contents Creation for Oculus Quest

Getting Started with WebVR Contents Creation for Oculus Quest

Slide deck of tutorial seminar which is going to be held 23 June for WebVR contents creation for Oculus Quest.

TakashiYoshinaga

June 21, 2019
Tweet

More Decks by TakashiYoshinaga

Other Decks in Technology

Transcript

  1. What’s A-Frame  JS library to create VR apps which

    work on web browser.  3D objects can be placed by writing HTML tags.  VR apps work on web browser. (ex. Chrome, Firefox)  Also available on WinMR, HTC Vive and Oculus Quest.
  2. Experience See around VR environment by mouse/key controll. Click inside

    the screen Rotation:drag & move a mouse Left/Right:[←][→] key Forward/Back:[↑][↓] key
  3. You can See Also... Primitive sample of getting input from

    controllers https://github.com/TakashiYoshinaga/Oculus- Quest-Input-Sample Source code of the goal of today’s tutorial. https://github.com/TakashiYoshinaga/Oculus- Quest-Interaction-Sample
  4. Today’s Tutorial Step1: Learning basic usage of A-Frame Step2: Making

    the simple VR environment. Step3: Writing script to achieve interaction.
  5. Today’s Tutorial Step1: Learning basic usage of A-Frame Step2: Making

    the simple VR environment. Step3: Writing script to achieve interaction.
  6. Remixing the Sample Code Click “Remix your own” button shown

    on the right bottom of preview image. Click
  7. Explanation of the Sample Code <html> <head> <title>Hello, WebVR! -

    A-Frame</title> <meta name="description" content="Hello, WebVR! - A-Frame"> <script src="https://aframe.io/releases/0.9.2/aframe.min.js"> </script> </head> <body> <a-scene background="color: #FAFAFA"> Description of 3D contents are written here. </a-scene> </body> </html>  A-Frame library is imported between <head></head>  Description of 3D objects are written between<a-scene></a-scene>
  8. Explanation of the Sample Code <a-scene background="color: #ECECEC"> <a-box position="-1

    0.5 -3" rotation="0 45 0" color="#4CC3D9"> </a-box> <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"> </a-sphere> <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder> <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane> </a-scene>  Primitive objects are defined as a-xxx https://aframe.io/docs/0.9.0/primitives /a-box.html (ex. Detail of a-box)
  9. Run

  10. How to Modify Objects? You can change parameters of components.

    For example...  position: x y z are used to modify the position of a CG. (0 1.25 -5)
  11. How to Modify Objects? Examples of components  position:x y

    z are used to modify the position.  rotation:x y z means rotation of each axis.  color:color code are used to define the color.  There are some parameters for each primitive object. X Z Y (0 1.25 -5) 【Others】 radius width height depth src (image file) 原点
  12. <a-scene background="color: #FAFAFA "> <a-box position="-1 0.5 -3" rotation="0 45

    0" color="#4CC3D9"> </a-box> <a-sphere position="0 1.25 -5" radius=" 1.25" color="#EF2D5E"> </a-sphere> <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder> <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane> </a-scene> Let’s Try to Edit Components #AAAAAA position="-1 0.5 -2" rotation="0 0 0" position="0 1.25 -4" radius="0.7" position="1 0.75 -2 height="0.7" position="0 0 0" width="10" height="10"
  13. Today’s Tutorial Step1: Learning basic usage of A-Frame Step2: Making

    the simple VR environment. Step3: Writing script to achieve interaction.
  14. Today’s Tutorial Step1: Learning basic usage of A-Frame Step2: Making

    the simple VR environment. Step3: Writing script to achieve interaction.
  15. Applying Texture Image <a-scene background="color: #AAAAAA"> <a-box position="-1 0.5 -2"

    rotation="0 0 0" color="#4CC3D9"> </a-box> <a-sphere position="0 1.25 -4" radius="0.7" color="#EF2D5E"> </a-sphere> <a-cylinder position="1 0.75 -2" radius="0.5" height="0.7" color="#FFC65D"></a-cylinder> <a-plane position="0 0 0" rotation="-90 0 0" width="10" height="10" color="#7BC8A4" shadow></a-plane> </a-scene>  Replace the a-sphere’s material to src instead color. To be continued to the next page... Delete color
  16. Applying Texture Image <a-scene background="color: #AAAAAA"> <a-box position="-1 0.5 -2"

    rotation="0 0 0" color="#4CC3D9"> </a-box> <a-sphere position="0 1.25 -4" radius="0.7" color="#EF2D5E"> </a-sphere> <a-cylinder position="1 0.75 -2" radius="0.5" height="0.7" color="#FFC65D"></a-cylinder> <a-plane position="0 0 0" rotation="-90 0 0" width="10" height="10" src="URL" shadow></a-plane> </a-scene> Paste the URL Add src  Change the a-sphere’s material to src instead color.  Paste the URL of the texture image on the right side of src.
  17. Duplication of Textured Plane <a-scene background="color: #AAAAAA"> <a-box position="-1 0.5

    -2" rotation="0 0 0" color="#4CC3D9"> </a-box> <a-sphere position="0 1.25 -4" radius="0.7" color="#EF2D5E"> </a-sphere> <a-cylinder position="1 0.75 -2" radius="0.5" height="0.7" color="#FFC65D"></a-cylinder> <a-plane position="0 0 0" rotation="-90 0 0" width="10" height="10" src="URL" shadow></a-plane> <a-plane position="0 5 0" rotation="90 0 0" width="10" height="10" src=“URL" shadow></a-plane> </a-scene> Copy & Paste
  18. Duplication of Textured Plane <a-plane position="0 0 0" rotation="-90 0

    0" width="10" height="10" src="URL"></a-plane> <a-plane position="0 5 0" rotation="90 0 0" width="10" height="10" src="URL"></a-plane> <a-plane position="0 2.5 -5" rotation="0 0 0" width="10" height="5" src="URL"></a-plane> <a-plane position="0 2.5 5" rotation="0 180 0" width="10" height="5" src="URL"></a-plane> <a-plane position="5 2.5 0" rotation="0 -90 0" width="10" height="5" src="URL"></a-plane> <a-plane position="-5 2.5 0" rotation="0 90 0" width="10" height="5" src="URL"></a-plane> Make 4 walls with the same procedure.
  19. Adding Controller Entity <a-plane position="0 0 0" rotation="-90 0 0"

    width="10" height="10" src="URL" shadow> </a-plane> <a-plane position="0 5 0" rotation="90 0 0" width="10" height="10" src="URL" shadow> </a-plane> <a-plane position="0 2.5 -5" rotation="0 0 0" width="10" height="5" src="URL" shadow> </a-plane> <a-plane position="0 2.5 5" rotation="0 180 0" width="10" height="5" src="URL" shadow> </a-plane> <a-plane position="5 2.5 0" rotation="0 -90 0" width="10" height="5" src="URL" shadow> </a-plane> <a-plane position="-5 2.5 0" rotation="0 90 0" width="10" height="5" src="URL" shadow> </a-plane> <a-entity laser-controls="hand: left"> </a-entity> <a-entity laser-controls="hand: right"> </a-entity> <a-entity> enables us to define original entity instead pre-defined primitive entities.
  20. Today’s Tutorial Step1: Learning basic usage of A-Frame Step2: Making

    the simple VR environment. Step3: Writing script to achieve interaction.
  21. Today’s Tutorial Step1: Learning basic usage of A-Frame Step2: Making

    the simple VR environment. Step3: Writing script to achieve interaction.
  22. Definition of Input Behavior <a-plane position="0 2.5 -5" rotation="0 0

    0" width="10" height="10" src="URL"> </a-plane> <a-plane position="0 2.5 5" rotation="0 180 0" width="10" height="10" src="URL"> </a-plane> <a-plane position="5 2.5 0" rotation="0 -90 0" width="10" height="10" src="URL"> </a-plane> <a-plane position="-5 2.5 0" rotation="0 90 0" width="10" height="10" src="URL"> </a-plane> <a-entity laser-controls="hand: left" input-listen> </a-entity> <a-entity laser-controls="hand: right" input-listen> </a-entity> Add input-listen component to describe behavior when input of controller is received. From next page, source code of input-listen is explained.
  23. Definition of Input Behavior <script> AFRAME.registerComponent('input-listen', { init:function () {

    //Initialization } , tick: function () { //Update } }); </script> <a-scene background="color: #AAAAAA"> <a-box position="-1 0.5 -2" rotation="0 0 0" color="#4CC3D9" shadow></a-box> <!--source code is omitted in this document--> <a-entity laser-controls="hand: left" input-listen> </a-entity> <a-entity laser-controls="hand: right" input-listen> </a-entity> </a-scene> 1.txt
  24. Definition of Input Behavior init:function () { //Initialization //Called when

    x button begin to be pressed (for Left Hand) this.el.addEventListener('xbuttondown', function (e) { /*Do something*/ }); //Called when x button is released (for Left Hand) this.el.addEventListener('xbuttonup', function (e) { }); //Called when grip button begin to be pressed (for Both Hand) this.el.addEventListener('gripdown', function (e) { }); //Called when grip button released. (for Both Hand) this.el.addEventListener('gripup', function (e) { }); } , 2.txt
  25. Visualization of Input Info with Text <a-scene background="color: #AAAAAA"> <!--Source

    is omitted in this slide.--> <a-plane position="-5 2.5 0" rotation="0 90 0" width="10" height="5" src="URL" shadow></a-plane> <a-entity camera position="0 1.6 0"> <a-text id="txt" value=" " position="0 0 -1" scale="0.5 0.5 0.5" align="center" color="#FFFFFF"> </a-text> </a-entity> <a-entity laser-controls="hand: left" input-listen> </a-entity> <a-entity laser-controls="hand: right" input-listen> </a-entity> </a-scene> 3.txt
  26. Visualization of Input Info with Text const txt = document.getElementById("txt");

    //Called when x button begin to be pressed (for Left Hand) this.el.addEventListener('xbuttondown', function (e) { txt.setAttribute("value", "x pressed"); }); //Called when x button is released (for Left Hand) this.el.addEventListener('xbuttonup', function (e) { txt.setAttribute("value", "x released"); }); //Called when grip button begin to be pressed (for Both Hand) this.el.addEventListener('gripdown', function (e) { txt.setAttribute("value", "grip pressed"); }); //Called when grip button released. (for Both Hand) this.el.addEventListener('gripup', function (e) { txt.setAttribute("value", "grip released"); }); 4.txt
  27. Duplication of the Project Remix Project I recommend to preserve

    this code as the primitive project. Click the content name
  28. Delete Lines of Visualization of Input const txt = document.getElementById("txt");

    //Called when x button begin to be pressed (for Left Hand) this.el.addEventListener('xbuttondown', function (e) { txt.setAttribute("value", "x pressed"); }); //Called when x button is released (for Left Hand) this.el.addEventListener('xbuttonup', function (e) { txt.setAttribute("value", "x released"); }); //Called when grip button begin to be pressed (for Both Hand) this.el.addEventListener('gripdown', function (e) { txt.setAttribute("value", "grip pressed"); }); //Called when grip button released. (for Both Hand) this.el.addEventListener('gripup', function (e) { txt.setAttribute("value", "grip released"); });
  29. Enabling Teleportation to the Content <html> <head> <meta charset="utf-8"> <title>Hello,

    WebVR! • A-Frame</title> <meta name="description" content="Hello, WebVR! • A-Frame"> <script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script> <script src="https://rawgit.com/fernandojsg/aframe-teleport- controls/master/dist/aframe-teleport-controls.min.js"></script> </head> 5.txt
  30. Enabling Teleportation to the Content <a-scene background="color: #AAAAAA"> <!—Source code

    is omitted in this slide.--> <a-entity id="cameraRig"> <a-entity camera position="0 1.6 0"> <a-text id="txt" value=" " position="0 0 -1" scale="0.5 0.5 0.5" align="center" color="#FFFFFF"> </a-text> </a-entity> <a-entity laser-controls="hand: left" input-listen> </a-entity> <a-entity laser-controls="hand: right" input-listen> </a-entity> </a-entity> </a-scene> <a-entity id="head" camera position="0 1.6 0"> Append camera and controller as children of <a-entity id="cameraRig"> </a-entity> to get them to be allowed jumping together to th destination.
  31. Enabling Teleportation to the Content <a-scene background="color: #AAAAAA"> <!--Source code

    is omitted in this slide.--> <a-entity id="cameraRig"> <a-entity id="head" camera position="0 1.6 0"> <a-text id="txt" value=" " position="0 0 -1" scale="0.5 0.5 0.5" align="center" color="#FFFFFF"> </a-text> </a-entity> <a-entity teleport-controls= "cameraRig: #cameraRig; teleportOrigin:#head; startEvents: teleportstart; endEvents: teleportend" laser-controls="hand: left" input-listen> </a-entity> <a-entity laser-controls="hand: right" input-listen> </a-entity> </a-entity> </a-scene> Next, teleportation function will be added to left-hand controller.
  32. Enabling Teleportation to the Content <a-scene background="color: #AAAAAA"> <!--中略--> <a-entity

    id="cameraRig"> <a-entity id="head" camera position="0 1.6 0"> <a-text id="txt" value=" " position="0 0 -1" scale="0.5 0.5 0.5" align="center" color="#FFFFFF"> </a-text> </a-entity> <a-entity teleport-controls= "cameraRig: #cameraRig; teleportOrigin:#head; startEvents: teleportstart; endEvents: teleportend" laser-controls="hand: left" input-listen> </a-entity> <a-entity laser-controls="hand: right" input-listen> </a-entity> </a-entity> </a-scene> Add teleport-controls component to left-hand controller. 6.txt
  33. Supplementation 1 <a-scene background="color: #AAAAAA"> <!--中略--> <a-entity id="cameraRig"> <a-entity id="head"

    camera position="0 1.6 0"> <a-text id="txt" value=" " position="0 0 -1" scale="0.5 0.5 0.5" align="center" color="#FFFFFF"> </a-text> </a-entity> <a-entity teleport-controls= "cameraRig: #cameraRig; teleportOrigin:#head; startEvents: teleportstart; endEvents: teleportend" laser-controls="hand: left" input-listen> </a-entity> <a-entity laser-controls="hand: right" input-listen> </a-entity> </a-entity> </a-scene> It means to allow jumpping #CameraRig and its children from #head
  34. Supplementation 2 <a-scene background="color: #AAAAAA"> <!--Omitted--> <a-entity id="cameraRig"> <a-entity id="head"

    camera position="0 1.6 0"> <a-text id="txt" value=" " position="0 0 -1" scale="0.5 0.5 0.5" align="center" color="#FFFFFF"> </a-text> </a-entity> <a-entity teleport-controls= "cameraRig: #cameraRig; teleportOrigin:#head; startEvents: teleportstart; endEvents: teleportend" laser-controls="hand: left" input-listen> </a-entity> <a-entity laser-controls="hand: right" input-listen> </a-entity> </a-entity> teleportstart is called to start pointing destination. teleportend is called to jump to pointed position.
  35. Enabling Teleportation to the Content init:function () { const txt

    = document.getElementById("txt"); ////Called when x button begin to be pressed this.el.addEventListener('xbuttondown', function (e) { //Start to point destination this.emit('teleportstart'); }); // //Called when x button is released this.el.addEventListener('xbuttonup', function (e) { //Jump to pointed position. this.emit('teleportend'); }); /*Following code is omitted in this slide.*/ }
  36. Adding Raycaster Component <a-scene background="color: #AAAAAA"> <!--中略--> <a-entity id="cameraRig"> <a-entity

    id="head" camera position="0 1.6 0"> <a-text id="txt" value=" " position="0 0 -1" scale="0.5 0.5 0.5" align="center" color="#FFFFFF"> </a-text> </a-entity> <a-entity teleport-controls= "cameraRig: #cameraRig; teleportOrigin:#head; startEvents: teleportstart; endEvents: teleportend" laser-controls="hand: left" input-listen> </a-entity> <a-entity laser-controls="hand: right" input-listen> </a-entity> </a-entity> </a-scene> Find controllers
  37. Adding Raycaster Component <a-scene background="color: #AAAAAA"> <!--中略--> <a-entity id="cameraRig"> <a-entity

    id="head" camera position="0 1.6 0"> <a-text id="txt" value=" " position="0 0 -1" scale="0.5 0.5 0.5" align="center" color="#FFFFFF"> </a-text> </a-entity> <a-entity teleport-controls= "cameraRig: #cameraRig; teleportOrigin:#head; startEvents: teleportstart; endEvents: teleportend“ raycaster="objects: .collidable; far:1.2;" laser-controls="hand: left" input-listen> </a-entity> <a-entity laser-controls="hand: right" input-listen> </a-entity> Raycaster will interact with collidable entity.(see next page) It just works when distance between controller & object is in 1.2m
  38. Adding Raycaster Component <a-scene background="color: #AAAAAA"> <!--中略--> <a-entity id="cameraRig"> <a-entity

    id="head" camera position="0 1.6 0"> <a-text id="txt" value=" " position="0 0 -1" scale="0.5 0.5 0.5" align="center" color="#FFFFFF"> </a-text> </a-entity> <a-entity teleport-controls= "cameraRig: #cameraRig; teleportOrigin:#head; startEvents: teleportstart; endEvents: teleportend" raycaster="objects: .collidable; far:1.2;" laser-controls="hand: left" input-listen> </a-entity> <a-entity raycaster="objects: .collidable; far:1.2;" laser-controls="hand: right" input-listen> </a-entity> Raycaster will interact with collidable entity.(see next page) It just works when distance between controller & object is in 1.2m
  39. Setting Entities as Collidable Object <a-scene background="color: #AAAAAA"> <a-box class="collidable"

    position="-1 0.5 -2" rotation="0 0 0" color="#4CC3D9" shadow> </a-box> <a-sphere class="collidable" position="0 1.25 -4" radius="0.7" color="#EF2D5E" shadow> </a-sphere> <a-cylinder class="collidable" position="1 0.75 -2" radius="0.5" height="0.6" color="#FFC65D" shadow></a-cylinder> <a-plane position="0 0 0" rotation="-90 0 0" width="10" height="10" src="URL" shadow></a-plane> <!—Omitted in this slide --> </a-scene> Checking intersection with raycaster is ON Floor and walls are not checked intersection
  40. Condition of Manipulation (1/2) init:function () { const txt =

    document.getElementById("txt"); this.el.grip=false; this.el.addEventListener('xbuttondown', function (e) { this.emit('teleportstart'); }); this.el.addEventListener('xbuttonup', function (e) { this.emit('teleportend'); }); this.el.addEventListener('gripdown', function (e) { this.grip=true; }); this.el.addEventListener('gripup', function (e) { this.grip=false; }); } , Holding grip is pressed or not.
  41. Condition of Manipulation (2/2) init:function () { /*Source code is

    omitted in this slide.*/ this.el.addEventListener('gripup', function (e) { this.grip=false; }); //called when raycaster intersected with something this.el.addEventListener('raycaster-intersection', function (e) { //Holding 1st object of detected entity as selected object. this.selectedObj = e.detail.els[0]; }); //called when raycaster intersection is cleared. this.el.addEventListener('raycaster-intersection-cleared', function (e) { //Reset selected object. this.selectedObj = null; }); } , Checking raycaster is intersected with CG or not 7.txt
  42. Manipulation init:function () { /* Omitted in this slide */

    this.el.addEventListener('raycaster-intersection', function (e) { this.selectedObj = event.detail.els[0]; }); this.el.addEventListener('raycaster-intersection-cleared', function (e) { this.selectedObj = null; }); }, //Update tick: function () { if (!this.el.selectedObj) { return; } if (!this.el.grip) { return; } //Make selected object to follow the tip of raycaster when //raycaster intersected object and grip is pressed. }
  43. Manipulation //update tick: function () { if (!this.el.selectedObj) { return;

    } if (this.el.grip == false) { return; } //Getting direction of raycaster attached on this controller. var ray = this.el.getAttribute("raycaster").direction; //Calculate 1.2m forward position relative to controller var p = new THREE.Vector3(ray.x, ray.y, ray.z); p.normalize(); p.multiplyScalar(1.2); //Convert local position to world position. this.el.object3D.localToWorld(p); //put the selected object on the tip of the raycaster this.el.selectedObj.object3D.position.set(p.x, p.y, p.z); } 8.txt
  44. Import Library of Physics <head> <meta charset="utf-8"> <title>Hello, WebVR! •

    A-Frame</title> <meta name="description" content="Hello, WebVR! • A-Frame"> <script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script> <script src="https://rawgit.com/fernandojsg/aframe-teleport- controls/master/dist/aframe-teleport-controls.min.js"></script> <script src="//cdn.rawgit.com/donmccurdy/aframe-physics- system/v3.3.0/dist/aframe-physics-system.min.js"></script> </head> <body> <script> All script is omitted in this slide.</script> <a-scene background="color: #AAAAAA"> /*Omitted*/ </a-entity> </body> 9.txt physics="gravity: 0; restitution: 0.9;"
  45. Adding Event of Trigger Down init:function () { /*Source code

    is omitted in this slide.*/ //Raycaster intersected with something. this.el.addEventListener('raycaster-intersection', function (e) { this.selectedObj = event.detail.els[0]; }); //Raycaster intersection is finished. this.el.addEventListener('raycaster-intersection-cleared', function (e) { this.selectedObj = null; }); //Calles when the trigger button begin to be pressed. this.el.addEventListener('triggerdown', function (e) { }); }
  46. Instantiation of Ball this.el.addEventListener('triggerdown', function (e) { //Getting the current

    position of the controller. var point = this.object3D.getWorldPosition(); //Instantiation of ball entity. var ball = document.createElement('a-sphere'); ball.setAttribute('class', 'ball'); ball.setAttribute('scale', '0.2 0.2 0.2'); ball.setAttribute('position', point); //Adding dynamic-body and its property to enable physics. ball.setAttribute('dynamic-body', 'shape: sphere; sphereRadius:0.2; '); //Generate ball entity in a-scene var scene = document.querySelector('a-scene'); scene.appendChild(ball); }); 10.txt
  47. Calculation of Shooting Vector this.el.addEventListener('triggerdown', function (e) { /*Source code

    is omitted in this slide.*/ //Generating ball entity in a-scene var scene = document.querySelector('a-scene'); scene.appendChild(ball); //Getting direction of raycaster component of the controller. var dir = this.getAttribute("raycaster").direction; //Setting direction and magnitude of shoot vector. var force = new THREE.Vector3(); force.set(dir.x, dir.y, dir.z); force.multiplyScalar(2000); //Declare and set force vecter. ball.force = this.object3D.localToWorld(force); }); 11.txt
  48. Shooting Bullet this.el.addEventListener('triggerdown', function (e) { /*Source code is omitted

    in this slide.*/ ball.force = this.object3D.localToWorld(force); //Shoot after finishing to load physics on ball ball.addEventListener('body-loaded', function (e) { //Getting position of ball var p = this.object3D.position; //Add force var f = this.force; this.body.applyForce( new CANNON.Vec3(f.x, f.y, f.z), new CANNON.Vec3(p.x, p.y, p.z) ); }); }); 12.txt
  49. Enabling Collision Detection <a-scene physics="debug: false; gravity: 0; restitution: 0.9;

    " background="color: #AAAAAA"> <a-box static-body class="collidable" --omitted-- ></a-box> <a-sphere static-body class="collidable" --omitted-- ></a-sphere> <a-cylinder static-body class="collidable" --omitted-- ></a-cylinder> <a-plane static-body position="0 0 0" --omitted-- ></a-plane> <a-plane static-body position="0 5 0" --omitted-- ></a-plane> <a-plane static-body position="0 2.5 -5" --omitted-- ></a-plane> <a-plane static-body position="0 2.5 5" --omitted-- ></a-plane> <a-plane static-body position="5 2.5 0" --omitted-- ></a-plane> <a-plane static-body position= "-5 2.5 0" --omitted-- ></a-plane> <a-entity id="cameraRig">--omitted--</a-entity> box, sphere, cylinder, planeにstatic-bodyを追加
  50. Remove Balls by Pressing A-Button init:function () { /*Source code

    is omitted in this slide.*/ //called when trigger button is started to be pressed this.el.addEventListener('triggerdown', function (e) { /*Source code is omitted in this slide.*/ }); //Called when pressing a-button is began. this.el.addEventListener('abuttondown', function (e) { //Obtain all entity of being ball class var els = document.querySelectorAll('.ball'); //Remove each balls from a-scene. for (var i = 0; i < els.length; i++) { els[i].parentNode.removeChild(els[i]); } }); } , 13.txt