最近のアーケードゲーム開発

皆様、こんにちは。
セガ・インタラクティブ 第三研究開発本部 開発一部 プログラマの渡邉です。
新年度も始まり、心機一転といった感じでしょうか。本ブログも開始してから1年と8ヶ月程度と相成りました。
時が経つのは早いなと思いつつ、日々ゲーム開発に勤しんでいます。
私は近年アーケード(業務用)ゲーム開発を行っていますが、以前は主にコンシューマ(家庭用)ゲーム開発に携わっていました。
セガグループではコンシューマ、アーケード、PC、モバイル、ブラウザ等々と様々な機種でゲームを開発、リリースしています。
ここまでの技術ブログの記事を振り返ってみれば、様々な所属部門の記事があることがお分かり頂けると思います。
機種が違えば、開発する際の前提やお約束が変わってくるものです。そこで本記事では、自身の経験を元にコンシューマゲーム開発との比較も交えつつ、最近のアーケードゲーム開発について紹介させていただければと思います。なお、アーケードゲームは開発内容によって、紹介したものと環境が違うこともあることを予め申し上げておきます。あくまで一例ということをご理解いただければ幸いです。
過去記事では特定の職種向けのテクニックや事例の紹介が多かったかと思いますが、概括的なお題ということもあり、極力職種問わずの内容になっております。技術的な側面を期待されている方には退屈かもしれませんがご容赦ください。


目次


開発環境/ハードウェア

コンシューマゲーム開発では各プラットフォーマーが提供する開発キットを使用します。(周辺機器等の拡張を除くと)そのハードウェア構成は基本変動することはないので、ハードウェア性能は一定です。ハードウェア性能が決まっている分、素早くソフトウェア開発に移行出来ますが、その制約下で開発することになります。特にマルチプラットフォームタイトルは厳しい制約下でソフトウェア開発を強いられることになるでしょう。
アーケードゲーム開発ではハードウェア構成から検討することになります。その為、タイトルに合わせた最適なハードウェアを構築可能ですが、その分ハードウェア構成の選定には時間がかかりがちです。また、タイトルリリース後しばらくして採用した部品が製造中止になる可能性もあるため、注意が必要です。
なお、アーケード筐体は家庭用ゲーム機に比べ若干大き目なので、スペースの確保が大変です。マルチプレイになると尚更です。


f:id:sgtech:20180423190402j:plain
弊社アーケードゲーム「Wonderland Wars」の開発用筐体エリアです。ちょっとしたゲームセンターですね。

使用言語/ソフトウェア

こちらはコンシューマ・アーケードあまり変わりありません。
クライアントアプリケーションの使用言語は C++ あるいは C# が主です。
最近では Unity や Unreal Engine 等といったゲームエンジンでの開発タイトルが増えています。
敢えて違う点を挙げるとすれば、プラットフォーマーの制約下に縛られないアーケードゲーム開発のほうがオープンソースや外部ライブラリを採用し易いかもしれません。
また、サーバー等インフラも自前で管理する為、専用モバイルアプリケーションやWebサイトとの連動も比較的容易です。(担当者の作業が容易だとは言いませんが…)


f:id:sgtech:20180423190419j:plain
弊社では、アーケードゲームのIP(知的財産)を様々なデバイスに展開する「マルチデバイス×ワンサービス」戦略を掲げており、タイトルに連動したスマートフォンアプリやWebサイト等を同時に開発、提供しています。例えば「Wonderland Wars」では、Web上で戦績等を確認出来る「Wonder.NET」や、スマートフォン向けのサポートアプリケーション「Wonderland LIBRARY APP」の提供を行っております。

ゲームデザイン

アーケードゲームではコンシューマゲームとの差別化を図る為、「家庭での再現は難しい」ことを念頭に置いたデザインを心がけることが多いです。
ディスプレイからコントローラーまでタイトルに最適な構成を構築出来ることはゲームデザイナーにとって喜ばしいことではありますが、やりすぎると移植性に欠けるため、注意が必要です。
また、パッケージ売りのコンシューマゲームと、1プレイ幾らのアーケードゲームではマネタイズが大きく違うわけですが、アーケードゲームでは店舗の利益を考慮し、プレイ回数を稼ぐことが可能なゲームデザインが求められます。1プレイ時間は短く(数分~十数分程度)、それでいてライブで盛り上がるための体験を重視したデザインが好まれます。

エラー処理/データ分析

アーケードゲームでは直接硬貨を投入して遊んでいただいている為、エラー周りの例外処理には気を遣います。
例えば、停電等による電断や通信不良等が発生した場合でも極力不利益が生じないよう、大切なプレイヤーデータを随時バックアップしたり、ある程度の追跡および状況分析が出来るようプレイログ情報を専用サーバーにアップロード等しています。

開発規約/出荷基準

コンシューマゲーム開発では「一定時間以上、画面を静止してはならない」といった各プラットフォーマーが定めた規約(Technical Requirements Checklist 等)を遵守する必要があります。また、CERO や ESRB 等といったレーティング機構の審査もパスしなくてはなりません。
対してアーケードゲーム開発では、共通の規約・審査機構は無く、各メーカー独自で定めています。
弊社でも独自のガイドラインを用意し、デバッグサポートチームや品質保証部の元、厳格にチェック・パスしたタイトルをリリースしています。
また、アーケードゲームは風営法の適用対象なので、仕様作成の段階で法務部と擦り合わせを行う等、法令遵守を心がけています。


f:id:sgtech:20180423190415p:plain
「Wonderland Wars」のチェックリストの一部です。実に 500 超の中項目があり、それぞれに数十~百程度のチェック項目が並んでいます。

顧客層

コンシューマゲームの顧客層は、各プラットフォーマーのターゲット機保有者、ターゲット機で遊んで下さるユーザーです。
アーケードゲームの場合、店舗に足を運んで遊んで下さるユーザーに加え、店舗(オペレーター)も顧客層に含みます。(いわゆる B to B to C の取引形態ですね)
ユーザーに楽しんでいただけるゲーム内容にするのは勿論ですが、店舗がオペレーションしやすい機能を実装することも忘れてはいけません。その為、入力テストや、クレジットの確認、店舗大会用の設定等を可能とする「テストモード」を通常用意します。


f:id:sgtech:20180423190410j:plainf:id:sgtech:20180423190406j:plain
こちらは「Wonderland Wars」のテストモードの一部で、入力デバイスが正常に動作するかのテスト画面です。アーケードゲームでは毎日様々なユーザーにプレイいただくため、パーツの摩耗も激しいです。オペレーターが筐体の状態を確認する際の補助となるよう、このようなモードを用意しております。

まとめ

いかがでしたでしょうか。
簡単な解説ではありましたが、アーケードゲーム開発とコンシューマゲーム開発、同じゲーム開発でも違いが見て取れたのではないでしょうか。
本記事が皆様の気付きの一助となれば幸甚です。
もしアーケードゲーム開発にご興味を持たれましたらセガ・インタラクティブ採用サイトを、
逆にコンシューマゲーム開発のほうが面白そうだと思われた方はセガゲームス採用サイトを、
とにかくゲーム作りに関わりたいと思われた方はセガグループ採用サイトを是非ご確認ください。
我々セガグループは共にゲームを作り続けてくれる方々を歓迎します。
採用情報 | 株式会社セガ・インタラクティブ -【SEGA Interactive Co., Ltd.】
採用情報 | 株式会社セガゲームス -【SEGA Games Co., Ltd.】
採用情報 | セガ企業情報サイト

(C)SEGA

Anima2Dでキャラクターアニメーションを作ろう!編

■ 共闘ことばRPG 「コトダマン」

こんにちは。
セガゲームス 開発統括部 アート&デザイン部 TAセクション 廣田です。


今春リリースの「共闘ことばRPG コトダマン」では全てのキャラクターアニメーション(700キャラ以上!)をAnima2D で作成しました。タイトルリリース前ですが、一足先にコトダマンのキャラクターを使って、Anima2D のセットアップからアニメーション作成を解説していきます。

