WebVR für die Oculus Quest

Seit einigen Wochen bin ich begeisterter Besitzer einer Oculus Quest. Ich bin begeistert darüber, wie echt sich Virtuelle Realität anfühlt. Mein Gehirn lässt sich bereitwillig Achterbahnen, Laserschwerter oder Unterwasserwelten vorgaukeln. Beim ersten Achterbahnen musste ich die Brille wieder abnehmen, weil mir schlecht wurde. 🙂 Und ich bin ein begeisterter Reale Realität Achterbahner.

Also Zeit, sich mit WebVR auseinanderzusetzen.

Ich bin jetzt also Hirn-Erweiterung-Überzeugter. Und ich möchte auch Welten bauen können. Ich habe hier mit Unity, der Unreal-Engine und Blender gerechnet, um virtuelle Modelle zu bauen. Aber ich wurde verblüfft – es geht auch auch in HTML. Bei Mozilla wurde die HTML Erweiterung A-Frame entwickelt, mir der 3D Welten wie HTML Seiten geschrieben werden können.  Im Folgenden fasse ich mal meine ersten Erfahrungen damit zusammen. Alle Codes unter https://github.com/zenbox/webvr/step-by-step.

Ich habe es (nur) mit der Oculus Quest getestet.

Die erste Datei (step-001.html) ist eine Basisszene. Zwei Objekte, Controller zum Greifen, Lichter und ein großer Fußboden, damit nichts herunterfällt. Es ist wirklich einfach!

Schritt für Schritt

<a-scene physics>
...
    <a-box id="ground" width="50" height="0.1" depth="50" position="0 -0.05 0" material="src: ../assets/figures/wood-planks.jpg; repeat:50 25;" static-body></a-box>
    <a-box id="box" color="orange" width="0.5" height="1" depth="0.5" position="-0.5 0.5 -1" rotation="0 0 0" dynamic-body></a-box>
...
</a-scene>

In der Szene steckt eine Box und eine Bodenplatte. „physics“ sorgt für Schwerkraft, Masse und Kollisionen. Masse und Texturen, Position und Rotation werden als Attribute geschrieben. Die Eigenschaft „dynamic-body“ macht aus einem Körper einen mit Masse – er fällt nach unten. Körpern. „static-body“  erzeugt einen fest im Raum stehenden Körper. Beide erhalten Kollisionsfähigkeit. So fällt die kleine Box auf den Boden und bleibt dort liegen.

Einbinden des Frameworks A-Frame

Damit das überhaupt geht muss natürlich A-Frame eingebunden werden. Das Basisframework gibt es unter https://aframe.io/releases/0.9.2/aframe.js
Ich habe hier noch einige andere Skripte eingebunden. Ausserdem kommt ein Standard Stylesheet dazu, dass für A-Frame arbeitet.

<html class="a-fullscreen">

<head>
    <title>Oculus</title>
    <meta name="viewport"
        content="width=device-width,initial-scale=1,maximum-scale=1,shrink-to-fit=no,user-scalable=no,minimal-ui,viewport-fit=cover">
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <link href="../assets/css/main.css" rel="stylesheet">

    <!-- the aframe standard library -->
    <script src="https://aframe.io/releases/0.9.2/aframe.js"></script>

    <!-- adding physics -->
    <script src="../lib/aframe/aframe-physics-system.min.js"></script>
    <script src="../lib/aframe/aframe-event-set-component.min.js"></script>
    <script src="../lib/aframe/aframe-physics-extras.min.js"></script>
    <script src="../lib/aframe/aframe-environment-component.min.js"></script>

    <!-- superhands code -->
    <script src="https://cdn.rawgit.com/donmccurdy/aframe-extras/v4.1.2/dist/aframe-extras.min.js"></script>
    <script src="https://unpkg.com/super-hands@3.0.0/dist/super-hands.min.js"></script>
</head>

<body>

Ready.

<html class="a-fullscreen">

