touchdesignerでの展示(http://www.ycam.jp/events/2017/hosoo/)投入レポート

# touchdesignerを触って一ヶ月で展示するまでの知見

## 対象
タッチを触って間もない人、タッチを触ろうか買おうか迷ってる人

## 前振り

![IMG_0007.jpg](https://qiita-image-store.s3.amazonaws.com/0/11590/e0b2a075-712a-74f6-6385-e1e081fc00a2.jpeg)

http://www.ycam.jp/events/2017/hosoo/
今月9日から、YCAMという美術館で”布のデミウルゴス”という展示が始まりました。
慶應義塾大学筧研究室では、西陣織に様々な素材を織り込む実験を行い、その成果物を展示しています。

その中の一つで、ドットパターンが印刷された紙を指し示すとその位置情報が取れる「アノトペン」を使った作品に、TouchDesignerを活用することにしました。
TD歴1ヶ月ちょいにも関わらずアドカレに参加してしまったので、1ヶ月あればこんくらいはできる＆展示等で使いがちなTipsの備忘録的なところを書いていこうと思います。

## 要件
![IMG_9920.jpg](https://qiita-image-store.s3.amazonaws.com/0/11590/2a50bf19-f8b6-006e-cc6e-f7c92ad8ccc8.jpeg)
職人さんから来たデータを元に西陣織の3Dモデルを作成。
特殊な紙を織り込んだ布に対してアノトペンで指し示した場所のレイヤー構造をズームして見ることができ、更にレイヤー構造の情報を拾って会場に流れる音響にも変化を与えます。

## touchdesignerで作る

「センサのデータを受けて3Dモデルを表示しているカメラを動かす」という、やることは比較的シンプル＆現場で色々と調整したい＆単純に触ってみたいという理由から、touchdesignerを採用してみました。

### LineSOPを使い、touchdesignerで西陣織を織る
####.chanフォーマットの活用
今回の西陣織は1種類の縦糸と、3種類の横糸+アノトペン用のシートが織り込まれていて、そのデータは職人さんからBMPでいただいていました。
さすがにこのデータのパースをTDでやるのはちょっと手間取りそうだったので今回はoFで糸が「何層目にいるか」という情報を記録した.chanファイルを作成しました。

.chanファイルはテキストでChannelデータを作れるので、以下のようなノリでoFでも簡単に書き出せます

```cpp
//vector<ofVec3f> tateLineのY座標を.chanに入れる
string tate_chan = "";

for (int i = 0;i < tateLine.size();i++)
	tate_chan += ofToString(tateLine[i].y) + "\n";

ofBuffer buf;
buf.append(tate_chan);
ofBufferToFile("tate.chan", buf);
```
####Point SOPで変形
書き出したチャンネルを適用するため、LineSOP->copy->Pointの順で組んでいきます。
https://vimeo.com/90916787
Line SOPを変形させる方法はここが分かりやすくて参考にしました。

<img width="1295" alt="スクリーンショット 2017-12-08 14.59.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/11590/3d35b3a0-cdb5-561a-1154-2ed7d9cb7c07.png">

経糸６００本、緯糸１３６８なので、経糸の場合は１３６８の頂点を持つLineSOPを、６００本コピーします。
Y座標の高さをPoint SOP内で
```
me.inputPoint.y + op('filein1')['chan1'].eval(me.inputPoint.index)
```
として、file in CHOPから持ってきたoFのデータと足し合わせました。ラインの頂点に凹凸ができて、織りの模様が見えてきます。

<img width="1610" alt="スクリーンショット 2017-12-08 14.57.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/11590/6c946748-afc3-41d9-e74b-628788e9f8a4.png">

とここまでの段階で、今回の織り図案が600本 x 1368本 = 82万頂点で、これが4レイヤー分あるので超重くなってしまいました。
このSOPを作るだけで起動に1〜2分かかってしまいつらいので、今回はSave GeometryからTOGファイルを作り、完成したSOPを読み込ませるようにしてます。

<img width="467" alt="スクリーンショット 2017-12-08 15.03.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/11590/8cd6b2f5-a126-6a6b-f4ef-0bdeb015190d.png">
データビジュアライズ系は、このようにして初期設定的なCookが溜まりがちなので、SOPを保存しておくと幸せになれそうです。

### OSCを受けてパースする
![IMG_0503.jpg](https://qiita-image-store.s3.amazonaws.com/0/11590/87714f0e-8f63-8db6-ed7b-16f5b8d76299.jpeg)

これで糸の構造を表した3Dデータが作れたので、センサーを使ってカメラをグリグリします。

####OSC in CHOPで、値が変化した時のみCookする
机の下のセンサーが、布の移動した位置を読み取りtouchdesignerへとOSCを送ってくれているので、それを受け取ります。

<img width="1072" alt="スクリーンショット 2017-12-08 15.41.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/11590/8045e241-15fd-b0b8-f348-87a5e80c8bd0.png">
数値データであれば、osc in CHOPを作るだけなので非常に便利ですね…
ただ、データが送られていない時もoscin CHOPからは数値が送られ続けていて、装置のアクティブ/非アクティブが分かりづらかったです。

今回それだと都合が悪かったので、NullCHOPをはさみ、Cook TypeをSelective、Check valueをONにすることでOSCで値が変化した時だけアクションを起こすという仕組みにしました。

<img width="1089" alt="スクリーンショット 2017-12-08 16.03.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/11590/9d3fa72c-56a3-62db-2737-c437d7857d12.png">

これにtimerCHOPを組み合わせる事で「インタラクション発生時には織り構造にズーム、暫く操作が無い時は布の全体像を見せる」というコーディングだと地味に面倒くさいやつがサクサクっと実装できました。嬉しい。
![IMG_0500.JPG](https://qiita-image-store.s3.amazonaws.com/0/11590/56adee6d-85e0-9a61-0d9c-599eced7db3a.jpeg)![IMG_0501.JPG](https://qiita-image-store.s3.amazonaws.com/0/11590/5f2a3a50-9bee-1322-ded9-ddb32355c2a4.jpeg)

布を動かすとライトが当たっている箇所にズームして、任意の場所の織り構造を見ることができます。

####map的コンテナを自分で作ってみる
センサーから来る座標系とカメラ座標系は違うので、リマップするため＆自作コンテナTOXの勉強のためにMapコンテナを自作しています。
parameter CHOPの値を見て、script CHOPを使いマップ関数を適用した数値を吐き出しています。
<img width="1101" alt="スクリーンショット 2017-12-08 15.34.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/11590/56b02277-081d-ead0-e012-b4ccd50e5a91.png">
<img width="374" alt="スクリーンショット 2017-12-08 15.37.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/11590/2984811d-07bc-89d5-2e53-b6bad655c599.png">
パラメータに入出力の最大最小値の入力項目を追加して、その値からマップした数値を出力します。リマップ用に作りましたが、音響の微調整なんかでも活用したり、なんやかんやで死ぬほど使いました。


### 他アプリのフォーマットに則ってOSCを送ったり、ファイルのパスを指示する（SuperColliderとの連携）

今回空間の音響も合わせてコントロールするため、オーディオもTDで…！と思ったのですが、時間的にも難易度が高そうだったので今回は断念、、SuperColliderで音響合成して連携することにしました。

####やや込み入ったOSCを送る
SuperColliderは送信するべきOSCフォーマットが決まっているので、OSC out CHOPで複数の値をまとめたりするにはどうすればいいんだ…？とハマってしまったのですが、そういう時はOSC out DATを使えということでした。

<img width="1258" alt="スクリーンショット 2017-12-08 16.27.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/11590/31eb738b-413e-277c-e41d-defaf4d52da4.png">
OSC out DATに送信先やポート番号を指定して、スクリプトからsendOSCメソッドを呼び出し送信しています。

####プロジェクトの情報を取得する

SuperColliderは鳴らす音の定義ファイルを読み込ませる事ができるのですが、定義ファイルを

```
TDのプロジェクトが入ったフォルダのパス/sc/Synth.scsyndef
```

という感じでまとめたので、展示用実機に入れた際変更しなくて済むように相対パス的なものを突っ込みたいです。

スクリプト上でプロジェクトファイルのパスを指定したい場合は

```
var('TOUCH')
```
という関数でプロジェクトファイルの絶対パスが指定できました。
他にも色々な環境変数がゲットできて、以下のwikiページで見ることができます。
http://www.derivative.ca/wiki088/index.php?title=Variables

![IMG_9891.jpg](https://qiita-image-store.s3.amazonaws.com/0/11590/7a5e772a-bc39-d25b-82ea-c80f09664f00.jpeg)
音響の他にも、会場照明とも連動するためにOSCを使っています。

###おわり
これは便利だった…けどまた必要になった時には忘れてそう…という所を中心にまとめてみました。なのでテクニカル的な統一感がなくてすみません…

今回TouchDesignerは完全に初投入だった上にかなり現場マターな要素が多かったのですが、とても柔軟に対応できた上、ファシリティ的な要素に殆ど気を使う事なくコンテンツの調整に注力できたので、これは今後も使っていきたいやつだ…という感想でした。

今も安定して動いているみたいで、他にも色々な展示物があってなかなか見ごたえがあるので、是非山口に起こしの際はお立ち寄りいただけると幸いです！