Tag: Webxr

  • VR panorama browser

    Zoals ik afgelopen week al schreef, wilde ik de panorama-viewer verder uitbreiden om meer foto’s toe te voegen. Interacties in de derde dimensie werken echter nét anders dan op het platte scherm. Daarnaast zijn allerlei conventies nog helemaal niet uitgewerkt, dus iedereen doet maar wat en dat is heel verfrissend.

    In de 20e eeuw werden de nieuwe grafische interfaces aangeleerd door het gebruik van bedieningselementen die waren ontworpen naar het voorbeeld van een fysieke tegenhanger, een skeuomorfisme zoals dat heet. Mappen, schuifknoppen en zandlopers; allemaal elementen uit de echte wereld om ons te laten begrijpen hoe de interface werkt in de platte digitale wereld.


    Meta Quest: Zwevende 2D windows met een 3D sausje

    Digitale 3D werelden kunnen werken op een heel andere manier, maar de interface-ontwerpers maken het zich er makkelijk vanaf en plakken gewoon een 2D interface in de lucht, want die kennen we al. Ze willen het ons nu nog niet te lastig maken, maar de échte revolutie moet nog komen, denk ik.

    Gemiste kans
    Apple visionOS: Nog niet veel beter

    Simpel

    Hoe dan ook, ik wilde iets simpels maken om mee te beginnen. Met A-Frame doe je dat met Custom Elements in HTML. Hieronder zie je het specifieke deel om de scene te definiëren.

    <a-scene>
        <a-assets>
            <img id="image-0"   src="image-0.jpg">
            <img id="city"      src="https://cdn.aframe.io/a-painter/images/sky.jpg">
            <img id="floor"     src="https://cdn.aframe.io/a-painter/images/floor.jpg">
        </a-assets>
        <a-sky src="#city"></a-sky>
        <a-curvedimage id="panorama"    src="#image-0"
                       position="0 2 0" height="2.5" radius="2"
                       theta-start="60" theta-length="240"></a-curvedimage>
        <a-cylinder id="ground" src="#floor" radius="32" height="0.1"></a-cylinder>
    </a-scene>
    

    Eerst definieer je een aantal assets, in dit geval afbeeldingen, waar je vanaf andere plekken naar kan verwijzen. Om te voorkomen dat je in het luchtledige lijkt te zweven is het verstandig een a-sky toe te voegen met een 360º afbeelding. Daarnaast heb ik een a-cylinder toegevoegd die als een soort vloer dient.

    De a-curvedimage bevat het echte panorama-plaatje en is eigenlijk een boogsegment van de wand van een cilinder. Het is een beetje zoeken naar de juiste waardes, maar de meeste van mijn panorama’s zijn ongeveer 240º. Als het niet helemaal klopt, is dat nog niet zo’n ramp, want dat zie je amper, behalve als je met veel rechte lijnen werkt en het allemaal precies zou moet passen.

    Nu voeg ik nog twee a-image toe onder de panorama om zometeen vooruit en achteruit te kunnen en voila, de scène is zo’n beetje klaar:

    Overzicht van de scene
    Overzicht van de scene

    Met A-Frame hoef je je om de rendering verder geen zorgen meer te maken. Je headset schakelt om naar VR-modus en je wordt omringd door de scène die je hebt gebouwd. De interactie daarentegen zul je wel zelf moeten opbouwen, want anders dan op het platte web kan je hier niet gewoon ergens een <a href=...> wegzetten om een link te maken.

    Interactie

    In 2D interfaces zijn we gewend dat we één aanwijzer hebben die we eventueel met meerdere apparaten kunnen bedienen ( muis, touchpad, tekenpen, …). In de 3D wereld zijn al die apparaten opeens onafhankelijke bedieningen geworden, vergelijkbaar met hoe een smartphone elke vinger apart detecteert en “multitouch gestures” herkent. A-Frame ondersteunt hoofd- en controller-tracking, dus je kijkrichting en wat je met je controllers doet kan als invoer dienen. Omdat je hoofd (waarschijnlijk) geen knoppen heeft, werkt een interactie daarmee anders dan met een hand-controller.

    Een controller declareer je door een a-entity te maken met een aantal attributen, bijvoorbeeld zo:

    <a-entity oculus-touch-controls="hand: right" 
              laser-controls 
              b-button-listener></a-entity>
    

    Met oculus-touch-controls="hand: right" zeg je dat je de Meta Quest controller voor de rechter hand wil configureren. De laser-controls zorgt ervoor dat de controller een laserstraal afschiet in de wijsrichting, en dat een aantal events worden afgevuurd als die laserstraal een object raakt, waarover later meer.

    Uit de VR-modus gaan

    Ten slotte koppel ik met b-button-listener mijn eigen code aan de controller hardware:

    AFRAME.registerComponent('b-button-listener', {
        init: function () {
            this.el.addEventListener('bbuttondown', function (e) {
                const sceneEl = document.querySelector('a-scene');
                if (sceneEl.is('vr-mode')) {
                    sceneEl.exitVR();
                }
            });
        }
    });
    

    Dit zorgt ervoor dat als je op de B knop op de controller drukt wanneer je in VR-mode bent, dat je uit VR-mode gaat.

    Een foto vooruit of achteruit gaan

    De twee kleine fotootjes onderaan op het screenshot had ik nog niet aan de scène toegevoegd, dus dat doen we nog even:

    <a-image id="prev-image"        src="#image-2"
             position="-1 0.5 -1.5" rotation="-45 30 0"
             width="1"              height="0.33"
             cursor-listener="direction: prev"></a-image>
    <a-image id="next-image"        src="#image-1"
             position="1 0.5 -1.5"  rotation="-45 -30 0"
             width="1"              height="0.33"
             cursor-listener="direction: next"></a-image>
    

    Hier zie je de cursor-listener component. Deze code is straks verantwoordelijk voor het naar het click signaal luisteren dat de laser-controls component produceert wanneer je op een van de a-images “klikt”. Je ziet dat je extra informatie kan meegeven, net als bij de oculus-touch-controls, om de component te configureren.

    AFRAME.registerComponent('cursor-listener', {
        schema: {
            direction: {type: 'string', default: 'next'}
        },
    
        init: function () {
            this.el.addEventListener('click', (e) => {
                switch (this.data.direction) {
                    case 'prev':
                        nextImage(-1);
                        break;
                    default:
                        nextImage(1);
                        break;
                }
            });
        }
    });
    

    In de code hierboven wordt aan this.el, dat is de a-image waar het op staat, een event listener toegevoegd voor het click signaal. Afhankelijk van de waarde van direction zal hij nu de volgende of de vorige afbeelding inladen.

    De logica voor het wisselen van de afbeelding is niet A-Frame of WebXR specifiek en kan je vinden in de source van de panorama pagina (net als de rest van deze blog trouwens).

    En dat is het! Het resultaat is een wereld waarin je kan schakelen tussen zes panorama’s met behulp van je controllers! Voor degenen zonder headset, een filmpje:

    Lees verder
  • Aan de slag in Virtual Reality met WebXR

    We hebben onszelf laatst een VR-headset cadeau gedaan. Om Beat Saber te spelen natuurlijk, maar ook om lekker mee te knutselen. Er zijn native ontwikkelomgevingen voor zo’n beetje elke headset die op de markt te krijgen is, maar er is ook een W3C specificatie voor VR- en AR-applicaties, gezamenlijk vaak XR genoemd. Die specificatie heet WebXR en breidt het 2D web uit met de derde dimensie.

    Nu is de W3C specificatie vrij low-level dus is het lastig daar een toepassing mee te maken, maar er zijn al frameworks ontwikkeld die het veel makkelijker maken. Een van die frameworks is A-Frame en daarmee heb ik al een simpele viewer geknutseld voor de panoramafoto’s die ik in de loop van de tijd heb gemaakt.

    Met een desktop browser kan je die pagina gewoon openen en in XR-emulatie bekijken, met een headset krijg je een “immersieve ervaring” zoals dat zo mooi heet.

    Kijk maar eens naar het panorama van de Pont du Gard in VR wat ik afgelopen vakantie heb gemaakt.

    Pont du Gard

    Ik wil de viewer nog verder uitbreiden zodat het een echte applicatie is waarin je meerdere panorama’s kan bekijken, want ze komen in VR echt veel beter tot hun recht dan op een plat beeldscherm.

    Lees verder