<head>
    <title>Oculus</title>
    <meta name="viewport"
        content="width=device-width,initial-scale=1,maximum-scale=1,shrink-to-fit=no,user-scalable=no,minimal-ui,viewport-fit=cover">
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <link href="../assets/css/main.css" rel="stylesheet">

    <!-- the aframe standard library -->
    <script src="https://aframe.io/releases/0.9.2/aframe.js"></script>

    <!-- adding physics -->
    <script src="../lib/aframe/aframe-physics-system.min.js"></script>
    <script src="../lib/aframe/aframe-event-set-component.min.js"></script>
    <script src="../lib/aframe/aframe-physics-extras.min.js"></script>
    <script src="../lib/aframe/aframe-environment-component.min.js"></script>

    <!-- superhands code -->
    <script src="https://cdn.rawgit.com/donmccurdy/aframe-extras/v4.1.2/dist/aframe-extras.min.js"></script>
    <script src="https://unpkg.com/super-hands@3.0.0/dist/super-hands.min.js"></script>
</head>

<body>
    <a-scene physics>
        <!-- common assets -->
        <a-assets>
            <!-- - - - - - - - - - - -->
            <!--
                the oculus controller (hands-left, hands-right) MIXIN
                enables interacting between controler an objects
                
                using 'superhands'
                using a 'sphere-collider' for superhands  
                
                hover & drag-drop won't have any obvious effect without some additional event handlers or components.
                
                colliderEvent: collision                -> makes objects grabbable
                colliderEvent: raycaster-intersection:  -> ???
            -->
            <a-mixin id="interaction" physics-collider phase-shift static-body="shape: sphere; sphereRadius: 0.02;"
                sphere-collider="objects: #box, #sphere" collision-filter laser-controls line raycaster="
            showLine: true; 
            objects: .cube" collision-filter="collisionForces: false" super-hands="
            colliderEvent: collisions;
            colliderEventProperty: els;
            colliderEndEvent: collisions;
            colliderEndEventProperty: clearedEls;
            
            grabStartButtons: gripdown, mousedown;
            grabEndButtons: gripup, mouseup;
            
            startButtons: triggerdown; 
            endButtons: triggerup;">
            </a-mixin>
            <!-- - - - - - - - - - - -->
        </a-assets>

        <!--
            the camera in a rig
        -->
        <a-entity id="rig" position="0 0 0">
            <a-entity id="camera" camera="active: true" look-controls wasd-controls></a-entity>

            <!-- 
                the oculus controller (hands-left, hands-right)
                using the interaction mixin (assets)
            -->
            <a-entity mixin="interaction" hand-controls="left"></a-entity>
            <a-entity mixin="interaction" hand-controls="right"></a-entity>

        </a-entity>

        <!-- 
            a group of objects 
            as a group, they can be moved or animated together
        -->
        <a-entity position="0 0 0" rotation="0 0 0">
            <!-- - - - - - - - - - - -->
            <!-- 
                the ground object 
            -->
            <a-box id="ground" width="50" height="0.1" depth="50" position="0 -0.05 0"
                material="src: ../assets/figures/wood-planks.jpg; repeat:50 25;" static-body>
            </a-box>

            <!-- 
                2 simple objects
                the id's are registered in the sphere-sollider object list
                this enabled grabbing and scaling 
            -->
            <a-box id="box" color="orange" width="0.5" height="1" depth="0.5" position="-0.5 0.5 -1" rotation="0 0 0"
                hoverable grabbable stretchable draggable droppable dynamic-body>
            </a-box>

            <a-sphere id="sphere" color="orange" radius="0.25" position="0.5 0.5 -1" rotation="0 0 0" hoverable
                grabbable stretchable draggable droppable dynamic-body></a-sphere>
            <!-- - - - - - - - - - - -->
        </a-entity>

        <a-light type="spot" angle="15" intensity="0.25" position="-1 8 0" color="hsla(0, 50%, 100%)" target="#box">
        </a-light>
        <a-light type="spot" angle="15" intensity="0.25" position="-1 8 0" color="hsla(0, 50%, 100%)" target="#sphere">
        </a-light>
        <a-light type="spot" angle="15" intensity="0.25" position="-1 8 0" color="hsla(0, 50%, 100%)" target="#rig">
        </a-light>
    </a-scene>
</body>

</html>