本記事ではThree.jsを使ったARコンテンツの実装シリーズ第一弾として、Three.js×AR.jsでマーカーベースARを実装していきます。
▼Three.jsのAR開発記事 第二弾
マーカーなし(マーカーレス)ARはこちらをご覧ください
1. ARマーカーの用意
まずはARマーカーを用意していきましょう。
AR.jsではプリセット(デフォルト)のマーカーか、オリジナルのマーカーを使用するか選択できます。
プリセットのマーカーは以下の「Hiro」マーカーと「Kanji」マーカーの2種類。
こちらを使用する場合はこの章を読み飛ばしてください。
オリジナルの画像でマーカーを用意したい場合は、専用のマーカーファイルである.pattファイルを作る必要があります。
こちらのマーカージェネレーターで、.pattファイルを作成します。
AR.js Marker Training
左の「UPLOAD」を選択し好きな画像を選択。
また、お好みで「UPLOAD」ボタンの下にあるPattern Ratio(枠の太さ)、Image size(画像サイズ)、Border color(枠の色)を調節してください。
※Pattern Ratioを変更した場合は、後ほどコード側で指定する必要があるため数値を覚えておきましょう。
調節が終わったら「DOWNLOAD MARKER」を選択して.pattファイルを出力します。
実際にかざして使う画像データは「DOWNLOAD IMAGE」を選択すると出力できます。
筆者は以下のようなマーカーを作成。🐄
※マーカーの認識精度:
使用する画像によって認識精度の安定/不安定が変わります。試してみて、認識が安定しない場合は画像を変更してマーカーを作ってみるのがいいかもしれません。
詳しくはこちらの記事もご覧ください。
2. シーンの作成
マーカーが準備できたら早速シーンを用意していきます。
まずはthree.jsとar.jsのcdnを用意します。
▼index.html
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.js"></script>
<script src="https://raw.githack.com/AR-js-org/AR.js/3.1.0/three.js/build/ar.js"></script>
</head>
Three.jsシーン作成
次にThree.jsのシーンを作成しつつ、threex-artoolkitを使用してARの処理を書いていきます。
※threex-artoolkitは、AR.jsがベースとしているartoolkitをThree.jsで簡単に扱えるようにする拡張機能です。
▼script.js
let w;
let h;
let canvas;
let scene;
let camera;
let renderer;
let object;
let arToolkitSource;
let arToolkitContext;
const init = () => {
w = window.innerWidth;
h = window.innerHeight;
canvas = document.getElementById("canvas");
setScene();
setCamera();
setObject();
setArToolkit();
setRenderer();
};
const setScene = () => {
scene = new THREE.Scene();
scene.visible = false;
};
const setCamera = () => {
camera = new THREE.PerspectiveCamera(45, w / h, 0.1, 30);
scene.add(camera);
};
const setArToolkit = () => {
arToolkitSource = new THREEx.ArToolkitSource({
sourceType: "webcam",
});
arToolkitSource.init(() => {
setTimeout(() => {
onResize();
}, 2000);
});
arToolkitContext = new THREEx.ArToolkitContext({
cameraParametersUrl:
THREEx.ArToolkitContext.baseURL + "../data/data/camera_para.dat",
detectionMode: "mono",
// ※1 作ったマーカーのPattern Ratioを入れる
patternRatio: 0.8,
});
arToolkitContext.init(
(onCompleted = () => {
camera.projectionMatrix.copy(arToolkitContext.getProjectionMatrix());
})
);
let onRenderFcts = [];
onRenderFcts.push(() => {
if (arToolkitSource.ready === false) return;
arToolkitContext.update(arToolkitSource.domElement);
scene.visible = camera.visible;
});
const markerControls = new THREEx.ArMarkerControls(arToolkitContext, camera, {
type: "pattern",
// ※2 マーカーのpattファイルのパスを入れる
patternUrl: "/static/patt/marker.patt",
changeMatrixMode: "cameraTransformMatrix",
});
};
const setObject = () => {
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshNormalMaterial();
object = new THREE.Mesh(geometry, material);
object.position.set(0, 0, 0);
scene.add(object);
};
const setRenderer = () => {
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
canvas: canvas,
});
renderer.setClearColor(0x000000, 0);
renderer.setSize(w, h);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setAnimationLoop(() => {
render();
});
};
const render = () => {
if (arToolkitSource.ready) {
arToolkitContext.update(arToolkitSource.domElement);
scene.visible = camera.visible;
}
renderer.render(scene, camera);
};
const onResize = () => {
arToolkitSource.onResizeElement();
arToolkitSource.copyElementSizeTo(renderer.domElement);
if (arToolkitContext.arController !== null) {
arToolkitSource.copyElementSizeTo(arToolkitContext.arController.canvas);
}
};
window.addEventListener("resize", () => {
onResize();
});
window.onload = () => {
init();
};
※1の箇所では、前章でオリジナルマーカーのpatternRatioを変更している場合は、patternRatioの数値を必要に応じて変更します。
patternRatioを変更していない/プリセットのマーカーを使用している場合は、patternRatio自体の記述を削除してしまってOKです。
※2の箇所ではマーカーの.pattファイルのパスを記入します。
プリセットのHiro/Kanjiマーカーを使用する場合は以下のようにします。
▼Hiroマーカー
patternUrl: THREEx.ArToolkitContext.baseURL + "../data/data/patt.hiro"
▼Kanjiマーカー
patternUrl: THREEx.ArToolkitContext.baseURL + "../data/data/patt.kanji"
無事に表示されました。
検証
うまく表示されない場合は、※1のpatternRatioの数値が合っているかをご確認ください。
また、マーカーが正常に認識できているか確認したい場合は、markerControls
を定義した後に以下のイベントを入れてみましょう。
markerControls.addEventListener("markerFound", () => {
// マーカーが見つかっている時は毎秒呼ばれる
console.log("marker found");
});
このmarkerFound
イベントはカメラ映像からマーカーが検出されている間は毎秒呼ばれるため、そもそもマーカーが検出されているか、マーカーは検出できているがオブジェクトの描画がうまくいっていないか…を検証できます。
パラメーター
その他、threex-arttoolkitを構成する3つのクラスArToolkitSource
、ArToolkitContext
、ArMarkerControls
は、渡すパラメーターによって検出の仕方などの微調整ができます。
詳しくはAR.jsのドキュメントをご覧ください。
まとめ
今回はARマーカーを使用したThree.js×AR.jsの基本的な実装をご紹介しました。
次回はマーカーなしの実装についての記事を書きたいと思っております、お楽しみに。