使用JSARToolKit5 开发AR应用 (1) 简介

相关站点

jsartoolkit5 - ARToolkit.js
html

Talkingdata - 用数据的心智去超越ios

three.js 系列教程 - 良心之做git


介绍

本文是使用JSARToolKit5构建加强现实(AR)Web应用程序的简短介绍。
咱们将要学习什么是JSARToolKit5,您可使用它AR应用程序,以及如何使用Three.js 3D引擎来构建3D AR对象。
我也会简要介绍一下AR是什么。

加强现实

加强现实是一个用于谈论将虚拟对象添加到现实世界中的术语。
你也可能据说过虚拟现实,这是关于将你运送到彻底虚拟的地方。
二者使用了不少相同的技术,但用例不一样。
使用AR,您能够将虚拟宜家家具放在您所在地的地板上,看看它们的外观与其余家具类似。
使用VR,您能够将本身传送到公寓的建筑蓝图中,看看建筑物的外观。
AR将东西添加到现实世界中,VR替代现实世界。


AR的另外一个用途是将智能添加到现实世界中。
灯光开关有一条线路,他们控制的光线,树叶告诉你什么样的树,名称悬停在人的头上,导航箭头出如今街上,天空中的线条指导你认识你的朋友,翻译显示在您正在查看的文字之上。
向世界增长知识和遥控器。
经过了解您正在查看的内容,您能够下拉所了解的内容以及您可使用的内容。

简而言之,JSARToolKit5是最新和最新版本的ARToolKit加强现实库的JavaScript端口。
您可使用JSARToolKit5将对象添加到图像和视频中,并使它们看起来像是现实世界场景的一部分。
不只如此,您还可使虚拟对象交互和动画化。

为了演示您可使用JSARToolKit5进行的应用程序种类,咱们将编写一个小型的AR应用程序,从设备的相机中增长视频。
该应用程序将在视频Feed中放置一个小框,您能够点击框打开它,并查看内部的内容。

让咱们开始吧!

JSARToolKit的基础知识

经过跟踪视频中的特殊图像,JSARToolKit能够起做用。
这些特殊图像称为AR标记,JSARToolKit能够肯定视频中的哪些位置以及它们指向的方向。
经过从JSARToolKit获取AR标记的位置和方向,您能够在正确的位置在视频顶部绘制3D对象,使其看起来像对象是视频的一部分。

要加载JSARToolKit,请将最小脚本包含在您的网页中。

<script src="build/artoolkit.min.js"></script>复制代码

是的,如你所想,咱们将须要三件事来构建咱们的AR应用程序。
咱们将须要一个AR标记,一个视频,以及在视频之上绘制3D图形的方法。
对于标记,咱们将使用一个特殊的内置标记,称为BarcodeMarker。
咱们将使用getUserMedia API从您的设备摄像头获取的视频。
咱们将使用Three.js来作3D图形。
咱们首先要作的是建立视频源。
为此,咱们将使用getUserMedia API获取设备摄像头的URL,而后使用该URL做为视频元素的源。
有了这个就可让视频元素来显示设备摄像头的视频信息。

全部这一切的简单方法是在JSARToolKit5中使用一个帮助函数:
选项对象中的onSuccess回调使用即用型视频元素进行调用。
请注意,在Android版Chrome上,只有在与网页进行互动后,才能播放手机影片。
ARController.getUserMedia添加了一个播放视频的窗口级触摸事件监听器。

ARController.getUserMedia(options)github

var video = ARController.getUserMedia({
	maxARVideoSize: 320, // do AR processing on scaled down video of this size
	facing: "environment",
	onSuccess: function(video) {
		console.log('got video', video);
	}
});复制代码

咱们须要作的第一件事就是建立一个ARController。
ARController跟踪咱们注册的标记,并从视频源中读出像素。

...

var arController = new ARController(video, 'Data/camera_para.dat');
arController.onload = function() {
	console.log('ARController ready for use', arController);
};

...复制代码

您也能够经过显式加载ARCameraParam来编写(也许您想要重用它):

...

var camera = new ARCameraParam('Data/camera_para.dat');
camera.onload = function() {
	var arController = new ARController(video.videoWidth, video.videoHeight, camera);
	console.log('ARController ready for use', arController);
};

...复制代码

从JSARToolKit获取标记位置

AR标记

标记是JSARToolKit用于跟踪视频和图像中对象的3D位置的特殊图像。
您能够将它们视为黑客,使软件更容易了解图像中的内容。
而不是必须了解整个图像,软件能够专一于在图像中找到矩形形状,并将矩形的内容与注册的标记进行比较。

