Newer
Older
AegisforEcosystem / next / AR.js-3.4.0 / three.js / examples / measure-it.html
@KAOKA Daisuke KAOKA Daisuke on 31 May 2022 11 KB into AR.js
<!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>
<!-- 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> - Measure the distance between 2 markers
		- hiro and kanji
		<br />
		Contact me any time at <a href='https://twitter.com/nicolocarp' target='_blank'>@nicolocarp</a>
	</div>
	<script>
		//////////////////////////////////////////////////////////////////////////////////
		//		Init
		//////////////////////////////////////////////////////////////////////////////////

		// init renderer
		var renderer = new THREE.WebGLRenderer({
			antialias: true,
			alpha: true
		});
		renderer.setClearColor(new THREE.Color('lightgrey'), 0)
		renderer.setSize(640, 480);
		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, markerControls;
		// init scene and camera
		var scene = new THREE.Scene();

		//////////////////////////////////////////////////////////////////////////////////
		//		Initialize a basic camera
		//////////////////////////////////////////////////////////////////////////////////

		// Create a camera
		var camera = new THREE.Camera();
		scene.add(camera);
		var markerRoot1 = new THREE.Group
		markerRoot1.name = 'marker1'
		scene.add(markerRoot1)
		var markerRoot2 = new THREE.Group
		markerRoot2.name = 'marker2'
		scene.add(markerRoot2)

		////////////////////////////////////////////////////////////////////////////////
		//          handle arToolkitSource
		////////////////////////////////////////////////////////////////////////////////

		var arToolkitSource = new THREEx.ArToolkitSource({
			// to read from the webcam
			sourceType: 'webcam',

			// to read from an image
			// sourceType : 'image',
			// sourceUrl : THREEx.ArToolkitContext.baseURL + '../data/images/img.jpg',

			// to read from a video
			// sourceType : 'video',
			// sourceUrl : THREEx.ArToolkitContext.baseURL + '../data/videos/headtracking.mp4',
		})

		arToolkitSource.init(function onReady() {
			initARContext()
			onResize()
		})

		// handle resize
		window.addEventListener('resize', function () {
			onResize()
		})
		function onResize() {
			arToolkitSource.onResizeElement()
			arToolkitSource.copyElementSizeTo(renderer.domElement)
			if (arToolkitContext.arController !== null) {
				arToolkitSource.copyElementSizeTo(arToolkitContext.arController.canvas)
			}
		}
		////////////////////////////////////////////////////////////////////////////////
		//          initialize arToolkitContext
		////////////////////////////////////////////////////////////////////////////////
		function initARContext() {
			console.log('initARContext()');
			// create atToolkitContext
			arToolkitContext = new THREEx.ArToolkitContext({
				cameraParametersUrl: THREEx.ArToolkitContext.baseURL + '../data/data/camera_para.dat',
				detectionMode: 'mono',
			})
			// 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;
			})
			// build markerControls for markerRoot1
			markerControls = new THREEx.ArMarkerControls(arToolkitContext, markerRoot1, {
				type: 'pattern',
				patternUrl: THREEx.ArToolkitContext.baseURL + '../data/data/patt.hiro',
				// patternUrl : THREEx.ArToolkitContext.baseURL + '../data/data/patt.kanji',
			})
			// build markerControls for markerRoot2
			markerControls = new THREEx.ArMarkerControls(arToolkitContext, markerRoot2, {
				type: 'pattern',
				// patternUrl : THREEx.ArToolkitContext.baseURL + '../data/data/patt.hiro',
				patternUrl: THREEx.ArToolkitContext.baseURL + '../data/data/patt.kanji',
			})
		}

		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)
		})

			; (function () {

				//////////////////////////////////////////////////////////////////////////////
				//		markerRoot1
				//////////////////////////////////////////////////////////////////////////////

				// build markerControls



				// add a gizmo in the center of the marker
				var geometry = new THREE.OctahedronGeometry(0.1, 0)
				var material = new THREE.MeshNormalMaterial({
					wireframe: true
				});
				var mesh = new THREE.Mesh(geometry, material);
				markerRoot1.add(mesh);

				//////////////////////////////////////////////////////////////////////////////
				//		markerRoot2
				//////////////////////////////////////////////////////////////////////////////

				// add a gizmo in the center of the marker
				var geometry = new THREE.OctahedronGeometry(0.1, 0)
				var material = new THREE.MeshNormalMaterial({
					wireframe: true
				});
				var mesh = new THREE.Mesh(geometry, material);
				markerRoot2.add(mesh);
			})()


			; (function () {
				var markerRoot1 = scene.getObjectByName('marker1')
				var markerRoot2 = scene.getObjectByName('marker2')

				var container = new THREE.Group
				scene.add(container)

				// update container.visible and scanningSpinner visibility
				onRenderFcts.push(function () {
					if (markerRoot1.visible === true && markerRoot2.visible === true) {
						container.visible = true
						document.querySelector('.scanningSpinner').style.display = 'none'
					} else {
						container.visible = false
						document.querySelector('.scanningSpinner').style.display = ''
					}
				})

				//////////////////////////////////////////////////////////////////////////////
				//		build lineMesh
				//////////////////////////////////////////////////////////////////////////////
				var material = new THREE.LineDashedMaterial({
					dashSize: 1,
					gapSize: 1,
				});
				var geometry = new THREE.BufferGeometry();
				var vertices = new Float32Array([
					1.0, 0.0, -3.0,
					-1.0, 0.0, -3.0
				]);
				const positionNumComponents = 3;
				geometry.setAttribute('position',
					new THREE.BufferAttribute(new Float32Array(vertices), positionNumComponents));
				var lineMesh = new THREE.Line(geometry, material);
				container.add(lineMesh);

				// update lineMesh
				onRenderFcts.push(function () {
					var geometry = lineMesh.geometry
					vertices = [
						markerRoot1.position.x, markerRoot1.position.y, markerRoot1.position.z,
						markerRoot2.position.x, markerRoot2.position.y, markerRoot2.position.z,
					];
					geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
					geometry.verticesNeedUpdate = true

					geometry.computeBoundingSphere();
					lineMesh.computeLineDistances();

					var length = markerRoot1.position.distanceTo(markerRoot2.position)
					lineMesh.material.scale = length * 10
					lineMesh.material.needsUpdate = true
				})


				//////////////////////////////////////////////////////////////////////////////
				//		display the distance between the 2 markers
				//////////////////////////////////////////////////////////////////////////////

				// build texture
				var canvas = document.createElement('canvas');
				canvas.width = 128;
				canvas.height = 64;
				var context = canvas.getContext('2d');
				var texture = new THREE.CanvasTexture(canvas);

				// build sprite
				var material = new THREE.SpriteMaterial({
					map: texture,
					color: 0xffffff,
				});
				var sprite = new THREE.Sprite(material);
				sprite.scale.multiplyScalar(0.5)
				container.add(sprite)

				// upload measure
				onRenderFcts.push(function () {
					// update sprite position
					sprite.position.addVectors(markerRoot1.position, markerRoot2.position).multiplyScalar(1 / 2)

					// get the text to display
					var length = markerRoot1.position.distanceTo(markerRoot2.position)
					var text = length.toFixed(2)

					// put the text in the sprite
					context.font = '40px monospace';
					context.clearRect(0, 0, canvas.width, canvas.height);
					context.fillStyle = '#fff';
					context.fillText(text, canvas.width / 4, 3 * canvas.height / 4)
					sprite.material.map.needsUpdate = true
				})

			})()
		//////////////////////////////////////////////////////////////////////////////////
		//		render the whole thing on the page
		//////////////////////////////////////////////////////////////////////////////////

		// render the scene
		onRenderFcts.push(function () {
			renderer.render(scene, camera);
		})

		// 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>

	<!-- Scanning animation when the marker are not visible -->
	<div class="scanningSpinner">
		<label>
			Scanning
		</label>
		<div class="rect1"></div>
		<div class="rect2"></div>
		<div class="rect3"></div>
	</div>
	<style>
		.scanningSpinner {
			margin: 100px auto;
			height: 40px;
			text-align: center;
		}

		.scanningSpinner label {
			display: block;
			color: #333;
			font-size: 200%;
		}

		.scanningSpinner>div {
			background-color: #333;
			height: 100%;
			width: 6px;
			display: inline-block;

			-webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out;
			animation: sk-stretchdelay 1.2s infinite ease-in-out;
		}

		.scanningSpinner .rect2 {
			-webkit-animation-delay: -1.1s;
			animation-delay: -1.1s;
		}

		.scanningSpinner .rect3 {
			-webkit-animation-delay: -1.0s;
			animation-delay: -1.0s;
		}

		@-webkit-keyframes sk-stretchdelay {

			0%,
			40%,
			100% {
				-webkit-transform: scaleY(0.4)
			}

			20% {
				-webkit-transform: scaleY(1.0)
			}
		}

		@keyframes sk-stretchdelay {

			0%,
			40%,
			100% {
				transform: scaleY(0.4);
				-webkit-transform: scaleY(0.4);
			}

			20% {
				transform: scaleY(1.0);
				-webkit-transform: scaleY(1.0);
			}
		}
	</style>

</body>