diff --git a/TODO.md b/TODO.md index d3b1998a41afedca020ae243a0f60829e91c2dfe..7770c18906af9e676f40bab01b52a2cfc7115536 100644 --- a/TODO.md +++ b/TODO.md @@ -10,6 +10,11 @@ - ```arglCameraFrustum(&((arc->paramLT)->param), arc->nearPlane, arc->farPlane, arc->cameraLens);``` - this should be called in setNearPlane +- do test with a special webrtc emulation layer + - so i can download video and/or image - better for testing +- handle pwa stuff - useful for phone + - https://twitter.com/jerome_etienne/status/888008537984708608 + # aframe-ar.js new - there is a resize every 1/60 seconds ?? - test on mobile diff --git a/aframe/aframe-ar-new.js b/aframe/aframe-ar-new.js new file mode 100644 index 0000000000000000000000000000000000000000..9eaad380406ec2b3fe1a3a08edcc78a2a95f5e02 --- /dev/null +++ b/aframe/aframe-ar-new.js @@ -0,0 +1,373 @@ +////////////////////////////////////////////////////////////////////////////// +// Code Separator +////////////////////////////////////////////////////////////////////////////// + +// to keep backward compatibility with deprecated code +// AFRAME.registerComponent('arjs', buildSystemParameter()) +// AFRAME.registerComponent('artoolkit', buildSystemParameter()) + +// function buildSystemParameter(){ return { +// AFRAME.registerSystem('arjs', { +AFRAME.registerSystem('arjs', { + schema: { + trackingBackend : { + type: 'string', + default: 'artoolkit', + }, + areaLearningButton : { + type: 'boolean', + default: true, + }, + performanceProfile : { + type: 'string', + default: 'default', + }, + + // old parameters + debug : { + type: 'boolean', + default: false + }, + detectionMode : { + type: 'string', + default: '', + }, + matrixCodeType : { + type: 'string', + default: '', + }, + cameraParametersUrl : { + type: 'string', + default: '', + }, + maxDetectionRate : { + type: 'number', + default: -1 + }, + sourceType : { + type: 'string', + default: '', + }, + sourceUrl : { + type: 'string', + default: '', + }, + sourceWidth : { + type: 'number', + default: -1 + }, + sourceHeight : { + type: 'number', + default: -1 + }, + displayWidth : { + type: 'number', + default: -1 + }, + displayHeight : { + type: 'number', + default: -1 + }, + canvasWidth : { + type: 'number', + default: -1 + }, + canvasHeight : { + type: 'number', + default: -1 + }, + }, + + ////////////////////////////////////////////////////////////////////////////// + // Code Separator + ////////////////////////////////////////////////////////////////////////////// + + + init: function () { + var _this = this + + // setup artoolkitProfile + var artoolkitProfile = new THREEx.ArToolkitProfile() + artoolkitProfile.sourceWebcam() + artoolkitProfile.trackingBackend(this.data.trackingBackend) + artoolkitProfile.performance(this.data.performanceProfile) + + + ////////////////////////////////////////////////////////////////////////////// + // honor this.data + ////////////////////////////////////////////////////////////////////////////// + + // honor this.data and push what has been modified into artoolkitProfile + if( this.data.debug !== false ) artoolkitProfile.contextParameters.debug = this.data.debug + if( this.data.detectionMode !== '' ) artoolkitProfile.contextParameters.detectionMode = this.data.detectionMode + if( this.data.matrixCodeType !== '' ) artoolkitProfile.contextParameters.matrixCodeType = this.data.matrixCodeType + if( this.data.cameraParametersUrl !== '' ) artoolkitProfile.contextParameters.cameraParametersUrl = this.data.cameraParametersUrl + if( this.data.maxDetectionRate !== -1 ) artoolkitProfile.contextParameters.maxDetectionRate = this.data.maxDetectionRate + + if( this.data.sourceType !== '' ) artoolkitProfile.contextParameters.sourceType = this.data.sourceType + if( this.data.sourceUrl !== '' ) artoolkitProfile.contextParameters.sourceUrl = this.data.sourceUrl + if( this.data.sourceWidth !== -1 ) artoolkitProfile.contextParameters.sourceWidth = this.data.sourceWidth + if( this.data.sourceHeight !== -1 ) artoolkitProfile.contextParameters.sourceHeight = this.data.sourceHeight + if( this.data.displayWidth !== -1 ) artoolkitProfile.contextParameters.displayWidth = this.data.displayWidth + if( this.data.displayHeight !== -1 ) artoolkitProfile.contextParameters.displayHeight = this.data.displayHeight + if( this.data.canvasWidth !== -1 ) artoolkitProfile.contextParameters.canvasWidth = this.data.canvasWidth + if( this.data.canvasHeight !== -1 ) artoolkitProfile.contextParameters.canvasHeight = this.data.canvasHeight + + //////////////////////////////////////////////////////////////////////////////// + // handle arToolkitSource + //////////////////////////////////////////////////////////////////////////////// + + var arToolkitSource = new THREEx.ArToolkitSource(artoolkitProfile.sourceParameters) + this.arToolkitSource = arToolkitSource + arToolkitSource.init(function onReady(){ + // handle resize of renderer + onResize() + + // kludge to write a 'resize' event - use exponentialBackoff delay + var startedAt = Date.now() + var exponentialBackoffDelay = 1000/60 + setTimeout(function callback(){ + if( Date.now() - startedAt > 5*1000 ) return + // update delay + exponentialBackoffDelay *= 1.2; + exponentialBackoffDelay = Math.min(exponentialBackoffDelay, 1*1000) + setTimeout(callback, exponentialBackoffDelay) + // trigger a resize + window.dispatchEvent(new Event('resize')); + console.log('trigger a resize', exponentialBackoffDelay) + }, exponentialBackoffDelay) + }) + + // handle resize + window.addEventListener('resize', onResize) + function onResize(){ + // ugly kludge to get resize on aframe... not even sure it works + arToolkitSource.onResizeElement() + arToolkitSource.copyElementSizeTo(document.body) + + var buttonElement = document.querySelector('.a-enter-vr') + if( buttonElement ){ + buttonElement.style.position = 'fixed' + } + } + //////////////////////////////////////////////////////////////////////////////// + // initialize arToolkitContext + //////////////////////////////////////////////////////////////////////////////// + // create atToolkitContext + var arToolkitContext = new THREEx.ArToolkitContext(artoolkitProfile.contextParameters) + this.arToolkitContext = arToolkitContext + // initialize it + arToolkitContext.init(function onCompleted(){ + // // copy projection matrix to camera + // var projectionMatrixArr = arToolkitContext.arController.getCameraMatrix(); + // _this.sceneEl.camera.projectionMatrix.fromArray(projprojectionMatrixArrectionMatrix); + }) + + ////////////////////////////////////////////////////////////////////////////// + // area learning + ////////////////////////////////////////////////////////////////////////////// + + // export function to navigateToLearnerPage + this.navigateToLearnerPage = function(){ + var learnerURL = THREEx.ArToolkitContext.baseURL + 'examples/multi-markers/examples/learner.html' + THREEx.ArMultiMarkerUtils.navigateToLearnerPage(learnerURL, _this.data.trackingBackend) + } + + // export function to initAreaLearningButton + this.initAreaLearningButton = function(){ + // honor arjsSystem.data.areaLearningButton + if( this.data.areaLearningButton === false ) return + + // if there is already a button, do nothing + if( document.querySelector('#arjsAreaLearningButton') !== null ) return + + // create the img + var imgElement = document.createElement('img') + imgElement.id = 'arjsAreaLearningButton' + imgElement.style.position = 'fixed' + imgElement.style.bottom = '16px' + imgElement.style.left = '16px' + imgElement.style.width = '48px' + imgElement.style.height = '48px' + imgElement.style.zIndex = 1 + imgElement.src = THREEx.ArToolkitContext.baseURL + "examples/multi-markers/examples/images/record-start.png" + document.body.appendChild(imgElement) + imgElement.addEventListener('click', function(){ + _this.navigateToLearnerPage() + }) + } + + }, + + tick : function(now, delta){ + if( this.arToolkitSource.ready === false ) return + + // copy projection matrix to camera + if( this.arToolkitContext.arController !== null ){ + this.el.sceneEl.camera.projectionMatrix.copy( this.arToolkitContext.getProjectionMatrix() ); + } + + this.arToolkitContext.update( this.arToolkitSource.domElement ) + }, +}) + + +////////////////////////////////////////////////////////////////////////////// +// arjsmarker +////////////////////////////////////////////////////////////////////////////// +AFRAME.registerComponent('arjsmarker', { + dependencies: ['arjs', 'artoolkit'], + schema: { + preset: { + type: 'string', + }, + markerhelpers : { // IIF preset === 'area' + type: 'boolean', + default: false, + }, + + // controls parameters + size: { + type: 'number', + default: 1 + }, + type: { + type: 'string', + }, + patternUrl: { + type: 'string', + }, + barcodeValue: { + type: 'number' + }, + changeMatrixMode: { + type: 'string', + default : 'modelViewMatrix', + }, + minConfidence: { + type: 'number', + default: 0.6, + }, + }, + init: function () { + var _this = this + // actually init arMarkerControls + var arjsSystem = this.el.sceneEl.systems.arjs || this.el.sceneEl.systems.artoolkit + + var artoolkitContext = arjsSystem.arToolkitContext + var scene = this.el.sceneEl.object3D + + // honor this.data.preset + if( this.data.preset === 'hiro' ){ + this.data.type = 'pattern' + this.data.patternUrl = THREEx.ArToolkitContext.baseURL+'examples/marker-training/examples/pattern-files/pattern-hiro.patt' + }else if( this.data.preset === 'kanji' ){ + this.data.type = 'pattern' + this.data.patternUrl = THREEx.ArToolkitContext.baseURL+'examples/marker-training/examples/pattern-files/pattern-kanji.patt' + }else if( this.data.preset === 'area' ){ + this.data.type = 'area' + }else { + console.assert( this.data.preset === '', 'illegal preset value '+this.data.preset) + } + + // build a smoothedControls + this._markerRoot = new THREE.Group() + scene.add(this._markerRoot) + + this._arMarkerControls = null + this._multiMarkerControls = null + + // create the controls + if( this.data.type === 'area' ){ + // if no localStorage.ARjsMultiMarkerFile, then write one with default marker + if( localStorage.getItem('ARjsMultiMarkerFile') === null ){ + THREEx.ArMultiMarkerUtils.storeDefaultMultiMarkerFile(arjsSystem.data.trackingBackend) + } + + // get multiMarkerFile from localStorage + console.assert( localStorage.getItem('ARjsMultiMarkerFile') !== null ) + var multiMarkerFile = localStorage.getItem('ARjsMultiMarkerFile') + + // create ArMultiMarkerControls + this._multiMarkerControls = THREEx.ArMultiMarkerControls.fromJSON(artoolkitContext, scene, this._markerRoot, multiMarkerFile, { + changeMatrixMode : this.data.changeMatrixMode + }) +console.log('this.data.markerhelpers', this.data.markerhelpers) + // display THREEx.ArMarkerHelper if needed - useful to debug + if( this.data.markerhelpers === true ){ + this._multiMarkerControls.subMarkersControls.forEach(function(subMarkerControls){ + // add an helper to visuable each sub-marker + var markerHelper = new THREEx.ArMarkerHelper(subMarkerControls) + scene.add( markerHelper.object3d ) + }) + } + }else if( this.data.type === 'pattern' || this.data.type === 'barcode' || this.data.type === 'unknown' ){ + this._arMarkerControls = new THREEx.ArMarkerControls(artoolkitContext, this._markerRoot, this.data) + }else console.assert(false) + + // build a smoothedControls + this.arSmoothedControls = new THREEx.ArSmoothedControls(this.el.object3D) + + + + // honor arjsSystem.data.areaLearningButton + if( this.data.type === 'area' ) arjsSystem.initAreaLearningButton() + }, + remove : function(){ + // this._arMarkerControls.dispose() + }, + update: function () { + // FIXME this mean to change the recode in trackBarcodeMarkerId ? + // var markerRoot = this.el.object3D; + // markerRoot.userData.size = this.data.size; + }, + tick: function(){ + if( this.data.changeMatrixMode === 'cameraTransformMatrix' ){ + this.el.sceneEl.object3D.visible = this.el.object3D.visible; + } + if( this._multiMarkerControls !== null ){ + // update smoothedControls parameters depending on how many markers are visible in multiMarkerControls + this._multiMarkerControls.updateSmoothedControls(this.arSmoothedControls) + } + + // update smoothedControls position + this.arSmoothedControls.update(this._markerRoot) + } +}); + +////////////////////////////////////////////////////////////////////////////// +// define some primitives shortcuts +////////////////////////////////////////////////////////////////////////////// + +AFRAME.registerPrimitive('a-marker', AFRAME.utils.extendDeep({}, AFRAME.primitives.getMeshMixin(), { + defaultComponents: { + 'arjsmarker': {}, + }, + mappings: { + 'type': 'arjsmarker.type', + 'size': 'arjsmarker.size', + 'url': 'arjsmarker.patternUrl', + 'value': 'arjsmarker.barcodeValue', + 'preset': 'arjsmarker.preset', + 'minConfidence': 'arjsmarker.minConfidence', + 'markerhelpers': 'arjsmarker.markerhelpers', + } +})); + +AFRAME.registerPrimitive('a-marker-camera', AFRAME.utils.extendDeep({}, AFRAME.primitives.getMeshMixin(), { + defaultComponents: { + 'arjsmarker': { + changeMatrixMode: 'cameraTransformMatrix' + }, + 'camera': true, + }, + mappings: { + 'type': 'arjsmarker.type', + 'size': 'arjsmarker.size', + 'url': 'arjsmarker.patternUrl', + 'value': 'arjsmarker.barcodeValue', + 'preset': 'arjsmarker.preset', + 'minConfidence': 'arjsmarker.minConfidence', + 'markerhelpers': 'arjsmarker.markerhelpers', + } +})); diff --git a/aframe/aframe-ar.js b/aframe/aframe-ar.js index 6f1585c2c9fae2954da6b68d1de8119b3f678f92..b698d2e9d4012523718de7f8a1423194c1902d63 100644 --- a/aframe/aframe-ar.js +++ b/aframe/aframe-ar.js @@ -123,7 +123,7 @@ AFRAME.registerSystem('arjs', { // handle resize of renderer onResize() -// TODO this is crappy +// TODO this is crappy - code an exponential backoff - max 1 seconds // kludge to write a 'resize' event var startedAt = Date.now() var timerId = setInterval(function(){ @@ -140,7 +140,8 @@ AFRAME.registerSystem('arjs', { window.addEventListener('resize', onResize) function onResize(){ // ugly kludge to get resize on aframe... not even sure it works - arToolkitSource.onResize(document.body) + arToolkitSource.onResizeElement() + arToolkitSource.copyElementSizeTo(document.body) var buttonElement = document.querySelector('.a-enter-vr') if( buttonElement ){ @@ -263,7 +264,6 @@ AFRAME.registerComponent('arjsmarker', { this.data.patternUrl = THREEx.ArToolkitContext.baseURL+'examples/marker-training/examples/pattern-files/pattern-kanji.patt' }else if( this.data.preset === 'area' ){ this.data.type = 'area' - // fall through }else { console.assert( this.data.preset === '', 'illegal preset value '+this.data.preset) } diff --git a/aframe/build/aframe-ar.js b/aframe/build/aframe-ar.js index c76a0caaa33b88cf3b76de60999024d3eacb727e..e728ff0b5a1a42bff40d71d836bf55ef14547d9d 100644 --- a/aframe/build/aframe-ar.js +++ b/aframe/build/aframe-ar.js @@ -41,7 +41,6 @@ var THREEx = THREEx || {} * - seems an easy light layer for clickable object * - up to */ - THREEx.ARClickability = function(sourceElement){ this._sourceElement = sourceElement // Create cameraPicking @@ -80,6 +79,39 @@ THREEx.ARClickability.prototype.computeIntersects = function(domEvent, objects){ THREEx.ARClickability.prototype.update = function(){ } + +////////////////////////////////////////////////////////////////////////////// +// Code Separator +////////////////////////////////////////////////////////////////////////////// + +THREEx.ARClickability.tangoPickingPointCloud = function(artoolkitContext, mouseX, mouseY){ + var vrDisplay = artoolkitContext._tangoContext.vrDisplay + if (vrDisplay === null ) return + var pointAndPlane = vrDisplay.getPickingPointAndPlaneInPointCloud(mouseX, mouseY) + if( pointAndPlane == null ) { + console.warn('Could not retrieve the correct point and plane.') + return null + } + + // FIXME not sure what this is + var boundingSphereRadius = 0.01 + + // the bigger the number the likeliest it crash chromium-webar + + // Orient and position the model in the picking point according + // to the picking plane. The offset is half of the model size. + var object3d = new THREE.Object3D + THREE.WebAR.positionAndRotateObject3DWithPickingPointAndPlaneInPointCloud( + pointAndPlane, object3d, boundingSphereRadius + ) + object3d.rotateZ(-Math.PI/2) + + // return the result + var result = {} + result.position = object3d.position + result.quaternion = object3d.quaternion + return result +} var THREEx = THREEx || {} /** * - videoTexture @@ -478,7 +510,6 @@ THREEx.ArMarkerControls.prototype._initArtoolkit = function(){ }else{ console.log(false, 'invalid marker type', _this.parameters.type) } - // listen to the event arController.addEventListener('getMarker', function(event){ @@ -612,136 +643,6 @@ THREEx.ArSmoothedControls.prototype.update = function(targetObject3d){ var present = performance.now()/1000 - ////////////////////////////////////////////////////////////////////////////// - // handle object3d.visible with minVisibleDelay/minUnvisibleDelay - ////////////////////////////////////////////////////////////////////////////// - if( targetObject3d.visible === false ) this._visibleStartedAt = null - if( targetObject3d.visible === true ) this._unvisibleStartedAt = null - - if( wasVisible === false && targetObject3d.visible === true ){ - if( this._visibleStartedAt === null ) this._visibleStartedAt = present - var visibleFor = present - this._visibleStartedAt - if( visibleFor >= this.parameters.minVisibleDelay ){ - object3d.visible = true - this._visibleStartedAt = null - } - console.log('visibleFor', visibleFor) - } - - if( wasVisible === true && targetObject3d.visible === false ){ - if( this._unvisibleStartedAt === null ) this._unvisibleStartedAt = present - var unvisibleFor = present - this._unvisibleStartedAt - if( unvisibleFor >= this.parameters.minUnvisibleDelay ){ - object3d.visible = false - } - // console.log('unvisibleFor', unvisibleFor) - } - - // disabled minVisibleDelay+minUnvisibleDelay - // if( true ){ - // object3d.visible = targetObject3d.visible - // } - - ////////////////////////////////////////////////////////////////////////////// - // apply lerp on positon/quaternion/scale - ////////////////////////////////////////////////////////////////////////////// - - // apply lerp steps - require fix time steps to behave the same no matter the fps - if( this._lastLerpStepAt === null ){ - applyOneSlepStep() - this._lastLerpStepAt = present - }else{ - var nStepsToDo = Math.floor( (present - this._lastLerpStepAt)/this.parameters.lerpStepDelay ) - for(var i = 0; i < nStepsToDo; i++){ - applyOneSlepStep() - this._lastLerpStepAt += this.parameters.lerpStepDelay - } - } - - // update the matrix - this.object3d.updateMatrix() - - // disable the lerp by directly copying targetObject3d position/quaternion/scale - if( false ){ - this.object3d.position.copy( targetObject3d.position ) - this.object3d.quaternion.copy( targetObject3d.quaternion ) - this.object3d.scale.copy( targetObject3d.scale ) - this.object3d.updateMatrix() - } - - ////////////////////////////////////////////////////////////////////////////// - // honor becameVisible/becameUnVisible event - ////////////////////////////////////////////////////////////////////////////// - // honor becameVisible event - if( wasVisible === false && object3d.visible === true ){ - this.dispatchEvent({ type: 'becameVisible' }) - } - // honor becameUnVisible event - if( wasVisible === true && object3d.visible === false ){ - this.dispatchEvent({ type: 'becameUnVisible' }) - } - return - - - function applyOneSlepStep(){ - object3d.position.lerp(targetObject3d.position, parameters.lerpPosition) - object3d.quaternion.slerp(targetObject3d.quaternion, parameters.lerpQuaternion) - object3d.scale.lerp(targetObject3d.scale, parameters.lerpScale) - } -} -var THREEx = THREEx || {} - -/** - * - lerp position/quaternino/scale - * - minDelayDetected - * - minDelayUndetected - * @param {[type]} object3d [description] - * @param {[type]} parameters [description] - */ -THREEx.ArSmoothedControls = function(object3d, parameters){ - var _this = this - - THREEx.ArBaseControls.call(this, object3d) - - // copy parameters - this.object3d.visible = false - - this._lastLerpStepAt = null - this._visibleStartedAt = null - this._unvisibleStartedAt = null - - // handle default parameters - parameters = parameters || {} - this.parameters = { - // lerp coeficient for the position - between [0,1] - default to 1 - lerpPosition: parameters.lerpPosition !== undefined ? parameters.lerpPosition : 0.8, - // lerp coeficient for the quaternion - between [0,1] - default to 1 - lerpQuaternion: parameters.lerpQuaternion !== undefined ? parameters.lerpQuaternion : 0.2, - // lerp coeficient for the scale - between [0,1] - default to 1 - lerpScale: parameters.lerpScale !== undefined ? parameters.lerpScale : 0.7, - // delay for lerp fixed steps - in seconds - default to 1/120 - lerpStepDelay: parameters.fixStepDelay !== undefined ? parameters.fixStepDelay : 1/60, - // minimum delay the sub-control must be visible before this controls become visible - default to 0 seconds - minVisibleDelay: parameters.minVisibleDelay !== undefined ? parameters.minVisibleDelay : 0.0, - // minimum delay the sub-control must be unvisible before this controls become unvisible - default to 0 seconds - minUnvisibleDelay: parameters.minUnvisibleDelay !== undefined ? parameters.minUnvisibleDelay : 0.2, - } -} - -THREEx.ArSmoothedControls.prototype = Object.create( THREEx.ArBaseControls.prototype ); -THREEx.ArSmoothedControls.prototype.constructor = THREEx.ArSmoothedControls; - -////////////////////////////////////////////////////////////////////////////// -// update function -////////////////////////////////////////////////////////////////////////////// - -THREEx.ArSmoothedControls.prototype.update = function(targetObject3d){ - var object3d = this.object3d - var parameters = this.parameters - var wasVisible = object3d.visible - var present = performance.now()/1000 - - ////////////////////////////////////////////////////////////////////////////// // handle object3d.visible with minVisibleDelay/minUnvisibleDelay ////////////////////////////////////////////////////////////////////////////// @@ -830,7 +731,7 @@ THREEx.ArToolkitContext = function(parameters){ // debug - true if one should display artoolkit debug canvas, false otherwise debug: parameters.debug !== undefined ? parameters.debug : false, // the mode of detection - ['color', 'color_and_matrix', 'mono', 'mono_and_matrix'] - detectionMode: parameters.detectionMode !== undefined ? parameters.detectionMode : 'color_and_matrix', + detectionMode: parameters.detectionMode !== undefined ? parameters.detectionMode : 'mono', // type of matrix code - valid iif detectionMode end with 'matrix' - [3x3, 3x3_HAMMING63, 3x3_PARITY65, 4x4, 4x4_BCH_13_9_3, 4x4_BCH_13_5_5] matrixCodeType: parameters.matrixCodeType !== undefined ? parameters.matrixCodeType : '3x3', @@ -865,17 +766,48 @@ THREEx.ArToolkitContext.baseURL = 'https://jeromeetienne.github.io/AR.js/three.j THREEx.ArToolkitContext.REVISION = '1.0.1-dev' +/** + * Create a default camera for this trackingBackend + * @param {string} trackingBackend - the tracking to user + * @return {THREE.Camera} the created camera + */ +THREEx.ArToolkitContext.createDefaultCamera = function( trackingBackend ){ + console.assert(false, 'use ARjs.Utils.createDefaultCamera instead') + // Create a camera + if( trackingBackend === 'artoolkit' ){ + var camera = new THREE.Camera(); + }else if( trackingBackend === 'aruco' ){ + var camera = new THREE.PerspectiveCamera(42, renderer.domElement.width / renderer.domElement.height, 0.01, 100); + }else if( trackingBackend === 'tango' ){ + var camera = new THREE.PerspectiveCamera(42, renderer.domElement.width / renderer.domElement.height, 0.01, 100); + }else console.assert(false) + return camera +} + + ////////////////////////////////////////////////////////////////////////////// // init functions ////////////////////////////////////////////////////////////////////////////// THREEx.ArToolkitContext.prototype.init = function(onCompleted){ + var _this = this if( this.parameters.trackingBackend === 'artoolkit' ){ - this._initArtoolkit(onCompleted) + this._initArtoolkit(done) }else if( this.parameters.trackingBackend === 'aruco' ){ - this._initAruco(onCompleted) + this._initAruco(done) }else if( this.parameters.trackingBackend === 'tango' ){ - this._initTango(onCompleted) + this._initTango(done) }else console.assert(false) + return + + function done(){ + // dispatch event + _this.dispatchEvent({ + type: 'initialized' + }); + + onCompleted && onCompleted() + } + } //////////////////////////////////////////////////////////////////////////////// // update function @@ -918,8 +850,6 @@ THREEx.ArToolkitContext.prototype.update = function(srcElement){ return true; } - - //////////////////////////////////////////////////////////////////////////////// // Add/Remove markerControls //////////////////////////////////////////////////////////////////////////////// @@ -1002,7 +932,7 @@ THREEx.ArToolkitContext.prototype._initArtoolkit = function(onCompleted){ // arController.setThresholdMode(artoolkit.AR_LABELING_THRESH_MODE_AUTO_OTSU) // notify - onCompleted && onCompleted() + onCompleted() }) return this } @@ -1056,7 +986,7 @@ THREEx.ArToolkitContext.prototype._initAruco = function(onCompleted){ setTimeout(function(){ - onCompleted && onCompleted() + onCompleted() }, 0) } @@ -1093,6 +1023,7 @@ THREEx.ArToolkitContext.prototype._initTango = function(onCompleted){ var _this = this // check webvr is available if (navigator.getVRDisplays) { + // do nothing } else if (navigator.getVRDevices) { alert("Your browser supports WebVR but not the latest version. See webvr.info for more info."); } else { @@ -1102,6 +1033,7 @@ THREEx.ArToolkitContext.prototype._initTango = function(onCompleted){ this._tangoContext = { vrDisplay: null, + vrPointCloud: null, frameData: new VRFrameData(), } @@ -1109,20 +1041,23 @@ THREEx.ArToolkitContext.prototype._initTango = function(onCompleted){ // get vrDisplay navigator.getVRDisplays().then(function (vrDisplays) { if( vrDisplays.length === 0 ) alert('no vrDisplays available') - var vrDisplay = vrDisplays[0] - _this._tangoContext.vrDisplay = vrDisplay + var vrDisplay = _this._tangoContext.vrDisplay = vrDisplays[0] + console.log('vrDisplays.displayName :', vrDisplay.displayName) + // init vrPointCloud + if( vrDisplay.displayName === "Tango VR Device" ){ + _this._tangoContext.vrPointCloud = new THREE.WebAR.VRPointCloud(vrDisplay, true) + } - var canvasElement = document.createElement('canvas') - document.body.appendChild(canvasElement) - var layers = [{ source: canvasElement }] -// vrDisplay.requestPresent(layers).then(function() { -// console.log('vrdisplay request accepted') -// }); -// window.vrDisplay = vrDisplay + // NOTE it doesnt seem necessary and it fails on tango + // var canvasElement = document.createElement('canvas') + // document.body.appendChild(canvasElement) + // _this._tangoContext.requestPresent([{ source: canvasElement }]).then(function() { + // console.log('vrdisplay request accepted') + // }); - onCompleted && onCompleted() + onCompleted() }); } @@ -1132,9 +1067,19 @@ THREEx.ArToolkitContext.prototype._updateTango = function(srcElement){ var _this = this var arMarkersControls = this._arMarkersControls var tangoContext= this._tangoContext + var vrDisplay = this._tangoContext.vrDisplay // check vrDisplay is already initialized - if( tangoContext.vrDisplay === null ) return + if( vrDisplay === null ) return + + + // Update the point cloud. Only if the point cloud will be shown the geometry is also updated. + if( vrDisplay.displayName === "Tango VR Device" ){ + var showPointCloud = true + var pointsToSkip = 0 + _this._tangoContext.vrPointCloud.update(showPointCloud, pointsToSkip, true) + } + if( this._arMarkersControls.length === 0 ) return @@ -1145,20 +1090,29 @@ THREEx.ArToolkitContext.prototype._updateTango = function(srcElement){ var frameData = this._tangoContext.frameData // read frameData - tangoContext.vrDisplay.getFrameData(frameData); + vrDisplay.getFrameData(frameData); + + if( frameData.pose.position === null ) return + if( frameData.pose.orientation === null ) return // create cameraTransformMatrix var position = new THREE.Vector3().fromArray(frameData.pose.position) var quaternion = new THREE.Quaternion().fromArray(frameData.pose.orientation) - var scale = new THREE.Vector3(1,1,1) + var scale = new THREE.Vector3(1,1,1) var cameraTransformMatrix = new THREE.Matrix4().compose(position, quaternion, scale) // compute modelViewMatrix from cameraTransformMatrix var modelViewMatrix = new THREE.Matrix4() modelViewMatrix.getInverse( cameraTransformMatrix ) - - console.log('position', position) foundControls.updateWithModelViewMatrix(modelViewMatrix) + + // console.log('position', position) + // if( position.x !== 0 || position.y !== 0 || position.z !== 0 ){ + // console.log('vrDisplay tracking') + // }else{ + // console.log('vrDisplay NOT tracking') + // } + } var THREEx = THREEx || {} @@ -1254,22 +1208,27 @@ THREEx.ArToolkitProfile.prototype.performance = function(label) { ////////////////////////////////////////////////////////////////////////////// // Marker ////////////////////////////////////////////////////////////////////////////// -THREEx.ArToolkitProfile.prototype.kanjiMarker = function () { - this.contextParameters.detectionMode = 'mono' - this.defaultMarkerParameters.type = 'pattern' - this.defaultMarkerParameters.patternUrl = THREEx.ArToolkitContext.baseURL + '../data/data/patt.kanji' - return this -} -THREEx.ArToolkitProfile.prototype.hiroMarker = function () { - this.contextParameters.detectionMode = 'mono' +THREEx.ArToolkitProfile.prototype.defaultMarker = function (trackingBackend) { + trackingBackend = trackingBackend || this.contextParameters.trackingBackend + + if( trackingBackend === 'artoolkit' ){ + this.contextParameters.detectionMode = 'mono' + this.defaultMarkerParameters.type = 'pattern' + this.defaultMarkerParameters.patternUrl = THREEx.ArToolkitContext.baseURL + '../data/data/patt.hiro' + }else if( trackingBackend === 'aruco' ){ + this.contextParameters.detectionMode = 'mono' + this.defaultMarkerParameters.type = 'barcode' + this.defaultMarkerParameters.barcodeValue = 1001 + }else if( trackingBackend === 'tango' ){ + // FIXME temporary placeholder - to reevaluate later + this.defaultMarkerParameters.type = 'barcode' + this.defaultMarkerParameters.barcodeValue = 1001 + }else console.assert(false) - this.defaultMarkerParameters.type = 'pattern' - this.defaultMarkerParameters.patternUrl = THREEx.ArToolkitContext.baseURL + '../data/data/patt.hiro' return this } - ////////////////////////////////////////////////////////////////////////////// // Source ////////////////////////////////////////////////////////////////////////////// @@ -1297,6 +1256,7 @@ THREEx.ArToolkitProfile.prototype.sourceImage = function (url) { ////////////////////////////////////////////////////////////////////////////// THREEx.ArToolkitProfile.prototype.trackingBackend = function (trackingBackend) { this.contextParameters.trackingBackend = trackingBackend + return this } var THREEx = THREEx || {} @@ -1534,7 +1494,7 @@ THREEx.ArToolkitSource.prototype.toggleMobileTorch = function(){ // handle resize //////////////////////////////////////////////////////////////////////////////// -THREEx.ArToolkitSource.prototype.onResize = function(mirrorDomElements){ +THREEx.ArToolkitSource.prototype.onResizeElement = function(mirrorDomElements){ var _this = this var screenWidth = window.innerWidth var screenHeight = window.innerHeight @@ -1576,6 +1536,11 @@ THREEx.ArToolkitSource.prototype.onResize = function(mirrorDomElements){ this.domElement.style.marginLeft = '0px' } + + if( arguments.length !== 0 ){ + debugger + console.warn('use bad signature for arToolkitSource.copyElementSizeTo') + } // honor default parameters // if( mirrorDomElements !== undefined ) console.warn('still use the old resize. fix it') if( mirrorDomElements === undefined ) mirrorDomElements = [] @@ -1583,16 +1548,68 @@ THREEx.ArToolkitSource.prototype.onResize = function(mirrorDomElements){ // Mirror _this.domElement.style to mirrorDomElements mirrorDomElements.forEach(function(domElement){ - _this.copySizeTo(domElement) + _this.copyElementSizeTo(domElement) }) } -THREEx.ArToolkitSource.prototype.copySizeTo = function(otherElement){ +THREEx.ArToolkitSource.prototype.copyElementSizeTo = function(otherElement){ otherElement.style.width = this.domElement.style.width otherElement.style.height = this.domElement.style.height otherElement.style.marginLeft = this.domElement.style.marginLeft otherElement.style.marginTop = this.domElement.style.marginTop } + +////////////////////////////////////////////////////////////////////////////// +// Code Separator +////////////////////////////////////////////////////////////////////////////// + +THREEx.ArToolkitSource.prototype.copySizeTo = function(){ + console.warn('obsolete function arToolkitSource.copySizeTo. Use arToolkitSource.copyElementSizeTo' ) + this.copyElementSizeTo.apply(this, arguments) +} + +THREEx.ArToolkitSource.prototype.onResize = function(){ + console.warn('obsolete function arToolkitSource.onResize. Use arToolkitSource.onResizeElement' ) + this.onResizeElement.apply(this, arguments) +} + +////////////////////////////////////////////////////////////////////////////// +// Code Separator +////////////////////////////////////////////////////////////////////////////// + +THREEx.ArToolkitSource.prototype.onResize2 = function(arToolkitContext, renderer, camera){ + var trackingBackend = arToolkitContext.parameters.trackingBackend + + // RESIZE DOMELEMENT + if( trackingBackend === 'artoolkit' ){ + this.onResizeElement() + this.copyElementSizeTo(renderer.domElement) + + if( arToolkitContext.arController !== null ){ + this.copyElementSizeTo(arToolkitContext.arController.canvas) + } + }else if( trackingBackend === 'aruco' ){ + this.onResizeElement() + this.copyElementSizeTo(renderer.domElement) + + this.copyElementSizeTo(arToolkitContext.arucoContext.canvas) + }else if( trackingBackend === 'tango' ){ + renderer.setSize( window.innerWidth, window.innerHeight ) + }else console.assert(false, 'unhandled trackingBackend '+trackingBackend) + + + // RESIZE CAMERA + if( trackingBackend === 'artoolkit' ){ + camera.projectionMatrix.copy( arToolkitContext.getProjectionMatrix() ); + }else if( trackingBackend === 'aruco' ){ + camera.aspect = renderer.domElement.width / renderer.domElement.height; + camera.updateProjectionMatrix(); + }else if( trackingBackend === 'tango' ){ + var vrDisplay = arToolkitContext._tangoContext.vrDisplay + // make camera fit vrDisplay + if( vrDisplay && vrDisplay.displayName === "Tango VR Device" ) THREE.WebAR.resizeVRSeeThroughCamera(vrDisplay, camera) + }else console.assert(false, 'unhandled trackingBackend '+trackingBackend) +} var THREEx = THREEx || {} THREEx.ArVideoInWebgl = function(videoTexture){ @@ -2355,6 +2372,13 @@ THREEx.ArMultiMarkerUtils = {} ////////////////////////////////////////////////////////////////////////////// // navigateToLearnerPage ////////////////////////////////////////////////////////////////////////////// + +/** + * Navigate to the multi-marker learner page + * + * @param {String} learnerBaseURL - the base url for the learner + * @param {String} trackingBackend - the tracking backend to use + */ THREEx.ArMultiMarkerUtils.navigateToLearnerPage = function(learnerBaseURL, trackingBackend){ var learnerParameters = { backURL : location.href, @@ -2367,6 +2391,12 @@ THREEx.ArMultiMarkerUtils.navigateToLearnerPage = function(learnerBaseURL, track ////////////////////////////////////////////////////////////////////////////// // DefaultMultiMarkerFile ////////////////////////////////////////////////////////////////////////////// + +/** + * Create and store a default multi-marker file + * + * @param {String} trackingBackend - the tracking backend to use + */ THREEx.ArMultiMarkerUtils.storeDefaultMultiMarkerFile = function(trackingBackend){ var file = THREEx.ArMultiMarkerUtils.createDefaultMultiMarkerFile(trackingBackend) // json.strinfy the value and store it in localStorage @@ -2374,7 +2404,15 @@ THREEx.ArMultiMarkerUtils.storeDefaultMultiMarkerFile = function(trackingBackend } + +/** + * Create a default multi-marker file + * @param {String} trackingBackend - the tracking backend to use + * @return {Object} - json object of the multi-marker file + */ THREEx.ArMultiMarkerUtils.createDefaultMultiMarkerFile = function(trackingBackend){ + console.assert(trackingBackend) + if( trackingBackend === undefined ) debugger // create the base file var file = { meta : { @@ -2383,7 +2421,7 @@ THREEx.ArMultiMarkerUtils.createDefaultMultiMarkerFile = function(trackingBacken }, trackingBackend : trackingBackend, subMarkersControls : [ - // empty for now... + // empty for now... being filled ] } // add a subMarkersControls @@ -2407,6 +2445,12 @@ THREEx.ArMultiMarkerUtils.createDefaultMultiMarkerFile = function(trackingBacken // createDefaultMarkersControlsParameters ////////////////////////////////////////////////////////////////////////////// +/** + * Create a default controls parameters for the multi-marker learner + * + * @param {String} trackingBackend - the tracking backend to use + * @return {Object} - json object containing the controls parameters + */ THREEx.ArMultiMarkerUtils.createDefaultMarkersControlsParameters = function(trackingBackend){ var link = document.createElement('a') link.href = THREEx.ArToolkitContext.baseURL @@ -2594,7 +2638,7 @@ AFRAME.registerSystem('arjs', { // handle resize of renderer onResize() -// TODO this is crappy +// TODO this is crappy - code an exponential backoff - max 1 seconds // kludge to write a 'resize' event var startedAt = Date.now() var timerId = setInterval(function(){ @@ -2611,7 +2655,8 @@ AFRAME.registerSystem('arjs', { window.addEventListener('resize', onResize) function onResize(){ // ugly kludge to get resize on aframe... not even sure it works - arToolkitSource.onResize(document.body) + arToolkitSource.onResizeElement() + arToolkitSource.copyElementSizeTo(document.body) var buttonElement = document.querySelector('.a-enter-vr') if( buttonElement ){ @@ -2734,7 +2779,6 @@ AFRAME.registerComponent('arjsmarker', { this.data.patternUrl = THREEx.ArToolkitContext.baseURL+'examples/marker-training/examples/pattern-files/pattern-kanji.patt' }else if( this.data.preset === 'area' ){ this.data.type = 'area' - // fall through }else { console.assert( this.data.preset === '', 'illegal preset value '+this.data.preset) } diff --git a/aframe/examples/basic.html b/aframe/examples/basic.html index 0560f371fc2a453f0771ef20948907c1a4745651..af3a03faae734ab56a5254508e8fcc7b8802225c 100644 --- a/aframe/examples/basic.html +++ b/aframe/examples/basic.html @@ -16,7 +16,7 @@ - + diff --git a/aframe/examples/minimal.html b/aframe/examples/minimal.html index 09fe0901ab1f191f76fab5c20b2cf194824cfff3..2de9289500d55da4b3e750b27366f1a7bac884d5 100644 --- a/aframe/examples/minimal.html +++ b/aframe/examples/minimal.html @@ -2,7 +2,7 @@ - + diff --git a/aframe/examples/mobile-performance.html b/aframe/examples/mobile-performance.html index 4ec128bf73c552ae42a7f6a873296c835e5951b0..c929584a6f4a4c38b2aa2ee44a2e6cd4d257c43b 100644 --- a/aframe/examples/mobile-performance.html +++ b/aframe/examples/mobile-performance.html @@ -14,7 +14,7 @@ - + diff --git a/aframe/examples/multiple-independent-markers.html b/aframe/examples/multiple-independent-markers.html index 6607741ca8dd7a5cbaec1d6ea603d02d69e01feb..3b498ff98fc08f5e8b02a91b54dc4c6ede0f5347 100644 --- a/aframe/examples/multiple-independent-markers.html +++ b/aframe/examples/multiple-independent-markers.html @@ -17,7 +17,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -35,7 +35,7 @@ - + diff --git a/aframe/examples/test-runner.html b/aframe/examples/test-runner.html index 5bffd2d5170a24582d184d36845fe66f03235b67..dc2d0ac35f7129a4b6c9fe6658648a85cbcff3a3 100644 --- a/aframe/examples/test-runner.html +++ b/aframe/examples/test-runner.html @@ -14,7 +14,7 @@ - + diff --git a/aframe/examples/tracking-tango.html b/aframe/examples/tracking-tango.html new file mode 100644 index 0000000000000000000000000000000000000000..0b3268c6f7a96b6cc6dbc48c7ecd55b0b6931d63 --- /dev/null +++ b/aframe/examples/tracking-tango.html @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + +
+ AR.js - tango example for a-frame by @jerome_etienne +
+ + + + + + + + + + + + + + + diff --git a/three.js/build/ar.js b/three.js/build/ar.js index bc4a0448cb2c11f4daa926a087089e13aaa80fcb..691c6722c2601d4d70fcd90167f33554a636e9b4 100644 --- a/three.js/build/ar.js +++ b/three.js/build/ar.js @@ -1662,7 +1662,6 @@ var THREEx = THREEx || {} * - seems an easy light layer for clickable object * - up to */ - THREEx.ARClickability = function(sourceElement){ this._sourceElement = sourceElement // Create cameraPicking @@ -1701,6 +1700,39 @@ THREEx.ARClickability.prototype.computeIntersects = function(domEvent, objects){ THREEx.ARClickability.prototype.update = function(){ } + +////////////////////////////////////////////////////////////////////////////// +// Code Separator +////////////////////////////////////////////////////////////////////////////// + +THREEx.ARClickability.tangoPickingPointCloud = function(artoolkitContext, mouseX, mouseY){ + var vrDisplay = artoolkitContext._tangoContext.vrDisplay + if (vrDisplay === null ) return + var pointAndPlane = vrDisplay.getPickingPointAndPlaneInPointCloud(mouseX, mouseY) + if( pointAndPlane == null ) { + console.warn('Could not retrieve the correct point and plane.') + return null + } + + // FIXME not sure what this is + var boundingSphereRadius = 0.01 + + // the bigger the number the likeliest it crash chromium-webar + + // Orient and position the model in the picking point according + // to the picking plane. The offset is half of the model size. + var object3d = new THREE.Object3D + THREE.WebAR.positionAndRotateObject3DWithPickingPointAndPlaneInPointCloud( + pointAndPlane, object3d, boundingSphereRadius + ) + object3d.rotateZ(-Math.PI/2) + + // return the result + var result = {} + result.position = object3d.position + result.quaternion = object3d.quaternion + return result +} var THREEx = THREEx || {} /** * - videoTexture @@ -2099,7 +2131,6 @@ THREEx.ArMarkerControls.prototype._initArtoolkit = function(){ }else{ console.log(false, 'invalid marker type', _this.parameters.type) } - // listen to the event arController.addEventListener('getMarker', function(event){ @@ -2233,136 +2264,6 @@ THREEx.ArSmoothedControls.prototype.update = function(targetObject3d){ var present = performance.now()/1000 - ////////////////////////////////////////////////////////////////////////////// - // handle object3d.visible with minVisibleDelay/minUnvisibleDelay - ////////////////////////////////////////////////////////////////////////////// - if( targetObject3d.visible === false ) this._visibleStartedAt = null - if( targetObject3d.visible === true ) this._unvisibleStartedAt = null - - if( wasVisible === false && targetObject3d.visible === true ){ - if( this._visibleStartedAt === null ) this._visibleStartedAt = present - var visibleFor = present - this._visibleStartedAt - if( visibleFor >= this.parameters.minVisibleDelay ){ - object3d.visible = true - this._visibleStartedAt = null - } - console.log('visibleFor', visibleFor) - } - - if( wasVisible === true && targetObject3d.visible === false ){ - if( this._unvisibleStartedAt === null ) this._unvisibleStartedAt = present - var unvisibleFor = present - this._unvisibleStartedAt - if( unvisibleFor >= this.parameters.minUnvisibleDelay ){ - object3d.visible = false - } - // console.log('unvisibleFor', unvisibleFor) - } - - // disabled minVisibleDelay+minUnvisibleDelay - // if( true ){ - // object3d.visible = targetObject3d.visible - // } - - ////////////////////////////////////////////////////////////////////////////// - // apply lerp on positon/quaternion/scale - ////////////////////////////////////////////////////////////////////////////// - - // apply lerp steps - require fix time steps to behave the same no matter the fps - if( this._lastLerpStepAt === null ){ - applyOneSlepStep() - this._lastLerpStepAt = present - }else{ - var nStepsToDo = Math.floor( (present - this._lastLerpStepAt)/this.parameters.lerpStepDelay ) - for(var i = 0; i < nStepsToDo; i++){ - applyOneSlepStep() - this._lastLerpStepAt += this.parameters.lerpStepDelay - } - } - - // update the matrix - this.object3d.updateMatrix() - - // disable the lerp by directly copying targetObject3d position/quaternion/scale - if( false ){ - this.object3d.position.copy( targetObject3d.position ) - this.object3d.quaternion.copy( targetObject3d.quaternion ) - this.object3d.scale.copy( targetObject3d.scale ) - this.object3d.updateMatrix() - } - - ////////////////////////////////////////////////////////////////////////////// - // honor becameVisible/becameUnVisible event - ////////////////////////////////////////////////////////////////////////////// - // honor becameVisible event - if( wasVisible === false && object3d.visible === true ){ - this.dispatchEvent({ type: 'becameVisible' }) - } - // honor becameUnVisible event - if( wasVisible === true && object3d.visible === false ){ - this.dispatchEvent({ type: 'becameUnVisible' }) - } - return - - - function applyOneSlepStep(){ - object3d.position.lerp(targetObject3d.position, parameters.lerpPosition) - object3d.quaternion.slerp(targetObject3d.quaternion, parameters.lerpQuaternion) - object3d.scale.lerp(targetObject3d.scale, parameters.lerpScale) - } -} -var THREEx = THREEx || {} - -/** - * - lerp position/quaternino/scale - * - minDelayDetected - * - minDelayUndetected - * @param {[type]} object3d [description] - * @param {[type]} parameters [description] - */ -THREEx.ArSmoothedControls = function(object3d, parameters){ - var _this = this - - THREEx.ArBaseControls.call(this, object3d) - - // copy parameters - this.object3d.visible = false - - this._lastLerpStepAt = null - this._visibleStartedAt = null - this._unvisibleStartedAt = null - - // handle default parameters - parameters = parameters || {} - this.parameters = { - // lerp coeficient for the position - between [0,1] - default to 1 - lerpPosition: parameters.lerpPosition !== undefined ? parameters.lerpPosition : 0.8, - // lerp coeficient for the quaternion - between [0,1] - default to 1 - lerpQuaternion: parameters.lerpQuaternion !== undefined ? parameters.lerpQuaternion : 0.2, - // lerp coeficient for the scale - between [0,1] - default to 1 - lerpScale: parameters.lerpScale !== undefined ? parameters.lerpScale : 0.7, - // delay for lerp fixed steps - in seconds - default to 1/120 - lerpStepDelay: parameters.fixStepDelay !== undefined ? parameters.fixStepDelay : 1/60, - // minimum delay the sub-control must be visible before this controls become visible - default to 0 seconds - minVisibleDelay: parameters.minVisibleDelay !== undefined ? parameters.minVisibleDelay : 0.0, - // minimum delay the sub-control must be unvisible before this controls become unvisible - default to 0 seconds - minUnvisibleDelay: parameters.minUnvisibleDelay !== undefined ? parameters.minUnvisibleDelay : 0.2, - } -} - -THREEx.ArSmoothedControls.prototype = Object.create( THREEx.ArBaseControls.prototype ); -THREEx.ArSmoothedControls.prototype.constructor = THREEx.ArSmoothedControls; - -////////////////////////////////////////////////////////////////////////////// -// update function -////////////////////////////////////////////////////////////////////////////// - -THREEx.ArSmoothedControls.prototype.update = function(targetObject3d){ - var object3d = this.object3d - var parameters = this.parameters - var wasVisible = object3d.visible - var present = performance.now()/1000 - - ////////////////////////////////////////////////////////////////////////////// // handle object3d.visible with minVisibleDelay/minUnvisibleDelay ////////////////////////////////////////////////////////////////////////////// @@ -2451,7 +2352,7 @@ THREEx.ArToolkitContext = function(parameters){ // debug - true if one should display artoolkit debug canvas, false otherwise debug: parameters.debug !== undefined ? parameters.debug : false, // the mode of detection - ['color', 'color_and_matrix', 'mono', 'mono_and_matrix'] - detectionMode: parameters.detectionMode !== undefined ? parameters.detectionMode : 'color_and_matrix', + detectionMode: parameters.detectionMode !== undefined ? parameters.detectionMode : 'mono', // type of matrix code - valid iif detectionMode end with 'matrix' - [3x3, 3x3_HAMMING63, 3x3_PARITY65, 4x4, 4x4_BCH_13_9_3, 4x4_BCH_13_5_5] matrixCodeType: parameters.matrixCodeType !== undefined ? parameters.matrixCodeType : '3x3', @@ -2486,17 +2387,48 @@ THREEx.ArToolkitContext.baseURL = 'https://jeromeetienne.github.io/AR.js/three.j THREEx.ArToolkitContext.REVISION = '1.0.1-dev' +/** + * Create a default camera for this trackingBackend + * @param {string} trackingBackend - the tracking to user + * @return {THREE.Camera} the created camera + */ +THREEx.ArToolkitContext.createDefaultCamera = function( trackingBackend ){ + console.assert(false, 'use ARjs.Utils.createDefaultCamera instead') + // Create a camera + if( trackingBackend === 'artoolkit' ){ + var camera = new THREE.Camera(); + }else if( trackingBackend === 'aruco' ){ + var camera = new THREE.PerspectiveCamera(42, renderer.domElement.width / renderer.domElement.height, 0.01, 100); + }else if( trackingBackend === 'tango' ){ + var camera = new THREE.PerspectiveCamera(42, renderer.domElement.width / renderer.domElement.height, 0.01, 100); + }else console.assert(false) + return camera +} + + ////////////////////////////////////////////////////////////////////////////// // init functions ////////////////////////////////////////////////////////////////////////////// THREEx.ArToolkitContext.prototype.init = function(onCompleted){ + var _this = this if( this.parameters.trackingBackend === 'artoolkit' ){ - this._initArtoolkit(onCompleted) + this._initArtoolkit(done) }else if( this.parameters.trackingBackend === 'aruco' ){ - this._initAruco(onCompleted) + this._initAruco(done) }else if( this.parameters.trackingBackend === 'tango' ){ - this._initTango(onCompleted) + this._initTango(done) }else console.assert(false) + return + + function done(){ + // dispatch event + _this.dispatchEvent({ + type: 'initialized' + }); + + onCompleted && onCompleted() + } + } //////////////////////////////////////////////////////////////////////////////// // update function @@ -2539,8 +2471,6 @@ THREEx.ArToolkitContext.prototype.update = function(srcElement){ return true; } - - //////////////////////////////////////////////////////////////////////////////// // Add/Remove markerControls //////////////////////////////////////////////////////////////////////////////// @@ -2623,7 +2553,7 @@ THREEx.ArToolkitContext.prototype._initArtoolkit = function(onCompleted){ // arController.setThresholdMode(artoolkit.AR_LABELING_THRESH_MODE_AUTO_OTSU) // notify - onCompleted && onCompleted() + onCompleted() }) return this } @@ -2677,7 +2607,7 @@ THREEx.ArToolkitContext.prototype._initAruco = function(onCompleted){ setTimeout(function(){ - onCompleted && onCompleted() + onCompleted() }, 0) } @@ -2714,6 +2644,7 @@ THREEx.ArToolkitContext.prototype._initTango = function(onCompleted){ var _this = this // check webvr is available if (navigator.getVRDisplays) { + // do nothing } else if (navigator.getVRDevices) { alert("Your browser supports WebVR but not the latest version. See webvr.info for more info."); } else { @@ -2723,6 +2654,7 @@ THREEx.ArToolkitContext.prototype._initTango = function(onCompleted){ this._tangoContext = { vrDisplay: null, + vrPointCloud: null, frameData: new VRFrameData(), } @@ -2730,20 +2662,23 @@ THREEx.ArToolkitContext.prototype._initTango = function(onCompleted){ // get vrDisplay navigator.getVRDisplays().then(function (vrDisplays) { if( vrDisplays.length === 0 ) alert('no vrDisplays available') - var vrDisplay = vrDisplays[0] - _this._tangoContext.vrDisplay = vrDisplay + var vrDisplay = _this._tangoContext.vrDisplay = vrDisplays[0] + console.log('vrDisplays.displayName :', vrDisplay.displayName) + // init vrPointCloud + if( vrDisplay.displayName === "Tango VR Device" ){ + _this._tangoContext.vrPointCloud = new THREE.WebAR.VRPointCloud(vrDisplay, true) + } - var canvasElement = document.createElement('canvas') - document.body.appendChild(canvasElement) - var layers = [{ source: canvasElement }] -// vrDisplay.requestPresent(layers).then(function() { -// console.log('vrdisplay request accepted') -// }); -// window.vrDisplay = vrDisplay + // NOTE it doesnt seem necessary and it fails on tango + // var canvasElement = document.createElement('canvas') + // document.body.appendChild(canvasElement) + // _this._tangoContext.requestPresent([{ source: canvasElement }]).then(function() { + // console.log('vrdisplay request accepted') + // }); - onCompleted && onCompleted() + onCompleted() }); } @@ -2753,9 +2688,19 @@ THREEx.ArToolkitContext.prototype._updateTango = function(srcElement){ var _this = this var arMarkersControls = this._arMarkersControls var tangoContext= this._tangoContext + var vrDisplay = this._tangoContext.vrDisplay // check vrDisplay is already initialized - if( tangoContext.vrDisplay === null ) return + if( vrDisplay === null ) return + + + // Update the point cloud. Only if the point cloud will be shown the geometry is also updated. + if( vrDisplay.displayName === "Tango VR Device" ){ + var showPointCloud = true + var pointsToSkip = 0 + _this._tangoContext.vrPointCloud.update(showPointCloud, pointsToSkip, true) + } + if( this._arMarkersControls.length === 0 ) return @@ -2766,20 +2711,29 @@ THREEx.ArToolkitContext.prototype._updateTango = function(srcElement){ var frameData = this._tangoContext.frameData // read frameData - tangoContext.vrDisplay.getFrameData(frameData); + vrDisplay.getFrameData(frameData); + + if( frameData.pose.position === null ) return + if( frameData.pose.orientation === null ) return // create cameraTransformMatrix var position = new THREE.Vector3().fromArray(frameData.pose.position) var quaternion = new THREE.Quaternion().fromArray(frameData.pose.orientation) - var scale = new THREE.Vector3(1,1,1) + var scale = new THREE.Vector3(1,1,1) var cameraTransformMatrix = new THREE.Matrix4().compose(position, quaternion, scale) // compute modelViewMatrix from cameraTransformMatrix var modelViewMatrix = new THREE.Matrix4() modelViewMatrix.getInverse( cameraTransformMatrix ) - - console.log('position', position) foundControls.updateWithModelViewMatrix(modelViewMatrix) + + // console.log('position', position) + // if( position.x !== 0 || position.y !== 0 || position.z !== 0 ){ + // console.log('vrDisplay tracking') + // }else{ + // console.log('vrDisplay NOT tracking') + // } + } var THREEx = THREEx || {} @@ -2875,22 +2829,27 @@ THREEx.ArToolkitProfile.prototype.performance = function(label) { ////////////////////////////////////////////////////////////////////////////// // Marker ////////////////////////////////////////////////////////////////////////////// -THREEx.ArToolkitProfile.prototype.kanjiMarker = function () { - this.contextParameters.detectionMode = 'mono' - this.defaultMarkerParameters.type = 'pattern' - this.defaultMarkerParameters.patternUrl = THREEx.ArToolkitContext.baseURL + '../data/data/patt.kanji' - return this -} -THREEx.ArToolkitProfile.prototype.hiroMarker = function () { - this.contextParameters.detectionMode = 'mono' +THREEx.ArToolkitProfile.prototype.defaultMarker = function (trackingBackend) { + trackingBackend = trackingBackend || this.contextParameters.trackingBackend + + if( trackingBackend === 'artoolkit' ){ + this.contextParameters.detectionMode = 'mono' + this.defaultMarkerParameters.type = 'pattern' + this.defaultMarkerParameters.patternUrl = THREEx.ArToolkitContext.baseURL + '../data/data/patt.hiro' + }else if( trackingBackend === 'aruco' ){ + this.contextParameters.detectionMode = 'mono' + this.defaultMarkerParameters.type = 'barcode' + this.defaultMarkerParameters.barcodeValue = 1001 + }else if( trackingBackend === 'tango' ){ + // FIXME temporary placeholder - to reevaluate later + this.defaultMarkerParameters.type = 'barcode' + this.defaultMarkerParameters.barcodeValue = 1001 + }else console.assert(false) - this.defaultMarkerParameters.type = 'pattern' - this.defaultMarkerParameters.patternUrl = THREEx.ArToolkitContext.baseURL + '../data/data/patt.hiro' return this } - ////////////////////////////////////////////////////////////////////////////// // Source ////////////////////////////////////////////////////////////////////////////// @@ -2918,6 +2877,7 @@ THREEx.ArToolkitProfile.prototype.sourceImage = function (url) { ////////////////////////////////////////////////////////////////////////////// THREEx.ArToolkitProfile.prototype.trackingBackend = function (trackingBackend) { this.contextParameters.trackingBackend = trackingBackend + return this } var THREEx = THREEx || {} @@ -3155,7 +3115,7 @@ THREEx.ArToolkitSource.prototype.toggleMobileTorch = function(){ // handle resize //////////////////////////////////////////////////////////////////////////////// -THREEx.ArToolkitSource.prototype.onResize = function(mirrorDomElements){ +THREEx.ArToolkitSource.prototype.onResizeElement = function(mirrorDomElements){ var _this = this var screenWidth = window.innerWidth var screenHeight = window.innerHeight @@ -3197,6 +3157,8 @@ THREEx.ArToolkitSource.prototype.onResize = function(mirrorDomElements){ this.domElement.style.marginLeft = '0px' } + + if( arguments.length !== 0 ) console.warn('use bad signature for arToolkitSource.copyElementSizeTo') // honor default parameters // if( mirrorDomElements !== undefined ) console.warn('still use the old resize. fix it') if( mirrorDomElements === undefined ) mirrorDomElements = [] @@ -3208,12 +3170,64 @@ THREEx.ArToolkitSource.prototype.onResize = function(mirrorDomElements){ }) } -THREEx.ArToolkitSource.prototype.copySizeTo = function(otherElement){ +THREEx.ArToolkitSource.prototype.copyElementSizeTo = function(otherElement){ otherElement.style.width = this.domElement.style.width otherElement.style.height = this.domElement.style.height otherElement.style.marginLeft = this.domElement.style.marginLeft otherElement.style.marginTop = this.domElement.style.marginTop } + +////////////////////////////////////////////////////////////////////////////// +// Code Separator +////////////////////////////////////////////////////////////////////////////// + +THREEx.ArToolkitSource.prototype.copySizeTo = function(){ + console.warn('obsolete function arToolkitSource.copySizeTo. Use arToolkitSource.copyElementSizeTo' ) + this.copyElementSizeTo.apply(this, arguments) +} + +THREEx.ArToolkitSource.prototype.onResize = function(){ + console.warn('obsolete function arToolkitSource.onResize. Use arToolkitSource.onResizeElement' ) + this.onResizeElement.apply(this, arguments) +} + +////////////////////////////////////////////////////////////////////////////// +// Code Separator +////////////////////////////////////////////////////////////////////////////// + +THREEx.ArToolkitSource.prototype.onResize2 = function(arToolkitContext, renderer, camera){ + var trackingBackend = arToolkitContext.parameters.trackingBackend + + // RESIZE DOMELEMENT + if( trackingBackend === 'artoolkit' ){ + this.onResizeElement() + this.copyElementSizeTo(renderer.domElement) + + if( arToolkitContext.arController !== null ){ + this.copyElementSizeTo(arToolkitContext.arController.canvas) + } + }else if( trackingBackend === 'aruco' ){ + this.onResizeElement() + this.copyElementSizeTo(renderer.domElement) + + this.copyElementSizeTo(arToolkitContext.arucoContext.canvas) + }else if( trackingBackend === 'tango' ){ + renderer.setSize( window.innerWidth, window.innerHeight ) + }else console.assert(false, 'unhandled trackingBackend '+trackingBackend) + + + // RESIZE CAMERA + if( trackingBackend === 'artoolkit' ){ + camera.projectionMatrix.copy( arToolkitContext.getProjectionMatrix() ); + }else if( trackingBackend === 'aruco' ){ + camera.aspect = renderer.domElement.width / renderer.domElement.height; + camera.updateProjectionMatrix(); + }else if( trackingBackend === 'tango' ){ + var vrDisplay = arToolkitContext._tangoContext.vrDisplay + // make camera fit vrDisplay + if( vrDisplay && vrDisplay.displayName === "Tango VR Device" ) THREE.WebAR.resizeVRSeeThroughCamera(vrDisplay, camera) + }else console.assert(false, 'unhandled trackingBackend '+trackingBackend) +} var THREEx = THREEx || {} THREEx.ArVideoInWebgl = function(videoTexture){ @@ -3976,6 +3990,13 @@ THREEx.ArMultiMarkerUtils = {} ////////////////////////////////////////////////////////////////////////////// // navigateToLearnerPage ////////////////////////////////////////////////////////////////////////////// + +/** + * Navigate to the multi-marker learner page + * + * @param {String} learnerBaseURL - the base url for the learner + * @param {String} trackingBackend - the tracking backend to use + */ THREEx.ArMultiMarkerUtils.navigateToLearnerPage = function(learnerBaseURL, trackingBackend){ var learnerParameters = { backURL : location.href, @@ -3988,6 +4009,12 @@ THREEx.ArMultiMarkerUtils.navigateToLearnerPage = function(learnerBaseURL, track ////////////////////////////////////////////////////////////////////////////// // DefaultMultiMarkerFile ////////////////////////////////////////////////////////////////////////////// + +/** + * Create and store a default multi-marker file + * + * @param {String} trackingBackend - the tracking backend to use + */ THREEx.ArMultiMarkerUtils.storeDefaultMultiMarkerFile = function(trackingBackend){ var file = THREEx.ArMultiMarkerUtils.createDefaultMultiMarkerFile(trackingBackend) // json.strinfy the value and store it in localStorage @@ -3995,7 +4022,15 @@ THREEx.ArMultiMarkerUtils.storeDefaultMultiMarkerFile = function(trackingBackend } + +/** + * Create a default multi-marker file + * @param {String} trackingBackend - the tracking backend to use + * @return {Object} - json object of the multi-marker file + */ THREEx.ArMultiMarkerUtils.createDefaultMultiMarkerFile = function(trackingBackend){ + console.assert(trackingBackend) + if( trackingBackend === undefined ) debugger // create the base file var file = { meta : { @@ -4004,7 +4039,7 @@ THREEx.ArMultiMarkerUtils.createDefaultMultiMarkerFile = function(trackingBacken }, trackingBackend : trackingBackend, subMarkersControls : [ - // empty for now... + // empty for now... being filled ] } // add a subMarkersControls @@ -4028,6 +4063,12 @@ THREEx.ArMultiMarkerUtils.createDefaultMultiMarkerFile = function(trackingBacken // createDefaultMarkersControlsParameters ////////////////////////////////////////////////////////////////////////////// +/** + * Create a default controls parameters for the multi-marker learner + * + * @param {String} trackingBackend - the tracking backend to use + * @return {Object} - json object containing the controls parameters + */ THREEx.ArMultiMarkerUtils.createDefaultMarkersControlsParameters = function(trackingBackend){ var link = document.createElement('a') link.href = THREEx.ArToolkitContext.baseURL diff --git a/three.js/examples/dev.html b/three.js/examples/dev.html index ab4ddf3517a6c280068886ff66184d85d8742f35..e43959c60c32a7cdee59389446cc2856fa2a1cee 100644 --- a/three.js/examples/dev.html +++ b/three.js/examples/dev.html @@ -85,10 +85,10 @@ onResize() }) function onResize(){ - arToolkitSource.onResize() - arToolkitSource.copySizeTo(renderer.domElement) + arToolkitSource.onResizeElement() + arToolkitSource.copyElementSizeTo(renderer.domElement) if( arToolkitContext.arController !== null ){ - arToolkitSource.copySizeTo(arToolkitContext.arController.canvas) + arToolkitSource.copyElementSizeTo(arToolkitContext.arController.canvas) } } diff --git a/three.js/threex-artoolkitsource.js b/three.js/threex-artoolkitsource.js index 6fa503a40afa5169a82c4721f89c93ab8db935c0..cc2b88659baa850de17509eac31a7f9819f93c05 100644 --- a/three.js/threex-artoolkitsource.js +++ b/three.js/threex-artoolkitsource.js @@ -277,7 +277,10 @@ THREEx.ArToolkitSource.prototype.onResizeElement = function(mirrorDomElements){ } - if( arguments.length !== 0 ) console.warn('use bad signature for arToolkitSource.copyElementSizeTo') + if( arguments.length !== 0 ){ + debugger + console.warn('use bad signature for arToolkitSource.copyElementSizeTo') + } // honor default parameters // if( mirrorDomElements !== undefined ) console.warn('still use the old resize. fix it') if( mirrorDomElements === undefined ) mirrorDomElements = [] @@ -285,7 +288,7 @@ THREEx.ArToolkitSource.prototype.onResizeElement = function(mirrorDomElements){ // Mirror _this.domElement.style to mirrorDomElements mirrorDomElements.forEach(function(domElement){ - _this.copySizeTo(domElement) + _this.copyElementSizeTo(domElement) }) } diff --git a/webvr-polyfill/build/artoolkit-webvr-polyfill.js b/webvr-polyfill/build/artoolkit-webvr-polyfill.js index 1bead6f507f85fe0ef8fbd4c2b6ba8a602fcea6a..f38ef3b51a95a4aef6338ea88ef2191edc09d3c5 100644 --- a/webvr-polyfill/build/artoolkit-webvr-polyfill.js +++ b/webvr-polyfill/build/artoolkit-webvr-polyfill.js @@ -1662,7 +1662,6 @@ var THREEx = THREEx || {} * - seems an easy light layer for clickable object * - up to */ - THREEx.ARClickability = function(sourceElement){ this._sourceElement = sourceElement // Create cameraPicking @@ -1701,6 +1700,39 @@ THREEx.ARClickability.prototype.computeIntersects = function(domEvent, objects){ THREEx.ARClickability.prototype.update = function(){ } + +////////////////////////////////////////////////////////////////////////////// +// Code Separator +////////////////////////////////////////////////////////////////////////////// + +THREEx.ARClickability.tangoPickingPointCloud = function(artoolkitContext, mouseX, mouseY){ + var vrDisplay = artoolkitContext._tangoContext.vrDisplay + if (vrDisplay === null ) return + var pointAndPlane = vrDisplay.getPickingPointAndPlaneInPointCloud(mouseX, mouseY) + if( pointAndPlane == null ) { + console.warn('Could not retrieve the correct point and plane.') + return null + } + + // FIXME not sure what this is + var boundingSphereRadius = 0.01 + + // the bigger the number the likeliest it crash chromium-webar + + // Orient and position the model in the picking point according + // to the picking plane. The offset is half of the model size. + var object3d = new THREE.Object3D + THREE.WebAR.positionAndRotateObject3DWithPickingPointAndPlaneInPointCloud( + pointAndPlane, object3d, boundingSphereRadius + ) + object3d.rotateZ(-Math.PI/2) + + // return the result + var result = {} + result.position = object3d.position + result.quaternion = object3d.quaternion + return result +} var THREEx = THREEx || {} /** * - videoTexture @@ -2099,7 +2131,6 @@ THREEx.ArMarkerControls.prototype._initArtoolkit = function(){ }else{ console.log(false, 'invalid marker type', _this.parameters.type) } - // listen to the event arController.addEventListener('getMarker', function(event){ @@ -2233,136 +2264,6 @@ THREEx.ArSmoothedControls.prototype.update = function(targetObject3d){ var present = performance.now()/1000 - ////////////////////////////////////////////////////////////////////////////// - // handle object3d.visible with minVisibleDelay/minUnvisibleDelay - ////////////////////////////////////////////////////////////////////////////// - if( targetObject3d.visible === false ) this._visibleStartedAt = null - if( targetObject3d.visible === true ) this._unvisibleStartedAt = null - - if( wasVisible === false && targetObject3d.visible === true ){ - if( this._visibleStartedAt === null ) this._visibleStartedAt = present - var visibleFor = present - this._visibleStartedAt - if( visibleFor >= this.parameters.minVisibleDelay ){ - object3d.visible = true - this._visibleStartedAt = null - } - console.log('visibleFor', visibleFor) - } - - if( wasVisible === true && targetObject3d.visible === false ){ - if( this._unvisibleStartedAt === null ) this._unvisibleStartedAt = present - var unvisibleFor = present - this._unvisibleStartedAt - if( unvisibleFor >= this.parameters.minUnvisibleDelay ){ - object3d.visible = false - } - // console.log('unvisibleFor', unvisibleFor) - } - - // disabled minVisibleDelay+minUnvisibleDelay - // if( true ){ - // object3d.visible = targetObject3d.visible - // } - - ////////////////////////////////////////////////////////////////////////////// - // apply lerp on positon/quaternion/scale - ////////////////////////////////////////////////////////////////////////////// - - // apply lerp steps - require fix time steps to behave the same no matter the fps - if( this._lastLerpStepAt === null ){ - applyOneSlepStep() - this._lastLerpStepAt = present - }else{ - var nStepsToDo = Math.floor( (present - this._lastLerpStepAt)/this.parameters.lerpStepDelay ) - for(var i = 0; i < nStepsToDo; i++){ - applyOneSlepStep() - this._lastLerpStepAt += this.parameters.lerpStepDelay - } - } - - // update the matrix - this.object3d.updateMatrix() - - // disable the lerp by directly copying targetObject3d position/quaternion/scale - if( false ){ - this.object3d.position.copy( targetObject3d.position ) - this.object3d.quaternion.copy( targetObject3d.quaternion ) - this.object3d.scale.copy( targetObject3d.scale ) - this.object3d.updateMatrix() - } - - ////////////////////////////////////////////////////////////////////////////// - // honor becameVisible/becameUnVisible event - ////////////////////////////////////////////////////////////////////////////// - // honor becameVisible event - if( wasVisible === false && object3d.visible === true ){ - this.dispatchEvent({ type: 'becameVisible' }) - } - // honor becameUnVisible event - if( wasVisible === true && object3d.visible === false ){ - this.dispatchEvent({ type: 'becameUnVisible' }) - } - return - - - function applyOneSlepStep(){ - object3d.position.lerp(targetObject3d.position, parameters.lerpPosition) - object3d.quaternion.slerp(targetObject3d.quaternion, parameters.lerpQuaternion) - object3d.scale.lerp(targetObject3d.scale, parameters.lerpScale) - } -} -var THREEx = THREEx || {} - -/** - * - lerp position/quaternino/scale - * - minDelayDetected - * - minDelayUndetected - * @param {[type]} object3d [description] - * @param {[type]} parameters [description] - */ -THREEx.ArSmoothedControls = function(object3d, parameters){ - var _this = this - - THREEx.ArBaseControls.call(this, object3d) - - // copy parameters - this.object3d.visible = false - - this._lastLerpStepAt = null - this._visibleStartedAt = null - this._unvisibleStartedAt = null - - // handle default parameters - parameters = parameters || {} - this.parameters = { - // lerp coeficient for the position - between [0,1] - default to 1 - lerpPosition: parameters.lerpPosition !== undefined ? parameters.lerpPosition : 0.8, - // lerp coeficient for the quaternion - between [0,1] - default to 1 - lerpQuaternion: parameters.lerpQuaternion !== undefined ? parameters.lerpQuaternion : 0.2, - // lerp coeficient for the scale - between [0,1] - default to 1 - lerpScale: parameters.lerpScale !== undefined ? parameters.lerpScale : 0.7, - // delay for lerp fixed steps - in seconds - default to 1/120 - lerpStepDelay: parameters.fixStepDelay !== undefined ? parameters.fixStepDelay : 1/60, - // minimum delay the sub-control must be visible before this controls become visible - default to 0 seconds - minVisibleDelay: parameters.minVisibleDelay !== undefined ? parameters.minVisibleDelay : 0.0, - // minimum delay the sub-control must be unvisible before this controls become unvisible - default to 0 seconds - minUnvisibleDelay: parameters.minUnvisibleDelay !== undefined ? parameters.minUnvisibleDelay : 0.2, - } -} - -THREEx.ArSmoothedControls.prototype = Object.create( THREEx.ArBaseControls.prototype ); -THREEx.ArSmoothedControls.prototype.constructor = THREEx.ArSmoothedControls; - -////////////////////////////////////////////////////////////////////////////// -// update function -////////////////////////////////////////////////////////////////////////////// - -THREEx.ArSmoothedControls.prototype.update = function(targetObject3d){ - var object3d = this.object3d - var parameters = this.parameters - var wasVisible = object3d.visible - var present = performance.now()/1000 - - ////////////////////////////////////////////////////////////////////////////// // handle object3d.visible with minVisibleDelay/minUnvisibleDelay ////////////////////////////////////////////////////////////////////////////// @@ -2451,7 +2352,7 @@ THREEx.ArToolkitContext = function(parameters){ // debug - true if one should display artoolkit debug canvas, false otherwise debug: parameters.debug !== undefined ? parameters.debug : false, // the mode of detection - ['color', 'color_and_matrix', 'mono', 'mono_and_matrix'] - detectionMode: parameters.detectionMode !== undefined ? parameters.detectionMode : 'color_and_matrix', + detectionMode: parameters.detectionMode !== undefined ? parameters.detectionMode : 'mono', // type of matrix code - valid iif detectionMode end with 'matrix' - [3x3, 3x3_HAMMING63, 3x3_PARITY65, 4x4, 4x4_BCH_13_9_3, 4x4_BCH_13_5_5] matrixCodeType: parameters.matrixCodeType !== undefined ? parameters.matrixCodeType : '3x3', @@ -2486,17 +2387,48 @@ THREEx.ArToolkitContext.baseURL = 'https://jeromeetienne.github.io/AR.js/three.j THREEx.ArToolkitContext.REVISION = '1.0.1-dev' +/** + * Create a default camera for this trackingBackend + * @param {string} trackingBackend - the tracking to user + * @return {THREE.Camera} the created camera + */ +THREEx.ArToolkitContext.createDefaultCamera = function( trackingBackend ){ + console.assert(false, 'use ARjs.Utils.createDefaultCamera instead') + // Create a camera + if( trackingBackend === 'artoolkit' ){ + var camera = new THREE.Camera(); + }else if( trackingBackend === 'aruco' ){ + var camera = new THREE.PerspectiveCamera(42, renderer.domElement.width / renderer.domElement.height, 0.01, 100); + }else if( trackingBackend === 'tango' ){ + var camera = new THREE.PerspectiveCamera(42, renderer.domElement.width / renderer.domElement.height, 0.01, 100); + }else console.assert(false) + return camera +} + + ////////////////////////////////////////////////////////////////////////////// // init functions ////////////////////////////////////////////////////////////////////////////// THREEx.ArToolkitContext.prototype.init = function(onCompleted){ + var _this = this if( this.parameters.trackingBackend === 'artoolkit' ){ - this._initArtoolkit(onCompleted) + this._initArtoolkit(done) }else if( this.parameters.trackingBackend === 'aruco' ){ - this._initAruco(onCompleted) + this._initAruco(done) }else if( this.parameters.trackingBackend === 'tango' ){ - this._initTango(onCompleted) + this._initTango(done) }else console.assert(false) + return + + function done(){ + // dispatch event + _this.dispatchEvent({ + type: 'initialized' + }); + + onCompleted && onCompleted() + } + } //////////////////////////////////////////////////////////////////////////////// // update function @@ -2539,8 +2471,6 @@ THREEx.ArToolkitContext.prototype.update = function(srcElement){ return true; } - - //////////////////////////////////////////////////////////////////////////////// // Add/Remove markerControls //////////////////////////////////////////////////////////////////////////////// @@ -2623,7 +2553,7 @@ THREEx.ArToolkitContext.prototype._initArtoolkit = function(onCompleted){ // arController.setThresholdMode(artoolkit.AR_LABELING_THRESH_MODE_AUTO_OTSU) // notify - onCompleted && onCompleted() + onCompleted() }) return this } @@ -2677,7 +2607,7 @@ THREEx.ArToolkitContext.prototype._initAruco = function(onCompleted){ setTimeout(function(){ - onCompleted && onCompleted() + onCompleted() }, 0) } @@ -2714,6 +2644,7 @@ THREEx.ArToolkitContext.prototype._initTango = function(onCompleted){ var _this = this // check webvr is available if (navigator.getVRDisplays) { + // do nothing } else if (navigator.getVRDevices) { alert("Your browser supports WebVR but not the latest version. See webvr.info for more info."); } else { @@ -2723,6 +2654,7 @@ THREEx.ArToolkitContext.prototype._initTango = function(onCompleted){ this._tangoContext = { vrDisplay: null, + vrPointCloud: null, frameData: new VRFrameData(), } @@ -2730,20 +2662,23 @@ THREEx.ArToolkitContext.prototype._initTango = function(onCompleted){ // get vrDisplay navigator.getVRDisplays().then(function (vrDisplays) { if( vrDisplays.length === 0 ) alert('no vrDisplays available') - var vrDisplay = vrDisplays[0] - _this._tangoContext.vrDisplay = vrDisplay + var vrDisplay = _this._tangoContext.vrDisplay = vrDisplays[0] + console.log('vrDisplays.displayName :', vrDisplay.displayName) + // init vrPointCloud + if( vrDisplay.displayName === "Tango VR Device" ){ + _this._tangoContext.vrPointCloud = new THREE.WebAR.VRPointCloud(vrDisplay, true) + } - var canvasElement = document.createElement('canvas') - document.body.appendChild(canvasElement) - var layers = [{ source: canvasElement }] -// vrDisplay.requestPresent(layers).then(function() { -// console.log('vrdisplay request accepted') -// }); -// window.vrDisplay = vrDisplay + // NOTE it doesnt seem necessary and it fails on tango + // var canvasElement = document.createElement('canvas') + // document.body.appendChild(canvasElement) + // _this._tangoContext.requestPresent([{ source: canvasElement }]).then(function() { + // console.log('vrdisplay request accepted') + // }); - onCompleted && onCompleted() + onCompleted() }); } @@ -2753,9 +2688,19 @@ THREEx.ArToolkitContext.prototype._updateTango = function(srcElement){ var _this = this var arMarkersControls = this._arMarkersControls var tangoContext= this._tangoContext + var vrDisplay = this._tangoContext.vrDisplay // check vrDisplay is already initialized - if( tangoContext.vrDisplay === null ) return + if( vrDisplay === null ) return + + + // Update the point cloud. Only if the point cloud will be shown the geometry is also updated. + if( vrDisplay.displayName === "Tango VR Device" ){ + var showPointCloud = true + var pointsToSkip = 0 + _this._tangoContext.vrPointCloud.update(showPointCloud, pointsToSkip, true) + } + if( this._arMarkersControls.length === 0 ) return @@ -2766,20 +2711,29 @@ THREEx.ArToolkitContext.prototype._updateTango = function(srcElement){ var frameData = this._tangoContext.frameData // read frameData - tangoContext.vrDisplay.getFrameData(frameData); + vrDisplay.getFrameData(frameData); + + if( frameData.pose.position === null ) return + if( frameData.pose.orientation === null ) return // create cameraTransformMatrix var position = new THREE.Vector3().fromArray(frameData.pose.position) var quaternion = new THREE.Quaternion().fromArray(frameData.pose.orientation) - var scale = new THREE.Vector3(1,1,1) + var scale = new THREE.Vector3(1,1,1) var cameraTransformMatrix = new THREE.Matrix4().compose(position, quaternion, scale) // compute modelViewMatrix from cameraTransformMatrix var modelViewMatrix = new THREE.Matrix4() modelViewMatrix.getInverse( cameraTransformMatrix ) - - console.log('position', position) foundControls.updateWithModelViewMatrix(modelViewMatrix) + + // console.log('position', position) + // if( position.x !== 0 || position.y !== 0 || position.z !== 0 ){ + // console.log('vrDisplay tracking') + // }else{ + // console.log('vrDisplay NOT tracking') + // } + } var THREEx = THREEx || {} @@ -2875,22 +2829,27 @@ THREEx.ArToolkitProfile.prototype.performance = function(label) { ////////////////////////////////////////////////////////////////////////////// // Marker ////////////////////////////////////////////////////////////////////////////// -THREEx.ArToolkitProfile.prototype.kanjiMarker = function () { - this.contextParameters.detectionMode = 'mono' - this.defaultMarkerParameters.type = 'pattern' - this.defaultMarkerParameters.patternUrl = THREEx.ArToolkitContext.baseURL + '../data/data/patt.kanji' - return this -} -THREEx.ArToolkitProfile.prototype.hiroMarker = function () { - this.contextParameters.detectionMode = 'mono' +THREEx.ArToolkitProfile.prototype.defaultMarker = function (trackingBackend) { + trackingBackend = trackingBackend || this.contextParameters.trackingBackend + + if( trackingBackend === 'artoolkit' ){ + this.contextParameters.detectionMode = 'mono' + this.defaultMarkerParameters.type = 'pattern' + this.defaultMarkerParameters.patternUrl = THREEx.ArToolkitContext.baseURL + '../data/data/patt.hiro' + }else if( trackingBackend === 'aruco' ){ + this.contextParameters.detectionMode = 'mono' + this.defaultMarkerParameters.type = 'barcode' + this.defaultMarkerParameters.barcodeValue = 1001 + }else if( trackingBackend === 'tango' ){ + // FIXME temporary placeholder - to reevaluate later + this.defaultMarkerParameters.type = 'barcode' + this.defaultMarkerParameters.barcodeValue = 1001 + }else console.assert(false) - this.defaultMarkerParameters.type = 'pattern' - this.defaultMarkerParameters.patternUrl = THREEx.ArToolkitContext.baseURL + '../data/data/patt.hiro' return this } - ////////////////////////////////////////////////////////////////////////////// // Source ////////////////////////////////////////////////////////////////////////////// @@ -2918,6 +2877,7 @@ THREEx.ArToolkitProfile.prototype.sourceImage = function (url) { ////////////////////////////////////////////////////////////////////////////// THREEx.ArToolkitProfile.prototype.trackingBackend = function (trackingBackend) { this.contextParameters.trackingBackend = trackingBackend + return this } var THREEx = THREEx || {} @@ -3155,7 +3115,7 @@ THREEx.ArToolkitSource.prototype.toggleMobileTorch = function(){ // handle resize //////////////////////////////////////////////////////////////////////////////// -THREEx.ArToolkitSource.prototype.onResize = function(mirrorDomElements){ +THREEx.ArToolkitSource.prototype.onResizeElement = function(mirrorDomElements){ var _this = this var screenWidth = window.innerWidth var screenHeight = window.innerHeight @@ -3197,6 +3157,8 @@ THREEx.ArToolkitSource.prototype.onResize = function(mirrorDomElements){ this.domElement.style.marginLeft = '0px' } + + if( arguments.length !== 0 ) console.warn('use bad signature for arToolkitSource.copyElementSizeTo') // honor default parameters // if( mirrorDomElements !== undefined ) console.warn('still use the old resize. fix it') if( mirrorDomElements === undefined ) mirrorDomElements = [] @@ -3208,12 +3170,64 @@ THREEx.ArToolkitSource.prototype.onResize = function(mirrorDomElements){ }) } -THREEx.ArToolkitSource.prototype.copySizeTo = function(otherElement){ +THREEx.ArToolkitSource.prototype.copyElementSizeTo = function(otherElement){ otherElement.style.width = this.domElement.style.width otherElement.style.height = this.domElement.style.height otherElement.style.marginLeft = this.domElement.style.marginLeft otherElement.style.marginTop = this.domElement.style.marginTop } + +////////////////////////////////////////////////////////////////////////////// +// Code Separator +////////////////////////////////////////////////////////////////////////////// + +THREEx.ArToolkitSource.prototype.copySizeTo = function(){ + console.warn('obsolete function arToolkitSource.copySizeTo. Use arToolkitSource.copyElementSizeTo' ) + this.copyElementSizeTo.apply(this, arguments) +} + +THREEx.ArToolkitSource.prototype.onResize = function(){ + console.warn('obsolete function arToolkitSource.onResize. Use arToolkitSource.onResizeElement' ) + this.onResizeElement.apply(this, arguments) +} + +////////////////////////////////////////////////////////////////////////////// +// Code Separator +////////////////////////////////////////////////////////////////////////////// + +THREEx.ArToolkitSource.prototype.onResize2 = function(arToolkitContext, renderer, camera){ + var trackingBackend = arToolkitContext.parameters.trackingBackend + + // RESIZE DOMELEMENT + if( trackingBackend === 'artoolkit' ){ + this.onResizeElement() + this.copyElementSizeTo(renderer.domElement) + + if( arToolkitContext.arController !== null ){ + this.copyElementSizeTo(arToolkitContext.arController.canvas) + } + }else if( trackingBackend === 'aruco' ){ + this.onResizeElement() + this.copyElementSizeTo(renderer.domElement) + + this.copyElementSizeTo(arToolkitContext.arucoContext.canvas) + }else if( trackingBackend === 'tango' ){ + renderer.setSize( window.innerWidth, window.innerHeight ) + }else console.assert(false, 'unhandled trackingBackend '+trackingBackend) + + + // RESIZE CAMERA + if( trackingBackend === 'artoolkit' ){ + camera.projectionMatrix.copy( arToolkitContext.getProjectionMatrix() ); + }else if( trackingBackend === 'aruco' ){ + camera.aspect = renderer.domElement.width / renderer.domElement.height; + camera.updateProjectionMatrix(); + }else if( trackingBackend === 'tango' ){ + var vrDisplay = arToolkitContext._tangoContext.vrDisplay + // make camera fit vrDisplay + if( vrDisplay && vrDisplay.displayName === "Tango VR Device" ) THREE.WebAR.resizeVRSeeThroughCamera(vrDisplay, camera) + }else console.assert(false, 'unhandled trackingBackend '+trackingBackend) +} var THREEx = THREEx || {} THREEx.ArVideoInWebgl = function(videoTexture){