<!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 threex.artoolkit --> <script src="../build/ar-threex.js"></script> <script>THREEx.ArToolkitContext.baseURL = '../'</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/AR-js-org/AR.js/" target="_blank">AR.js</a> - developement playground <br /> Contact me any time at <a href='https://twitter.com/nicolocarp' target='_blank'>@nicolocarp</a> </div> <div style='position: absolute;bottom: 0;right: 0;background-color: rgba(255,255,255,0.4); padding: 1em; z-index: 1;'> <label title='Select the profile you like'>Profile : <select id='artoolkitProfile'> <option value="desktop-fast">desktop-fast</option> <option value="desktop-normal">desktop-normal</option> <option value="phone-normal">phone-normal</option> <option value="phone-slow">phone-slow</option> <option value="dynamic" selected>dynamic</option> </select> </label> </div> <script> ////////////////////////////////////////////////////////////////////////////////// // Init ////////////////////////////////////////////////////////////////////////////////// // init renderer var renderer = new THREE.WebGLRenderer({ // antialias : true, alpha: true }); renderer.setClearColor(new THREE.Color('lightgrey'), 0) // renderer.setPixelRatio( 2 ); 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); // array of functions for the rendering loop var onRenderFcts = []; var arToolkitContext, artoolkitMarker; // init scene and camera var scene = new THREE.Scene(); var ambient = new THREE.AmbientLight(0x666666); scene.add(ambient); var directionalLight = new THREE.DirectionalLight(0x887766); directionalLight.position.set(-1, 1, 1).normalize(); scene.add(directionalLight); ////////////////////////////////////////////////////////////////////////////////// // Initialize a basic camera ////////////////////////////////////////////////////////////////////////////////// // Create a camera var camera = new THREE.Camera(); scene.add(camera); var markerRoot = new THREE.Group scene.add(markerRoot) ////////////////////////////////////////////////////////////////////////////// // handle profile ui ////////////////////////////////////////////////////////////////////////////// if (localStorage.getItem('artoolkitPerformanceProfile') !== null) { var domElement = document.querySelector('#artoolkitProfile') domElement.value = localStorage.getItem('artoolkitPerformanceProfile') } document.querySelector('#artoolkitProfile').addEventListener('change', function () { var domElement = document.querySelector('#artoolkitProfile') localStorage.setItem('artoolkitPerformanceProfile', domElement.value); location.reload(); }) //////////////////////////////////////////////////////////////////////////////// // handle ArToolkitProfile //////////////////////////////////////////////////////////////////////////////// var artoolkitProfile = new THREEx.ArToolkitProfile() artoolkitProfile.sourceWebcam() // artoolkitProfile.sourceVideo(THREEx.ArToolkitContext.baseURL + '../data/videos/headtracking.mp4').kanjiMarker(); // artoolkitProfile.sourceImage(THREEx.ArToolkitContext.baseURL + '../data/images/img.jpg').hiroMarker() // artoolkitProfile.performance('desktop-fast') if (localStorage.getItem('artoolkitPerformanceProfile') !== null) { var label = localStorage.getItem('artoolkitPerformanceProfile') console.log('Using stored profile', label) artoolkitProfile.performance(label) } ////////////////////////////////////////////////////////////////////////////// // handle arToolkitSource ////////////////////////////////////////////////////////////////////////////// var arToolkitSource = new THREEx.ArToolkitSource(artoolkitProfile.sourceParameters) arToolkitSource.init(function onReady() { initARContext() onResize() }) // handle resize window.addEventListener('resize', function () { onResize() }) function onResize() { arToolkitSource.onResizeElement() arToolkitSource.copyElementSizeTo(renderer.domElement) if (window.arToolkitContext.arController !== null) { arToolkitSource.copyElementSizeTo(window.arToolkitContext.arController.canvas) } } //////////////////////////////////////////////////////////////////////////////// // initialize arToolkitContext //////////////////////////////////////////////////////////////////////////////// function initARContext() { console.log('initARContext()'); // create atToolkitContext arToolkitContext = new THREEx.ArToolkitContext(artoolkitProfile.contextParameters) // initialize it arToolkitContext.init(function onCompleted() { // copy projection matrix to camera camera.projectionMatrix.copy(arToolkitContext.getProjectionMatrix()); arToolkitContext.arController.orientation = getSourceOrientation(); arToolkitContext.arController.options.orientation = getSourceOrientation(); console.log('arToolkitContext', arToolkitContext); window.arToolkitContext = arToolkitContext; }) artoolkitMarker = new THREEx.ArMarkerControls(arToolkitContext, markerRoot, artoolkitProfile.defaultMarkerParameters) } function getSourceOrientation() { if (!arToolkitSource) { return null; } console.log( 'actual source dimensions', arToolkitSource.domElement.videoWidth, arToolkitSource.domElement.videoHeight ); if (arToolkitSource.domElement.videoWidth > arToolkitSource.domElement.videoHeight) { console.log('source orientation', 'landscape'); return 'landscape'; } else { console.log('source orientation', 'portrait'); return 'portrait'; } } // update artoolkit on every frame onRenderFcts.push(function () { if (!arToolkitContext || !arToolkitSource || !arToolkitSource.ready) { return; } arToolkitContext.update(arToolkitSource.domElement) }) ////////////////////////////////////////////////////////////////////////////////// // add an object in the scene ////////////////////////////////////////////////////////////////////////////////// // 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 markerRoot.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 markerRoot.add(mesh); onRenderFcts.push(function () { mesh.rotation.x += 0.1 }) ////////////////////////////////////////////////////////////////////////////////// // 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>