ARCS logo.js Augmented Reality Component System

Source: arviewer.js

arcs_module( 
    function(ARCS, three) {
        var ARViewer;
        
        /** 
         * @class ARViewer 
         * @classdesc Simple compositing viewer for augmented reality
         */        
        ARViewer = ARCS.Component.create(
            /** @lends ARViewer.prototype */
            function () {
                var container, sourceAspectRatio, sourceHeight;
            
                var renderer, scene2d, scene3d, camera2d, camera3d, videoSource, videoTexture;
                
                var aspectRatioKept = true;
                
                var sceneId;
                
                
                // scenegraph initializations
                scene2d = new THREE.Scene();
                camera2d = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5);
                scene2d.add(camera2d);
                
                scene3d = new THREE.Scene();

                /**
                 * Initializes the widgets (HTML elements) needed as a basis 
                 * for the viewer.
                 * @param cName {string} id of the container that will enclose the scene renderer
                 * @param vName {string} id of the element at the source of the video stream
                 * @function ARViewer#setWidgets
                 */
                this.setWidgets = function(cName,vName) {
                    container = document.getElementById(cName);
                    videoSource = document.getElementById(vName);
                    var containerStyle = window.getComputedStyle(container);
                    var videoStyle = window.getComputedStyle(videoSource);
                    sourceAspectRatio = parseInt(videoStyle.width) / parseInt(videoStyle.height);
                    sourceHeight = parseInt(videoStyle.height);
                    
                    container.width = parseInt(containerStyle.width);
                    container.height = parseInt(containerStyle.height);

                    renderer = new THREE.WebGLRenderer();
                    renderer.setClearColor(0x000000, 1);
                    renderer.setSize(container.width, container.height);
                    container.appendChild(renderer.domElement);
    
                    var theta = 45; //2*Math.atan2(container.height/2,focalLength)*180/3.14159265;
                    camera3d = new THREE.PerspectiveCamera(theta, container.width / container.height, 0.1, 10000);
                    scene3d.add(camera3d);
  
                    var _light = new THREE.DirectionalLight(0xffffff);
                    _light.position.set(0,5,5);
  
                    scene3d.add(_light);
                    
                    
                    videoTexture = new THREE.Texture(videoSource);
                    var geometry = new THREE.PlaneGeometry(1.0, 1.0, 0.0);
                    var material = new THREE.MeshBasicMaterial( {map: videoTexture, depthTest: false, depthWrite: false} );
                    var mesh = new THREE.Mesh(geometry, material);
                    var textureObject = new THREE.Object3D();
                    textureObject.position.z = -1;
                    textureObject.add(mesh);
                    scene2d.add(textureObject);
                    
                    updateAspectRatio();
                };
 
                /**
                 * Set the focal length of the virtual camera for very simple 
                 * camera models.
                 * @param focal {numeric} focal length (in pixels) of the camera.
                 * @function ARViewer#setFocal
                 */
                this.setFocal = function (focal) {
                    var theta = 2*Math.atan(0.5*sourceHeight/focal)*180/Math.PI;
                    camera3d.fov = theta;
                    console.log(theta);
                    //camera3d.updateProjectionMatrix();
                    updateAspectRatio();
                };
            
                
                /**
                 * Set intrinsic camera parameters for the virtual camera
                 * @param intrinsics {array} linearized array of camera parameters
                 * @function ARViewer#setIntrinsics
                 */
                
                this.setIntrinsics = function (parameters) {
                    /*3 set here the intrinsic parameters of camera3d
                     *  camera3d should be of type THREE.FrustumCamera
                     * you should frustum accordingly to intrinsic parameters
                     */
                    
                    // camera3d = new THREE.FrustumCamera( ... ) ;
                    
                    
                };
                
                
                /**
                 * Set extrinsic camera parameters for the virtual camera
                 * @param markers {array} an array of markers 
                 * @function ARViewer#setExtrinsics
                 */
                this.setExtrinsics = function (markers) {
                    /*2 set here the extrinsic parameters of camera3d
                     *  Each marker has 3 major properties :
                     *  - id is the marker id;
                     *  - pose.rotation gives its orientation using a rotation matrix
                     *    and is a 3x3 array
                     *  - pose.position gives its position with respect to the camera
                     *    and is a vector with 3 components.
                     */
                    var i ;
                    for ( i = 0; i < arr.length; i++) {
                        if ( markers[i].id === sceneId ) {
                             // put here the code to set orientation and position of object camera3d
                             // see also documentation of Object3D (API Three.js)
                             // since a camera is an Object3D
                            
                            
                        }
                    }
                    
                    
                };
                
                
                this.setSceneId = function (id) {
                    sceneId = id;                    
                };
                
                this.setSize = function(width, height) {
                    var W = width|0;
                    var H = height|0;
                    
                    container.width = width;
                    container.height = height;
                    renderer.setSize(W,H);

                    updateAspectRatio();
                };
            
                this.keepAspectRatio = function (b) {
                    aspectRatioKept = b;
                };
                
                var updateAspectRatio = function () {
                    var cAspectRatio = container.width / container.height;
                    var actualWidth, actualHeight;
                    var xoff, yoff;
                    
                    if (aspectRatioKept == true) {
                        // cameras have the source aspect ratio
                        camera2d.aspect = sourceAspectRatio;
                        camera2d.updateProjectionMatrix();
                        camera3d.aspect = sourceAspectRatio;
                        camera3d.updateProjectionMatrix();
                        // then, we should adjust viewport accordingly.
                        if (cAspectRatio > sourceAspectRatio) {
                            actualHeight = container.height;
                            actualWidth = actualHeight * sourceAspectRatio; 
                        } else {
                            actualWidth = container.width;
                            actualHeight = actualWidth / sourceAspectRatio;
                        }
                        
                        xoff = (container.width - actualWidth) / 2 ;
                        yoff = (container.height - actualHeight) / 2;                        
                        renderer.setViewport(xoff, yoff, actualWidth, actualHeight);
                    } else {
                        // for 3D camera, we will have to recompute the actual
                        // aspect ratio.
                        
                        // but first reset viewport, just in case
                        renderer.setViewport(0, 0, container.width, container.height);
                        camera2d.aspect = cAspectRatio ;
                        camera2d.updateProjectionMatrix();
                        camera3d.aspect = sourceAspectRatio;  
                        camera3d.updateProjectionMatrix();
                        console.log(camera3d.projectionMatrix);
                    }
                    
                };
                
                /**
                 * Adds new objects to the current 3D scene
                 * @param scene {object} 3D object as defined by Three.js to add to the scene.
                 * @function ARViewer#addScene
                 */
                this.addScene = function (scene) {
                    scene3d.add(scene);
                };
            
                /**
                 * Removes an object from the current 3D scene
                 * @param scene {object} 3D object as defined by Three.js to remove from the scene.
                 * @function ARViewer#removeScene
                 */
                this.removeScene = function (scene) {
                    scene3d.remove(scene);
                };
                
                /**
                 * Triggers the rendering of the composite scene
                 * @function ARViewer#render
                 */
                this.render = function () {
                    videoTexture.needsUpdate = true;
                    renderer.autoClear = false;
                    renderer.clear();
                    renderer.render(scene2d, camera2d);
                    renderer.render(scene3d, camera3d);
                };
                
                /**
                 * Computes the ideal camera position to see the whole 3D scene.
                 * Mainly useful for debugging
                 * @function ARViewer#viewAll
                 */                
                this.viewAll = function () {
                    var box = new THREE.Box3();                    
                    box.setFromObject(scene3d);
                    var center = box.center();
                    var radius = box.getBoundingSphere().radius;
                    
                    camera3d.position.x = center.x ;
                    camera3d.position.y = center.y ;
                    var c = Math.cos(camera3d.fov/2);
                    var s = Math.sin(camera3d.fov/2);
                    
                    camera3d.position.z = center.z + 1.2 * radius*s*( 1 + s / c ) ;
                };
                
                
                this.resetCamera = function () {
                    camera3d.position.x = camera3d.position.y = camera3d.position.z = 0;
                    camera3d.up = THREE.Object3D.DefaultUp.clone();
                }
            
            },
            /** @lends ARViewer.slots */
            ['setWidgets','setFocal','viewAll','setSize','addScene','resetCamera','removeScene','render','keepAspectRatio'],
            []
        );
        return {ARViewer: ARViewer}; 
    },
    [ 'deps/three.js/index','deps/three.js/frustumcamera']
);