介紹html
JSARToolKit5是一個WebAR庫。這是我對JSARToolKit5的初次學習將其翻譯了出來水平有限敬請斧正。git
github: github.com/artoolkit/j…github
這篇文章簡要的說明了如何用JSARToolKit5建虛擬現實WebAPP。咱們講學習什麼是JSARToolKit5,什麼類型的ARAPP你可使用以及若是若是用ThreeJS 3D引擎去構建3D部件。我也將簡要的闡述AR是什麼以及我認爲何AR是酷炫的。canvas
簡要的說JSARToolKit5 是ARToolKit 庫的JS部分。你可使用JSARToolKit5 將對象加入圖像或者影像之中,使其彷彿位於真實世界之中。不只如此你可讓虛擬對象鮮活可交互(interactive and animated)。api
爲了證實這類應用是咱們能夠用JSARToolKit5製做出來的咱們將寫一個小的AR應用增長影像到攝像頭上。這個應用能夠講一個小的盒子放在視頻流中你能夠點擊盒子打開它而後能夠看到盒子裏面有什麼。 JSARToolKit的基礎瀏覽器
JSARToolKit 的工做原理是跟蹤視頻中的特殊的影像。這些特殊的影像叫作AR markers,JSARToolKit 可以分辨出他們在視頻流中的位置以及他們指向哪那個方向。經過得到AR markers位置和方向你能夠在影像的上面正確的畫出3D的對象,讓其彷彿就在其中。想要加載JSARToolKit將壓縮的script放到網頁中便可。bash
咱們須要三樣東西來構建AR應用。包括AR marker、一個攝像頭以及一個將三維對象畫到攝像頭上的方式。針對marker咱們將使用一個特別的嵌入式marker--"BarcodeMarker"。攝像頭咱們將使用設備攝像頭(經過getUserMedia API實現)。對於三維部件將使用Three.js實現。首先咱們將完成攝像頭資源的設置。咱們將使用getUserMedia API得到攝像頭的URL以後這個URL將做爲video對象的資源(video html標籤)。經過這個咱們將得到一個video元素來展現視頻流。app
這個實現的一個簡單方式是使用一個JSARToolKit5的輔助函數ARController.getUserMedia(options). 成功回調將帶回一個能夠被使用的video元素。注意在Chrome for Android手機視頻只有在與頁面進行交互以後纔會執行。ARController.getUserMedia 添加了一個窗口級別的觸摸事件來操做視頻元素。less
咱們要作的第一件事就是建立ARController。ARController保持着追蹤已經註冊的標記(markers )而且從數據中讀取視頻資源。咱們如今來建立新奇的視頻元素( video element)。同時咱們應該明確的寫出ARCameraParam 有助於複用。dom
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);
}
});
var arController = new ARController(video, 'Data/camera_para.dat');
arController.onload = function() {
console.log('ARController ready for use', arController);
};
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);
};
複製代碼
如今咱們有個視頻鉤子( video hooked)掛接到了管理器上咱們也準備追蹤AR markers攝像頭中的AR markers。當咱們看到AR markers咱們想知道他的細節包括他在那裏以及他的位置。
幸運的是ARToolKit 準備了全部的數學並給咱們了一個能夠重用的變化矩陣來找出攝像頭中的marker。
// 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找到了標記爲止,咱們能夠將其拷貝到應該被展現到marker上面的Three.js對象。注意若是逆向移動marker 出攝像頭外追蹤會消失而且Three.js不會得到更新。你可讓他待在原地,讓他忽然消失或者淡出。我更傾向於淡出失去跟蹤的對象,可是他須要對於對象有着高精度的控制。
最酷的事情是Three.js object跟蹤的marker是一個普通的Three.js object。因此咱們能夠用普通的技巧來處理如今的工做。在這個例子上咱們使用一個接觸時間來判斷你何時敲這個對象以及處理。下面的代碼是Three.js 鼠標光線跟蹤代碼。他從鼠標的位置投射出一個光線到3D場景而且檢查投射到物體上的光線是否又被阻擋隔斷的狀況,若是找到了隔斷也就是意味着鼠標在物體上面。這樣就能夠作出一個可以敲擊的Three.js 場景。
我添加了一個小的渲染到了敲擊時間上,這樣當點擊盒子對象時他會打開。爲了檢查,打開demo頁並將攝像頭打開。如今你的相機是一個平面的marker點擊會出現效果。
代碼方面,我用了Three.js 交互在JSARToolKit5中。他處理了上面所說的全部東西,並造成了一些簡單的方法。把js/artoolkit.three.js加上就行。以上的示例Firefox Android or Chrome Android支持桌面也能夠IOS能夠徹底不支持。
<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>
複製代碼
沒有幫助的JSARToolKit 和Three.js
也許你不想使用helpers。或者你想用JSARToolKit結合其餘的繪製庫,下面將介紹如何使用未集成JSARToolKit 庫。
手動集成JSARToolKit 並不須要太多的工做。首先我須要跟蹤markers經過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場景以及跟蹤barcode marker。你能夠在攝像頭上面覆蓋AR場景。只須要在攝像頭的上賣弄疊加一個平面。
// 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(); // 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 還支持C方式進行API調用。 it's pretty neat(原文)。若是你看到了marker在以前的幀。咱們能夠用以前的marker矩陣做爲輸入進行矩陣計算。經過使用以前的矩陣做爲基礎來做計算咱們能夠達到基本的追蹤。 Emscripten?如何調試?
JSARToolKit5 是JSARToolkit 庫的一部分由Emscripten實現的。因爲使人驚奇的C / C ++到ASM.js編譯器。JSARToolKit5 運行了一個近乎本地的速度,在其餘的瀏覽器也不是太笨重。而且更好的是,而且若是從上游庫更新只須要一個編譯。(也可能須要一些添加行用於綁定)
結果、JSARToolKit 有兩個版本一個是調試版構建完整的全部調試符號,使生活便於調試代碼庫的C ++端。另一個是壓縮版用於加載和編譯。
用 build/artoolkit.debug.js and js/artoolkit.api.js 就能夠進行調試。artoolkit.api.js文件包含ARController和ARCameraParam的實現的C ++ < - > JS API綁定
我將繼續推動。