<!DOCTYPE html> <meta name='viewport' content='width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'> <!-- three.js library --> <script src='../../vendor/three.js/build/three.js'></script> <script src='../../vendor/three.js/examples/js/libs/stats.min.js'></script> <!-- include ar-threex.js and ar.js --> <script src="../../../build/ar-threex.js"></script> <script src="../../../build/ar.js"></script> <script>THREEx.ArToolkitContext.baseURL = '../../../'</script> <script src='threex-screenasportal/threex-screenasportal.js'></script> <script>THREEx.ScreenAsPortal.baseURL = 'threex-screenasportal/'</script> <body style='margin : 0px; overflow: hidden; font-family: Monospace;'><div style='position: absolute; top: 10px; width:100%; text-align: center;z-index:1';> <a href='https://github.com/jeromeetienne/AR.js/' target='_blank'>AR.js</a> - Multi marker by <a href='https://twitter.com/jerome_etienne' target='_blank'>@jerome_etienne</a> </div> <!-- info at the top of page --> <div style='position: fixed; bottom: 10px; width:100%; text-align: center;z-index:1';> tracking backend: <a href='javascript:void(0)' onclick='trackingBackendSet("artoolkit")'>artoolkit</a> <br> <a href='javascript:void(0)' onclick='markerHelpersToggleVisibility()'>Marker helpers</a> - <a href='javascript:void(0)' onclick='resetMarkerFile()'>reset area</a> </div> <!-- display record button --> <div style='position: fixed; bottom: 16px; right: 16px; z-index:1';> <style> #recordButton:hover { cursor: pointer; } </style> <img id='recordButton' src="images/record-start.png" width='64px' height='64px'> </div> <script> ;(function(){ ////////////////////////////////////////////////////////////////////////////////// // Init ////////////////////////////////////////////////////////////////////////////////// // init renderer var renderer = new THREE.WebGLRenderer({ alpha: true }); renderer.setClearColor(new THREE.Color('lightgrey'), 0) renderer.setSize( window.innerWidth, window.innerHeight ); renderer.domElement.style.position = 'absolute' renderer.domElement.style.top = '0px' renderer.domElement.style.left = '0px' document.body.appendChild( renderer.domElement ); // init scene and camera var scene = new THREE.Scene(); // array of functions for the rendering loop var onRenderFcts= []; //////////////////////////////////////////////////////////////////////////////// // handle urlOptions //////////////////////////////////////////////////////////////////////////////// var hasHash = location.hash.substring(1) !== '' ? true : false if( hasHash === true ){ var urlOptions = JSON.parse(decodeURIComponent(location.hash.substring(1))) }else{ var urlOptions = { trackingBackend: 'artoolkit', } } window.urlOptions = urlOptions urlOptionsUpdate() function urlOptionsUpdate(){ location.hash = '#'+encodeURIComponent(JSON.stringify(urlOptions)) } ////////////////////////////////////////////////////////////////////////////////// // Initialize a basic camera ////////////////////////////////////////////////////////////////////////////////// // Create a camera if( urlOptions.trackingBackend === 'artoolkit' ){ var camera = new THREE.Camera(); }else console.assert(false) scene.add(camera); //////////////////////////////////////////////////////////////////////////////// // handle arToolkitSource //////////////////////////////////////////////////////////////////////////////// var artoolkitProfile = new ARjs.Profile() artoolkitProfile.sourceWebcam() .trackingBackend(urlOptions.trackingBackend) var arToolkitSource = new ARjs.Source(artoolkitProfile.sourceParameters) arToolkitSource.init(function onReady(){ onResize() }) // handle resize window.addEventListener('resize', function(){ onResize() }) function onResize(){ arToolkitSource.onResizeElement() arToolkitSource.copyElementSizeTo(renderer.domElement) if( urlOptions.trackingBackend === 'artoolkit' ){ if( arToolkitContext.arController !== null ){ arToolkitSource.copyElementSizeTo(arToolkitContext.arController.canvas) } }else console.assert(false) } //////////////////////////////////////////////////////////////////////////////// // initialize arToolkitContext //////////////////////////////////////////////////////////////////////////////// // create atToolkitContext var arToolkitContext = new ARjs.Context(artoolkitProfile.contextParameters) // initialize it arToolkitContext.init(function onCompleted(){ // if artoolkit, copy projection matrix to camera if( arToolkitContext.parameters.trackingBackend === 'artoolkit' ){ camera.projectionMatrix.copy( arToolkitContext.getProjectionMatrix() ); } }) // update artoolkit on every frame onRenderFcts.push(function(){ if( arToolkitSource.ready === false ) return arToolkitContext.update( arToolkitSource.domElement ) }) ////////////////////////////////////////////////////////////////////////////// // get multiMarkerFile ////////////////////////////////////////////////////////////////////////////// // if no localStorage.ARjsMultiMarkerFile, then write one with default marker if( localStorage.getItem('ARjsMultiMarkerFile') === null ){ THREEx.ArMultiMarkerUtils.storeDefaultMultiMarkerFile(urlOptions.trackingBackend) } // get multiMarkerFile from localStorage console.assert( localStorage.getItem('ARjsMultiMarkerFile') !== null ) var multiMarkerFile = localStorage.getItem('ARjsMultiMarkerFile') ////////////////////////////////////////////////////////////////////////////// // Create ArMultiMarkerControls ////////////////////////////////////////////////////////////////////////////// // build a markerRoot var markerRoot = new THREE.Group() scene.add(markerRoot) // build a multiMarkerControls var multiMarkerControls = THREEx.ArMultiMarkerControls.fromJSON(arToolkitContext, scene, markerRoot, multiMarkerFile) // build a smoothedControls var smoothedRoot = new THREE.Group() scene.add(smoothedRoot) var smoothedControls = new THREEx.ArSmoothedControls(smoothedRoot) onRenderFcts.push(function(delta){ // update smoothedControls parameters depending on how many markers are visible in multiMarkerControls multiMarkerControls.updateSmoothedControls(smoothedControls) // update smoothedControls position smoothedControls.update(markerRoot) }) ////////////////////////////////////////////////////////////////////////////// // markerHelpers ////////////////////////////////////////////////////////////////////////////// // display THREEx.ArMarkerHelper if needed - useful to debug var markerHelpers = [] multiMarkerControls.subMarkersControls.forEach(function(subMarkerControls){ // add an helper to visuable each sub-marker var markerHelper = new THREEx.ArMarkerHelper(subMarkerControls) markerHelpers.push(markerHelper) subMarkerControls.object3d.add( markerHelper.object3d ) }) function markerHelpersToggleVisibility(){ var wasVisible = markerHelpers[0].object3d.visible markerHelpers.forEach(function(markerHelper){ markerHelper.object3d.visible = wasVisible ? false : true }) } window.markerHelpersToggleVisibility = markerHelpersToggleVisibility ////////////////////////////////////////////////////////////////////////////// // init UI ////////////////////////////////////////////////////////////////////////////// document.querySelector('#recordButton').addEventListener('click', function(){ urlOptionsUpdate() THREEx.ArMultiMarkerUtils.navigateToLearnerPage('learner.html', urlOptions.trackingBackend) }) window.resetMarkerFile = function(){ THREEx.ArMultiMarkerUtils.storeDefaultMultiMarkerFile(urlOptions.trackingBackend) location.reload() } function trackingBackendSet(trackingBackend){ THREEx.ArMultiMarkerUtils.storeDefaultMultiMarkerFile(trackingBackend) urlOptions.trackingBackend = trackingBackend urlOptionsUpdate() location.reload() } window.trackingBackendSet = trackingBackendSet ////////////////////////////////////////////////////////////////////////////////// // Add simple object on smoothedRoot ////////////////////////////////////////////////////////////////////////////////// ;(function(){ var arWorldRoot = new THREE.Group() var averageMatrix = THREEx.ArMultiMarkerControls.computeCenter(multiMarkerFile) averageMatrix.decompose(arWorldRoot.position, arWorldRoot.quaternion, arWorldRoot.scale) smoothedRoot.add(arWorldRoot) // markerRoot.add(arWorldRoot) // var screenAsPortal = new THREEx.ScreenAsPortal(multiMarkerFile) // arWorldRoot.add(screenAsPortal.object3d) var mesh = new THREE.AxesHelper() arWorldRoot.add(mesh) // add a torus knot var geometry = new THREE.BoxGeometry(1,1,1); var material = new THREE.MeshNormalMaterial({ transparent : true, opacity: 0.5, side: THREE.DoubleSide }); var mesh = new THREE.Mesh( geometry, material ); mesh.position.y = geometry.parameters.height/2 arWorldRoot.add(mesh) var geometry = new THREE.TorusKnotGeometry(0.3,0.1,64,16); var material = new THREE.MeshNormalMaterial(); var mesh = new THREE.Mesh( geometry, material ); mesh.position.y = 0.5 arWorldRoot.add( mesh ); onRenderFcts.push(function(delta){ mesh.rotation.x += delta * Math.PI }) })() ////////////////////////////////////////////////////////////////////////////////// // render the whole thing on the page ////////////////////////////////////////////////////////////////////////////////// var stats = new Stats(); // document.body.appendChild( stats.dom ); // render the scene onRenderFcts.push(function(){ renderer.render( scene, camera ); stats.update(); }) // run the rendering loop var lastTimeMsec= null requestAnimationFrame(function animate(nowMsec){ // keep looping requestAnimationFrame( animate ); // measure time lastTimeMsec = lastTimeMsec || nowMsec-1000/60 var deltaMsec = Math.min(200, nowMsec - lastTimeMsec) lastTimeMsec = nowMsec // call each update function onRenderFcts.forEach(function(onRenderFct){ onRenderFct(deltaMsec/1000, nowMsec/1000) }) }) })() </script></body>