In drei Schritten zu Virtual Reality im Browser

3D Objekte im Browser sind für viele User kein Fremdwort mehr und bei richtigem Einsatz können damit beeindruckende Effekte erzielt werden. Falls du Grundkenntnisse in HTML und Javascript mitbringst, dann ist es eine Frage von wenigen Minuten räumliche Webseiten zu erschaffen. Dafür benötigst du zum einen A-Frame und zum anderen solltest du folgende Regeln und Tipps beachten:

Seit der Einführung von WebGL für mobile Devices, insbesondere seit iOS8, kann man deviceübergreifende Visuals und Applikationen in 3D entwickeln, die für alle über die Weboberfläche erreichbar sind. Einer der Industriestandards für die Entwicklungsumgebung war schon seit vielen Jahren das Three.js Framework, welches WegGL mit Javascript zugänglich gemacht hat. Es gibt dafür auch Alternativen wie das Babylon.js oder das Whitestorm.js, beide sind aber nicht so stark verbreitet und die Community dahinter ist nicht so groß. Doch wie ist der Stand heute und wohin entwickelt sich Virtual Reality im Web?

VR Is the ‚Wild West‘ and Taming It Will Be Tough.

Meine ersten Erfahrungen mit Three.js habe ich in Form von einfachen Prototypen sammeln können. Über die Jahre kamen immer mehr Themen wie Shader, Animation oder Particles hinzu und in letzter Zeit nun auch WebVR. Derzeit ist es noch sehr experimentell und läuft nur in Nightlybuilds etc. Im Prinzip kann man das stereoskopische Rendern aber schon lange selber einstellen und durch Zugriff auf die Deviceorientation Welten für das Cardboard erschaffen. Wenn man aber bereits umfangreichere Projekte umgesetzt hat, weiß man wie komplex die Szenen werden können und wie nervig es sein kann, jedes mal das Szenen-Setup mit Lights/Camera/Render und co. einzustellen. Insgesamt ist der Einstieg sehr technisch und für viele stellt das reine Javascript eine Hürde dar, deswegen hat Mozilla ein Framework entwickelt, um Virtual Reality den Webentwicklern zugänglicher zu machen: A-Frame. Damit kann man nun innerhalb weniger Minuten einen Raum erstellen, der sowohl auf Desktop als auch auf mobilen Devices richtig dargestellt wird. Das Framework basiert auf dem Threejs Renderer und ermöglicht es VR mit Webkomponenten zu erstellen. So sieht zum Beispiel eine einfache Szene aus (mit reinem Three.js wäre diese um eine vielfaches länger):

<html>
  <head>
    <script src="https://aframe.io/releases/0.4.0/aframe.min.js"></script>
  </head>
  <body>
    <a-scene>
      <a-box color="#6173F4" opacity="0.8" depth="2"></a-box>
      <a-sphere radius="2" src="texture.png" position="1 1 0"></a-sphere>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>
  </body>
</html>

Im Folgenden gehe ich auf die drei wichtigsten Aspekte bei der Gestaltung und Umsetzung für WebVR ein. Zwar verwende ich hierfür A-Frame, die Prinzipien kann man jedoch auf alle Entwicklungsumgebungen anwenden.

Komponenten

Ähnlich React kann man bei A-Frame ebenfalls Komponenten, die komplett unabhängig sind, erstellen. Eine wichtige Komponente war beispielsweise der Hoverlistener, da der systeminterne Cursor einfach nicht zuverlässig in der Version 0.3.0 funktioniert hat. Des Weiteren möchte man oft auch bei Unterelementen des getriggerten Objekts Animationen auslösen. Hier ist ein Beispiel für einen Eventlistener um komplexere Animationen auf alle Unterobjekte anwenden zu können. 59Kl2cAN1vB0GXZvHRBE1HZ77Bwhm2isAfIAM1GEbF-zK1oWRv1ZVPoYd7VuP5ze_0zKGpCKshgKHKx8jUEri1NlSmh0egFbdyHzE6LvoMAI4av1wcwKsmUDuTGzHRrg


AFRAME.registerComponent('hover-listener', {
  init: function () {
    var hovered = false;
    this.el.addEventListener('raycaster-intersected', function(evt) {

    if (hovered  == true) {
        return
    }
    else {
        if (hovered !== true) {
          this.emit('hoveron');
          var all = this.children;
          for (var i = 0; i < all.length; i++) {
              var tableChild = all[i];
              tableChild.emit('childHoverOn');
          }

          hovered = true;
        }
    }

    }, true);
    this.el.addEventListener('raycaster-intersected-cleared', function(evt) {

          this.emit('hoveroff');
          var all = this.children;
          for (var i = 0; i < all.length; i++) {
              var tableChild = all[i];
              tableChild.emit('childHoverOff');
          }

          hovered = false;
    }, true);
  }
});

Man kann ebenfalls komplette „a-entities“ in diese Komponenten verpacken und Attribute mitgeben, dies ermöglicht auch einen viel besseren Austausch in der Community. So kann man beispielsweise mit einer Zeile einen Particlegenerator mit eigenen Einstellungen, in diesem Fall Schneepartikel, aufrufen.O2oNF5sLAfMlV5HQRtmEsug5rBCuoQHlJqDJfL6hug-zODOduMNhgVf7fzGW0oUNLbtTk3TGkdLa5uNng_AmpVNlSmh0egFbdyHzE6LvoMAI4av1wcwKsmUDuTGzHRrg


  <a-entity
   position="0 25.25 10"
   particle-system="preset: snow; size: 1; particleCount: 5000; maxAge: 2;">
  </a-entity>

