見出し画像

【技術解説】8thwallをつかったアプリ開発『Under Sea AR』

はじめに

こんにちは、デザイニウムの桐井です。
今回は、Niantic社の8thwallを使用して作成した"UNDER SEA AR "というARアプリについてご紹介したいと思います。

"UNDER SEA AR "は、周囲が海の中になったような気分が味わえるARアプリです。8thwallとThreejsを使用して開発しています。

アプリは、下記のリンクからスマートフォンで実際に試していただけます。
undersea-ar.web.app

開発環境について

8thwallでの開発には2種類のやり方があります。

1. Webブラウザから使用できるCloud Editorを使用して実装する方法
2. 任意のローカルEditorから開発する方法
 
の2種類があるので、それぞれのメリット、デメリットを紹介していきます。

1. Webブラウザから使用できるCloud Editorを使用する方法

メリット
すぐに実装を開始できる。
アプリが完成すればそのまま8thwallのホスティングサービスを利用してpublishできる。

デメリット
開発が非常にしづらい(オートコンプリート機能が効かない、バージョン管理の仕組みが使いにくい等々…

2. 任意のローカルEditorから開発する方法

メリット
自分の好みの環境で開発できる
プロジェクトの管理が用意

デメリット
開発をするまでに諸々と設定する必要がある
アプリをpublishにするには自分でホスティングサービスを用意しなければならない。

本当に簡単なものを作るにはCloud Editorでも良いのですが、ある程度のボリュームになればローカル環境での開発が必須のような気がします。
今回の"UNDER SEA AR"アプリもローカル環境下で開発しました。
こちらのリポジトリは8thwallが出しているもので、ベースにローカル開発を進めていく流れになっています。
https://github.com/8thwall/web

こちらは弊社のエンジニアが始めやすいようにある程度テンプレート化したリポジトリになります。わかりやすいのでおすすめです。https://github.com/Alex-DG/vite-8thwall-three-template

次項から、今回のアプリでこだわったところを数点解説していこうかと思います。

海の底のコースティクス表現

海の中を表現するために海中のコースティクス表現を考えました。
よくプールの底などに見えている模様のことです。

出典:https://www.comeluck.jp/54535.html

コースティクスができる原理は光の反射や屈折した光の集まりです。
フォトンマッピング(レンダリング方程式の近似解法)からある程度リアルにシミュレーションすることも可能なようですが、今回はそれっぽく見えれば良いということでセルラーノイズ(ウォーリーノイズ)を用いて模様を表現することにしました。
セルラーノイズ(ウォーリーノイズ)とは任意の点群からの最も近い点との距離によって出力されるノイズの一種のことです。
Steven Worleyによって 1996 年に開発されました。
基本的なアルゴリズムはこちらに記載されています。
 参照: https://thebookofshaders.com/12/?lan=jp

これを海底用のplaneに描画しています。

色味を調整する前の出力結果

色味をいい感じにして、境界線をぼかすようにしたらリアルにシミュレーションせずともそれっぽくはなったのではないでしょうか。

魚の群れの表現

もう一つが魚の群れの表現です。
バラバラに泳いでも良かったのですが、群れをなして泳いだほうが見栄えも良くなるかなと思い実装しました。
これも大変有名でシンプルなアルゴリズムがあります。群れ は 、鳥や魚、昆虫など多くの生物の特徴である、集団の動物行動です。クレイグ・レイノルズは、群れ行動のコンピューターシミュレーションを作成し、論文「Flocks,Herds,and Schools:A Distributed Behavioral Model[鳥 、家畜、魚の群れ:分散行動モデル]」 でそのアルゴリズムを発表しました。
よくBoidsアルゴリズムやFlockingアルゴリズムと呼ばれています。

アルゴリズムは至ってシンプルで、

  1. 分離 (Separation):近隣との衝突を避けるためのルール

  2. 整列(alignment):近隣と同じ方向に進むためのルール

  3. 結合(cohesion):近隣の中心に向かって集まっていくルール (集団を維持)

という3つのルールをそれぞれの個体(今回は魚のオブジェクト)に適用していく流れになります。

抜粋のコードになりますが、

分離:Separation
他の個体との距離が近ければ近いほど離れるような力を求めています。

separation (boids) {
  const vec = new THREE.Vector3(0, 0, 0);
  const myPos = this.position.clone();
    ...

  boids.forEach((o) => {
    const pos = o.position.clone();
    const dif = pos.sub(myPos).multiplyScalar(-1);
    const difLength = dif.length();

    vec.add(dif.normalize().divideScalar(difLength * difLength));
  });

  return vec.divideScalar(boids.length);
}


整列(alignment)
周囲の個体の速度に合わせるような力を求めています。

alignment (boids) {
  const vec = new THREE.Vector3(0, 0, 0);
  const myPos = this.position.clone();
  ...

  boids.forEach((o) => {
    vec.add(o.velocity);
  });

  const averageVelocity = vec.divideScalar(boids.length);
  const myVelocity = this.velocity;
  return averageVelocity.sub(myVelocity);
}


結合(cohesion)
個体が集まっていくような方向の力を求めています。

cohesion (boids) {
  const vec = new THREE.Vector3(0, 0, 0);
  const myPos = this.position.clone();
  ...
  
  boids.forEach((o) => {
    const pos = o.position.clone();
    vec.add(pos);
  });
  const averagePos = vec.divideScalar(boids.length);
  return averagePos.sub(myPos);
}


最後に求めたそれぞれの力にweightをかけて重み付けをして足し合わせることで各個体の加速度を求め更新していきます。

...
const separation = this.separation(boids).multiplyScalar(separatioWeight);
const alignment = this.alignment(boids).multiplyScalar(alignmentWeight);
const cohesion = this.cohesion(boids).multiplyScalar(cohesionWeight);

this.acceleration.add(separation.add(alignment).add(cohesion));
this.acceleration.divideScalar(
  separatioWeight + alignmentWeight + cohesionWeight,
);

より自然に見せたり、回転やアニメーションも考慮する場合はもっと書く必要がありますが基本的には3つのルールを各個体に適用することでアプリのような群れの表現を実装することができます。

さいごに

8thwallを使用して開発するメリットは、アプリのコンテンツ部分の実装に注力できることかなと思います。
簡単に、例えば何か3Dモデルを追加して動かすまでがとても早く手軽に試せるので、アイディアや表現部分に集中して実装することができます。最近はVPS機能も追加され、できることがどんどん増えているので非常にワクワクしています。

8thwallをつかった関連記事

The Designium.inc
Official website
Interactive website
Twitter
Instagram
Facebook


この記事が気に入ったらサポートをしてみませんか?