ポイントクラウドをモーフィングする

# はじめに
しゃんぺんです。こんにちは。
趣味でTouchDesignerを楽しんでいます。

この記事では、ポイントクラウド(以降、**点群**)のモーフィングについて紹介します。
サンプルファイルは[こちら](https://github.com/thinpedelica/pcl_morphing)。

## 参考資料
- **ポイントクラウドを扱う by Toyoshi Morioka**  
  https://note.com/toyoshimorioka/n/na8b33b9bf8c3

点群ビギナーは必読です。感謝のための語彙が足りません。
`Point File In TOP`を使った点群データの読み込みからレンダリングと、エフェクトの基礎を解説してくださっています。
本記事は、森岡さんのテキストの`発展形`の章を、試行錯誤した結果になります。

## 目標
点群に苦手意識があったのですが、腹をくくって勉強するきっかけになった映像です。

- **stillness by THINK AND SENSE**
  [![stillness](http://img.youtube.com/vi/A96wHgys8M4/0.jpg)](http://www.youtube.com/watch?v=A96wHgys8M4)

- **Dissolving Realities Vietnam by RubenFro**
  [![Dissolving Realities](http://img.youtube.com/vi/P7ekizIy8Rk/0.jpg)](http://www.youtube.com/watch?v=P7ekizIy8Rk)  

このような美しい点群映像を目指した結果が以下になります。
(目標を達成した、とは言っていない)

# 点群データのモーフィング
## 全体をモーフィング
`/project1/cross simple`

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">今日は森岡せんせいのテキストで<br>勉強させてもらいました🙏<a href="https://t.co/fAWVNVDfiZ">https://t.co/fAWVNVDfiZ</a> <a href="https://t.co/MBg65EU3CF">pic.twitter.com/MBg65EU3CF</a></p>&mdash; Shampagne (@Shampedelica) <a href="https://twitter.com/Shampedelica/status/1326159462378340353?ref_src=twsrc%5Etfw">November 10, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

![cross_simple_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880453/f68ad461-c4d6-cab2-0749-27a5f36ebcef.png)
これは非常に単純で、`点群の位置情報(xyz)のTOP`と、`同じデータ数(解像度)のTOP`を、`Cross TOP`でブレンドするだけです。
サンプルでは、`Pallete`にある`PointGenerator`で生成した適当な点群とブレンドしています。


## カメラの近くだけをモーフィング
`/project1/near camera`

次は特定の部分(カメラの近く)だけをモーフィングする方法です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">カメラが近づいたところだけ点群のY値を変更。<br><br>余談ですが、12月の歌舞伎座のチケットはとれましたが、ヌーミレパークのチケットはとれず、銀座の用事をまとめる作戦は失敗です。 <a href="https://t.co/62WYOHCU9h">pic.twitter.com/62WYOHCU9h</a></p>&mdash; Shampagne (@Shampedelica) <a href="https://twitter.com/Shampedelica/status/1326891991334965251?ref_src=twsrc%5Etfw">November 12, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#### カメラの位置を取得する
![near_camera_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880453/a6b41d7f-a565-7895-b791-24d8554ab2a9.png)
まずはカメラの位置を取得します。
カメラ位置は`Object CHOP`で取得できます。今回はじめて知りました。
便利ですね！

#### カメラからの距離を計算する

![near_camera_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880453/60de7f7a-e446-e56c-c75d-53fa27efcac3.png)
森岡先生のテキストで紹介されている方法で計算します。

- カメラ位置を原点(0.0, 0.0, 0.0)にする(`sub1`)
  `点群の位置情報(xyz)のTOP` から `カメラ位置のTOP`を引き算すると、
  カメラの位置にいる点の座標が原点(0.0, 0.0, 0.0)になりますね

- カメラ位置からの距離を計算する(`math6`)

- 距離の最大値を調べる(`analyze1`)

- 距離を0～1で正規化する(`comp2`)

これで、`カメラからの距離(0.0～1.0)が設定されたTOP`ができあがりました。

#### カメラからの距離に応じた値を作る

![near_camera_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880453/b33b4131-6fef-5e43-32d6-02737e71e8d2.png)
「カメラの近く」の閾値を「0.4」(`threshold`)とし、この閾値から「カメラからの距離(0.0～1.0)」を減算します(`sub2`)。
これにより、ざっくり以下のようになりました。

- threshold(0.4) - カメラの近く(0.0～0.4)   
  => 正の値(0.4 ~ 0.0) 
- threshold(0.4) - カメラの遠く(0.4～1.0)  
  => 負の値(0.0 ~ -0.6)

つぎの`limit TOP`では、以下の2つを実施しています。

- 負の値を全て0.0にclampする
- Gチャネル(Y値)以外をマスクする(Y方向の動きを作るため)

これで、`カメラの近くは距離に応じた値`、`カメラの遠くはすべて0.0`のTOPができました。
あとは適当に値を調整して、`点群の位置情報(xyz)のTOP`に足したり引いたりすると、良い感じの動きになりました。
(ここまで書いて、点の位置を直接加減算するこの処理はモーフィングと呼んでいいのか？という疑問がでてきましたが、見逃してください)

## Curl Noiseを使ってモーフィング
`/project1/curl noise`

点群の動きにもう少しうねりが欲しいと思い、[こちら](https://www.youtube.com/watch?v=DkSwEY-m9GA)のチュートリアルを参考にCurl Noiseを導入しました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ComputeShaderのdispatch sizeと点群の解像度が不一致で、端のpixelの位置が計算されていなかったのが原因。<br><br>Fitで解像度を変更して解消、再提出。 <a href="https://t.co/rY1wBHxG9J">pic.twitter.com/rY1wBHxG9J</a></p>&mdash; Shampagne (@Shampedelica) <a href="https://twitter.com/Shampedelica/status/1329072516573237248?ref_src=twsrc%5Etfw">November 18, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


シェーダーはチュートリアルから全く変更ありません(変更できません)。
やっているのは以下の2点です。

#### アルファ値の変更
![curl_noise_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880453/72e65356-5636-7677-08c6-344ca20d497d.png)
`点群の位置情報(xyz)のTOP`のアルファチャネルを乱数にします。
これはCurlNoiseのLifeの初期値に使われます。

#### 解像度の変更

![curl_noise_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880453/5bb90e5e-2f0c-9ff8-2030-9c354e246233.png)
`点群の位置情報(xyz)のTOP`の解像度を、ComputeShaderが処理する解像度に切り上げます。
ここが不一致していると位置計算されないPixelが(0.0, 0.0, 0.0)になり、モーフィングしたときに一部の点群が原点に集まってくるという事象に悩まされます(悩みました！)。


## ソートされた点群データをモーフィング
`/project1/cross height`

最後は、特定の高さの点群だけをモーフィングする方法です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Y値の低い部分だけモーフィング。<br><br>余談ですが、<br>+Jのダウン良いなぁって思いながら先週色々見ていたら、<br>知らないうちに他のブランドでダウンをポチっていたような気がしていたけど、<br>気のせいじゃなかったみたいで今日届いた。 <a href="https://t.co/R3QwOu0tJ2">pic.twitter.com/R3QwOu0tJ2</a></p>&mdash; Shampagne (@Shampedelica) <a href="https://twitter.com/Shampedelica/status/1327988310174666753?ref_src=twsrc%5Etfw">November 15, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

これは、点群データがソートされている必要があります。
今回、僕は`TDSW Vol.032`でもらった`base_shifter.tox`でソートしました。
このtoxは、点群の原点位置の補正が簡単に出来て、たいへん便利です。
`Vol.032`では、TouchDesignerでの点群基礎以外に、点群ユーザ必携のCloud Compareの使い方なども説明されているため、ぜひ受講してみてください。

- [TouchDesigner Vol.032 Creative Techniques with Point Clouds and Depth Maps by Richard Burns](https://www.patreon.com/posts/event-vol-032-39867674)

`base_shifter.tox`では、点群の数が多くなってくると固まってしまい動きませんでした。
点群の数が多いときのソート方法は、森岡先生が[こちら](https://note.com/toyoshimorioka/n/ndc748586d22c)の記事で紹介してくださっています。

![cross_height_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880453/4676e3cc-c25f-9b42-99a5-3178cdfa2d63.png)
サンプルの点群データはY値でソートしています。
点群データがソートされていれば、あとは`Matte TOP`でモーフィングする部分としない部分を分けるだけです。
点群のソート、すごく強力ですね。

# おわりに
重たい点群操作がTOPだけでサクサク動くのは非常にありがたいですね。derivative様に感謝です。
点群の入門記事を書いてくださった森岡先生にも感謝いたします。

TouchDesignerをはじめて1年ちょっと経ちましたが、TDSWをはじめ多くの方の記事やチュートリアル動画のおかげで、少しずつ成長してこれました。
この場を借りて御礼申しあげます。
ありがとうございます！！！