xrviewer.js 6.5 KB
       
import ARCS from '../build/arcs.js';
import * as THREE from '../deps/three.js/index.js';
import {ARButton} from '../deps/three.js/ARButton.js';
        
var XRViewer;

/** 
    * @class XRViewer 
    * @classdesc Simple compositing viewer for augmented reality using WebXR
    * @param [config] {object} configuration object for the viewer
    * @param [config.rootElement="document.body"] {string} element on which to attach renderer
    * @param [config.sessionConfig] {object} an object to configure an immersive 
    * session as formulated in WebXR specification.
    */        
XRViewer = ARCS.Component.create(
    /** @lends XRViewer.prototype */
    function (config) {
        let renderer, scene, camera;
        let sceneId;
        let container;
        let self = this;
        let defaultStyle;
        
        let _config = config || {};
        
        container = (_config.rootElement !== undefined)?
            document.querySelector(_config.rootElement):document.body;
        container = container || document.body;
        let rootOverlay = container;

        if (_config.sessionConfig && _config.sessionConfig.domOverlay 
            && _config.sessionConfig.domOverlay && _config.sessionConfig.domOverlay.root) {
            rootOverlay = document.querySelector(_config.sessionConfig.domOverlay.root) || rootOverlay;
            _config.sessionConfig.domOverlay.root = rootOverlay; // || document.body;            
        }
        
        let defaultDisplay = window.getComputedStyle(rootOverlay).getPropertyValue("display");
        let firstFrame = true;
        
        // scenegraph initializations
        scene = new THREE.Scene();

        renderer = new THREE.WebGLRenderer();
        //renderer.setClearColor(0x000000, 1);
        renderer.setSize(container.width, container.height);
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.xr.enabled = true;
        renderer.xr.cameraAutoUpdate = false;
        container.appendChild(renderer.domElement);
        rootOverlay.appendChild(ARButton.createButton(renderer,_config.sessionConfig));

        var theta = 45;
        camera = new THREE.PerspectiveCamera(theta, container.width / container.height, 0.01, 10);

        var _light = new THREE.DirectionalLight(0xffffff);
        _light.position.set(0,5,5);

        scene.add(_light);
        
        /*renderer.domElement.addEventListener('webglcontextlost', (event) => {
            console.log(event);
        });*/
        
        
        /**
            * Adds new objects to the current 3D scene
            * @param scene {object} 3D object as defined by Three.js to add to the scene.
            * @slot
            * @function XRViewer#addScene
            */
        this.addScene = function (subScene) {
            scene.add(subScene);
        };
    
        /**
            * Removes an object from the current 3D scene
            * @param scene {object} 3D object as defined by Three.js to remove from the scene.
            * @slot
            * @function XRViewer#removeScene
            */
        this.removeScene = function (subScene) {
            scene.remove(subScene);
        };
        
        /**
         * Sets the pose 
         * @param pos {object} a position with x, y and z coordinates
         * @param rot {object} unused so far
         * @slot
         * @function XRViewer#setPose
         */
        this.setPose = function(pos, rot) {
            let session = renderer.xr.getSession();
            let p = camera.position;
            let q = new THREE.Quaternion();
            q.setFromRotationMatrix(camera.matrixWorld);
            
            session.requestReferenceSpace(renderer.xr.getReferenceSpace()).then(
                (space) => {
                    let xrSpace = space;
                    xrSpace = xrSpace.getOffsetReferenceSpace(
                        new XRRigidTransform(
                            { x: p.x, y: p.y, z: p.z, w: 1 },
                            { x: q.x, y: q.y, z: q.z, w: q.w}
                        )
                    );
                    // we will also have to modify the orientation
                    // because offset position is not enough
                    xrSpace = xrSpace.getOffsetReferenceSpace(
                        new XRRigidTransform(
                            { x: pos.x, y: pos.y, z:pos.z, w:1},
                            { x: 0, y:0, z:0, w:1}
                        )
                    );
                }
            );
            
        };
        
        /**
         * Starts the animation loop.
         * Each time an animation frame is obtained, preRender and postRender 
         * signals are triggered
         * @slot 
         * @function XRViewer#start
         * @triggers preRender
         * @triggers postRender
         */        
        this.start = function() {
            renderer.setAnimationLoop(render);
        };
        
        let render = function (time, frame) {
            if (frame) {
                renderer.xr.updateCamera(camera);
                if (firstFrame)  {
                    renderer.xr.getSession().addEventListener('end',() => {
                        firstFrame = true;
                        rootOverlay.style.display = defaultDisplay;
                        self.emit('onEnded');
                    });                    
                    firstFrame = false;
                    self.emit('onStarted');
                }
                
                //console.log(JSON.stringify(renderer.xr.getCamera().position));
                let pose = frame.getViewerPose(renderer.xr.getReferenceSpace());
                console.log(pose);
                /*for (let xrView of pose.views) {
                if (xrView.camera) {
                    console.log("I can see a camera");
                } */               
                
                /*if (pose) {
                    console.log(pose.views[0].projectionMatrix);
                }*/
                self.emit("onRender",time,renderer.xr.getCamera(),frame);

            }
            renderer.render(scene, camera);
        }
        
    },
    /** @lends XRViewer.slots */
    ['addScene','removeScene','start','setPose'],
    ['onRender','onEnded', 'onStarted']
);

/**
 * emitted when a frame is obtained after rendering of the scene.
 * @function XRViewer#onRender
 * @signal
 * @param time {number} time elapsed since the beginning of the loop in seconds
 * @param camera {THREE.Camera} the camera object
 * @param frame {XRFrame} a frame as setup by the WebXR loop
 */ 

export default {XRViewer: XRViewer};