如今咱们将视频链接,咱们已经准备好开始跟踪视频中的AR标记。
一旦咱们看到一个AR标记,咱们想获得它的细节,找出它在哪里和它指向哪个方向。

幸运的是,这个ARToolKit负责全部的计算,并给咱们一个很好的易于使用的转换矩阵。
获取视频中的标记。

// Set the ARController pattern detection mode to detect barcode markers.
arController.setPatternDetectionMode( artoolkit.AR_MATRIX_CODE_DETECTION );

// Add an event listener to listen to getMarker events on the ARController.
// Whenever ARController#process detects a marker, it fires a getMarker event
// with the marker details.
//
var detectedBarcodeMarkers = {};
arController.addEventListener('getMarker', function(ev) {
	var barcodeId = ev.data.marker.idMatrix;
	if (barcodeId !== -1) {
		console.log("saw a barcode marker with id", barcodeId);

		// Note that you need to copy the values of the transformation matrix,
		// as the event transformation matrix is reused for each marker event
		// sent by an ARController.
		//
		var transform = ev.data.matrix;
		if (!detectedBarcodeMarkers[barcodeId]) {
			detectedBarcodeMarkers[barcodeId] = {
				visible: true,
				matrix: new Float32Array(16)
			}
		}
		detectedBarcodeMarkers[barcodeId].visible = true;
		detectedBarcodeMarkers[barcodeId].matrix.set(transform);

	}
});

var cameraMatrix = arController.getCameraMatrix();

for (var i in detectedBarcodeMarkers) {
	detectedBarcodeMarkers.visible = false;
}

// Process a video frame to find markers in it.
// Each detected marker fires a getMarker event.
//
arController.process(video);复制代码

使用JSARToolKit与Three.js

如今咱们有从JSARToolKit的标记位置,咱们能够将它们复制应该出如今的标记的Three.js对象之上。
请注意,若是将标记移动到相机外部,则跟踪将丢失,而且Three.js对象将不会被更新。
你可使对象保持原来的位置,忽然消失或淡出。
我喜欢淡化已经失去跟踪的对象,但它能够有点垂手可得地控制对象中材料的全部不透明度。

很酷的是,跟踪标记的Three.js对象是一个普通的Three.js对象。
因此咱们可使用咱们全部的一般的技巧。
对于此演示,咱们将添加一个触摸事件处理程序来检测什么时候触摸对象并在执行时对对象进行动画处理。
下面的代码是一般的Three.js鼠标射线播放代码,它将一个从鼠标坐标的射线投射到3D场景,并检查射线对场景中的物体,看看它们中有任何一个与射线相交。
若是咱们找到一个交叉点,则意味着相交对象位于鼠标光标下方。
在你的tap事件侦听器和presto中添加raycasting代码!
你有一个能够打开的Three.js场景。

我添加了一个小动画到tap侦听器,因此当你点击框对象,它打开,东西飞出来。
要查看它,请访问演示页面,并容许访问您的相机。
如今把你的相机放在一张带标记的一张纸上。
Hohoo,你如今能够看到这个盒子。
点击它打开它!

在代码方面 JSARToolKit5中使用Three.js集成。
它完成了咱们上面设置的全部东西,并将其打包成几个易于使用的方法。
只需加载

js/artoolkit.three.jscanvas

<script src="build/artoolkit.min.js"></script>
<script src="js/artoolkit.three.js"></script>
<script>
ARController.getUserMediaThreeScene(
	facing: 'environment',
	onSuccess: function(arScene, arController, arCameraParam) {

		arController.setPatternDetectionMode(artoolkit.AR_MATRIX_CODE_DETECTION);

		// Track the barcode marker with id 20.
		// markerRoot is a THREE.Object3D that tracks the marker position.
		//
		var markerRoot = arController.createThreeBarcodeMarker(20);

		// Add the openable box to the marker root.
		//
		var box = createOpenableBox();
		markerRoot.add(box);

		// Add the marker root to the AR scene.
		//
		arScene.scene.add(markerRoot);


		// Add event handlers to make the box open/close on tap.
		//
		window.addEventListener('touchend', function(ev) {
			if (box.hit( ev.touches[0], arScene.camera )) {
				box.toggleOpen();
			}
		}, false);

		window.addEventListener('mouseup', function(ev) {
			if (box.hit( ev, arScene.camera )) {
				box.toggleOpen();
			}
		}, false);


		// Create renderer and deal with mobile orientation.
		//
		var renderer = new THREE.WebGLRenderer({antialias: true});
		var f = Math.min(
			window.innerWidth / arScene.video.videoWidth,
			window.innerHeight / arScene.video.videoHeight
		);
		var w = f * arScene.video.videoWidth;
		var h = f * arScene.video.videoHeight;

		if (arController.orientation === 'portrait') {
			renderer.setSize(h,w);
			renderer.domElement.style.transformOrigin = '0 0';
			renderer.domElement.style.transform = 'rotate(-90deg) translateX(-100%)';
		} else {
			renderer.setSize(w,h);
		}
		document.body.appendChild(renderer.domElement);


		// Call arScene.renderOn on each frame,
		// it does marker detection, updates the Three.js scene and draws a new frame.
		//
		var tick = function() {
			requestAnimationFrame(tick);
			arScene.renderOn(renderer);
		};
		tick();

	}
);
</script>复制代码

