/** * AR object * @param augmented * @param apiAR * @returns {R3.AR} * @constructor */ R3.AR = function( augmented, apiAR ) { this.augmented = augmented; if (R3.Utils.UndefinedOrNull(apiAR)) { apiAR = {}; } R3.API.AR.call( this, apiAR.id, apiAR.name, apiAR.parent, apiAR.video, apiAR.pathCamera, apiAR.pathMarker, apiAR.scene, apiAR.camera, apiAR.videoScene, apiAR.videoCamera ); if ( R3.Utils.Defined(this.video) && R3.Utils.Defined(this.video.componentType) && !(this.video instanceof R3.Video) ) { this.video = R3.Component.ConstructFromObject(this.video); } if ( R3.Utils.Defined(this.scene) && R3.Utils.Defined(this.scene.componentType) && !(this.scene instanceof R3.D3.Scene) ) { this.scene = R3.Component.ConstructFromObject(this.scene); } if ( R3.Utils.Defined(this.camera) && R3.Utils.Defined(this.camera.componentType) && !(this.camera instanceof R3.D3.Camera.Orthographic) ) { this.camera = R3.Component.ConstructFromObject(this.camera); } if ( R3.Utils.Defined(this.videoScene) && R3.Utils.Defined(this.videoScene.componentType) && !(this.videoScene instanceof R3.D3.Scene) ) { this.videoScene = R3.Component.ConstructFromObject(this.videoScene); } if ( R3.Utils.Defined(this.videoCamera) && R3.Utils.Defined(this.videoCamera.componentType) && !(this.videoCamera instanceof R3.D3.Camera.Orthographic) ) { this.videoCamera = R3.Component.ConstructFromObject(this.videoCamera); } R3.Component.call( this, { 'video' : R3.Video, 'scene' : R3.D3.Scene, 'camera' : R3.D3.Camera, 'videoScene' : R3.D3.Scene, 'videoCamera' : R3.D3.Camera } ); }; R3.AR.prototype = Object.create(R3.Component.prototype); R3.AR.prototype.constructor = R3.AR; /** * Creates a light instance * @returns {*} */ R3.AR.prototype.createInstance = function() { ARController.prototype.setupThree = function(arComponent) { return function() { if (this.THREE_JS_ENABLED) { return; } this.THREE_JS_ENABLED = true; /* Listen to getMarker events to keep track of Three.js markers. */ this.addEventListener( 'getMarker', function (event) { if (event.data.type === artoolkit.PATTERN_MARKER) { // console.log('found marker'); /** * We want to update the camera */ var modelViewMatrix = new THREE.Matrix4().fromArray(event.data.matrix); /** * Apply context._axisTransformMatrix - change artoolkit axis to match usual webgl one */ var tmpMatrix = new THREE.Matrix4().copy(this._artoolkitProjectionAxisTransformMatrix); tmpMatrix.multiply(modelViewMatrix); modelViewMatrix.copy(tmpMatrix); /** * Change axis orientation on marker - artoolkit say Z is normal to the marker - ar.js say Y is normal to the marker */ var markerAxisTransformMatrix = new THREE.Matrix4().makeRotationX(Math.PI / 2); modelViewMatrix.multiply(markerAxisTransformMatrix); arComponent.camera.instance.matrix.getInverse(modelViewMatrix); /** * Decompose - the matrix into .position, .quaternion, .scale */ arComponent.camera.instance.matrix.decompose( arComponent.camera.instance.position, arComponent.camera.instance.quaternion, arComponent.camera.instance.scale ); // get projectionMatrixArr from artoolkit var projectionMatrixArr = this.camera_mat; var projectionMatrix = new THREE.Matrix4().fromArray(projectionMatrixArr); // apply context._axisTransformMatrix - change artoolkit axis to match usual webgl one projectionMatrix.multiply(this._artoolkitProjectionAxisTransformMatrix); arComponent.camera.instance.projectionMatrix.copy(projectionMatrix); arComponent.camera.updateFromInstance(); arComponent.camera.instance.fov = arComponent.camera.fov; arComponent.camera.instance.near = arComponent.camera.near; arComponent.camera.instance.far = arComponent.camera.far; arComponent.camera.instance.filmGauge = arComponent.camera.filmGauge; arComponent.camera.instance.filmOffset = arComponent.camera.filmOffset; arComponent.camera.instance.focus = arComponent.camera.focus; arComponent.camera.instance.zoom = arComponent.camera.zoom; arComponent.camera.instance.aspect = arComponent.camera.aspect; arComponent.camera.instance.updateProjectionMatrix(); } } ); this.threePatternMarkers = {}; this._artoolkitProjectionAxisTransformMatrix = new THREE.Matrix4(); this._artoolkitProjectionAxisTransformMatrix.multiply(new THREE.Matrix4().makeRotationY(Math.PI)); this._artoolkitProjectionAxisTransformMatrix.multiply(new THREE.Matrix4().makeRotationZ(Math.PI)); } }(this); R3.Event.Emit( R3.Event.GET_RENDER_CONFIGURATION, null, function (renderConfiguration) { if (this.scene === null) { this.scene = renderConfiguration.activeScene; } if (this.camera === null) { this.camera = renderConfiguration.activeCamera; } if (this.renderer === null) { this.renderer = renderConfiguration.activeRenderer; } }.bind(this) ); if (this.augmented.augmentedType === R3.AugmentedRuntime.JS_AR_TOOLKIT_5) { console.warn('Using js artoolkit 5'); if (this.scene === null) { console.warn('there is no default scene to create an AR component with'); return; } if (this.camera === null) { console.warn('there is no default camera to create an AR component with'); return; } ARController.getUserMediaThreeScene( { maxARVideoSize: 320, cameraParam: this.pathCamera, onSuccess: function (arScene, arController, arCamera) { R3.Event.Emit( R3.Event.GET_RENDER_CONFIGURATION, null, function(renderConfiguration) { this.videoCamera.instance = arScene.videoCamera; this.videoScene.instance = arScene.videoScene; this.videoScene.camera = this.videoCamera; //arScene.videoScene.children[0].material.map.flipY = true; /** * Also update the video texture before render */ this.subscribe( R3.Event.BEFORE_RENDER, function() { arScene.videoScene.children[0].material.map.needsUpdate = true; } ); if (renderConfiguration.activeScenes.indexOf(this.videoScene) === -1) { console.log('not adding video scene to default active scenes'); //renderConfiguration.activeScenes.unshift(this.videoScene); } }.bind(this) ); arController.loadMarker( this.pathMarker, function (markerId) { var markerRoot = arController.createThreeMarker(markerId); markerRoot.add(this.scene.instance); this.instance = { arScene: arScene, arController: arController, arCamera: arCamera }; R3.Component.prototype.createInstance.call(this); }.bind(this) ); }.bind(this) } ); return; } if (this.augmented.augmentedType === R3.AugmentedRuntime.AR_JS) { console.log('using ar.js'); var size = R3.Utils.GetWindowSize(); this.arToolkitSource = new THREEx.ArToolkitSource( { sourceType: 'webcam', sourceWidth: size.width, sourceHeight: size.height, displayWidth: size.width, displayHeight: size.height } ); this.arToolkitSource.init( function initialized() { this.arToolkitSource.domElement.setAttribute('muted', ''); this.video.instance = this.arToolkitSource.domElement; this.arToolkitContext = new THREEx.ArToolkitContext( { cameraParametersUrl: this.pathCamera, detectionMode: 'mono', maxDetectionRate: 30, canvasWidth: 80*3, canvasHeight: 60*3 } ); this.arToolkitContext.init( function initialized() { this.controls = new THREEx.ArMarkerControls( this.arToolkitContext, this.camera.instance, { type: 'pattern', patternUrl: this.pathMarker, changeMatrixMode: 'cameraTransformMatrix' } ); this.instance = { arToolkitContext: this.arToolkitContext, arToolkitSource: this.arToolkitSource }; this.scene.instance.add(this.camera.instance); this.resize(); /** * Copy the projectionmatrix of the context to our camera * UPDATE - don't do this cause it messes up the projection matrix */ // this.camera.instance.projectionMatrix.copy( // this.arToolkitContext.getProjectionMatrix() // ); R3.Component.prototype.createInstance.call(this); }.bind(this) ) }.bind(this) ); } }; /** * Updates the instance with the current state */ R3.AR.prototype.updateInstance = function(property) { if (R3.Utils.UndefinedOrNull(property)) { console.warn('unknown property update for AR: ' + property); } if (property === 'id') { return; } if (property === 'name') { return; } if (property === 'video') { console.warn('todo: update video'); return; } if (property === 'pathCamera') { console.warn('todo: update pathCamera'); return; } if (property === 'pathMarker') { console.warn('todo: update pathMarker'); return; } if (property === 'scene') { console.warn('todo: update scene'); return; } if (property === 'camera') { console.warn('todo: update camera'); // // if (this.augmented.augmentedType === R3.AugmentedRuntime.AR_JS) { // // if (this.camera) { // this.controls = new THREEx.ArMarkerControls( // this.arToolkitContext, // this.camera.instance, // { // type: 'pattern', // patternUrl: this.pathMarker, // changeMatrixMode: 'cameraTransformMatrix' // } // ); // } // } return; } if (property === 'videoScene') { console.warn('todo: update videoScene'); return; } if (property === 'videoCamera') { console.warn('todo: update videoCamera'); return; } R3.Component.prototype.updateInstance.call(this, property); }; /** * Converts a R3.AR to a R3.API.AR * @returns {R3.API.AR} */ R3.AR.prototype.toApiObject = function() { return new R3.API.AR( this.id, this.name, R3.Utils.IdOrNull(this.parent), R3.Utils.IdOrNull(this.video), this.pathCamera, this.pathMarker, R3.Utils.IdOrNull(this.scene), R3.Utils.IdOrNull(this.camera), R3.Utils.IdOrNull(this.videoScene), R3.Utils.IdOrNull(this.videoCamera) ); }; R3.AR.prototype.beforeRender = function() { if (this.augmented.augmentedType === R3.AugmentedRuntime.JS_AR_TOOLKIT_5) { this.instance.arScene.process(); this.instance.arScene.renderOn(renderer.instance); return; } if (this.augmented.augmentedType === R3.AugmentedRuntime.AR_JS) { this.arToolkitContext.update( this.arToolkitSource.domElement ); return; } }; R3.AR.prototype.resize = function() { if (this.augmented.augmentedType === R3.AugmentedRuntime.AR_JS) { console.log('updating AR size'); this.arToolkitSource.onResizeElement(); if (this.arToolkitContext.arController !== null){ this.arToolkitSource.copyElementSizeTo( this.arToolkitContext.arController.canvas ) } } };