Interaktionen

Bei der Gestaltung von Interaktionen für Crossdevice Anwendungen in  VR ist man sehr stark eingeschränkt, denn man sollte vom minimalsten Devicesetup ausgehen und das wäre einfach nur ein Smartphone. Die mögliche Eingabe erfolgt somit nur durch einen virtuellen Cursor, der langes „Anvisieren“ von Objekten im Raum ermöglicht. Es ist ein Navigationspattern, das den meisten Nutzern noch nicht bekannt ist und muss sich erst etablieren, deswegen sollte man den Cursor zumindest mit Farb/Größenänderungen bei „hover“ versehen. Die Interaktion des Hoverns wird mit „fusing“ bezeichnet und resultiert nach einer gewissen Zeit in einem als Klick aufgefassten Event. Der Cursor wird in der Kamera platziert und kann mit einer Animation versehen werden:

         <a-entity camera look-controls wasd-controls>
             <a-cursor radius-outer="0.03" radius-inner="0.02" position="0 0 -0.05" material="color: cyan; shader: flat" max-distance="10">
                 <a-animation begin="cursor-hovering" easing="ease-in" attribute="color" fill="forwards" from="cyan" to="#7ED321" dur="350"></a-animation>
             </a-cursor>
         </a-entity>

Eine weitere Navigationsmöglichkeit im Raum sind die Checkpoints, man visiert ein Objekt an und wird zu diesem teleportiert. Auf diese Weise muss man nicht selbst Eingaben tätigen und braucht keine weiteren Devices: tBFXk3y4JRdAfkuKSdVQSy5QRvOuSQCGLNSxDPQWceabN_WSyPnBDzPVMjMQ68qSlnSt1zWj_GjzEcmDLBVRE1NlSmh0egFbdyHzE6LvoMAI4av1wcwKsmUDuTGzHRrg

Templates

Dadurch, dass die Elemente an sich als HTML Komponenten benutzt werden, eignen sich die gängigen Template-Engines wie die Nunjucks, um die Szenen besser zu strukturieren und Inhalte nachzuladen. Hierfür gibst es eine eigene Template-Erweiterung. Um beispielsweise einen Wald zu erschaffen, definieren wir ein Template für einen Baum und versehen das Template mit einer Komponente für zufällige Position und Größe:

        <a-assets>
          <script id="forest" type="text/x-nunjucks-template">

            {% for x in range(0, 50) %}
                <a-entity template="src: templates/components/forest.template; type: nunjucks"
                          randomize
                          ></a-entity>
            {% endfor %}

          </script>
        </a-assets>
  AFRAME.registerComponent('randomize', {
  schema: {
    min: {default: {x: 0, y: 0, z: 0}, type: 'vec3'},
    max: {default: {x: 2.5, y: 2.5, z: 2.5}, type: 'vec3'},
    maxRotation: {default: {x: 360, y: 360, z: 360}, type: 'vec3'}
  },

  update: function () {
    var rand = Math.random();

    var data = this.data;
    var max = data.max;
    var min = data.min;
    var maxRotation = data.maxRotation;
    var randScale = Math.random();

    this.el.setAttribute('position', {
      x: Math.random()* 50 - 8,
      y: randScale * 2 - 2,
      z: Math.random()* 20 + 8
    });

    this.el.setAttribute('scale', {
      x: randScale * max.x + min.x,
      y: randScale * max.y + min.y,
      z: randScale * max.z + min.z
    });

    this.el.setAttribute('rotation', {
      x: 0,
      y: Math.random() * maxRotation.y + min.y,
      z: 0
    });
  }
});

O09fA3N9BsgX2qs9jEXRjCf_dT17fvBx8HIOJs6GOjmFjA-WwxzqNaTB_h8o0P7QBUCIBXc_8XTU9-NdbAjTrVNlSmh0egFbdyHzE6LvoMAI4av1wcwKsmUDuTGzHRrg

Mit Templates können wir auch sehr einfach das Neuladen der Seite verhindern ohne für statische Projekte zu React greifen zu müssen. Dafür erstellen wir eine Switch-Komponente, die wie ein Link zwischen den Szenen verwendet wird:

AFRAME.registerComponent('switch-template', {
    init: function () {

        var id = this.el.id;

        this.el.addEventListener('click', function(evt) {

            var id = this.id;
            var targetScene = document.getElementById("templateSource");

            var target = "templates/scenes/" + id + ".html"

            targetScene.setAttribute('template', 'src', target);

        });

    }
});

Diese kann nun auf alle Elemente angewendet werden, wichtig ist nur für sich die Templatenamen und ID’s zu definieren.

  <a-plane width="0.5" height="0.15" position="0 0 0.5" id="{{ id }}" switch-template > </a-plane>

Einsatzbereiche

Aktuell würde ich den möglichen Einsatzbereich für Spiele oder experimentelle Anwendungen beschränken, aufwändige Szenen laufen nicht performant auf allen Geräten und verbrauchen einiges an Grafikleistung. Insbesondere merkt man dies bei Androidsmartphones und älteren Macbook Modellen. Nativ programmierte VR-Apps laufen einfach flüssiger und können den gesamten Content speichern, was bei größeren 3D Modellen einfach von Vorteil ist. Nichtsdestotrotz entwickelt sich der Bereich rund um das WebGL(2) extrem rasant und es werden täglich spannende Projekte veröffentlicht. Du möchtest dich in diesem spannenden Feld weiterentwickeln, neue VR-Technologien einsetzen und erforschen? Dann bist du hier genau richtig: Karriere bei DieProduktMacher

TAGS > , , , , , , , , ,

Post a comment