使用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移動網絡應用程序。
不能低估發展中玩樂的重要性。





複製代碼
相關文章
相關標籤/搜索