チュートリアル / Mayaにおける魅惑のプロップリグ~モジュラーリギングシステムの基本と応用~
第7回:リグモジュールの開発とセットアップ その6〜⾃動⾞〜
- GAZEN
- Maya
- アニメ
- キャラクター・リグ
- ゲーム
- コラム
- スクリプト・API
- チュートリアル
- 学生・初心者
- 映画・TV
今回の題材
こんにちは、久保です。
今回もプロップのセットアップを進めていこうと思います。
さて 今回の題材はこちら
はい自動車です。
カッコいいスポーツカーでもよかったのですが、実用的なタイプにしてみました。
構造の観察と情報収集
今回は自動車ということで身近なものです。
ですが、まずは自動車の挙動と構造について調べてみようと思います。
稼働部位の観察
とりあえず実際に動いている自動車を観察して、どこが動いているのかを確認してみます。
ざっくりまとめると
・タイヤ回転(進行方向)
・タイヤ回転 (前輪 水平方向)
・タイヤ上下移動
・車体の傾き 前後・左右
割と当たり前のことが大半ではありますが、まぁ念のため。
ではこれらの動きの元となる構造について調べていきます。
サスペンション
車体の傾きとタイヤの上下移動はサスペンションで制御していることが多いようです。
サスペンションは車体とタイヤの間に組み込むことで、路面からの衝撃を軽減しつつタイヤの接地を保つというものです。
サスペンションの方式は大きく分けて 車軸懸架式 と独立懸架式 があるようです。
簡単に言うと
・車軸懸架式は 左右のタイヤがつながっているもの
・独立懸架式は 左右のタイヤが独立しているもの
という感じです。
一見 独立懸架式 の方が高性能に思えますが、
傾いた際に車体下部の空間を確保するために車軸懸架式を採用している車もあるそうです。
サスペンションの働きは市街地の自動車だとイマイチ判りづらいので、インターネットで調べてみました。
オフロード 4WD サスペンションなどで調べると色々でてきます。
調べてみると思ってた以上にサスペンションの働きは重要だということがわかりました。
さらにサスペンションの細かい形状についてはさらにいくつか種類がありますが、今回は割愛します。
興味が無くても是非調べてみてください!
ステアリング
タイヤを曲がりたい方向に向けるわけですが、そのままタイヤの向きを変えるだけでは駄目なようです。
もし前輪が並行になったまま曲がろうとすると、それぞれのタイヤの軌道が交差するため曲がれません。
実際はタイヤ同士がぶつかるのではなく、内側のタイヤがスリップしてしまいます。
それを避けるために、左右のタイヤの角度を変える必要があります。
具体的には後輪の軸上に置いた点を中心とした円に沿うように、それぞれのタイヤの向きを合わせます。
タイヤがたくさんついているタイプの車両だと、
曲がるためにこのようにタイヤの向きを変えるものもありました。
設計
ではセットアップの訴求内容を・・・・
と思いましたが、冒頭で観察した挙動の再現を目標とします。
これに1点だけ、車両全体を前後左右に傾けられる機能を追加します。
必要要素分解
・車両全体の傾き
これは以前作成した tiltCtrlモジュールが使えそうです。
・車体の傾き
サスペンションについては 車軸懸架式 を想定しようと思います。
これもtiltCtrlモジュールが使えそうですが、サスペンションが効いてる感じを出すには水平に保つ機能があると良さそうです。
・タイヤの調整
タイヤ個々に 位置・向き・回転をマニュアルで調整できるコントローラーを設置します。
これはモジュールを新作しようと思います。
・ステアリング制御
個々にタイヤの向きを変えても対応できますが、コントローラー1つでいい感じの向きにしてくれるようにしようと思います。
こちらもモジュールを新作しようと思います。
傾きセットアップ
まずは全体・車体の傾きセットアップを進めます。
とりあえず入れ込み
ひとまずtiltCtrlモジュールをそのまま使用して、ビルドしてみます。
全体傾きの支点を
・前後タイヤの接地点
・左右タイヤの外側
に設定しました。
車体の傾きについては、サスペンション効いてる感を出したいので
・前後タイヤの中心軸より内側
・左右タイヤより内側
に設定しました。
動きは問題なさそうです。
水平維持の試作
では追加機能の水平維持を試作していきます。
車体の水平を保持させたいわけですが、world Y回転には追従してほしくないですね。
tiltコントローラーがtranslate制御なので、水平維持のギミックは 回転でも位置でもどちらでも良さそうです。
位置でやるなら
world固定用ノード(worldTarget)をpointConstraintを使用し、位置だけをコントローラー(target)の親に追従させます。
こうすることで、 world固定用ノードは常にコントローラーの親の回転の影響を受けずに常に直上に配置されます。
参考データ:carA/sampleScenes/suspensionSample_pointConstraint.ma(記事の最後のダウンロードリンクからダウンロードできます。)
回転でやるなら
orientConstraintを使用して、親空間内にworld固定用のノードの向きを引き込みます。
そこからtwist成分(world Y回転)を除外したノード(試作ではaimConstraintを使用)を作成します。
これによって常に直上を向いた状態になるので、 world固定用ノードの親とすれば固定ができます。
参考データ:carA/sampleScenes/suspensionSample_orientConstraint.ma(記事の最後のダウンロードリンクからダウンロードできます。)
どちらの方法でも問題はなさそうですが、今回は回転を採用しようと思います。
さてここで、
・水平を維持するギミックを別モジュール(aimConstraintSetup)で作って、tiltCtrlにコントローラーの親空間切り替え機能だけ追加する
または
・tiltCtrlモジュールに全部収める
どちらにすべきか悩ましいですが、今回は後者の入れ込む方針で進めます。
実装
処理の設計を図に起こすとこのようになります。
・local / worldのウェイトによる切り替えが必要なので、 双方のターゲットを用意しておきます。
・ひとまずworld = rootJoint と定義し、world切り替えの有無をパラメーターとして入れておきます。
・ついでに、rotJointをオフセットで動かせるコントローラーも追加しました。
書ききれなくなったので、処理を別に書き出してみました。
こう見ると インプットとアウトプットがはっきりしています。
スクリプトで作るのもいいですが、この処理をbifrostグラフで作成して呼び出しやすくしておくと色々捗りそうですね。
機能追加に伴い、リグモジュールのパラメーターを幾つか追加しました。
SSRig/rigModules/tiltCtrl.py
_ATTRS = [
"rotJoint",
"aimPointDistance",
"aimAxis",
"frontAxis",
"useParentSpace", ## 追加
"useOffsetCtrl", ## 追加
"setCtrlPrefix",
"ctrlColor",
"useParamCtrl",
"useParamPrefix"
]
_ATTR_DICT = {
"rotJoint": {"type":"message", "multi":False, "default":""},
"aimAxis": {"type":"enum", "enumList":["x","y","z","-x","-y","-z"], "default":"x"},
"frontAxis": {"type":"enum", "enumList":["x","y","z","-x","-y","-z"], "default":"-y"},
"aimPointDistance": {"type":"double", "multi":False, "default":0.0, "min":0.0, "max":100},
"useParentSpace": {"type":"bool", "multi":False, "default":False},
"useOffsetCtrl": {"type":"bool", "multi":False, "default":False},
}
リグモジュールをアップデートして、ビルドしてみます。
追従率が1.0だとちょっとやりすぎなので、0.8にしてみました。
車体の水平維持が追加されたので、乗り心地がマシになりました。
タイヤセットアップ
タイヤについては、タイヤ個々の調整セットアップとステアリング制御のセットアップの2種類があります。
タイヤ個々制御試作
まずはタイヤ個々に 位置・向き・回転をマニュアルで調整できるコントローラーを作成します。
jointは1つで、コントローラーを階層化して制御しようと思います。
場合によっては 向き と 回転の軸がずれている可能性も考えられるので、
モジュール作成時にはそこが調整できるように何かマーカーを用意した方が良さそうです。
ステアリングの試作
後輪の軸上に置いた点を中心とした円に沿うように、それぞれのタイヤの向きを合わせる必要があります。
文字で見てもちょっとピンとこないので、aimConstraintを使用して一旦可視化してみました。
参考データ:carA/sampleScenes/steeringSample_v001.ma(記事の最後のダウンロードリンクからダウンロードできます。)
なるほど。
後輪の軸上をaimPointが移動できるようにすれば良さそうですが、
正面を向かせるには軸上から離れる必要がありそのまま使うのは難しそうです。
ではもう少し調整してみます。
参考データ:carA/sampleScenes/steeringSample_v002.ma(記事の最後のダウンロードリンクからダウンロードできます。)
ベクトルとaimConstraintを使用して、後輪の軸上をaimPointが移動するようにしてみました。
また、正面の場合はaimPointが前輪の左外側にくるように分岐させています。
この構造をタイヤ個々制御と共存させたいので、このモジュールは ステアリング制御 + タイヤ個々制御試作を同梱したものにしようと思います。
構造を一度整理して書き起こしてみました。
projectionVectorの処理についてはこのような感じです。
aimPoint(P’)を求めたいので、
rearWheelCenter(A) からrearWheel_L方向に伸ばした ABベクトル に対して、
wheelDirSample(C) からコントローラーへのベクトルに直交する CDベクトルを投影します。
投影したベクトル APベクトルを D'Pベクトル : ACベクトル の比率分だけ伸ばし P'を求めます。
ベクトルのあれこれが少々面倒ですが、構造自体はシンプルではあります。
実装
まずはタイヤ個々用のリグモジュールを作成しました。
wheels:タイヤのセットが複数ある場合も考慮してmultiにしました。
steeringRollAxis:向き用の軸と回転用の軸を指定します。
steeringMarker:必要であれば向き用コントローラーの位置を定義するtransformノードを登録します。
reverseTranslateAxis:左右のコントローラーで translateの方向が反転していると使いづらそうなので、軸を反転させるか否かを決めます。
SSRig/rigModules/wheelCtrl.py
_ATTRS = [
"wheels",
"ctrlColor",
"mirrorSetupSetting"
]
_ATTR_DICT = {
"wheels": {"type":"compound","ch":["wheelJoint","steeringRollAxis","steeringMarker"],"multi":True},
"wheelJoint": {"type":"message", "multi":False, "default":""},
"steeringRollAxis": {"type":"enum", "enumList":["xy","xz","yx","yz","zx","zy"], "default":"yx","multi":False},
"steeringMarker": {"type":"message", "multi":False, "default":""},
"mirrorSetupSetting": {"type":"compound","ch":["mirrorSetup","mirrorCtrlColor","reverseTranslateAxis"],"multi":False},
"mirrorSetup": {"type":"bool", "multi":False, "default":False},
"mirrorCtrlColor": {"type":"enum","enumList": rigSettings.COLORS_LIST,"default":"yellow"},
"reverseTranslateAxis": {"type":"enum", "enumList":["xy","yz","zx","none"], "default":"xy","multi":False},
}
このモジュールを使用して、ステアリング用のリグモジュールも作成しました。
前輪と後輪をそれぞれ定義できるようにしています。
frontWheel_L/R:前輪に関しては、車輪毎のコントローラーもつけたいので wheelCtrlモジュールで必要な情報も追加しました。
leftSideAxis_L/R:前輪の左側を向いてる軸を定義します。
SSRig/rigModules/steeringWheelCtrl.py
_ATTRS = [
"frontWheel_L",
"frontWheel_R",
"rearWheel_L",
"rearWheel_R",
"setCtrlPrefix",
"ctrlColor"
]
_ATTR_DICT = {
"frontWheel_L": {"type":"compound","ch":["frontWheelJoint_L","steeringRollAxis_L","steeringMarker_L","reverseTranslateAxis_L","ctrlColor_L","leftSideAxis_L","useOtherSideFromName"],"multi":False},
"frontWheel_R": {"type":"compound","ch":["frontWheelJoint_R","steeringRollAxis_R","steeringMarker_R","reverseTranslateAxis_R","ctrlColor_R","leftSideAxis_R"],"multi":False},
"frontWheelJoint_L": {"type":"message", "multi":False, "default":""},
"frontWheelJoint_R": {"type":"message", "multi":False, "default":""},
"steeringRollAxis_L": {"type":"enum", "enumList":["xy","xz","yx","yz","zx","zy"], "default":"yx","multi":False},
"steeringRollAxis_R": {"type":"enum", "enumList":["xy","xz","yx","yz","zx","zy"], "default":"yx","multi":False},
"steeringMarker_L": {"type":"message", "multi":False, "default":""},
"steeringMarker_R": {"type":"message", "multi":False, "default":""},
"useOtherSideFromName": {"type":"bool", "multi":False, "default":True},
"leftSideAxis_L": {"type":"enum", "enumList":["x","y","z","-x","-y","-z"], "default":"x","multi":False},
"leftSideAxis_R": {"type":"enum", "enumList":["x","y","z","-x","-y","-z"], "default":"x","multi":False},
"ctrlColor_L": {"type":"enum","enumList": rigSettings.COLORS_LIST,"default":"red"},
"ctrlColor_R": {"type":"enum","enumList": rigSettings.COLORS_LIST,"default":"blue"},
"reverseTranslateAxis_L": {"type":"enum", "enumList":["xy","yz","zx","none"], "default":"none","multi":False},
"reverseTranslateAxis_R": {"type":"enum", "enumList":["xy","yz","zx","none"], "default":"xy","multi":False},
"rearWheel_L": {"type":"compound","ch":["rearWheelJoint_L","rearUseOtherSideFromName"],"multi":False},
"rearWheel_R": {"type":"compound","ch":["rearWheelJoint_R"],"multi":False},
"rearWheelJoint_L": {"type":"message", "multi":False, "default":""},
"rearWheelJoint_R": {"type":"message", "multi":False, "default":""},
"rearUseOtherSideFromName": {"type":"bool", "multi":False, "default":True},
}
前後輪にモジュールを設定し、ビルドしてみます。
想定通りに動いてくれているようですね。
基本的な構造のセットアップはできたので、今回は一旦ここまでにしたいと思います。
出来上がったデータはこちらに保存してあります。
carA/mayaScenes/carA_asset_v0001.ma
終わりに
今回は自動車という身近なものを題材としました。
架空の物であれば ”こういうものなんです!” で通せないこともないですけども、
身近なものであるが故に、想像だけで進めてしまうと違和感を生む原因になってしまいますね。
冒頭で 車は横には進めない と書きましたが、
実は過去に真横に移動して縦列駐車を簡単にできる!というコンセプトカーがありました。
もしかすると、数年後には横移動する自動車が当たり前になっているかもしれませんね。
そうなったときには 車が横移動する機構を調べなければ・・・




