在Firefox Android或Chrome Android上最佳浏览。
也能够在桌面浏览器上工做,尽管与网络摄像头视频进行互动有点麻烦。
不幸的是,iOS不支持网站上的实时摄像机,所以您没法在iOS上观看此演示。

(ios11 目前支持)segmentfault

没有助手的JSARToolKit和Three.js

好的,因此这样你能够和帮助者一块儿作一个Three.js的场景。
也许你不想由于某些缘由使用助手。
或者您要将JSARToolKit与其余绘图库一块儿使用。
很好,让我来看看你如何使用原始的JSARToolKit与Three.js。

手动执行Three.js集成并非那么多工做,只须要一堆样板。
首先,咱们须要使用getMarker事件侦听器跟踪标记。
如下,我将跟踪ID 20的条形码标记的位置和可见性。

// Create a marker root object to keep track of the marker.
//
var markerRoot = new THREE.Object3D();

// Make the marker root matrix manually managed.
//
markerRoot.matrixAutoUpdate = false;

// Add a getMarker event listener that keeps track of barcode marker with id 20.
// 
arController.addEventListener('getMarker', function(ev) {
	if (ev.data.marker.idMatrix === 20) {

		// The marker was found in this video frame, make it visible.
		markerRoot.visible = true;

		// Copy the marker transformation matrix to the markerRoot matrix.
		markerRoot.matrix.elements.set(ev.matrix);

	}
});

// Add a cube to the marker root.
//
markerRoot.add( new THREE.Mesh(new THREE.BoxGeometry(1,1,1), new THREE.NormalGeometry()) );

// Create renderer with a size that matches the video.
//
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(video.videoWidth, video.videoHeight);
document.body.appendChild(renderer.domElement);

// Set up the scene and camera.
//
var scene = new THREE.Scene();
var camera = new THREE.Camera();
scene.add(camera);
scene.add(markerRoot);

// Make the camera matrix manually managed.
//
camera.matrixAutoUpdate = false;

// Set the camera matrix to the AR camera matrix.
//
camera.matrix.elements.set(arController.getCameraMatrix());

// On each frame, detect markers, update their positions and
// render the frame on the renderer.
//
var tick = function() {
	requestAnimationFrame(tick);

	// Hide the marker, we don't know if it's visible in this frame.
	markerRoot.visible = false;

	// Process detects markers in the video frame and sends
	// getMarker events to the event listeners.
	arController.process(video);

	// Render the updated scene.
	renderer.render(scene, camera);
};
tick();复制代码

不要让上面的吓到你,它只是获得了不少评论的几行代码。
这意味着渲染渲染器上的AR场景并跟踪条形码标记。
您可能还想将AR场景叠加在视频Feed的顶部。
咱们补充一点。
没有什么太复杂,只是在其余任何事情以前用视频绘制飞机。

// To display the video, first create a texture from it.
var videoTex = new THREE.Texture(video);

// Use linear downscaling for videoTex
// (otherwise it needs to be power-of-two sized and you
// need to generate mipmaps, which are kinda useless here)
videoTex.minFilter = THREE.LinearFilter;

// And unflip the video Y-axis.
videoTex.flipY = false;

// Then create a plane textured with the video.
var plane = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(2, 2),
  new THREE.MeshBasicMaterial({map: videoTex, side: THREE.DoubleSide})
);