さらに次回、Anima2Dでの制作をサポートするスクリプトについても書いていく予定です。

公式

好評配信中です!
kotodaman.sega.jp

Twitter

この記事で紹介しているキャラクターは、全てコトダマンのAnima2Dキャラクターです。
Twitterでは他のキャラクターもたくさん登場していますので、Anima2Dのサンプルとして是非ご覧ください!
(フォローもお願いします!)

twitter.com


■Anima2D とは

f:id:sgtech:20180326002518p:plain
2017 年から Unity テクノロジーが提供しているアセットで、無料で利用できます。
将来的に Unity への組み込みを予定しているようです。
これを利用することで、Unity 内で 2D ボーンアニメーションができるようになります。
3DCGツールを使っている方なら、板ポリゴンにテクスチャーを貼り、ボーンを入れて2D イラストを動かすという工程がUnity内でできるようになったと思ってもらうと分かりやすいでしょう。

ドキュメント

上記画像にある、DocumentationというリンクからPDFをダウンロードできます(英語)

f:id:sgtech:20180326002249g:plain:w256

■Anima2D のメリット

  1. FCurve エディタが使用できる(MayaやSoftimageで慣れたアニメーターの作業・修正スピードが格段に違う)
  2. Unity のスクリプティングによる拡張ができる(セットアップの自動化や機能追加・作業支援ツールの作成など)
  3. Unity 内で作業できるので、他ツールからのエクスポート/インポートの手間が無い。
  4. メッシュをある程度自動で切ってくれる
  5. 学習コストが安い(Unityを触ったことがある+3DCGツールでアニメーションを作成した事があればすぐ)
  6. ゲーム画面内で見ながら作成・修正できる。(Shuriken のエフェクトも同時に作成可能)
  7. Unityの公式アセットになった。

コトダマンでは700キャラ以上のアニメーションを作るにあたり、Spine, Live2Dも検討したのですが、上記理由でAnima2Dを採用しました(数字は選択理由順)。
簡潔に言うと「作業スピード+スクリプティングによるカスタマイズ」が選択理由です。

f:id:sgtech:20180326002126g:plain:w200

■Anima2Dのデメリット

この場合は違うツールを選択した方が良いです。

  • Unity 以外で開発を行う可能性がある(Cocos2D など)
  • フリーフォームデフォーメーション(頂点を動かしての細かいアニメーション)を行う

フリーフォームでフォーメーションをやるかどうかが一番の判断基準ですが、作り方によっては、コトダマンのように魅力的に動かせますよ!

f:id:sgtech:20180326002111g:plain:w200

■Anima2D を準備する

では、さっそく始めてみましょう。
まずは、アセットストアから「Anima2D」で検索してダウンロードします。
後述する Skinned Mesh Combiner(複数のキャラパーツを1ドローにまとめてくれるスクリプト)が入っているので、Examples も含めてインポートを行っておきましょう。
(最低限でも、Examples/Scriptsのみはインポートしてください)


f:id:sgtech:20180326002151p:plain

■全体の流れ

イラスト → パーツ分け → パーツ配置 → ボーン配置 → ウエイト付け → アニメーション作成 → 描画最適化
という流れで進みます。


f:id:sgtech:20180326000954p:plain:w1000
f:id:sgtech:20180326002142g:plain:w200

■イラストの準備(パーツ分け)

Anima2Dで動かすために、キャラクターのパーツ分けを行います。

f:id:sgtech:20180326001438p:plain

コツ

  • まずはキャラクターがどう動くのか、アニメーションを決定しましょう。ここをきちんと計画しておかないと、アニメーションを作り始めてから、パーツが分かれていなくて動かせない!などの問題が出てきます。
  • それでも、どう動かすかが決めきれない場合は、基本的に関節単位で分割します。
  • Photoshop上でCtrl+Tでパーツを回転させて、パーツの割り具合と動きを確認してみましょう。隙間が見える場合は塗り足すか、それをカバーするような動きに変更します。
  • 上腕・下腕・手、足などはパーツを分けておいた方が破綻せず、動きも大胆に作れるようになるので、分けておくのをオススメします。

Photoshopデータの作り方

  • パーツを切り分ける。1 パーツ 1 レイヤー。
  • 英数字でレイヤー名を付ける
  • パーツの書き出し。1パーツ1画像(.png)

後でこのルールを元に、Unity取り込みまでを自動化するスクリプトを作成します。

f:id:sgtech:20180326002331g:plain

■Unityへの取り込み

1枚のテクスチャーに収める

TexturePackerやSpriteUVなどを使って、1枚のテクスチャーにパーツを配置します。


f:id:sgtech:20180326000951p:plain:w128

マルチスプライトに設定

  • テクスチャーをUnityに読み込んだら、SpriteModeをMultipleに設定します。
  • 必要があれば、Sprite Editor ボタンを押して、スプライトを切り直します。


f:id:sgtech:20180326001435j:plain

Anima2D SpriteMesh に変換

  • テクスチャーを右クリック → Create → Anima2D → SpriteMesh でAnima2DのSpriteMeshを作成します。
  • テクスチャーファイルを選んで実行すると、まとめてSpriteMeshが生成されます
  • マルチスプライトの各要素(青い四角アイコン)を選んで、同じようにCreate → Anima2D → SpriteMeshとすれば、1個単位でSpriteMeshを生成されます。SpriteEditorで後からスプライトを追加した場合など、単品でSpriteMeshを作る事ができます。


f:id:sgtech:20180326002323p:plain
f:id:sgtech:20180326002319j:plain:w256
グリーンのオブジェクトがAnima2D のスプライトです。


f:id:sgtech:20180326002840g:plain

■Unity階層の準備

まず、メッシュとボーンを配置するための階層構造を準備しましょう。
GameObject -> Create Emptyで画像のような階層を組みます。

character → キャラクタートップ階層(全体に関するスクリプトはここに付けます)
/mesh → メッシュを置きます
/bone → ボーンを置きます


f:id:sgtech:20180326001422j:plain
f:id:sgtech:20180326001812g:plain:w256

■パーツ(SpriteMesh)を並べる

配置テンプレート(下敷き)の準備

キャラクターの1枚画像を下敷きとして用意し、これをガイドにパーツを配置していきます。

  • キャラの全身画像を用意し、Sprite(2D)に設定します。


f:id:sgtech:20180326002244j:plain

  • Hierarchy上にtemplate画像を置き、InspectorでColorのAlphaを半透明に設定し、配置ガイドにします。


f:id:sgtech:20180326002431p:plain

  • そして・・・頑張ってSpriteMeshを並べていきます!


f:id:sgtech:20180326002415p:plain

パーツの前後関係の設定(Order in Layer)

Order in Layerでパーツの前後関係を設定します。数字が大きい方が前面に描画されます。

  • 分かりやすいように、Hierarchy上でPhotoshopと同じ順に並べます。
  • Order in Layerを下から順に番号を振っていきます。


f:id:sgtech:20180326002426p:plain

この項目の工程は非常に面倒なので、後でスクリプトで自動化します!


f:id:sgtech:20180326002945g:plain:w200


■ボーンの配置と設定

配置

計画したアニメーションに合わせて、配置したパーツの上にボーンを並べていきます。


f:id:sgtech:20180326000958j:plain:w256

  • Hierarchy上で右クリックし、CreateObject→2D Object → Bone でボーンを出します。(またはAlt+Shift+B)


f:id:sgtech:20180326001419p:plain

  • ボーンの根本を掴むと移動、先の方を選ぶと回転ができます
  • Transform, Rotationツールを切り替える必要はありません。


f:id:sgtech:20180326002903g:plain

親子階層の設定

配置が終わったらHierarchy上で親子関係を組み立てます。


f:id:sgtech:20180326002420j:plain

boneの設定

