MotionBuilderっぽいビュー切り替えをMayaでやる

## はじめに
この記事は[Maya Advent Calendar 2019](https://qiita.com/advent-calendar/2019/maya)の1日目の記事になります。
今年もアドベントカレンダーのシーズンがやってきましたね！

この記事を書いている現時点(2019/11/28)で、Maya Advent Calendar 2019 は埋まり切っていませんが、
きっと誰かがリアルタイムに残りの枠を埋めてくれることでしょう！
(2019/12/12 追記 : 無事埋まりました！参加していただいた皆様に感謝！)

さて、そんなわけで私からは「MotionBuilderっぽいビュー切り替えをMayaでやる」というお題目で執筆させていただきます。

### 諸注意
今回は個人的な都合上、記事内で扱う言語はPythonではなく**MEL**になっています。
ただ、Pythonに置き換えても問題ない内容ですのでもし試してみたいという方はご自身でPythonに置き換えてくださいませ。

## MotionBuilderのビュー切り替えについて
皆さんはMotionBuilderを使用したことがあるでしょうか？
私はあまり使用したことがありません。

ただ、MotionBuilder用のツールを作成する機会は何度かあったため、
その時に少しだけ操作を覚えました。

そこでひとつ気に入った操作があり、それが今回のテーマである「ビュー切り替え」というわけです。

実際にご覧ください。

**▼Ctrl+F**
![fb.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/f9d1a54e-6cd6-b56c-5d42-144d3fb91c45.gif)
**▼Ctrl+R**
![lr.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/d18c3bb1-fda7-f6a4-26e3-082fcdf7d9c7.gif)
**▼Ctrl+T**
![tb.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/b391ba4b-66e2-34b2-e60c-0cd7f83c07ca.gif)

こんな感じで、ただショートカットでビューを正面/背面, 左/右, 上/下に切り替えることが出来るだけの機能なのですが、これがまた結構便利で当時の私はMayaにもあったらいいのになと思ったわけです。

## Mayaはどんな感じなの？
ここで一度Mayaの標準ショートカットによるビュー切り替えを見てみましょう。

**▼Space → カーソルを切り替えたいビューの上まで移動 → Space**
![mn.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/f5728920-4103-72a6-8fe8-1351b6a1178c.gif)

こんな感じで、**ただビューをショートカットで切り替えたいだけなのにとても冗長に感じませんか？**
私はそう思います。

こんなんじゃあ頻繁にビューを切り替えて作業したい場合にとても不便です。
これはもうMotionBuilderの操作を移植するしかありませんね！


## Mayaで似たような機能を探してみる
というわけで、先ほど紹介した**ビューを正面/背面, 左/右, 上/下をワンボタンで切り替える機能**を
Mayaでも出来るようにしていきたいわけなのですが、実際これくらいの機能なら標準でも備わってそうに思いませんか？

はい、実際無くはないです。

それがこちら
**▼カメラアイコンを右クリック →　切り替えたいビューを選択**
![ss.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/deef51bd-eb70-d885-3853-9596d97cea75.gif)

コマンドとしてはこんな感じ。

```:mel
// persp 
lookThroughModelPanel persp modelPanel4;

// front
lookThroughModelPanel front modelPanel4;

// side
lookThroughModelPanel side modelPanel4;

// top
lookThroughModelPanel top modelPanel4;


```

※行末の"modelPanel4"の数字部分は環境によって変わることがあります

それじゃあこのコマンドをショートカットに登録すれば解決するのでは？
って思いますよね。

ところがどっこい、このコマンドのやっていることは、Mayaの新規シーンに最初から存在する、
`persp`, `front`, `side`, `top` という**カメラノード**に切り替えているだけなのです。

**▼これ**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/232529ac-e386-4739-9c7f-1812e7b61a13.png)

なので、このコマンドをいくら連打してもカメラのTransformは変化することがないため、
MotionBuilderのように**1操作で正面/背面のようにトグルさせることは出来ないのです。**


・・・ただ、このコマンドを使っていい感じになんとかすれば、
それっぽい挙動ができそうな気がしてきました。

諦めずに頑張っていきましょう。

## lookThroughModelPanelコマンドで切り替えたカメラを反転させる
もう大体お察しかと思いますが、MotionBuilderのようなビュー切り替えをやりたい場合は、
**1. lookThroughModelPanelコマンドをショートカットに登録し、**
**2. 同じショートカットを2度連続で押した場合はカメラを反転させる**

ということが出来れば実現が出来そうです。

早速実験してみましょう。

### ①通常のカメラのTransformの状態を確認する
まずは通常時のfrontカメラのTransform状態を確認してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/3db9dee1-748a-2024-8abd-0c30414d2a38.png)
このような状態になっています。

この数値をどうにか弄ればカメラの反転が出来そうですね。

### ②カメラのTransformを弄って反転させてみる
frontカメラはTranslateのZ軸が大きく関わっているカメラです。
なので、現在の値に`*-1`すればワールド空間上の位置を反転させることができます。
こんな感じ

```:mel
{
    lookThroughModelPanel front modelPanel4;
    float $tz = `getAttr "front.translateZ"`;
    setAttr "front.translateZ" ($tz *-1);
}
```
このコマンドを実行すると・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/d2b5e216-7c65-57cf-2a14-bcdc7cff15c4.png)

わお、なんと**対象物が画面内から消えてしまいました！**
なんてこった！

なーんちゃって
ご安心ください、これくらい想定通りです。