// The video plane shouldn't care about the z-buffer. plane.material.depthTest = false; plane.material.depthWrite = false; // Create a scene and a camera to draw the video. var videoScene = new THREE.Scene(); var videoCamera = new THREE.OrthographicCamera(-1, 1, -1, 1, -1, 1); videoScene.add(videoCamera); videoScene.add(plane); // Set the renderer autoClear to false, otherwise it // clears the canvas before each render call. renderer.autoClear = false; // Draw the videoScene before the AR scene. var tick = function() { requestAnimationFrame(tick); markerRoot.visible = false; arController.process(video); // Clear the renderer before drawing the videoScene, // followed by the AR scene. renderer.clear(); renderer.render(videoScene, videoCamera); renderer.render(scene, camera); }; tick();复制代码


JSARController ARController具备内置的肖像模式校订功能。
因此,若是你经过一个肖像模式的视频,它旋转90度,使景观照相机参数正常工做。
其结果是,您的渲染器画布最终在其侧面,这不是我想要的。
如下是如何纠正它:

// Rotate the video plane and the renderer if the arController is in portrait mode.
if (arController.orientation === 'portrait') {
	plane.rotation.z = Math.PI/2;

	renderer.setSize(video.videoHeight, video.videoWidth);
	renderer.domElement.style.transformOrigin = '0 0';
	renderer.domElement.style.transform = 'rotate(-90deg) translateX(-100%)';
} else {
	renderer.setSize(video.videoWidth, video.videoHeight);	
}复制代码

如何编写ARToolKit 风格的代码

若是你以为这个整个事件循环不是你的风格。
JSARToolKit5还暴露了C风格的ARToolKit API。
由于这很符合你们的思惟习惯!

如下是ARtoolkit使用C风格处理Marker的循环方法:api

// Detect barcode markers
arController.setPatternDetectionMode(artoolkit.AR_MATRIX_CODE_DETECTION);

// Process the video frame.
arController.detectMarker(video);

var markerMatrix = new Float32Array(12);
var glMatrix = new Float32Array(16);

// Get the number of markers from the ARController and iterate over each marker.
var markers = arController.getMarkerNum();
for (var i=0; i < markers.length; i++) {

	var marker = arController.getMarker(i);

	// If we found the number 5 marker, let's get its transform matrix. if (marker.idMatrix === 5) { arController.getTransMatSquare(i, 1 /* marker width */, markerMatrix); // And convert it to a WebGL matrix. arController.transMatToGLMat(markerMatrix, glMatrix); // Do something with the glMatrix ... } }复制代码

若是咱们在前一帧中看到了标记,咱们可使用先前的标记矩阵做为矩阵计算的输入。
经过使用先前的矩阵做为当前矩阵计算的基础,咱们能够实现更稳定的跟踪。

// ... skip to the marker detection loop
if (marker.idMatrix === 5) {
	if (markerWasInPreviousFrame) {
		// Get the marker matrix using continuous tracking
		arController.getTransMatSquareCont(i, 1, markerMatrix, markerMatrix);
	} else {
		arController.getTransMatSquare(i, 1, markerMatrix);	
	}

	// ... The rest is as usual
}
复制代码

Emscripten?如何调试?

哦,是的,ARToolKit库的JSARToolKit5端口由Emscripten提供支持,Emscripten是使人惊奇的C / C ++到ASM.js编译器。
所以,JSARToolKit5在Firefox附近以原始速度运行,而在其余浏览器上运行速度也不算过高。
并且,更好的是,从上游库移植新功能和改进只是一个编译(您须要添加几行绑定。)

所以,JSARToolKit带有两种变体。
一个是调试版本,内置全部调试符号,使生活更容易调试代码库的C ++端。
另外一个是通过优化的优化版本,加载和运行速度更快。

要使用调试版本,加载 build/artoolkit.debug.js并js/artoolkit.api.js进入您的页面。该

artoolkit.api.js文件包含与ARController和ARCameraParam的实现一块儿的C ++ < - > JS API绑定。浏览器

<script src="build/artoolkit.debug.js"></script>
<script src="js/artoolkit.api.js"></script>复制代码

结论

如今你知道JSARToolKit是一个在视频和图像中跟踪AR标记的库。
您还知道AR标记是特殊图像,而且它们在JSARToolKit中有三种不一样的类型。
您也能够知道,您可使用Three.js在视频中的AR标记之上绘制3D图形(您固然知道如何使这种状况发生!由于您很棒,而且阅读了代码示例!)

我但愿你可以采起这些杂事,并使用它们来构建使人眼花缭乱的AR应用程序的将来,使每一个人的生活变得更好,甚至没法想象会有多好(A LOT BETTER)。
或至少有乐趣制做一些AR移动网络应用程序。
不能低估发展中玩乐的重要性。





复制代码
相关文章
相关标签/搜索