Hierarchy上での親子関係とは別に、bone自体にChildという設定項目があります。
Anima2Dが計算する時に使うボーンの親子情報です。

  • IKで動かす場合は、必ず設定します。
  • 子階層に向かって、ボーンの向きと長さが自動で設定されるようになります。腕・脚など、関節部分は見た目が分かりやすくなります。

f:id:sgtech:20180326002628p:plain

Colorの項目でボーンに色を設定できます。
自分で分かりやすい色に設定しましょう。
f:id:sgtech:20180326002438p:plain

Color ボーンカラー。見た目の変更。
Child 子ボーン。IKを使うなら設定必須。
Length ボーンの長さ。Childが設定されていると自動計算されます。

コツ

  • 階層構造は最後に組みましょう。
  • 骨の配置時に階層構造も組みたくなるのですが、先にやってしまうと親の骨を動かした時に、子の位置もずれてしまうので、手戻りが発生します。


f:id:sgtech:20180326003427g:plain

■メッシュにボーンを割り当てる

メッシュを選んで、対応するボーンを設定します。

  • メッシュを選択
  • Bonesの右下の「+」を、割り当てたい骨の数だけ押します。
  • 出てきた空欄に、ドラッグ&ドロップでボーンを割り当てます
  • (まだメッシュにバインドしていないため警告が出ますが、今は大丈夫です)

f:id:sgtech:20180326002524p:plain

  • 階層をまとめて割り当てたい場合は、SetBonesにドラッグ&ドロップすれば、子階層まで一気に設定してくれます。

f:id:sgtech:20180326002617p:plain


f:id:sgtech:20180326003037g:plain

■メッシュ割り

メッシュはボーンに合わせて割ると綺麗に曲がりますので、ボーン配置後にメッシュ割りをします。

SpriteMesh Editor

Anima2D用のメッシュ割り&ウエイト付を行うエディタです。
Unity上部メニュー → Window → Anima2D → SpriteMeshEditor で表示します。

Sliceツールの利用

左上のSliceボタンを押すと、メッシュを自動で割ってくれます。
f:id:sgtech:20180326002620j:plain

Outline Detail 画像形状をどれだけ正しく追跡するか。値を上げると画像に沿ってメッシュが切られますが、頂点数が多くなります。
Alpha cutout メッシュを切る時のアルファの許容値。値を上げるほど画像の輪郭に近いメッシュが切られます。OutlineDetailの値が高くないとあまり効果はありません。
Tessellation メッシュの中を分割するか。画像の輪郭だけでなく、内部にも頂点が生成されます
Detect Holes ドーナツのような穴の空いた画像部分のメッシュをくり抜くか。

画像は自動で生成されたメッシュです。
手間を掛けたくない場合は、決め打ちパラメーターでもある程度の結果にはなりますが、Sliceのスライダーを動かし、自動で割ってから手で調整するのが楽でしょう。


f:id:sgtech:20180326003159j:plain

手動でのメッシュの調整

頂点の追加 Shift+クリック
頂点の削除 Del


f:id:sgtech:20180326003405g:plain

■ウエイトの設定

Bindボタンを押すと、メッシュに骨がバインドされ、自動的にウエイトが割り振られます。
ウインドウ下にWeightTool, Inspectorが出てきますので、これらのツールを使ってウエイトを調整していきます。

  • 頂点を選択(Ctrlを押しながらで複数選択可)
  • ウエイトを割り振りたい骨を選択
  • Weight Toolのスライダーでウエイトの割合を設定する


f:id:sgtech:20180326001940g:plain

Weight tool(SpriteMeshEditor:右下)

f:id:sgtech:20180326002516j:plain

Overlay メッシュ上にウエイトカラーを表示します
Pies 各頂点上にウエイトの割合を表示します
Smooth ウエイト分配をスムーズ化します。選択した頂点だけにも掛けられます
Auto 自動でウエイトを割り振ります。選択した頂点だけにも掛けられます

Inspector(SpriteMeshEditor:左下)

SpriteMeshEditorで選択したものの情報が表示されます。
画像は頂点を選択した場合です。
選択頂点に割り当てられている、ボーンとウエイトの確認・調整ができます。
f:id:sgtech:20180326002513j:plain

コツ

  • ウエイトを付けた後に、バインドしたまま、頂点の追加と削除ができます。
  • 後から足した頂点にはウエイトが割り振られていませんので(黒い点)、Autoボタンなどで忘れずにウエイト設定しましょう。
  • Unbindすると、設定したウエイトが初期化されてしまいます! 骨位置が違うと思ったら、早めにUnbindして骨位置を調整しましょう。ここはAnima2Dで改善して欲しい所です。

f:id:sgtech:20180326003412p:plain:w300

f:id:sgtech:20180326003347g:plain:w300

■リギング

IKの設定

  • 先端の骨を右クリック→2D Object→IK Limb(IK CCD2D) を選択して、IKコントローラーを出します。
  • グリーンの円がIKコントローラーです。


f:id:sgtech:20180326002522j:plain

IK Limb(2ボーンIK)

腕・脚など2本の骨を制御する時に使用します。
f:id:sgtech:20180326002626j:plain

Record IKコントローラーを動かした時に、ボーン側にキーを打ってくれます。実機上でIKの計算コストを掛けたくない時はONにしてアニメーションを作成します。
Target IKでコントロールされる骨。自動設定されます。
Restore Default Pose 計算を実行する前に初期ポーズを設定する。基本ON(現状ON以外の使い道が分かりません)
Flip 関節の曲がり方を反転。IK設定後に関節が逆に曲がってしまうならONにします。
Orient Child IKでコントロールされているボーンより、下階層にあるボーンの角度をどうするか。ON:IKコントローラーと同じ角度にする。OFF:階層の角度を維持する。

IK CCD2D(多関節IK)

尻尾などの長い関節の制御に使用します。
f:id:sgtech:20180326002623j:plain

Num Bones 多関節IKでコントロールするボーン数。自動設定されます。
Iterations 計算回数。大きいほど多関節ボーンがIKコントローラーを正しく追跡しますが、計算負荷が大きくなります。モバイルではデフォルトの10を基準とし、様子を見て値を下げましょう。
Damping 多関節ボーンの柔らかさ。1に近いほど固くなります。

Limb, CCD2Dの挙動の違い

IKによくある現象として、IKコントローラーとボーンが離れた時に、伸び切りが発生します。
伸び切った所から、再びIKコントローラーに接触すると、カクッとした動きになり非常に目立ちますが、
イラストを大胆に動かすと、どうしても伸び切り・カクつきが回避できない場合があります。
その場合は、2ボーンでもCCD2Dを使ってコントロールすると緩和されます。
Limbに比べて計算コストは高くなりますが、Iterationsの値(デフォルト10)を上げなければ、実機上でも問題ありません。
f:id:sgtech:20180326002756g:plain:w256

コントローラーの追加

ボーンに直接アニメーションを付けず、別階層でリグを組む時はコントローラーを利用します。

  • ボーンを右クリック → 2D Object → Controlでコントローラーを出します。
  • ボーンはコントローラーのTransformに追従するようになります。



f:id:sgtech:20180326003123g:plain

■ポーズマネージャー

定型ポーズの保存・読み込みができます。
ポーズライブラリや、同じ骨構造で違うキャラを作る場合など、色々活用できます。

Poseファイルの準備

  • Projectウインドウで右クリック → Create → Anima2D → Pose でポーズファイルを作成

コンポーネントのアタッチ

  • bone階層にPoseManagerコンポーネントをアタッチ。
  • 「+」ボタンを押してPoseファイルを設定
  • 必要なポーズ数分繰り返します。

f:id:sgtech:20180326000948p:plain

保存/読込

  • Save/Loadボタンで、ポーズの保存・読込ができます。