この現象はただカメラがワールド空間の+Z軸上から-Z上に移動しただけなので、当たり前のことなのです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/23386a4e-eb9a-8cf5-fd64-9bb6d04f3cd9.png)

あとは、このカメラのY軸を180度反転させてあげれば・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/b448c354-858a-79cc-0824-c00636269196.png)

こんな感じでカメラを反転できました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/860aa472-7033-3ff5-5e65-db43073a3a44.png)

(尺を稼ぐためにやたらと冗長に説明してみました)

ここまでのコード

```:mel
{
    lookThroughModelPanel front modelPanel4;
    float $tz = `getAttr "front.translateZ"`;
    setAttr "front.translateZ" ($tz *-1);
    setAttr "front.rotateY" 180; 
}
```

### カメラの反転をトグル化
先ほどまでのコードだと、ただlookThroughModelPanelによって切り替えたカメラを反転させただけです。
これに、条件分岐を加えて実行するたびに結果が反転するようにしてみましょう。

今回はとてもシンプル、というか泥臭い方法でやってみましょう。

まずは最終的なコードをご覧ください。

```:mel
{
    string $cam = `modelPanel -q -cam "modelPanel4"`;
    // 現在のカメラがfrontかどうか調べ、front以外ならfrontに切り替える
    if ($cam != "front"){
        lookThroughModelPanel front "modelPanel4";
    // frontだった場合、現在のTransform値を反転させる
    } else {
        float $tz = `getAttr "front.translateZ"`;
        setAttr "front.translateZ" ($tz *-1);  
    
        if(`getAttr "front.rotateY"`){
            setAttr "front.rotateY" 0;
        } else {
            setAttr "front.rotateY" 180;
        }
    }
}
```

これでfrontビューをトグル的に反転させることが出来るようになりました。

![ff.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/173294fe-552d-d315-379d-a072cb0b0546.gif)

あとは同じ要領でside, topにも対応し、ついでにperspに戻せるようなショートカットも作れば
**これで目標達成ですね！**



  
・・・と思いきや、もう一つ課題があります。

実は先ほどまでのコードだと`modelPanel4`というパネルにしか対応していません。
この`modelPanel4`が常にメインビューであればそこまで困らないのかもしれませんが、
↑のほうでﾁﾗっと説明したとおりこの順番は環境によって変わる可能性があります。

私の環境だとこのようになっていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/e4e58d9c-cb1c-291c-47b1-c23d74c120a9.png)


せっかくなので、どのパネル上でもビュー切り替えを出来るようになってたほうが便利ですよね！

早速実装してみましょう。

### 色んなmodelPanelに対応させる
Maya上のパネルを取得したい場合、`getPanel`というコマンドを使用します。
さらに、`-withFocus`というフラグを使用することで**現在パネルカーソルが乗っているパネルを取得することができます。**
![xx.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/9b3fc150-016d-bee8-563a-c19b9dae6c2f.gif)
(モタモタ・・)

これは便利そうだ！
早速先ほどのコードに追加して使ってみましょう！


```:mel
{
    // 現在アクティブなパネルのカメラを取得する
    string $currentPane = `getPanel -withFocus`;
    string $cam = `modelPanel -q -cam $currentPane`;

    // 現在のカメラがfrontかどうか調べ、front以外ならfrontに切り替える
    if ($cam != "front"){
        lookThroughModelPanel front $currentPane;
    // frontだった場合、現在のTransform値を反転させる
    } else {
        float $tz = `getAttr "front.translateZ"`;
        setAttr "front.translateZ" ($tz *-1);  
    
        if(`getAttr "front.rotateY"`){
            setAttr "front.rotateY" 0;
        } else {
            setAttr "front.rotateY" 180;
        }
    }
}
```

このコードを応用してfront以外のtopやside、そしてperspに戻せるショートカットも用意して・・・


出来ました！
![dd.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212052/28bd4d71-b6ac-ba64-0e56-856f376514c2.gif)

※ただし、今のままのコードだとマウスカーソルがScriptEditor等のmodelPanel以外で使用した場合にエラーになってしまうため、ちょっとした修正が必要です。が、記事を書くのが疲れたのでそこの説明割愛させていただきます･･･!


## おすすめホットキー
とまあそんなわけで、私はこのスクリプトを以下のようなホットキーに割り当てて日常的に使用しています。

| ホットキー | カメラ |
|:-:|:-:|
|Alt+1|persp|
| Alt+2  |front   |
|Alt+3   | side  |
|Alt+4   |top   |

普通のカメラ操作でも使用するAltを起点にすることで、指の移動を少なくスムーズにビュー切り替えを出来るっていう寸法よ。
是非お試しください。

## おわりに
いかがでしたでしょうか。
大急ぎで書いたので少々雑な感じになってしまいましたが、自作したオレオレMayaショートカットをお披露目できたので大変満足です。

今回紹介したスクリプトは元がMotionBuilderの機能なため、アニメーション作業にとても便利な事はもちろん、
モデリング時にも結構使えるので我ながら大変気に入っております。

もしよければ、残りのAdventCalendarの枠を使って皆さんの自慢のショートカットを公開してみてはいかがでしょうか？
私気になります！（枠を埋めるのに必死）
(2019/12/12 追記 : 再・無事埋まりました！しっかりしたネタから小粒なネタまでレパートリーも様々！感謝！)

明日の記事は[sho7noka](https://qiita.com/sho7noka)さんによるMayaとVSCodeの統合のお話です。お楽しみに！