🍣Processing for AndroidでARお寿司爆弾を実装する

# はじめに
この記事は[クソアプリ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/kuso-app) の3日目の記事です。
投稿が遅れてすみません（土下座）

今回はProcessing for AndroidのAR機能を使ってお寿司爆弾を作りました。
具体的には、**「スマホカメラから取り込んだ現実世界の映像にARでお寿司の3Dモデルを重ねて配置して、一定時間が経過するとお寿司のネタが吹っ飛ぶ」** というAndroidアプリを作成しました。
「作る目的は？」とか「どんな役に立つの？」とか、そんな問いはクソアプリ開発には無用でしょう！
考えすぎて我に返る前に完成させられるかが勝負です。では参りましょう！

# 完成品🍣
とりあえず完成品をご覧ください。
![osushi_single_low_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/828745/196c6878-55ca-448c-ca4f-31325d9fa223.gif)
こんな感じでタップした場所にARでお寿司が出現し、カウントダウンの後にネタが吹っ飛びます。ネタが地面に接触するとシャリとともに消滅します。複数を同時に設置することも可能です。
![osushi_many_short.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/828745/b4eca9bc-08f1-d499-7500-8028fcc3a380.gif)


# レシピ解説
では技術的な部分について解説していきます。

## Processing for Android
今回はAndroidアプリを作成するために[Processing](https://processing.org/)という言語を使用しました。Processingはデジタルアートの制作に特化した言語です。コンテンツ制作以外の煩わしい処理を自動で行ってくれるためユーザーはコンテンツの制作のみに集中することができます。
また、この言語はJavaの一部として動くように作られており、Processingで作成したスケッチをAndroid上で動かせるようにするためのライブラリが[Processing for Android](https://android.processing.org/)です。こちらもほとんどの操作が簡略化されており、ユーザーはAndroidアプリの開発に詳しくなくてもIDEに従って操作をすることで比較的簡単にスケッチをAndroid上で実行できるようになっています。

### AR in Processing
Processing for AndroidではAR機能も非常に簡単に利用することができます。
[Processing for Androidのチュートリアル](https://android.processing.org/tutorials/ar_intro/index.html)では、「3Dコンテンツを現実世界の映像に重ねて描画するためには、物体認識やデバイスの姿勢検知など複雑な処理を実装する必要があるが、これらを自動で計算するためのフレームワークとしてGoogleの提供するARCoreがある。ProcessingからARCoreに直接アクセスすることも可能だが、ProcessingのAndroidモードのARライブラリを通してARCoreを使用することでさらに簡単にARコンテンツを作成することができる。」と説明されています。
先ほどの完成品の映像の中でも、奥行を考慮した上でタップしたポイントにお寿司が置かれていたり、スマホの動きに合わせて視点が移動したりしていますが、特別にコードを書くことなく自動でこういった処理を行ってくれます。

## 開発の流れ
### お寿司の3Dデータを作成
まずARで描画するためのお寿司をつくります。Processingでは.objファイルを読み込むことができるため、.obj形式のお寿司を作ります。
今回は[Tinkercad](https://www.tinkercad.com/)を使用しました。
![maguro.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/828745/c605f776-4fdd-9e33-86f2-3b13da2b63e1.png)
こんな感じで握っていきます。
今回の実装ではネタを吹っ飛ばす時に、シャリとネタを分離する必要があるため最終的にそれぞれ別のobjファイルとして保存しました。右上のエクスポートボタンから.OBJを指定すると3Dモデルのメッシュ構造の情報を持つ.objファイルと色やテクスチャの情報を持つ.mtlファイルの組としてデータをダウンロードできます。

#### Tinkercadで作った3DモデルをProccessingで使用するときの注意点
Tinkercadで作った3DモデルをProccessingで使用するにあたっていくつか注意することがあります。
##### x軸回りの向き
Tinkercadで作成した3DモデルをそのままProcessingで読み込むとx軸回りに90度回転した向きで表示されてしまいます。そのためあらかじめTinkercadで作成する時点で下の画像のように90度回転させておくとProcessing側で扱いやすいです。
![osushi_tinker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/828745/b45e5a2e-2347-9fda-c4e7-29dbb254ea11.png)

##### ワークスペースの中心にオブジェクトを配置する
Tinkercadのワークスペースの中心にオブジェクトを配置しておかないとProcessingで読み込みだときに3Dモデルの座標がずれてしまいます。グリッドへのスナップなどをうまく使ってオブジェクトをワークスペースの中心に配置します。

##### オブジェクトの大きさ
Tinkercadで作ったオブジェクトをARを使用したProcessingで表示すると、思ったよりも3Dモデルが大きいことがあります。Tinkercad側で小さめに作っておくといいと思いますが、細かい調整はProcessing側の`scale()`関数で行うと良いと思います。

##### .mtlファイルの名前の変更
Tinkercadで作成した3Dモデルは.objファイルと.mtlファイルの組としてダウンロードされます。
当然これらのファイル名を変更したい場面もあると思いますが、特に.mtlファイル名を変更したときは注意が必要です。.objファイルは内部で.mtlファイルを読み込んでいるため、.mtlファイル名を変更したときはそのファイルを読み込んでいる.objファイルの中身を以下のように書き換える必要があります。
1. .objファイルをメモ帳等のテキストエディタで開く
1. `mtllib ~~.mtl` という部分を探す
1. `~~.mtl`を自分が変更した.mtlのファイル名に合わせる

### ProcessingによるARの実装
お寿司の3Dモデルができたので、いよいよコードを書いていきます。
コードを書くにあたって、公式サイトのチュートリアルの[サンプルコード](https://github.com/codeanticode/processing-android-tutorials/tree/master/ar/ex1_ar_intro)を参考にしました。
今回はProcessingのAndroidモードの環境構築については解説しません。[公式のチュートリアル](https://android.processing.org/tutorials/getting_started/index.html)等が参考になります。
実行環境は以下の通りです。どちらも絶妙に古いですが、最新のバージョンでも動くはずです。

#### 実行環境
- Processing 3.5.4
- Android 9

#### コードの解説
ProcessingでのARアプリ開発についての日本語の情報が少なく、僕自身今回の開発で苦労したこともあり、ARのスケッチに特有の書き方を中心に解説します。ソースコードとお寿司の3Dデータは[GitHub](https://github.com/keiyakeiya/kuso-app_Osushi-Bomb)にあります。

##### 3Dモデルの読み込み
先ほどTinkercadで作成した3Dモデルは、スケッチの.pdeファイルと同じ階層に`data`という名前のフォルダを作成しその中に配置します。`loadShape()`関数で読み込んで`PShape`クラスの変数に代入します。表示したいときは`shape(shari)`や`shape(neta)`のように使います。
```java:3Dモデルの読み込み
PShape shari;
PShape neta;

void setup() {
  shari = loadShape("shari.obj");
  neta = loadShape("neta.obj");
}
```

##### ARライブラリのインポート
ARを扱いやすくするために、[AR in Processing](#ar-in-processing)で説明したProcessingのARライブラリを使用します。
また`fullScren()`ではARレンダラを指定します。ARレンダラを使用することでスケッチをカメラ映像に重ねて、デバイスの動きを自動で更新してくれます。

```java:
import processing.ar.*; // ARライブラリをインポート
void setup() {
  fullScreen(AR); // ARレンダラを使用
}
```

##### ARライブラリで使用するクラス
AR機能を実装する際に必要になるクラスがいくつかあります。
###### ARTracker
ARのスケッチには1つ以上の`ARTracker`オブジェクトが必要で、カメラ映像から検出されたトラック可能な平面を扱うために使います。
###### ARTrackable
`ARTrackable`クラスは、`ARTracker`によって検出された平面を扱うためのクラスです。検出した平面の広さやその平面が床・天井・壁のどれなのかといった情報を取得したり、次に説明する`ARAnchor`を紐づけたりするために使用します。
###### ARAnchor
`ARAnchor`クラスは、`ARTrackable`オブジェクトに対して紐づけられた位置の情報を扱います。例えば画面をタップした時に、タップしたポイントが、ある一つの`ARTrackable`オブジェクトに対してどのような位置関係にあるか、といった情報を保存します。

##### それぞれのクラスの使いどころ
今回のプログラムで使用した場面を例に、それぞれのクラスの使い方を紹介します。
まず`ARTracker`については`setup()`内で使用する必要があります。これはもうテンプレートと考えていいと思います。

```java:ARTracker
import processing.ar.*;
ARTracker tracker; // ARTrackerクラスの変数を宣言

void setup() {
  fullScreen(AR);
  tracker = new ARTracker(this); // ARTrackerオブジェクトを作成
  tracker.start(); // start()メソッドでトラッキングを開始
}
```
タップ時に新しくお寿司を配置するときは通常のスケッチと同様`mousePressed()`内に処理を書いていきます。
`ARTrackable hit = tracker.get(mouseX, mouseY);`では`ARTracker`のメソッドを使ってタップしたポイントに存在するトラック可能な平面の`ARTrackable`オブジェクトを取得しています。
タップしたポイントにトラック可能な平面が存在した場合、`ARAnchor tapAnchor = new ARAnchor(hit);`でその平面に対するタップしたポイントの位置の情報を持つ`ARAnchor`オブジェクトを生成しています。この場面では、この`ARAnchor`オブジェクトこそお寿司を配置するために必要なアンカーの情報になります。
お寿司爆弾は自作の`Osushi`クラスで管理しており、それぞれのお寿司インスタンスに位置情報が必要なため、お寿司インスタンスを生成するときにこの`ARAnchor`オブジェクトを渡しています。

```java:タップ時の処理
ArrayList<Osushi> osushiBombs = new ArrayList<Osushi>(); //お寿司爆弾のインスタンスのリスト

// ----
// 省略
// ---

void mousePressed() {
  // お寿司の数をチェック
  if(osushiBombs.size() < maxOsushi) {
    ARTrackable hit = tracker.get(mouseX, mouseY);
    if (hit != null) {
      ARAnchor tapAnchor = new ARAnchor(hit);
      osushiBombs.add(new Osushi(millis(), tapAnchor));
    }
  }
}

// ----
// 省略
// ---

class Osushi {
// ----
// 省略
// ---
}
```

お寿司のレンダリングには先ほどの`ARAnchor`オブジェクトの情報を使います。
`this.anchor.attach();`を実行すると座標原点がアンカーの位置に移動します。
レンダリングが終わったら`this.anchor.detach();`で座標をもとに戻しています。
つまりこの2つのメソッドの間ではAR特有の難しいことを考えずに普通のスケッチと同様の感覚でコードを書くことができます。

```java:Osushiクラス
class Osushi {
// ----
// 省略
// ---
  ARAnchor anchor; //このお寿司のアンカー
  Osushi(int madeTimeIn, ARAnchor anchorIn) {
    this.madeTime = madeTimeIn;
    this.anchor = anchorIn;
  }
// ----
// 省略
// ---
  void render() {
    this.anchor.attach();
    pushMatrix();
      scale(this.scale*0.1);
      rotateY(this.muki);
      shape(shari);
      pushMatrix();
        translate(
            this.netaX.x,
            this.netaX.y,
            this.netaX.z
            );
        rotateZ(this.netaTheta.x);
        rotateY(this.netaTheta.y);
        rotateX(this.netaTheta.z);
        shape(neta);
      popMatrix();
    popMatrix();
    fill(0);
    pushMatrix();
      float x = this.remaining - floor(this.remaining);
      rotateY(TAU*x*x*(3-2*x));
      rotateX(PI);
      translate(0, -0.1, 0);
      scale(0.001);
      if(!this.isExploded) {
        text(round(this.remaining), 0, 0, 0);
      }
    popMatrix();
    noFill();
    this.anchor.detach();
  }
}
```
# まとめ
はじめてのARアプリ作成でしたが、ひとまず作りたかったものを形にすることができました🍣
ProcessingのARライブラリを使ってみて、やはりProcessingらしく難しい部分をユーザーが触らなくてもいいように仕組みを単純化してある印象を受けました。複雑なことをするためには不十分かもしれませんが、とりあえずARを使ってみたいという用途であればかなり扱いやすいと思います。
今回はここまででしたが、機会があればこのアプリをPlayストアでの配布までやりたいと思います。
ここまで読んでいただきありがとうございました！
# 参考
- [processing.org](https://processing.org/)
- [Processing - Wikipedia](https://en.wikipedia.org/wiki/Processing)
- [Processing for Android](https://android.processing.org/index.html)
- [AR in Processing](https://android.processing.org/tutorials/ar_intro/index.html)
- [Objファイル基礎 - yttm-work](https://yttm-work.jp/model_render/model_render_0001.html)