コツ

  • PoseManagerは、付いている階層以下のゲームオブジェクトのTransformを記録します。キャラクターの一番トップ階層につけてしまうと、メッシュの位置も記録されてしまい、違うキャラクター間でアニメーションを使いまわせなくなります。
  • アニメーションエディタをレコードにした状態で、PoseManagerのLoadボタンを押せば、ポーズがロードされて、自動的にキーが打たれます。モーションの開始/終了時に基本待機ポーズに戻す時などに使えます。
  • セットアップ中やアニメーション中に、デフォルトポーズに戻せるように、初期ポーズを登録しておくと良いでしょう。

f:id:sgtech:20180326003302g:plain

■アニメーション作成

Animation, Mecanimを準備

ここはUnity通常のフローなので、簡単に書きます。

  • Character階層を選択し、Animatorコンポーネントを付ける
  • Projectウインドウで右クリック→Create→Animator Controller。Animatorコンポーネントに設定。
  • Projectウインドウで右クリック→Create→Animation。
  • Animatorウインドウで右クリック → Create State → Empty。出てきたステートに、上のAnimationを設定。
  • Animationウインドウを開き(Ctrl+6)、ボーンを動かしてアニメーションを作成します。

パターンチェンジ(目パチ・口パク・着せ替え)

Anima2Dではパターンチェンジアニメーションを作成する事ができます。

  • メッシュを選択
  • Sprite Mesh Animation コンポーネントをアタッチ
  • 「+」を押して出てきた欄に、SpriteMeshを設定
  • Frameのスライダーを操作してパターンを切り替えます(上から順番に0, 1, 2・・・の値に対応しています)

f:id:sgtech:20180326003103g:plainf:id:sgtech:20180326000945j:plain

コツ

  • パターンチェンジするSpriteMeshの位置は、最初のメッシュ配置時にピッタリ同じ位置に合わせておきます。
  • アニメーションに追従する必要があるので、パターンチェンジメッシュも忘れずに骨をバインドしておきましょう。
  • 今回は目なので、パターンチェンジメッシュを全て頭の骨にバインドしています。これで頭の動きに合わせてついてきます。

IKによるアニメーション

