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. Getting Started with WebVR
    Contents Creation for Oculus Quest

    View Slide

  2. Please Download Sample Data
    http://arfukuoka.lolipop.jp/quest/Sample.zip

    View Slide

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

    View Slide

  4. Experience
    Access to the official site of A-Frame
    (https://aframe.io/)

    View Slide

  5. Experience
    Sample demos are shown on the left column.
    サンプル

    View Slide

  6. Experience
    Let’s see the most primitive sample Hello WebVR.
    Hello WebVR

    View Slide

  7. Experience
    See around VR environment by mouse/key controll.
    Click inside the screen
    Rotation:drag & move a mouse
    Left/Right:[←][→] key
    Forward/Back:[↑][↓] key

    View Slide

  8. Another Example
    360°Images also work with A-Frame easily.
    360°Image
    RICOH Theta

    View Slide

  9. Of course you can play on Oculus Quest

    View Slide

  10. The Goal of This Tutorial
    https://youtu.be/J-AQpvOawJ0

    View Slide

  11. Let’s Experience on Oculus Quest!
    https://quest-demo.glitch.me

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  15. Please log in your account of Glitch
    https://glitch.com/

    View Slide

  16. Getting Sample Code
    Click the link shown as GET STARTED
    GET STARTED

    View Slide

  17. Remixing the Sample Code
    Description of Hello WebVR
    Hello WebVR

    View Slide

  18. Remixing the Sample Code
    Click remix the starter example on Glitch
    Click

    View Slide

  19. Remixing the Sample Code
    Click “Remix your own” button shown on the
    right bottom of preview image.
    Click

    View Slide

  20. Click index.html to view the sample code.
    Click

    View Slide

  21. Explanation of the Sample Code


    Hello, WebVR! - A-Frame

    <br/>



    Description of 3D contents are written here.



     A-Frame library is imported between
     Description of 3D objects are written between

    View Slide

  22. Explanation of the Sample Code





    color="#FFC65D">
    width="4" height="4" color="#7BC8A4">

     Primitive objects are defined as a-xxx
    https://aframe.io/docs/0.9.0/primitives
    /a-box.html (ex. Detail of a-box)

    View Slide

  23. Run
    ①Show
    ②Next to The Code

    View Slide

  24. Run

    View Slide

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

    View Slide

  26. 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)
    原点

    View Slide






  27. color="#FFC65D">
    width="4" height="4" color="#7BC8A4">

    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"

    View Slide

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

    View Slide

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

    View Slide

  30. Applying Texture Image

    View Slide

  31. Applying Texture Image
    ①assets
    ②Add Asset → Upload

    View Slide

  32. Applying Texture Image
    ①back.png
    ②Open

    View Slide

  33. Applying Texture Image
    Click

    View Slide

  34. Applying Texture Image
    ①Click
    ②Click out of the dialog

    View Slide

  35. Applying Texture Image
    index.html

    View Slide

  36. Applying Texture Image





    color="#FFC65D">
    width="10" height="10" color="#7BC8A4" shadow>

     Replace the a-sphere’s material to src instead color.
    To be continued to the next page...
    Delete color

    View Slide

  37. Applying Texture Image





    color="#FFC65D">
    width="10" height="10" src="URL" shadow>
    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.

    View Slide

  38. Duplication of Textured Plane





    color="#FFC65D">
    width="10" height="10" src="URL" shadow>
    width="10" height="10" src=“URL" shadow>

    Copy & Paste

    View Slide

  39. Duplication of Textured Plane
    width="10" height="10" src="URL">
    width="10" height="10" src="URL">
    width="10" height="5" src="URL">
    width="10" height="5" src="URL">
    width="10" height="5" src="URL">
    width="10" height="5" src="URL">
    Make 4 walls with the same procedure.

    View Slide

  40. Modify URL of Your VR Content
    Click Text
    Modify a name

    View Slide

  41. Modify URL of Your VR Content
    https://XXXX-XXXX.glitch.me

    View Slide

  42. Test on Oculus Quest
    You will be immersed in the VR space you created.

    View Slide

  43. Adding Controller Entity
    width="10" height="10" src="URL" shadow>
    width="10" height="10" src="URL" shadow>
    width="10" height="5" src="URL" shadow>
    width="10" height="5" src="URL" shadow>
    width="10" height="5" src="URL" shadow>
    width="10" height="5" src="URL" shadow>


    enables us to define original entity
    instead pre-defined primitive entities.

    View Slide

  44. Before Test on Oculus Quest...
    Reload!

    View Slide

  45. Test on Oculus Quest
    Oculus Touch’s controller, not Quest’s, will appear.

    View Slide

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

    View Slide

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

    View Slide

  48. Definition of Input Behavior
    width="10" height="10" src="URL">
    width="10" height="10" src="URL">
    width="10" height="10" src="URL">
    width="10" height="10" src="URL">


    Add input-listen component to describe behavior
    when input of controller is received.
    From next page, source code of input-listen is explained.

    View Slide

  49. Definition of Input Behavior
    <br/>AFRAME.registerComponent('input-listen', {<br/>init:function () { //Initialization<br/>} ,<br/>tick: function () { //Update<br/>}<br/>});<br/>

    color="#4CC3D9" shadow>




    1.txt

    View Slide

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

    View Slide

  51. Visualization of Input Info with Text


    height="5" src="URL" shadow>

    scale="0.5 0.5 0.5" align="center" color="#FFFFFF">





    3.txt

    View Slide

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

    View Slide

  53. Before the Test on Oculus Quest
    Reload!!

    View Slide

  54. Test on Oculus Quest
    Each action of grip or a-button will appear.

    View Slide

  55. Reference
    https://aframe.io/docs/0.9.0/components/oculus-touch-controls.html
    ①Oculus-touch-controls
    ②Events
    Info of events are explained in the official reference in detail.

    View Slide

  56. Duplication of the Project
    Remix Project
    I recommend to preserve this code as the primitive project.
    Click the content name

    View Slide

  57. Modification of URL of the New Content
    Click the content name
    Replace the name as you like

    View Slide

  58. 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");
    });

    View Slide

  59. Enabling Teleportation to the Content



    Hello, WebVR! • A-Frame




    5.txt

    View Slide

  60. Enabling Teleportation to the Content




    scale="0.5 0.5 0.5" align="center" color="#FFFFFF">







    Append camera and controller as children of

    to get them to be allowed jumping together to th destination.

    View Slide

  61. Enabling Teleportation to the Content




    scale="0.5 0.5 0.5" align="center" color="#FFFFFF">


    "cameraRig: #cameraRig; teleportOrigin:#head;
    startEvents: teleportstart; endEvents: teleportend"
    laser-controls="hand: left" input-listen>



    Next, teleportation function will be added to left-hand controller.

    View Slide

  62. Enabling Teleportation to the Content




    scale="0.5 0.5 0.5" align="center" color="#FFFFFF">


    "cameraRig: #cameraRig; teleportOrigin:#head;
    startEvents: teleportstart; endEvents: teleportend"
    laser-controls="hand: left" input-listen>



    Add teleport-controls component to left-hand controller.
    6.txt

    View Slide

  63. Supplementation 1




    scale="0.5 0.5 0.5" align="center" color="#FFFFFF">


    "cameraRig: #cameraRig; teleportOrigin:#head;
    startEvents: teleportstart; endEvents: teleportend"
    laser-controls="hand: left" input-listen>



    It means to allow jumpping #CameraRig and its children from #head

    View Slide

  64. Supplementation 2




    scale="0.5 0.5 0.5" align="center" color="#FFFFFF">


    "cameraRig: #cameraRig; teleportOrigin:#head;
    startEvents: teleportstart; endEvents: teleportend"
    laser-controls="hand: left" input-listen>


    teleportstart is called to start pointing destination.
    teleportend is called to jump to pointed position.

    View Slide

  65. 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.*/
    }

    View Slide

  66. Check the URL Before Starting Test
    Remember
    the project name
    https://XXX-XXX.glitch.me

    View Slide

  67. Test on Oculus Quest
    Teleportation will be available.

    View Slide

  68. Text Step: Manipulation
    raycaster
    Checking
    intersection
    intersect
    Gripdown
    Manipulate!

    View Slide

  69. Adding Raycaster Component




    scale="0.5 0.5 0.5" align="center" color="#FFFFFF">


    "cameraRig: #cameraRig; teleportOrigin:#head;
    startEvents: teleportstart; endEvents: teleportend"
    laser-controls="hand: left" input-listen>
    laser-controls="hand: right" input-listen>


    Find controllers

    View Slide

  70. Adding Raycaster Component




    scale="0.5 0.5 0.5" align="center" color="#FFFFFF">


    "cameraRig: #cameraRig; teleportOrigin:#head;
    startEvents: teleportstart; endEvents: teleportend“
    raycaster="objects: .collidable; far:1.2;"
    laser-controls="hand: left" input-listen>
    laser-controls="hand: right" input-listen>
    Raycaster will interact with collidable entity.(see next page)
    It just works when distance between controller & object is in 1.2m

    View Slide

  71. Adding Raycaster Component




    scale="0.5 0.5 0.5" align="center" color="#FFFFFF">


    "cameraRig: #cameraRig; teleportOrigin:#head;
    startEvents: teleportstart; endEvents: teleportend"
    raycaster="objects: .collidable; far:1.2;"
    laser-controls="hand: left" input-listen>
    laser-controls="hand: right" input-listen>
    Raycaster will interact with collidable entity.(see next page)
    It just works when distance between controller & object is in 1.2m

    View Slide

  72. Setting Entities as Collidable Object

    color="#4CC3D9" shadow>
    color="#EF2D5E" shadow>
    height="0.6" color="#FFC65D" shadow>
    src="URL" shadow>

    Checking intersection
    with raycaster is ON
    Floor and walls are
    not checked intersection

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  77. Test on Oculus Quest
    3D objects will become manipulatable

    View Slide

  78. Reference of raycaster
    https://github.com/aframevr/aframe/blob/master/docs/co
    mponents/raycaster.md
    You can read more detail of raycaster below.

    View Slide

  79. Next Step:Shooting Bullet(ball)
    Press Trigger

    View Slide

  80. Import Library of Physics


    Hello, WebVR! • A-Frame






    All script is omitted in this slide.
    background="color: #AAAAAA">
    /*Omitted*/


    9.txt
    physics="gravity: 0; restitution: 0.9;"

    View Slide

  81. 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) {
    });
    }

    View Slide

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

    View Slide

  83. Test on Oculus Quest
    Ball will appear on the hand position but not be shot yet.

    View Slide

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

    View Slide

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

    View Slide

  86. Test on Oculus Quest
    Balls are shot but through the wall.

    View Slide

  87. Enabling Collision Detection
    background="color: #AAAAAA">









    --omitted--
    box, sphere, cylinder, planeにstatic-bodyを追加

    View Slide

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

    View Slide

  89. Completed!

    View Slide

  90. View Slide