カメラ手ぶれのブレ加減にMASHを応用してみる

この記事は [MayaPython Advent Calender](https://qiita.com/advent-calendar/2017/maya-python) 2017の10日目の記事です。

# カメラ手ぶれエクスプレッションの悩み

カメラリグに **なんちゃって手ぶれ** を仕込んでおくと便利なのですが、
乱数関数をエクスプレッションにいれて使ったりするんですが、

ヘルプ：乱数関数
http://help.autodesk.com/view/MAYALT/2018/JPN/?guid=GUID-CA91F705-2E91-425C-BEA3-E15162C4CB55

これだと微妙な問題がありました。

**だんだん強くなる/弱くなる** （振幅の増減）はできるのですが、
**だんだん速くなる/遅くなる** （波長の伸縮）ができないのです。

いえ、実際には波長の伸縮はできているのですが、
キーを打って徐々に伸縮してみると、アニメーション再生時にはフレームごとに飛んだ値を得てしまうことになり、ショットワークには使えません。

具体的には「だんだん速く/遅く」の間は **ガッタガタ** になります。その前後では、何事もなく普通にゆらゆらしてくれます。
その間はサンプリングする度に信号自体が変化するわけですから、さもありなん…

***

Maya 2016 Ext2 から、mainframe社のプロシージャルにアニメーションを作れるツールキット **「MASH」** が同梱されるようになりました

https://mash.mainframe.co.uk/
- doc : http://mash.mainframe.co.uk/docs/MASH-3-Documentation.html
- vimeo : https://vimeo.com/channels/mainframemash

これひょっとしてエクスプレションよりスマートに
先の問題を解決してくれるのでは？
ということで調べてみました。

# 結果

結果だけ先に書いておきます。

別に原理的には同じなので、結果も同じ、
キーを打ってだんだん速く/遅くしようとするとｶﾞﾀｶﾞﾀします。残念～

とはいえ、その状態に持っていくまでの手順は
エクスプレッション仕込むより楽だったとは思います。
当初の課題のクリアには至りませんでしたが、MASH自体はほかのところでも使っていけそうな気はします。

あと
やってみたらPython成分ほんのちょっとしかありませんでした。すいませんﾃﾍ

# MASH概要

今回何をやったかの前に、MASHの操作について軽く触れておきます。

ちなみにMaya 2018.1です

![mash01.png](https://qiita-image-store.s3.amazonaws.com/0/102581/693b2720-6c24-a57d-c7dd-9d6fd8113c67.png)

MASHでの作業に関連ありそうなワークスペースは「MASH」と「モーショングラフィクス」の二種類があります。今回はグラフエディタが含まれる「MASH」を選択します。

## MASH作業開始

MASHネットワークというのを作ります。

![mash03.png](https://qiita-image-store.s3.amazonaws.com/0/102581/32b4144c-26d2-4d72-1556-3a2d4cf58804.png)

MASHエディタの上の作成メニューから、
もしくはメインメニューの「MASH」メニューから作ります。

![mash04.png](https://qiita-image-store.s3.amazonaws.com/0/102581/7ec118b4-e449-0e9c-c639-d8ca967a6834.png)

そうすると、「MASH」と「MASH_Distribute」という構造がMASHエディタに作られます。
「MASH」は、MASHウェイターノードで、ここから様々なMASHネットワークノードを追加していきます。
「MASH_Distribute」はメッシュをクローン配置するためのノードです。

このほかに実は「MASH_Repro」というノードも作成されていて、ここで配置するメッシュを指定します。
MASHでプロシージャルアニメーションさせたいメッシュをリストに中ボタンドラッグして追加します。
MASHネットワーク作成時になにがしかのメッシュノードを選択していたら、勝手に入りますのでこの手順は不要です

![mash05.png](https://qiita-image-store.s3.amazonaws.com/0/102581/97136369-f77e-84d0-486a-d8c382ea992c.png)

追加したら増えます

![mash06.png](https://qiita-image-store.s3.amazonaws.com/0/102581/ec1225c4-d9a7-1275-2664-4a729d60af87.png)

このMASHウェイター、Distribute、ReproがMASHネットワークの最小単位という感じです。
以後はReproが見えてればいいので、元になったメッシュノードはhideしておいていいです。

アウトライナ的には、MASHとReproがDAGノード、ほかのMASHノードはDGノードで、
MASHエディタにはMASHウェイターや各MASHノードが表示されて、Reproは並びません。
MASHエディタ上の各ノードは、右のトグルスイッチで計算をパスできます。
こういうのでいいんだよこういうので。Mayaのほかのとこでも欲しい。

## Distribute

Reproで読んでいるメッシュを配置するためのノードです。
「配分タイプ」がけっこういろいろあって、タイプごとに操作できるパラメータがごりごり変わります。

![mash07.png](https://qiita-image-store.s3.amazonaws.com/0/102581/37e90852-7f88-181f-c454-ac35e24f0afe.png)

グリッド配置にしたところです。

「ボリューム」など指定した領域内にランダムに配置するタイプの場合、
配置が気に入らなかったら「ランダムシード」で結果を変えることができます。
（ばらばらに配置するならRandomというMASHネットワークノードもあるので、グリッドで綺麗に配置した後それでばらばらにするという手もありますね。「強さ」でランダム状態と整列状態を遷移できます）

DistributeはMASHネットワークの源流に一つだけ作成できて、さらに足したり順序を変えたりはできません（ちなみに源流がエディタの最下で、上へ向かって計算が進みます。スタックを上方向に積んで行く感じです）。
ただ、ReproメッシュをReproに登録はできるので、
あるMASHネットワークの結果を使って別のMASHネットワークを組んでいくということは可能です。
![mash13.png](https://qiita-image-store.s3.amazonaws.com/0/102581/76b00c82-e9d7-8603-090c-a038226226d9.png)
(▲)二重掛けした様子

という感じで、なにげにDistributeだけでしばらく遊べます。

## Signal
![mash08.png](https://qiita-image-store.s3.amazonaws.com/0/102581/3af5908c-7622-95ea-40bc-d469110c510d.png)

「MASH」の右の「+」メニューからか、Signalのアイコンを探して追加します。

いろんな種類の信号を出してくれます。
![mash09.png](https://qiita-image-store.s3.amazonaws.com/0/102581/2154fb5c-8fde-df73-dba3-d8dff479c708.png)

信号というとなんかわかりづらいですが、
要するに **乱数関数的なアニメーションが欲しい** ときにはこのノードの出番。

このノードが今回の主役で、
これでカメラ動かすのがまず最初の課題です

# シグナルの動きをカメラへ

今回の用途でいえば、
Distributeで複製等せず（カメラ増やしたくはないので）、
Reproにカメラが登録できれば、
あとはシグナルで動きを調整。
…となればいいのですが

![mash10.png](https://qiita-image-store.s3.amazonaws.com/0/102581/9c8490e9-2e7f-aec2-d89f-caeec6305efa.png)

とのこと。。。
メッシュモードが何かは分かりません。メッシュ以外のモードがあるならそれに切り替えちゃっていいので受領してください。。。

というわけもいかないのでPythonノードの登場です。

## Pythonノードで値を飛ばす

![mash11.png](https://qiita-image-store.s3.amazonaws.com/0/102581/3c2f9f2f-6de4-8689-c1aa-5c74e284bf16.png)

Pythonノードは、コードエディタがついているだけという非常に潔いノードです。
（あと減衰も付いてますね。オブジェクトを移動させて効果範囲を移動させたりできます）

![mash12.png](https://qiita-image-store.s3.amazonaws.com/0/102581/d1a0e883-fc2f-206c-9d97-0b23dd6f3012.png)

ただ、サンプルで最初から入っているコードは、
**配置数に合わせてy移動** しちゃう内容になっているので、
追加した瞬間メッシュが動いちゃって、すわ壊してしまったかという心境になります。
落ち着いてforループの箇所を削除します。

で、
![mash14.png](https://qiita-image-store.s3.amazonaws.com/0/102581/e6eb6fea-a9b0-253e-2dec-489a86a67a09.png)
cmdsが見えますので、そのままsetAttrでカメラに値を流し込むことにします。

流し込む値はsignalで作られたノイズ値を受けてゆらゆらするメッシュの位置情報ですが、
それは次のようにして取ります↓

```python
import openMASH
md = openMASH.MASHData(thisNode)
md.outPosition[0].x
```

このような感じで、`MASHData` の`outPosition`アトリビュートの中に、IDごとに入ってます。
今回はDistributeで増やしてないという前提で、`[0]`のx,y,zを使います。

```python
import openMASH

#initialise the MASH network data
md = openMASH.MASHData(thisNode)

cmds.setAttr('camera1.translateX', md.outPosition[0].x)
cmds.setAttr('camera1.translateY', md.outPosition[0].y)
cmds.setAttr('camera1.translateZ', md.outPosition[0].z)

#tell MASH to write the network data
md.setData()
```
結果こういう感じのコードになります。

## カメラの動きを確認

とりあえず、これでMASHネットワーク内のSignalノードを変化させると
カメラの動きも変わるようになりました。
実際、当該カメラをビューに指定すると視界が揺れることが確認できます。

**ただし**
非常に残念なことに、なぜかその動きをビューポート上では確認できませんでした(?????)
再生すると、Reproメッシュはゆらゆら動くし、カメラの視界も動くのですが、
ビューポート上ではカメラが動いているように見えないという。はて。

![mash15.png](https://qiita-image-store.s3.amazonaws.com/0/102581/dbd245ee-4f49-d285-25fb-34a1638b6e78.png)
(▲)うごいてます

![mash16.png](https://qiita-image-store.s3.amazonaws.com/0/102581/da03c7fe-e79d-90c4-868a-fd81e78452ca.png)

カメラを選択し直すと値は更新されているようなんですが、ビューポート上で観る限り
位置が変わっては見えません。ふーむ。
…まいいや今日はそこじゃない。

# だんだん速く遅く

してみます。

signalノードに`タイムスケール`という値があるので、これを増減させます。
`0.5`でもとの信号よりもゆったりとした波長、
`2`でより細かい波長が出力されます。

![mash97.png](https://qiita-image-store.s3.amazonaws.com/0/102581/0644315b-1101-31d3-f3b9-3ff7c08a9b8a.png)
なのでユーザー的には、たとえば`1`〜`2`に推移するようにキーを打てば
`遅い`〜`速い`と推移してくれるのでは……
と思いたいわけですが、
結果は最初に述べた通りです。
エクスプレッションと同様にガタガタしてしまいました。残念です。

# 別案を考えてみる

せっかくなのでもう少しMASHで遊んでみます。

MASHネットワークの各ノードには`強さ(~.Envelope)`のパラメータがあり、0〜1でキーを打つことができます。
では、**遅いsignal**と**速いsignal**の二つをMASHネットワーク中に置いて、
これを`強さ`で推移させて見てはどうでしょうか。

![mash98.png](https://qiita-image-store.s3.amazonaws.com/0/102581/76891a52-1a3a-d984-8a87-7988e4301469.png)
signalを二つ置いて、
その最終結果をカメラに送るために、最後にPythonノードを置きます。
作る順番は順不同でも、MASHエディタ上で適宜順番を変えられるので気楽です。
プロシージャルだ！スタックベースだ！
こういうのでいいん(略

お互いの`強さ`がクロスフェードするようにキーを打ってみました。
![mash99.png](https://qiita-image-store.s3.amazonaws.com/0/102581/68bcb426-bcd6-6641-12fb-ec1d1177c2fb.png)

結果として得られた動きは
グラフを伸縮するようなガタガタは見られず **まだ実用的** とは感じましたが、
ブレンド中の動きはそんなに良い動きではなく
期待するノイズ的挙動に対する『不気味の谷』を感じるような仕上がりになりました。

signal同士の波長が近ければまだ違和感なくブレンドになるでしょうが、
差が大きければブレンド中の違和感も大きくなると思います。

# まとめ

そしてPython要素が希薄ですいません… :innocent:
でも大事なところで活躍してるので許してくだしあ

結果的には狙ったようにはなりませんでしたが、
既に述べたようにMASH自体はなかなか楽しく、使い所を見つけてみたい次第。
複製やアニメーションだけでなく、blenderのAnimationNodesみたいにジオメトリ生成やプロシージャルモデリング的なところまで行くとより楽しそうだと思いました。

***

次は [yamahigashi@github](https://qiita.com/yamahigashi@github) さんの **「callback管理試案」** です！

***

***

# 参考

Maya ヘルプ - MASH ノードの概要 : http://help.autodesk.com/view/MAYAUL/2018/JPN/?guid=GUID-D4FECFDC-F91A-4BDC-A1B0-A24EB087B2DD

borndigital blog - MASH-チュートリアルムービー : https://support.borndigital.co.jp/hc/ja/articles/115010663467-Maya2018-MASH-チュートリアルムービー

MASH examples : https://knowledge.autodesk.com/ja/search-result/caas/CloudHelp/cloudhelp/2018/JPN/Maya-Tech-Docs/MASH/examples-html.html