IKコントローラーは、そのままアニメーションを付けて、実機再生可能です。

  • IK計算のコストを省くには、最後にアニメーションベイクする方法もありますが、全フレームにキーが打たれるのでアニメーションデータが大きくなります。(IKコントローラーを選択 → Unity上部メニュー → Window → Anima2D → Bake Animation
  • IKコントローラーのRecordボタンをONにすることで、IKコントローラーを動かした時に、骨側にアニメーションキーを打つ事ができます。(最後にIK Limb, IK CCD2DのActiveをOFFにするのを忘れずに。IK計算がされたままになります。)
  • IKのままアニメーション付けできるのがやはり楽ですが、実機での計算負荷を減らしたい場合は、Recordボタンの使用が落とし所だと思います。


f:id:sgtech:20180326003120p:plain


その他

2Dアニメーションを作成していますが、UnityなのでZ軸(奥行き)が存在します。
アニメーションで上手く使えば、面白い表現ができるかもしれません。

f:id:sgtech:20180326003249g:plain

■次回:Anima2Dを自動化しよう!スクリプトの作成

作業で面倒だった部分をスクリプトで自動化しましょう!

  • Photoshopからのエクスポート(各レイヤー毎の画像と、位置情報の出力)
  • 位置情報を元にAniam2Dメッシュを自動配置
  • Photoshopレイヤー順にOrderInLayerを設定
  • ボーンの配置
  • ゲームに出すための最適化

について書く予定です。


f:id:sgtech:20180326002657g:plain


 TAセクションではこのようにアーティストの制作に役立つ環境を提供できるよう力を注いでおります。やりたいことを遠回りせずに行える環境でお仕事したい方はぜひ下記の弊社グループ採用サイトをご確認ください。現在いろいろな職種でアーティストを多数募集しております!
採用情報 | セガ企業情報サイト


(C)SEGA

MayaからUnityへのUVアニメーションエクスポート

はじめに

こんにちは、セガ・インタラクティブ 第三研究開発本部 開発一部
ソフトウェアエンジニアのサカイと申します。
最近はアーケードゲームの開発をしています。

本日は、「MayaからUnityへのUVアニメーションエクスポート」
というテーマで書いていきます。作業記録のような書き方ですが、私の好みなので許してください。
いつもの作業の流れはこんな感じなのです。

まず、動機、計画について簡単にまとめた後、
本題のMayaからのエクスポートとUnityのインポートについて書きます。
最後に、まとめと今後の拡張案で締めます。

なるべく内容に間違いのないように努めますが、
必ず自身で調べて、確認するようお願いします。

概要

動機

現在、私のチームのアーティストはMayaでモデリングとアニメーションつけを行っています。
アニメーション作業の中にはUVアニメーションによるキャラクターの表情変化が含まれます。
しかし、Unityの標準機能ではUVアニメーションをMayaからインポートする方法がなさそうです。

Unity上で表情アニメーションだけ後付けすることは手間がかかりますし、不具合の元にもなります。
アーティストの要望は以下のような感じでしょうか。

  • Maya上でUVアニメーションもつけたい
  • Unityにインポートした後で手を加える必要がない

計画

少し調べたところでは、既存の拡張はなさそうです。位置等の別チャネルに入れる方法は手違いが生じそうです。
自作するしかないでしょう。下記2つの機能を使えば要望を満たせそうです。これらを使ってできない場合は、
別ファイルにUVアニメーションを出力 ⇒ インポート時に統合で実現は可能でしょう。プランBは常に考えておきます。

作業見積もりは、1日4~5時間作業できたとして、4日ぐらいでしょうか。調査が必要ですので長めに見積もっています。
後で不具合や修正要望が出たら片手間でも対応できるでしょう。

Mayaのエクスポート

”FBX Extensions Software Development Kit”というものが Autodeskさんから提供されています。
これを使うと、FBXのエクスポートのタイミングでFBXファイルの加工ができます。
Maya上のユーザデータを汚すこともなさそうです。

Unityのインポート

Unityには、FBXのロード後にユーザデータと共にフックする関数が用意されています。
AssetPostprocessor.OnPostprocessGameObjectWithUserProperties(Unityマニュアル)

適当なボックスを作成してテキスト形式のFBXで出力してみます。
以下のようにFBXファイルを修正すると、Unityでキーが”my_property”、値が”test”で取得できます。

Model: 1074780944, "Model::pCube1", "Mesh" {
    Version: 232
    Properties70:  {
        P: "RotationActive", "bool", "", "",1
        P: "InheritType", "enum", "", "",1
        P: "ScalingMax", "Vector3D", "Vector", "",0,0,0
        P: "DefaultAttributeIndex", "int", "Integer", "",0
        P: "currentUVSet", "KString", "", "U", "map1"
        P: "my_property", "KString", "", "U", "test"
    }
    Shading: T
    Culling: "CullingOff"
}

Mayaのエクスポートプラグイン

SDK

Autodesk FBXから"FBX Extensions Software Development Kit"をダウンロードします。
プラグインは C++ で書きます。詳細はドキュメントとサンプルで確認していただきたいですが、
FBXSDK_DLLEXPORT void MayaExt_ExportEnd(FbxScene* pFbxScene)で出力FBXを加工できそうです。
FbxSceneを作成した後に呼ばれる関数ということですね。

また、DCCツールのプラグイン開発ではツールのバージョンアップに対応する機会が多いため、
ビルド環境を構築する環境をCMakeで作成しておきます。

作成したDLLは以下のディレクトリにコピーします。2016 Extension 2で異なっているので注意します。

2016用: C:\Program Files\Autodesk\Maya2016\bin\plug-ins\FBX
2016.5用: C:\Program Files\Autodesk\Maya2016.5\plug-ins\fbx\plug-ins\FBX

UVアニメーションの検索

まずは、UVアニメーションはどこから取得できるか、Maya上で確認します。
アトリビュートエディタを見るとplace2dTextureにセットされているようです。
作り方によるでしょうが、上手く動かない場合が出たらその都度対応でよいと思います。
アトリビュートエディタ

ハイパーグラフ上では以下のようになっています。メッシュ ⇒ シェーダ ⇒ place2dTextureの順に辿れそうです。
ハイパーグラフ

シェーダがついたメッシュノードを走査するコードは以下になります。
これが一番速い易しいと思います。

{
    for(MItDependencyNodes nodeIterator(MFn::kMesh); !nodeIterator.isDone(); nodeIterator.next()){
        MObject node = nodeIterator.thisNode();
        if(node.isNull()){
            continue;
        }
        if(!node.hasFn(MFn::kDagNode)){
            continue;
        }

        MFnMesh mesh(node);
        MFnDagNode parent(mesh.parent(0));
        parent.getPath(nodePath_);
#ifdef APPDEBUG
        log_ << Log::indent << "path " << nodePath_.fullPathName().asChar() << Log::endl;
#endif

        for(unsigned int i=0; i<mesh.instanceCount(true); ++i){
            MObjectArray shaders;
            MIntArray indices;
            mesh.getConnectedShaders(i, shaders, indices);
            for(unsigned int j=0; j<shaders.length(); ++j){
                MFnDependencyNode shaderNode(shaders[j]);
#ifdef APPDEBUG
                log_ << Log::indent << "traverse shader " << shaderNode.name().asChar() << Log::endl;
#endif
                uuids_.clear();
                traverseConnections(shaderNode);
            }
        }
    }// for(MItDependencyNodes
}

次にマテリアルの属性を辿ります。ハイパーグラフ上の矢印を辿っているイメージです。
OpenMayaでこの辺りの詳細説明を見つけることができませんでした。
参考になるかはわかりませんが、MPlugについては以下の説明をリンクしておきます。
AutoDesk Area Japan 第68回:AttributeとPlugについて語る

ハイパーグラフを見るとわかりますが巡回しているので注意が必要です。
非巡回(DAG)なのはメッシュやスキンのノードツリーのところで、シェーダのところは巡回します。
UUIDで比較していると不具合がでそうですが、現在は問題がでていないのでそのままにしています。

void traverseConnections(const MFnDependencyNode& dst)
{
    //同じuuidが出現したら巡回している
#if 201516<MAYA_API_VERSION
    std::string uuid(dst.uuid().asString().asChar());
#else
    std::string uuid(dst.name().asChar());
#endif
    if(uuids_.end() != uuids_.find(uuid)){
        return;
    }
    uuids_.insert(uuid);
#ifdef APPDEBUG
    log_ << uuid.c_str() <<  Log::endl;
#endif
    Log::ScopeIndent scoped(log_);

    //繋がっているMPlugを全検索
    MPlugArray plugs;
    dst.getConnections(plugs);
    for(unsigned int i=0; i<plugs.length(); ++i){
        MPlugArray connections;
        connections.clear();
        plugs[i].connectedTo(connections, true, false);
        for(unsigned int j=0; j<connections.length(); ++j){
            if(connections[j].node().hasFn(MFn::kDagNode)){
                continue;
            }
            //アニメーション付きのplace2dTextureならアニメーション取得
            if(connections[j].isCompound()){
                for(unsigned int k=0; k<connections[j].numChildren(); ++k){
                    MPlug childPlug = connections[j].child(k);
                    if(MAnimUtil::isAnimated(childPlug)){
#ifdef APPDEBUG
                        log_ << "animated compound: " << childPlug.name().asChar() << Log::endl;
#endif
                        if(connections[j].node().apiType() == MFn::kPlace2dTexture){
                            runPlug(childPlug);
                        }
                    }
                }
            }else if(MAnimUtil::isAnimated(connections[j])){
#ifdef APPDEBUG
                log_ << "animated: " << connections[j].node().apiTypeStr() << Log::endl;
#endif
                if(connections[j].node().apiType() == MFn::kPlace2dTexture){
                    runPlug(connections[j]);
                }
            }
            MFnDependencyNode src(connections[j].node());
            traverseConnections(src);
        }
    }
}

最後に、アニメーションを取得してFBXにカスタムのプロパティを追加します。
プロパティは確実にUnityに渡すことができる文字列にしています。
コードを貼っているだけで申し訳ないですが、 本編ではこれで最後です。

void runPlug(const MPlug& plug)
{
    Log::ScopeIndent scoped(log_);
    MObjectArray animations;
    if(!MAnimUtil::findAnimation(plug, animations)){
        return;
    }
    for(unsigned int i=0; i<animations.length(); ++i){
        MObject animCurveNode = animations[i];
        if(!animCurveNode.hasFn(MFn::kAnimCurve)){
            continue;
        }
        MFnAttribute attribute(plug.attribute());
        if(attribute.name() == "offsetU"){
            writeAnimationCurve(plug, MFnAnimCurve(animCurveNode), "xxx_decal_tu");
        }else if(attribute.name() == "offsetV"){
            writeAnimationCurve(plug, MFnAnimCurve(animCurveNode), "xxx_decal_tv");
        }
    }
}

void writeAnimationCurve(const MPlug& plug, const MFnAnimCurve& animCurve, const char* name)
{
    //----
    //中略
    //----
    // ノードのパス文字列でFbxSceneからFbxNodeを検索する
    FbxNode* node = findNode(nodePath_.fullPathName());
    if(NULL == node){
        return;
    }
    FbxProperty propCurve = FbxProperty::Create(node, FbxStringDT, animName.Buffer());
    propCurve.ModifyFlag(FbxPropertyFlags::eUserDefined, true);
    //----
    //中略
    //----
    propCurve.Set(FbxString(animString.c_str()));
}

Unityのインポートエディタ拡張

Unity側は特に悩むところはないです。Maya側で設定したキー、上の例では"xxx_decal_tu"、"xxx_decal_tv"で
アニメーションが文字列としてインポートできるため、アニメーションを復元し他スキン用のアニメーションと合成すれば完成です。
気を付ける点は、設定する以下4つのシェーダプロパティはセットで設定します。Repeatのアニメーションがなければ適当に追加します。

private const string PropertyNameDecalTexRepeatU = "material._DecalTex_ST.x";
private const string PropertyNameDecalTexRepeatV = "material._DecalTex_ST.y";
private const string PropertyNameDecalTexOffsetU = "material._DecalTex_ST.z";
private const string PropertyNameDecalTexOffsetV = "material._DecalTex_ST.w";

表情をUVアニメーションで付けたかったため、デカールテクスチャです。
何の証明にもなりませんが、以下が復元合成したアニメーションです。
Unityアニメーション

まとめ

駆け足かつコードを貼り付けただけですが、MayaのUVアニメーションをUnityへインポートする方法の説明をしました。
作業自体のまとめは以下です。

  • 良かった点
    • 要望を達成した。
    • 作業期間は概ね予定どおりで終了した。
  • 問題点
    • DLL方式のプラグインの場合、DLLを解放する仕組みがないと開発がつらい。
      • Mayaの再起動に時間がかかる。だから、1日4~5時間作業で、他の仕事と同時進行の見積もり。
  • 改善点
    • Pythonだけで解決できないか。

発展

この記事を書くにあたりコードなどを見返していて、スキニングに削れそうなキーフレームがいくつかあることに気づきました。
現在は頑張って削る必要はないのですが、将来必要に応じてインポート拡張に入れる準備もしておきましょう。
コードだけですが。

public static AnimationCurve decimate(AnimationCurve src, float tolerance=1.0e-4f, int resolution=1024)
{
    System.Diagnostics.Debug.Assert(null != src);
    System.Diagnostics.Debug.Assert(0.0f<=tolerance);
    System.Diagnostics.Debug.Assert(0<resolution);

    AnimationCurve dst = new AnimationCurve(src.keys);
    int srcIndex=1;
    int dstIndex=1;
    float invResolution = 1.0f/resolution;
    for(;;) {
        if(dst.length<3) {
            break;
        }
        if((src.length-1)<=srcIndex) {
            break;
        }
        //キーを削除しても、セクションが似ているかチェック
        Keyframe key = dst[dstIndex];
        dst.RemoveKey(dstIndex);

        float start = src[srcIndex-1].time;
        float end = src[srcIndex+1].time;
        float duration = end - start;
        bool equal = true;
        if(1.0e-5f<duration) {
            for(int i = 1; i<resolution; ++i) {
                float time = i*invResolution*duration + start;
                float v0 = dst.Evaluate(time);
                float v1 = src.Evaluate(time);
                if(tolerance<Mathf.Abs(v0-v1)) {
                    equal = false;
                    break;
                }
            }
        }
        //似ていなかったらキーを元に戻す
        if(!equal) {
            dst.AddKey(key);
            ++dstIndex;
        }
        ++srcIndex;
    }
    return dst;
}

おわりに

いかがでしたでしょうか、何かしら楽しげな仕事風景を、というつもりがただコードのコピーになってしまいました。
私のように、コードを示された方が理解が進む人がたくさんいることを願います。
プロジェクト初期はこのような作業環境準備の仕事がほとんどです。
将来チームが楽をするためにしっかりと土台を作っておきたいものです。

私達、第三研究開発本部では、このような下支えの仕事に積極的な方、もちろんゲーム作りが好きな方と
一緒に働きたいと考えています。もしご興味を持たれましたら、弊社グループ採用サイトをご確認ください。

採用情報|株式会社セガ・インタラクティブ
採用情報|株式会社セガゲームス -【SEGA Games Co., Ltd.】

そんなことよりHoudiniやろうぜ!

初めての方は初めまして、そうでない方はお久しぶりです。
ここ10年龍が如くシリーズ製作にどっぷり浸かってるVFXアーティストの伊地知と申します。

今日は最近巷で大人気のHoudiniで基本部分の理解から簡単なエフェクトをUE4に表示してみるまでを皆さんにお届けしようと思います。

とりあえずこれだけは知っておきたい基礎知識
●操作方法
選択モード:s→2(Point)、3(Edge)、4(Primitive)、5(Vertex)
編集モード:Enter
カメラモード:Esc(選択モードや編集モードの時は一時的にSpace又はAlt)
ノード生成:Tab→ノード名検索キーワード(例えばattribute wrangleならaw、Sphereならsph)



Houdiniではジオメトリを扱う際に各コンポーネントの種類毎にグループとアトリビュートという情報が持てます。
データの構造と流れを各ノードに把握しておくのが重要になってきます。

コンポーネントの種類
Point、Primitive、Vertex、Detailの4種類があります。
f:id:sgtech:20180120232427p:plain
それぞれのコンポーネントにランダムで色を付けるとこの様になります。
それぞれ点、面、面毎の点、全体と覚えておくと良いでしょう

アトリビュートの種類
各コンポーネントにアトリビュートが持てます
デフォルトのアトリビュートとしてはP(座標),N(法線),uv,Cd(色)などがあります。
また独自のアトリビュートを作成して情報を格納しておくことが出来ます。
後述しますがwrangleでの記述方法としては
f@hogehoge = rand(@ptnum);
// 上記はfloat型のhogehogeというアトリビュートを作る例です。@の前の1文字で型の指定が出来ます。vならベクター型、sなら文字列型です。
// ちなみに右項は頂点番号をシードにして0~1までの乱数を生成しています。
●アトリビュートの確認方法
ビューポート上の画面下半分でAlt+] → Alt+8 と押して下さい。GeometrySpreadSheetが表示されます。
GeometrySpreadSheetはデータの構造を確認する上で重要なものなので常に表示してのが良いでしょう。
f:id:sgtech:20180120232423p:plain

