0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AR.jsにおけるgroupを作成して表示を可能にする理由について

Posted at

markerRoot = new THREE.Group() を使っているのは、AR.js のマーカー検出結果を「まとめて受け止める”空のコンテナ”」として機能させるためです。詳しく分解すると…

  1. マーカー座標系の原点を作る

    • ArMarkerControls は「マーカーを見つけたら、その位置・向きの変換行列(model‐view 行列)を指定のオブジェクトにコピーする」仕組みです。
    • 直接 scenecamera にコピーするとシーン全体やカメラの挙動がおかしくなるので、まずは “何も描かれていない空の Object3D” に書き込みます。
  2. 複数のメッシュを一括管理できる

    • THREE.Group は子オブジェクトを複数持てるコンテナです。
    • markerRoot.add(meshA, meshB, …) のように、マーカー上に表示したいモデル(立方体や glTF、UI など)をまとめて markerRoot の子にぶら下げれば、 → markerRoot の行列更新だけで 中のすべての子メッシュ が一斉に正しい位置・角度に動きます。
  3. シーン構造をシンプルに保つ

    • Group を使わずに、いきなり scene.add(mesh) をしてしまうと、マーカーが見えないときでもオブジェクトがちらついたり、座標系の切り替え処理が複雑になります。
    • markerRoot.visible を使えば「マーカー未検出時は markerRoot 以下をまるごと非表示にする」なども簡単に制御できます。

まとめ

  • markerRootTHREE.Group)=マーカーの座標系(原点)
  • ArMarkerControls → markerRoot.matrix を更新
  • markerRoot の子に追加したモデル群が「マーカーにくっついて動く」

という役割分担にすることで、シーン/カメラ本体には手を入れずに、マーカーに連動したコンテンツだけをグルーピングして管理できるようになるわけです。
ほぼそのとおりです。

厳密には、markerRoot 自体が「マーカー検出結果を書き込まれるオブジェクト(=ArMarkerControls が行列を設定するターゲット)」で、その下に「実際に表示したいメッシュやモデル」をぶら下げるイメージです。

  1. ArMarkerControls が起動時に登録された markerRoot の行列(markerRoot.matrix)を、毎フレーム「検出されたマーカーの位置・向き」に書き換え
  2. その結果として、
    markerRoot.add( yourMesh );  // 例えばこんな感じで
    
    でぶら下がった yourMesh は自動的に「マーカーに追従して動く」

──という順序になります。ですので「①マーカー検出結果をどうオブジェクトに反映させるか」は markerRoot 自体の役割、「②表示するオブジェクト」はその子要素、という扱いで正しい理解です。

 たとえば、以下のように具体的な数値を使って考えてみましょう。


例:マーカー検出結果から得られる markerRoot.matrix

AR.js 側でマーカーを検出すると、以下のようなワールド変換行列(4×4)が markerRoot.matrix にセットされたとします。

R₁₁ = cos 45° ≈ 0.707 0 R₁₃ = sin 45° ≈ 0.707 Tₓ = 0.2
0 1 0 Tᵧ = 0.1
R₃₁ = –sin 45° ≈ –0.707 0 R₃₃ = cos 45° ≈ 0.707 T_z = –1.3
0 0 0 1
  • ここで 回転は Y 軸まわりに 45°(マーカー面がやや横を向いている)
  • 並進(Tₓ, Tᵧ, T_z)はマーカー原点がワールド(カメラ座標系)上の (0.2, 0.1, –1.3) にある

markerRoot の子オブジェクト(メッシュ)の配置例

1. 子メッシュをマーカー原点に置く

// ローカル座標で (0, 0.5, 0)=マーカーの真上 0.5m
cube.position.set(0, 0.5, 0);
markerRoot.add(cube);

ワールド座標

x = Tₓ + (0.707 * 0 + 0.707 * 0) = 0.2  
y = Tᵧ +      1 * 0.5        = 0.1 + 0.5 = 0.6  
z = T_z + (–0.707 * 0 + 0.707 * 0) = –1.3

(0.2, 0.6, –1.3) にキューブが置かれる


2. 子メッシュをマーカー原点の右側に 1mずらす

// ローカル座標で (1, 0, 0)=マーカー右側 1m
cube2.position.set(1, 0, 0);
markerRoot.add(cube2);

ワールド座標

x = Tₓ + (0.707 * 1 + 0.707 * 0) = 0.2 + 0.707 = 0.907  
y = Tᵧ +      1 * 0          = 0.1  
z = T_z + (–0.707 * 1 + 0.707 * 0) = –1.3 – 0.707 = –2.007

(0.907, 0.1, –2.007) にキューブ2が置かれる


なぜ Group() が必要か、振り返り

  1. マーカーの回転・平行移動(上の R, T)をまず markerRoot.matrix に一括で設定

  2. その下にぶら下がっているすべての 子オブジェクト(cube, cube2 …)

    • ローカル座標で指定した (x, y, z) を
    • 上記行列でワールド座標に変換され

    自動的に「マーカーに対する相対位置」を保ったまま動きます。


具体的な流れ

  1. AR.js → markerRoot.matrix = 上の回転+並進行列
  2. Three.js → markerRoot.updateMatrixWorld() により、
    • 各子オブジェクトのワールド行列が markerRoot.matrix * 子オブジェクト.matrix として計算
  3. レンダラー → それぞれのワールド行列から画面に投影

――というわけで、「① マーカー検出結果(R,T)を書き込むのが markerRoot」「② その下に置いたメッシュが具体的に描画される」 という役割分担だ、という実感が掴めると思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?