最も簡単なVOPとwrangleの例:
VEXでアトリビュートを扱うにはVOP(VEX Oprater)wrangleを使った二通りの方法があります。

SphereSOPを作りPrimitiveTypeをPolygonにしてFrequencyを10に上げます。
f:id:sgtech:20180120232146p:plain

次にpointVOPSOPを作りiやダブルクリックでpointVOPの中に潜ると

f:id:sgtech:20180120232139p:plain

こんな感じのインターフェイスがあります。
左側のgeometryvopglobal1というノードはpointVOPの第1入力の事です。
そして右側のgeometryvopoutput1はこのVOPノードネットワークの結果を返します。
試しにgeometryvopglobal1の出力のP(頂点の位置)とgeometryvopoutput1の入力のCd(頂点カラー)を繋いでみましょう。
すると球に頂点カラーが設定されます。

では同じ事をwrangeでやってみましょう。

先程のsphereSOPの下にpointwrangleSOPを作成し繋げます。
f:id:sgtech:20180120232132p:plain

pointwrangleSOPのパラメータにはコードを書き込む為のテキストエリアが存在し
そこに@Cd = @P;と入力しても先程のVOPと同じ結果が得られます。
f:id:sgtech:20180120232126p:plain

この様にVOPやwrangleを用いて頂点座標や頂点カラー、法線、UVなど様々なアトリビュートにアクセス出来るのがVEXの強みです。
またwrangleの場合、非常に高速に動作する(C/C++コンパイル相当)のも魅力的です。

ちなみにこの例の場合Cd(頂点カラー)にマイナスの値が入り込んでくるので
VOPであればfit rangeVOPを用いてwrangleであればfit01関数を用いて0~1の間に合わせてやると正しいデータになります。
f:id:sgtech:20180120232119p:plain
f:id:sgtech:20180120232431p:plain

Attributeのコピーや転送
同じトポロジー同士であればAttribute Copy、距離でアトリビュートを転写するのであればAttribute Transferを使うと良いです。
また違うコンポーネントにアトリビュートを移したい時はAttributePromoteを使うのが定石です。

グループ
各コンポーネントにグループを設定出来ます。
バウンディングオブジェクトでポイントのグループを指定する例
f:id:sgtech:20180120232418p:plain
法線でプリミティブのグループを指定をする例
f:id:sgtech:20180120232414p:plain

グループのコンポーネントの変換
ポイントグループをプリミティブグループに変換するのはGroup Promoteで出来ます。

駆け足でしたがここまでで基本的なジオメトリに関する操作は理解出来たでしょう。
ここまでの知識とSOPの機能を学んでいけばプロシージャルモデリングは可能です。
他のDCCツールと比較して無い機能もあったりしますがそうした際はポータルサイトで、英語で調べるとたいていは情報を得られますので、
あまり心配しなくとも良いでしょう。



ではここからは実際にループするパーティクルを作成してUE4に出力してみましょう。

ループするパーティクルの作成

フォースフィールドの作成
まずはフォースフィールドを生み出すガイドとなるカーブを作成します。
LineとCircleからSweepに繋いでねじれたチューブを作ってCarveで螺旋を取り出すという事をやります。
その際Lineの方に@pscaleと@orientというアトリビュートを持たせてSweepに渡す事で形状の調整をします。
そしてCopyStampでY軸回転に均等コピーしておきます。
f:id:sgtech:20180120232809j:plain
point wrangleには

float div = (@ptnum)/float(@numpt);
f@pscale = chramp("widthControl",div)*chf("widthBase");
@orient = quaternion( radians(chf("roll")+div*360)*chi("twistNum")*chramp("twistPow",div),@N );
の様に記述してパラメータを出し調整する事ですぼんだ様な形状にする事が出来ます。
ちなみにアトリビュートを使わない設定にすると
f:id:sgtech:20180120232822j:plain
この様に均等なねじれになります。
あとはDOPNetworkに渡す前に@forceアトリビュートを作っておけばフォースのガイドは完成です。

ワンショットパーティクルの作成
DOPNetworkにつないでパーティクルを作成する際popnetという名前で作成しておけば
自動的にPOP ObjectPOP SourcePOP Solverを作って繋げておいてくれるので楽です。
f:id:sgtech:20180120232804j:plain

なぜループのパーティクルを作るのにワンショットを作るのかといいますと
シミュレーションでノイズをかけるとパーティクルは周期的にはなりませんので
ワンショットパーティクルを作成してそれを連続再生させてループに見せる手法を取るためです。
(残念ながらGameDevelopmentToolSetのMakeLoopはパーティクルには効きません)
f:id:sgtech:20180120232816p:plain
図にするとこんな感じです
f:id:sgtech:20180120232806p:plain
ファイルキャッシュにした時点でトライ&エラーがやりづらいのであらかじめワンショットの時点で
動きや雰囲気などを皆さんの感覚で良い感じに見えるようにしておきます。
もっとうまい方法があれば良いんですが世の中そう都合の良い話は無いですね。
DOPNetowork内に話を戻すのですが先程作ったフォースのガイドを
あらかじめDOPNetworkの2番目に繋いでおいてSOPGeometryのSOP Pathに

`opinputpath("..",1)`
としてfieldforceDOPに繋いでPOPSolverとoutputの間に差し込みます。
f:id:sgtech:20180120232930j:plain
またPOPSourceの下にちょっとしたノイズを足す為にPOP Wind DOPを足しておきます。
すると動き的にはこんな感じになります。
f:id:sgtech:20180120232919g:plain

ループパーティクルの作成
これをfile cacheSOPでキャッシュを取っておいて前述の半分にして折り返す処理をします。
Alt+Shit+Gを押してGlobal Animation Optionsを出してシーンのフレーム数を半分にして
Time Shiftでフレーム数の半分を足してMergeします
f:id:sgtech:20180120232916j:plain

すると動きがループになります。
f:id:sgtech:20180120232905g:plain

ブラーが欲しくなるので気持ち的にはここでTrailSOPを使いたくなるのですが
スタートフレームとエンドフレームで破綻するのでTrailは使わずに一旦file cacheに動きを保存しておいて
Time ShiftSOPのエクスプレッションで対応します。
f:id:sgtech:20180120232901j:plain
こうすることでループさせてもスタートとエンドがキレイにつながります。

パーティクルのメッシュ化
Particle Fluid Surfaceにつなげてパーティクルをメッシュ化します。
物凄く重いので形がカッコよくなった段階で一度file cacheに取りLoad From Diskにチェックを付け
滑らかに再生出来る状態で動きを確認します。
f:id:sgtech:20180120233044j:plain

メッシュの削減
Poly Reduceなどを用いて最適なポリゴン数にまで落とし込みます。
CleanやRemesh、Dissolveなども使っても良いかもしれません。
f:id:sgtech:20180120233019g:plain

VertexAnimationTexturesノードを使ってデータを出力する
この状態をUE4に持っていくことにします。
/outモジュールに移って Vertex Animation Texturesノードを作ります。
f:id:sgtech:20180120233014p:plain
このノード名がメニューに出てこない方は
github.com
をダウンロードして入れて下さい。
入れ方が分からない人は同梱されてるREADMEを読んで下さい。
(英語ですけどそんなに難しく無いので大体分かると思います。)
で、
f:id:sgtech:20180120233010p:plain
MethodはここではFluid、ExportNodeを設定、Target Poly Countを決定しRenderボタンを押します。
※@Cd(頂点カラー)のアトリビュートを設定しておけばColorMapのチェックボックスを付ける事で色情報も出せます。

VertexAnimationTexturesのシェーダをUE4上で構築する
次にVertexAnimationTexturesのシェーダをUE4に持っていきます。
VertexAnimationTexturesノードの下の方にあるFluid VertexAnimation UE4 Codeの+ボタンを押してUE4のシェーダーコードを表示し
f:id:sgtech:20180120233006p:plain
全選択してコピーします。
f:id:sgtech:20180120233137p:plain
UE4上で新規マテリアルを作成して
[ff:id:sgtech:20180120233132p:plain]
ダブルクリックしてマテリアルエディタを開きます。
f:id:sgtech:20180120233124p:plain
そして先程コピーしておいたUE4のシェーダーコードをペーストします。
f:id:sgtech:20180120233119p:plain
するとこの様にマテリアルエディタ上にシェーダのノードネットワークが構築されます。
f:id:sgtech:20180120233115p:plain
マテリアルエディタの詳細タブの目玉マークのプルダウンメニューからアドバンスな詳細を表示にチェックを付けます。
f:id:sgtech:20180120233308p:plain
さらにカスタムUVの数3に設定します。
あとはノードネットワークのコメントに従って対応するパラメータを接続します。
f:id:sgtech:20180120233303p:plain
これでマテリアルは完成です。

マテリアルインスタンスの設定
先程Renderボタンで作成されたFBX(モデル)とEXR(テクスチャ)をUE4にドラッグ&ドロップしてインポートします。
f:id:sgtech:20180120233259p:plain
「全てインポート」で構いません。
f:id:sgtech:20180120233251p:plain
次にマテリアルインスタンスを作ります。
f:id:sgtech:20180120233248p:plain
ダブルクリックして設定ウィンドウを開き先程作ったマテリアルを親マテリアルにします。
f:id:sgtech:20180120233420p:plain
HoudiniのVertex AnimationノードのBBOX MAXとMINの値をコピーして
UE4にペーストします。あと該当するチェックやフレーム数も同様です。
f:id:sgtech:20180120233417p:plain
あとポジションのテクスチャも設定しておきます。
f:id:sgtech:20180120233412p:plain
これでマテリアルインスタンスの設定は出来ました。

モデルにマテリアルインスタンスをアサインする
先程インポートしたFBXモデルをダブルクリックして設定ウィンドウを開きます。
マテリアルスロットに作成したマテリアルインスタンスを設定します。
ビルド設定の「最大制度のUVを使用」にチェックを付けてモデルへのマテリアルインスタンスの設定は終了です。
f:id:sgtech:20180120233409p:plain

これでモデルをビューポートにドラッグ&ドロップすればUE4上で再生出来るループする流体エフェクトの完成です。

f:id:sgtech:20180120233345g:plain

いかがでしたでしょうか?
ゲームに出力する部分は意外と手続き的な処理が多く煩わしさはありますが、Houdiniで作った流体表現が
ゲームに表示出来るというのは感慨深いものがあるのではないでしょうか?
こういったエフェクトの手法は日々進化していきます。
現状ビルボードが主流のゲームエフェクトですがデータとシェーダを工夫する事でこの様な表現が可能になりました。
5年後10年後どういった表現が可能になるのかワクワクしますね。

という訳で恒例の求人タイムです。
弊社ではHoudiniに興味を持って取り組めるような人を募集しています!
私の作ったシーンを見放題にもなれますし社内でハンズオンセミナーなども開催していますので
興味のある方は以下のリンクをクリックしてみてください。



採用情報 | セガ企業情報サイト

Ruby on Railsでアセットライブラリを作ろう!

 年の瀬も押し迫り、すっかり寒くなりましたね。今年最後のお役目をつとめます、セガゲームス開発統括部アート&デザイン部TA(テクニカルアーティスト)セクションの宮下です。
 普段はUnityでアーティストとプログラマを繋いだり、Mayaプラグイン(C++)やスクリプトを書いたり、たまにデザインデータを作ったりしてます。今回は、TAの業務でも少し変わったネタとして、Webアプリ作成についてお伝えします。とくに最新のネタというわけでもないので、プログラマの方には退屈な記事かと思いますが、ご容赦ください。

そもそもWebアプリって?

 ブラウザ上で動く、サーバーを介したアプリケーション、みなさんも普段から使ってますよね。GoogleやFacebook、Twitter、Slackなど、インターネットを通して提供されているサービスは、ほぼWebアプリと呼んでいいでしょう。あのような有用なサービス、そこまでいかなくてもちょっとしたサービスをプロジェクトや部署の中で提供できたら楽しくないですか?もちろん会社内でのWebアプリなので、インターネットではなく、イントラネットを使ったサービスということです。

Docker

 その方法の1つは、オープンソースのWebアプリを探してインストールし運用することです。最近はDockerというものがあって、簡単にWebアプリをPCにインストールできます。

docker run --name mattermost-preview -d --publish 8065:8065 mattermost/mattermost-preview

 Dockerがインストールされていれば、このコマンドを実行するだけでSlackのようなチャットサービスMattermostを提供できます。
 もしかすると、これぐらい当たり前のように感じられるかもしれませんが、まともにWebアプリをインストールしようとすると面倒なことになるので、このDockerはなかなか画期的です。
 ニーズにマッチしたオープンソースのWebアプリが見つかればいいですが、探しても見つからない…。そんなときは、もう1つの方法、自分で作るしかない!TAだから!(昔はデザグラマって言われてました…。今はいい言葉があります。)
 今回は、アセットライブラリとボット管理ツールなど3例、紹介します。

アセットライブラリ

f:id:sgtech:20171224002340j:plain
f:id:sgtech:20171224002335j:plain
 2015年に作った部内用のWebアプリで、アーティストの作成したデータの共有を目的としています。具体的には、psdやtgaなどの画像ファイル、UnityのスクリプトやPrefabなどを格納できるUnitypackageファイルなどを共有しています。基本的に誰でもブラウザからアップロード、ダウンロード可能で、検索やタグ付け、フォルダのような階層構造も持っています。合わせてgifサムネイルを自動的に作成しUnity上からアップロードできるUnityスクリプトも用意しました。モーションやエフェクトは、gifアニメで視覚的にどのようなアセットかを確認できます。
 ファイルをアップロードする機能を作って公開した直後に、誰かがアップロードしていると、他の人がアクセス不能状態になることが判明し、あわてたことを覚えています。1人で開発とテストをしているときには分からなかった問題だったのですが、原因はアップロードした画像のサムネイルを生成するなどの後処理がメインプロセスを占有してしまうためで、後処理を非同期にすることで対応しました。
 

ボット管理ツール

f:id:sgtech:20171224002348j:plain
 私たちの組織では、Cisco SPARKというチャットツール(チャットワークやSlackのようなものです)を導入しています。それにはボットを組み込む機能があり、何らかの情報をボットから提供することができます。ただし、APIが公開されているだけで、使うにはハードルが少々高い。そこで、ボット管理ツールをWebアプリとして作りました。
 このWebアプリでは、ボットのスケジュールや発言内容、週替わりや日替わりの当番の指定ができます。たとえば、特定のメッセージを決まった時刻に発言させる、毎週水曜日のミーティングの議事録当番を知らせる…といったことが可能になります。
 もともとは今参加しているプロジェクトの朝会当番を、ボットに教えてもらうために作ったのですが、現在では他プロジェクトやセクションのミーティング告知など、幅広く活用してもらっています。
 面白かったのは、本来当番のメンバー名を入力すべき箇所(上のスクリーンショットでぼかしの入っているところですね)に、カレーやラーメンなどの食べ物名を入れて、ボットに今日食べる昼ごはんを日替わりでつぶやかせているプロジェクトがあったことです。遊び心のある思いもよらなかった使い方に驚かされました。

アーティストアサイン管理ツール

f:id:sgtech:20171224002344j:plain
 プロジェクトがいくつも平行している中、アーティストのアサインの調整がスピーディに求められていませんか?私たちの組織では求められています。エクセルでの管理もいいのですが、もっと効果的に管理はできないものかと突貫で作り上げたのが、このWebアプリです。リーダーがメンバーのスケジュールを入力し、どういったスキルのアーティストを求めているのか、また、いつアーティストがプロジェクトからリリースされるのかを視覚的に分かるようにして管理しています。まだまだ発展途上のWebアプリで現在も作成中です。
 
 それでは、次にこのようなWebアプリの作成方法を簡単に説明します。

Ruby on Rails

 私、個人的にRubyが大好きで処理の自動化などに使っています。でも、MayaなどのDCCツールのスクリプトに採用されている言語はもっぱらPythonなので、実はあまりアーティストには勧められません。
 Webアプリを作るためのフレームワークとして、とても有名なものがあります。それが、このRubyで作られたフレームワーク「Ruby on Rails」です。「Ruby on Rails」の思想は、ほかのフレームワークにも大きな影響を与えていて、Pythonなら「Django」、phpなら「CakePHP」というフレームワークがあります。「Ruby on Rails」は2004年の誕生でなかなか歴史があり日本でも人気です。それゆえ、Web上での日本語の情報も豊富でビギナーにもお勧めできるフレームワークです。大抵の問題や要望は、Webで検索すれば解決できます。

 「Ruby on Rails」はActive Recordが有名で、この機能により簡単にデータベースにアクセスできます。具体的には、オブジェクトのインスタンスが、そのデータベースの1つの行を表すような仕組みです。

a = Game.new 
a.name = "sonic the hedgehog"
a.price = 5000
a.save

このコードで、新しい行を追加できます。すばらしい!

 「10分で Rails」とWebで検索するとたくさんヒットするように、とても簡単にWebアプリのひな形を作ることができます。ここでは「セガ」というWebアプリを新しく作ってみますね。

rails new sega
cd sega
rails generate scaffold game name:string price:integer
rake db:migrate
rails s

 これらを実行したのちに

 http://localhost:3000/games

にブラウザでアクセスすると、
f:id:sgtech:20171224002332j:plain
のような画面が出てくると思います。
New Gameをクリックすると、
f:id:sgtech:20171224002411j:plain
このような画面に遷移して、ゲーム名と値段を入れることができます。先ほどActive Recordでの例をブラウザから入力して、「Create Game」ボタンを押してみます。
f:id:sgtech:20171224002407j:plain
どうですか?簡単ですね!
 上記のアセットライブラリやボット管理ツールは、この「Ruby on Rails」のバージョン4で作成し、このようなひな形から肉付けして発展させたものです。そして、その作業を助けてくれるのがRubyGemsです。

RubyGems

 Webアプリの機能を作る上で、すべてを1から書くのはとても時間がかかります。RubyGemsはRubyのパッケージ管理システムで、世界中のスペシャリストたちが作ってくれた便利機能を簡単にインストールできます。ここで、さきほど紹介したアセットライブラリを作る上で組み込んだパッケージを紹介します。

devise

アカウント管理のためのGemです。ユーザーアカウントとパスワードにまつわる部分を簡単に実装できます。
github.com

CarrierWave

ファイルのアップロード機能を組み込むためのGemです。
github.com

kaminari

ページ切り替え機能を提供します。こういう名前が日本語由来のGemを見ると、ちょっとうれしくなりますね。
github.com

rmagick

画像フォーマットを扱うのに便利です。psdやtgaのサムネイルをブラウザで表示させるためにjpegに変換するのに使っています。ただ、psdをうまく処理できないケースがあって、それに対応するため、「psd.rb」というGemも使っています。
github.com

psd.rb

psdファイルを読み込んだり、サムネイルを作成するためのGemです。
github.com

ransack

便利な検索機能を提供してくれます。
github.com

最後に

 アセットライブラリのWebアプリ(サービス)と言えば、このサイトが良くできてます。
sketchfab.com
 こんなの作ってみたいですね。ブラウザさえ動けば、もはや何もいらない時代は意外と近そうです。

 ここまで読んでくださった方、ありがとうございました。
 TAセクションではこのようにアーティストの制作に役立つ環境を提供できるよう力を注いでおります。Unityの登場でTAの活躍できるフィールドは格段に広がり、シェーダーやポストエフェクトなど面白い表現を生み出せないかと日々切磋琢磨しております。そんな中でお仕事したい方はぜひ下記の弊社グループ採用サイトをご確認ください。いっしょに働きましょう!

採用情報 | セガ企業情報サイト

Powered by はてなブログ