それ以前はどうしていたのか?「龍が如くスタジオ」で行っていた3Dスキャンの歴史を簡単に説明します。見参!』の制作から3Dスキャンによるワークフローが導入されました。PS2世代までは写真を見てモデリングを行っていました。いわゆる目コピーです。制作クオリティはデザイナーのスキル頼りだったのです。見参!』から実在の俳優を登場させることにもなり、リアリティとクオリティの追及がさらに重要視されるようなりました。END』まで社外のスタジオで役者さんを撮影し、メッシュデータもそのスタジオで生成されたものを使用していました。3Dスキャンを行うようになりキャラクターのモデリング時間は40%削減でき、クオリティも上がりました。外部スタジオを利用していたころのスキャンメッシュそのスタジオでは当時としては最新式だった光学式(ヘリウムネオンレーザー)の3Dスキャナーを使用していましたが、スキャンメッシュの精度はごらんの通り、なんとなく誰だか認識できる程度で細かいディテールは撮れていません。END』の途中から導入が始まった社内撮影スタジオでスキャンされた3Dモデルです。投影式3Dスキャナを利用してキャプチャされた3Dモデルこの頃から社内に撮影専用スタジオを設け、テクスチャはカメラ1台(手持ち)での撮影からスタートし、後にカメラ5台(+三脚・ストロボ)でシャッターを同期させて撮影する方法に移行。精度の高いテクスチャを撮影できるようになりました。(走査型白色)方式*2の3Dスキャナーを導入しました。プロジェクターを用い撮影対象に画像を投影して専用ソフトウェアで解析して3Dメッシュを生成するという方法です。社内に専用スタジオを設け新しい3Dキャプチャのシステムを導入したことにより、メッシュの精度が以前より向上し時間面でも費用面でも社外スタジオの利用時に比べて大幅なコストカットを達成しました。暗室で5秒程度息を止めて動かないでいる必要があるため、まばたきや体が動いてしまうだけでメッシュの精度が低下するなど正確な3Dモデルのキャプチャは非常に難しく、撮影されている人の負担も大きかったのです。社外スタジオのスキャンデータも社内スタジオのスキャンデータも、どちらもテクスチャの生成ができなかった為、3Dメッシュを生成した後撮影した画像をメッシュにベイクしてテクスチャを自分たちで作成する必要がありました。その頃のテクスチャ作成方法は、DCCツール内部に画角が同一となるカメラを作成し、位置を合わせてカメラプロジェクションUVを作成しテクスチャベイクしていたのですが、この作業だけで数時間かかっていました。社外スタジオのスキャンデータも社内スタジオのスキャンデータもそのままではノーマルマップベイクのソースにできるほど精細にキャプチャできるわけではなく、Zbrushでのスカルプトによるディテールの追加作業は必須でした。PhotoScanの導入そんななか、フォトグラメトリーの技術を使い3Dメッシュを生成するPhotoScanというソフトウェアがプロジェクトに導入されました。上の写真は2015年から2018年現在まで使用している社内フォトスタジオです。事業所移転前の羽田にあった旧スタジオの様子なので手作り感あふれる仕上がりですが、ここで沢山の芸能人の方々をスキャンしてきた見た目にそぐわずできるヤツなんです・・・が、なんと!現在大崎の新オフィス内に「龍が如くスタジオ」キャラクター班こだわりの新スタジオを構築中なのです!今年度中に完成予定ですのでお楽しみに。話は戻って、カメラのスペックは以下のようになっています。55mm基本設計や機材の調達は社外の専門家に委託し、その後の運用、撮影のオペレーション、メンテナンスなどはキャラクター班が行っています。画像の現像X-Rite社のColorCheckerPassportと一緒に撮影した画像からカメラプロファイルを作成し全ての現像に使用します。「龍が如く」シリーズは常に部内開発のゲームエンジン上で制作されてきました。することでレスポンスが良く柔軟なゲーム開発が可能になり、デザイナーの時には無茶な要求にも短時間で実装することができるのです。』の開発時にアップデートされた内製ゲームエンジン「ドラゴンエンジン」は、それまでのゲームエンジンよりシームレスでリアルな表現が可能になりました。部内でゲームエンジンを開発できるような高い技術力を持ったプログラマがたくさんいるのも、「龍が如くスタジオ」がクオリティの高いゲームを素早く作れる要素の一つとなっています。前置きがだいぶ長くなってしまいましたが、本題のキャラクターワークフローの解説に移ります。今回は「龍が如く」シリーズ関連のプロモーションでおなじみ島野さんの顔制作に沿ってお伝えします。3Dメッシュ生成3Dメッシュの生成にはAGISoft社のPhotoScanというソフトウェアを使用しています。PhotoScanの操作画面このソフトウェアの導入により3Dメッシュの生成と同時にテクスチャも生成できるようになったことから、テクスチャをMaya上でベイクしていた数時間の作業が削減されテクスチャ作成時間が大幅に短縮できました。この一連のフローにより、デザイナーのスキルに依存していたクオリティの向上と制作時間が短縮し安定して高水準なクオリティがアウトプットできるようになったのです。フローでは実際に3Dメッシュを生成する過程を紹介しましょう。最後にテクスチャベイクで終了PhotoScnanは各画像のカメラの位置や画角を画像解析により取得し、ソフトウェア上で撮影環境を再現しますが、ソースにしている写真の点数が少ないと各画像の位置関係が予測できずカメラの位置情報が取得できなくなります。現在弊社スタジオは30台のカメラで構成されており、横の耳から後ろの首回りまで360度カバーできるようになりました。高密度クラウド上記の画像はポイントクラウド(点群)です。この状態では点群と認識できないくらい高密度なので寄ってみます。寄ってみます小さい点が見えるのがわかりますか...?このポイントクラウドを元にメッシュとテクスチャを生成します。PhotoScanで生成したポリゴンメッシュ上の画像は生成したメッシュデータです。1000万ポリゴンで生成しています。テクスチャ表示とUV上の画像はテクスチャです。PhotoScanが生成したポリゴンメッシュとUVに写真がベイクされます。これらを任意の形式でエクスポートしてR3DS社のWrapXというツールでPhotoScanからエクスポートした3Dメッシュにベースメッシュをシュリンクラップします。この工程の詳細は後ほど解説しますね。顔モデル作成フローPhotoScanやWrapXで得たソースを元に実際にどのようにゲームのデータに落としこむのでしょうか。スキャンメッシュとゲームメッシュを合わせるという作業になります。これはPhotoScanで生成したメッシュです。これがWrapXで生成したメッシュです。実際に合わせてみるとこうなります。わかりにくいですが目の周りのエッジフローが少し歪んでいますね。ゲームメッシュのエッジのラインがきちんとスキャンメッシュの特徴に沿うように修正していきます。目の周りはまつ毛や二重や粘膜の部分など細かい造形が多くPhotoScanでは再現しきれません。口の周りも唇の内側など写真には写らない部分はメッシュが生成されないので、その二か所はどうしても手作業で修正する必要があります。これらの作業は非常に重要で、メッシュの法線情報を正しく作ることによりクオリティを上げるという目的もありますが、「龍が如く」シリーズではフェイシャルモーションが複雑に動くためエッジフローが実際の筋肉の流れに沿っていないと後々イベントムービーシーンで思わぬ破たんを生みだす原因となってしまいます。この作業に関してはWrapXの導入でかなり効率化されました。次はテクスチャ作成なのですが、その前に簡単に描画周りを説明しておきます。「龍が如く」ではいわゆる主流ではない、f0値を扱ったPBRを採用しています。この理由は、「龍が如く」というプロジェクトがゴリゴリのフォトリアル指向ではないことと、ゲームに妖怪や怪物*3など現実にいないキャラクターが登場する可能性を加味し、ある程度振り切った表現ができる今の形に収まりました。テクスチャについて次は「ドラゴンエンジン」で使われているテクスチャについてです。顔一つの表情に沢山の種類のテクスチャが使われています上記の画像にあるような8枚*4のテクスチャをキャラクター班で作成して使用しています。DiffuseMap、NormalMap、ShinnessMap、AmbientOccrusionMapは、おそらく大体のプロジェクトでお馴染みだと思いますので説明は割愛します。アンビエントオクリュージョンマップアンビエントオクリュージョンマップをわざわざ1枚のマップで持っているのは、キャラ単体では画面を占める割合は低くスクリーンスペースのアンビエントオクリュージョンが充分に乗らないので個別でベイクしキャラごとに用意しているからです。トランスミッタンスマップ肌透過用のトランスミッタンスマップは、肌の薄い部分を表現するために使っています。逆光を当てられた時の耳や、指などに効果的です。F(0°)マップ黒い画像ですが、F(0°)マップと呼んでいます。F(0°)とは屈折率の比から求まる、0度のフレネル反射率という意味らしいです。屈折率0度、法線方向から見たときの、鏡面反射率、スペキュラーの総量です。mayaにあったmental_rayのマテリアルでは、IOR(屈折率)と書かれていることからリフレクションの強さにも影響します。値が高いほど正面から見ても環境が映りこみます。キャラクター班としては素材ごとに担当プログラマーに用意してもらった値で作業するという認識です。次にテクスチャの作成フローです。龍のテクスチャワークフローは、タンジェントノーマル、AO、シャイニネスの順番に一連の流れで制作しています。ディフューズは状況によって前後いたしますが、スキャンメッシュと生成された画像をソースに、ゲームメッシュでベイクすればほぼ終了です。タンジェントノーマルマップまずは16bit高解像度テクスチャを利用してディスプレイスメントマップを作成します。そのディスプレイスメントマップをZbrush上でスキャンメッシュにアサインしてゲームメッシュにベイクするのが目的です。PhotoScanにより自動で生成されたテクスチャがコレです。PhotoScanで生成したテクスチャご覧のとおりバラバラです。ほくろやシミなどの余計な凹凸情報になりえるものは先にフラットにしておきます。前処理が済んだらPhotoshop上でハイパス等を使いディスプレイスメントマップを作成します。次にZbrush上での作業にうつります。右側がZbrush上で、スキャンメッシュにディスプレイスメントマップを適用した状態です。ディスプレイスをかける前よりかなり細かい凹凸が表現できているのがわかりますでしょうか。先ほど調整したゲームメッシュをインポートし、レイヤー分けしてからスキャンメッシュにディスプレイスメントを適応します。その凹凸情報を、projectALLを使って転写します。スキャンメッシュにはエラーも多いので、この作業の前に事前にモーフターゲットを登録しておきprojectALLで投影したくない部分をマスクしてするなどして都合の悪い部分をフィルタリングしています。その後、キャラクターによってはさらにスカルプトしてディティールアップを図ります。後はSubdivisionの一番上と一番下をエクスポートし、XnormalやSubstance等のテクスチャベイカーを使ってタンジェントノーマルとAOを生成します。人によってはディフューズもこの段階でスキャンメッシュからベイクします。生成したテクスチャが...これですね。バラバラだったUVが繋がっています。スキャンメッシュからベイクによって得たデータとなります。ディフューズマップはベイクしたままというわけにはいかないのでさらに手を入れて調整します。テクスチャの撮影時に陰影を消すようにはしているものの、どうしても取りきれない陰影が入ってしまいますので手作業で余計な陰影を除去します。わかりづらいかもしれませんが、除去前と除去後で陰影の差が少し緩和されています。消しすぎると単調に見えるのでさじ加減に多少経験が必要な作業です。シャイニネスマップシャイニネスマップは、ノーマルマップをキャビティマップに変換するアクションを使い作成したマップをオーバレイで5枚重ね共通のトーンカーブを適用した後、光って欲しいところ、欲しくないところを既定の値で塗り完成です。すべてのキャラクターはUVが共通なので、実際はキャビティレイヤーの差し替えと個人で違う位置になる唇周りと眉毛周りの塗りの調整のみ行っています。Substanceでも同様に上の一連の作業が組んであります。トランスミッタンスマップつづいて肌透過用のトランスミッタンスマップの作成も紹介しましょう。顔モデルにスムースをかけた後に、白黒反転をしてアンビエントオクリュージョンをベイクしたものです。このフロー自体が正しいものなのかは正直わかりませんが、コストと効率を鑑みて、最も効果的なフローでした。処理軽減のため全てのキャラが同じテクスチャを使っています。以上ですべてのテクスチャ作成が完了です。仕上げにテクスチャの中間データはDDSを採用しているのでDDSで書き出します。その際のインターフェイスが煩雑で多くの設定ができてしまうので、デザイナーが迷わないようにツールを用意しました。リサイズのアルゴリズムとDDS保存形式を任意で選ぶことができます。元々はガンマ補正、レベル補正の設定や、ラップモード設定、ミップマップ設定など細かく分かれていたのですが、それらの仕様が確定されてからは、混乱を避けるため全て非表示にして触れないようにしてあります。細かいことですが、これによりかなりミスも少なくなりかなり効率的に作業できるようになりました。全身どうでしょう、島野さんに見えますか?「龍が如くスタジオ」流のフローでこのクオリティの顔モデルが今では1日もあれば誰でも制作できるようになりました!架空のキャラクターついでに架空キャラクターのフローについてもすこし触れてみましょう。基本的に弊社の社員に協力してもらい、リアルなキャラクターを作成する場合のフローでほぼそのまま再現します。その後、キャラクターの設定に合わせて修正します。このキャラクターは眉毛の角度や目つきの修正ぐらいしか行っていません。設定によっては元の風貌からは別人になるケースもあり、特に重要度の高いキャラになるとコンセプト画で用意した顔に近づけるために原形をとどめなくなります。その場合は、ほとんど肌のディフューズ以外は、使用しないのでデザイナーの腕の見せ所でしょうか。次は顔モデリング以外の話を簡単にご紹介します。顔のしわ各キャラクターには顔の表情が変わったときに表出する皺を表現するための皺マップが用意されています。下の画像はとあるキャラの顔の皺マップです。用意するマップはノーマルマップのみです。皺用のディフューズやシャイニネス等は用意しておらず、頂点カラーの塗分けによってノーマルマップの表出を制御しています。皺表出用の頂点カラーイベントムービー班が設定した表情のパターンに合わせて表出するようになっており、デザイナーの作業負担軽減の為全キャラクター設定はほとんど同じです。キャラ作成をサポートするツール群ここまでモデルを作成するフローを説明してきましたが、ここからはそのフローの作業を軽減するツールについてお話したいと思います。ウェイトのセットアップツールです。DCCツールをSoftimage*6からMayaに切り替えた経緯上、Softimageと同じ感覚でMayaでのウェイト編集を出来るようにする必要がありました。そこでまずはデザインサポートチームでウェイトのエディタを作成することになりました。顔のポリゴンメッシュはWrapXによって生成されたものを使っていれば全て同じUV・同じ頂点番号なので、ウェイトセットアップは頂点番号かUVのポジションでウェイトをアサインします。これで殆どの場合うまくいくのですが、目の形によって目を閉じた時に破綻したり眉毛の位置によっては眉毛が付いてこない、あるいは瞬きしたときに眉毛もついてくる等のバグが発生します。Maya用のウェイトエディターを使って修正していきます。ウェイトのスムースや、ジョイントのロック、ウェイトを保持したままのエッジ切り直し、スキンモデルのデュプリケート、スキンモデルのコンバインなど沢山の便利なツールが用意されています。このエディタが用意されてからはコンポーネントエディターの数倍速くウェイトの修正ができるようになりました。WrapX上記でチラホラ名前の挙がっていたツール、WrapXを紹介します。WrapXとは大抵はDCCツール上で行うシュリンクラップを、高精度で行うスタンドアロンのアプリケーションです。今は多機能な新バージョンもリリースしている古いツールですが、スクリプトで操作できるのが決め手でこのツールを長らく使用しています。「龍が如く」プロジェクトでは、PhotoScanで取得した高精細なポリゴンモデルを、リトポロジも兼ねて一定のトポロジのメッシュに落とし込む目的で使用しています。Pythonでスクリプトを書かないとカスタマイズができないのでデザイナーからしてみれば使いにくいツールですが、このツールを導入しあえてデザイナーが触れないようにしてリトポロジやポリゴンの削減をWrapXで吸収してしまえば、こだわりがちなデザイナーの工数も増えづらいのではないかという狙いもあります。WrapXでシュリンクラップを行います左がベースメッシュで約5000頂点あります。ベースメッシュとは、「龍が如く」プロジェクトにおいて素体として最初に作られるモデルで、ほぼすべてのキャラクターモデルはこのベースモデルを基準に作られています。右がスキャンメッシュです。既存のPhotoScanで生成した顔のメッシュやテクスチャ、トポロジを共通にするためのベースモデルを読み込み、最初は三点、両目頭と人中にポイントを指定して大まかに頭部の位置とスケールを合わせます。次に、詳細にシュリンクラップを行うため、位置合わせのためのポイントをPhotoScanのメッシュとベースモデル両方に指定していきます。計算を除外するポリゴンも指定する事ができるので、ソースのメッシュが大きく欠けている場合も、ベースのモデルを大きく変形させる事なくシュリンクラップを行う事ができます。設定が完了したら計算を行います。その過程をGifにしてみました。シュリンクラップの様子(約40倍速)最後にスキャンメッシュをシュリンクラップしたベースメッシュと、それに位置とスケールを合わせたスキャンメッシュをエクスポートして完了です。WrapXをMayaから操作するツール最初はWrapXのみでシュリンクラップの作業を行っていましたが、現在では手軽にシュリンクラップや編集が行えるようにMayaからコントロールできるツールを用意してあります。こちらのツールでは、WrapXの鬼門であったフローの途中で指定していたポイントの編集を行う機能も追加しました。顔のハイメッシュは、このWrapXのフローを採用することでまだ技術的に未熟なデザイナーでも比較的ハイスピード&ハイクオリティに作成できるようになり、トポロジを共通化することで面倒なウェイト関連の作業もストレスなく行う事ができるようになりました。LODの作成ゲーム制作の辛いところはここからLODを作成しないといけないところですが、LOD作成もツール側である程度自動化してあります。現在既成のLOD作成ツールは「龍が如く」プロジェクトでは使用せず、クオリティ重視で手作業によりLODを作成しています。顔のLODは先ほどのトポロジの共通化によりボタン一つでクオリティを維持したまま生成できるツールが使えるのでLOD制作の時間はほとんどかかっていません。そのほかのツール「龍が如く」プロジェクトではほかにもリアルなキャラモデルを短時間で作り上げる為に、いろいろなフローを取り入れています。「リアルにする為のフローを取り入れる=工数の増大につながる」ことが多いため、フローの採用とその際に増える工数の圧縮の為のツールの制作はセットで行うようにしています。MarvelousDesignerで作成したデータのリトポロジ用のツールなどがあります。MarverousDesignerは衣服などの3Dデータの作成や、シミュレーションを行えるアプリケーションです。リアリティのある衣服の3Dモデルを作成するには最適なアプリケーションでしたがリトポロジが大きな課題でした。この問題もデザインサポートチームでリトポロジーツールを作成し、さらにゲームエンジンにすぐに組み込めるようウェイトやマテリアルの設定、各種テクスチャの焼きつけなども簡易的に行えるようにしました。他には今まで作成した大量の顔データをブレンドして新しい顔を作るツール写真を撮影するだけでPhotoScanにより全自動でスキャンメッシュが生成されるツールそのPhotoScanで生成したスキャンメッシュを短時間でゲーム用のデータに落とし込むツールなど沢山あります。Mayaはスクリプトを覚えてツールを作れるようになるとあちこち自動化・高速化ができてとても楽しいツールです。私はデザイナーとしてセガに入社しましたが、今ではPythonでMayaのツールを作るのにすっかりハマっています。皆さん、はじめまして!セガ・インタラクティブ技術統括室の林田です。1997年入社、20年越えのおっさんプログラマです。入社以来、おおむねアーケードゲームに携わってます。いくつか私の代表作を紹介しておきましょう。Stageシリーズ、WCCFシリーズなどなど。古いタイトルもありますので、あまりご存知ないかもしれませんね。ご興味があればWebやYoutubeなどで検索してみてください。(Objective-Cネイティブ!)、あとは古い時代の部内ライブラリなども担当したことがあります。主な担当分野は、キャラクタアニメーション周り、あとは「火消し」と呼ばれる厄介な事件を解決する人、最近ではアンリアルエンジン4全般を担当しています。今回の記事は、セガテックブログ初(!)の「アンリアルエンジン4(以下UE4)」についてです。初のUE4記事ゆえ力が入ってしまい、とても長くなってしまいました。お時間のある時にゆっくり読んでいただければと思います。この記事は、UE4の(ちょっとマニアックな)TIPSを中心に書かせていただいています。紙面を余分に頂いて、我々がUE4タイトルをリリースする前にやっていた実験などの紹介などを、前半に書かせていただいています。「前置きはいいから、本題を!」という方は、途中を飛ばして「マクロは悪?」のあたりから読んでくださいませ。くじセガ製UE4タイトルは、お近くのゲームセンターで好評稼働中です。言い出しっぺが語るセガ×UE4タイトルを作る前は、こんな実験をしてました。今回の記事は...今回つかう題材は、UE4ぷちコン応募作品です。(Blueprintに限る)定数はどうしてますか?ゲーム用定数マクロライブラリを用意する。ノードグラフをより見やすく、便利にするための定数マクロマクロ内ローカル変数を活用する。当初から重くなるのは覚悟してました。セッションフロントエンドでCPU負荷をチェックしてみる。カリング処理を作ってみる。C++化も試してみる。弾幕で分かるBlueprintの限界おわりにインディーズのススメセガ・インタラクティブではUE4エンジニアを募集しています。セガ製UE4タイトルは、お近くのゲームセンターで好評稼働中です。GTの実車両や実在コース(実在コースは期間限定)を再現しています。体感してみてください。MOVIE開発チームより13年ぶりにアーケードゲームへ帰ってきました。ゲームのグラフィックやプログラムは全てUE4エンジンで完結しています。アーケードゲームらしく、筐体の音や振動が非常に凝った演出となっていますので、お近くのゲームセンターで見かけたら、ぜひプレイしてみてください。言い出しっぺが語るセガ×UE4何を隠そう、私がセガのアーケードゲームにUE4を持ち込もうと騒ぎ始めた張本人、いわゆる「言い出しっぺ」です。ご多分に漏れず「言い出しっぺの法則」が発動しまして、ここ数年は社内UE4担当大臣として活動しています。事情は脇に置いておいて(とは言え、おおむね多くの大手ゲームメーカーさんと同じ事情だと思います)、ここは「テック(技術)」ブログですから、UE4を使ってモノを作る話をしましょう。タイトルを作る前は、こんな実験をしてました。UE4を甘噛みしてみる実験(UE4.3のころ)四輪駆動のおもちゃが壁のあるコースを走るアレです。あのおもちゃと同様、前進しかできず、コリジョンで(壁に沿って)曲がるように作られています。原理的には非常に簡単ですので、興味のある方はぜひ真似をしてみてください。作り方ヒントこういうポリゴンを使って、スプラインメッシュでコースを作っています。コリジョンは見た目よりもかなり高い壁を作りましょう。ないとクルマが簡単に吹き飛んでコースアウトします。車はアクセルボタンに応じた前進しかしません。あとは運を天に任せて、うまく曲がってくれるのを祈る感じです。場合によっては吹き飛んでしまいますが、それはそれで楽しいかと思います。何ならブレーキ操作をできるようにして、コーナーではうまく減速するゲームにしても面白いでしょう。コースの各所にトリガーボリュームなどを置いて、「時間内に通過するとパワーアップ」などのギミックを入れても面白いでしょう。格好いい映像を作ってみる実験(UE4.5のころ)上記の「四輪駆動のおもちゃ」はプログラマ主導でやっており、アーティストにはコース作成だけお願いしていましたが、今度の実験はアーティスト主導で行いました。Designer/Painterも試しています。本職の人が作ると違いますね。DEADを意識するというテーマを悪用して(?)、作ったメンバーの趣味が存分に盛り込まれています(笑)。UE4の特徴である「物理ベースレンダリング」を活かそうと、光と影を意識した映像の実験となります。従来のセガのアーケードゲームとは多少趣が異なり、明暗のコントラストを強めに出しています。いわゆる「洋ゲー」に寄せた、といったところでしょうか。一通りゲームを作ってみる実験(UE4.9のころ)ここまでの実験である程度UE4が分かってきましたので、今度は一連のゲームの流れを作る実験をしました。何らかのタイトルプロジェクトを発足させる前に、踏める地雷はあらかじめ踏んでおこう、がテーマです。パーティクルエフェクト担当のアーティストや、ユーザーインターフェース担当のアーティストも参加して、チェインクロニクルをアーケード向けにアレンジしたらどうなるか?を試しに作ってみたものです。本家チェインクロニクルの倍(10人!)のプレイヤーキャラクタ、倍どころじゃない数の敵、パーティクルエフェクトが派手に飛び交い、カメラもグルングルン回る。これを80型の大型タッチパネルモニタで両手を振り回して遊ぶ。アーケードゲーム化するんだったら、派手に!大味に!半ばパニックになっちゃうくらい忙しい!そんな風にしちゃいました。これは作るのも楽しかったですね。この実験成果の報告会では、100名を超える社員が会議室に集まってしまい、大半は立ち見、エアコンが追いつかず会議室はどんどん暑くなるという事態に。おかげさまで社内へのUE4の認知度は高まり、UE4採用プロジェクトとしてSWDCとHODを発足させることが出来ました。ご注意いただきたいのですが、本家チェインクロニクルがUE4に移植される予定も、アーケード版をつくる予定も全くありません。実験の題材として使用しただけですので、「次のチェインクロニクルはUE4だ!」なんて、間違った情報をうっかり拡散してしまわないようにお願いしますね!さて、今回の記事は...20年越えのオッサンプログラマが、その経験をBlueprintに活かすとどうなるか、そういう話をできればいいなと思っています。UE4の紹介記事などもWebを検索すればたくさん見つかるようになりました。申し訳ありませんが、この記事には初心者向けの説明はあまりありません。それよりはもうちょっと深い部分、私視点でのUE4の「コーディング(code-ing)」ならぬ「ノーディング(node-ing)」事例などを紹介したいと思っています。初心者の皆さんには、有名な書籍をご紹介。初心者お断り!なんてバッサリ斬り捨ててしまうのも心が痛いので、書籍を数点ご紹介しますね。本を見つつ、Webで検索しつつ、おそらく最初は苦労されるかとは思いますが、それを乗り越えて楽しくなってきたら、ぜひこの記事に戻ってきてくださいませ!では、書いてある通りにやれば、何か動くものが出来上がる、おそらくはUE4ユーザーの大半がお世話になっている良書から。見る同じく、「書いてある通りにやれば何かできる」もう一冊。Kindle版この商品を含むブログを見るこちらは残念ながら、おそらくUnityで使われてただろうキャラクタモデルが流用されており、Unlit(ライティングなし)前提ですので、UE4の美しいレンダリングには触れられていません。それでもキャラクタをアニメーションさせて動かす等々、おそらく多くの皆さんがやりたいと思っているだろう要素は、ちゃんと揃っていますのでご安心を。お手軽に試してみたい方には、書籍ではありませんが、こちらの動画はいかがでしょうか。4で極める...」の著者、湊さんによる勉強会での公演の動画です。私も一番最初にこの動画をマネをすることで、UE4へのとっかかりを得ました。動画では画面の細かい文字が見えませんが、Blueprintのスクショを貼ってくれた方がいらっしゃいますので、こちら(↓)のページと合わせて見ると良いでしょう。www.jonki.netなお、この動画は慣れた方がサクサク組んでいらっしゃいますが、初心者にはテンポが速すぎて追いつけません(当時の私もそうでした)。一時停止や巻き戻しを繰り返して追いかける感じになりますので、決して、40分では完成しません。悪しからずご了承ください。2~3日かけてゆっくりやるくらいの心づもりで。UE4はアップデートの周期がとても短く(この記事の執筆時点でUE4.20.3。記事のチェックをしている間にUE4.21が出てしまいました)、気を抜くとあっという間に情報が古くなってしまいます。上記3つの書籍・動画は古いバージョンのものですので、お手持ちのUE4バージョンとは違い、もしかしたらメニューの位置やコマンドの名前などが変わってしまっているかもしれません。新旧のバージョン間の機能の違いを、Web検索などを駆使してなんとか見つけ出すのもUE4の勉強の一環だと思って、頑張ってみてください。Web上では、UE4は難しい...という声をチラホラ見かけます。確かにそうかもしれません。私も最初の2か月くらいは、UE4が嫌いでした。それを乗り越えて、ざっくりでもUE4が分かってきたころから、逆にサクサクものが作れていく感覚を覚え始めます。今では「テキストエディタを開いてプログラミング言語を入力する」こと自体に抵抗を覚えるくらいのUE4信者になってしまいました。BlueprintとMaterialは手放せません。C++/C#の時代は終わったなんて言っちゃっています。UE4はAAAタイトルすら作れちゃうくらいの豪華ツールです。大量の機能や設定の中から、今自分が欲しい機能を見出せるようになるには時間をかけて慣れるしかありません。今回つかう題材は、UE4ぷちコン応募作品です。株式会社ヒストリアさん主催の「UE4ぷちコン」はご存知でしょうか。毎回テーマが出され、それに沿ったゲームや映像作品をUE4で作って応募する、ちょっとしたゲームコンテストです。「UE4の勉強の成果」を発表する、勉強会の延長線上にあるもので、誰でも参加できます。皆さんも参加してみてはいかがでしょうか。一方で、意外と本気勢も多く(私もその一人ですね)、「ガチコン」と言われてしまうこともあるようです。ヒストリアの佐々木社長はこの言葉を嫌がっているようですが、幸か不幸か、初心者作品からプロ作品まで非常に幅広いレベル帯の作品が集まるコンテストになっており、自分の現在のレベルと、次に目指すべきレベルが見えやすい、とても良いイベントです。それはともかく、今回の記事は、私が第9回ぷちコンに応募したゲームを題材にお話しようと思っています。ONEテーマは「ループ」。丸い地球上(マップがループしている)でのシューティングゲームを作ってみました。ありがたいことに、「カナマイ賞」を受賞することができ、アンリアルフェスWEST2018でプレイアブル展示していただきました。社内でも、毎日昼休みにスコアアタックをしてくれるドハマリプレイヤーが出現。記念にご本人の強い要望に応えて、このゲームのexeを進呈しました。第10回ぷちコン応募作品「MAGITYPE」つい先日行われました、第10回ぷちコンにも応募させていただいています。【UE4ぷちコン#10応募作品】MAGITYPEテーマは「ぷち」。ぷちコンの「ぷち」です。安易に思いつく「プチプチ」(梱包材のアレです)は断固避ける!と意気込んだものの、制作期間の6割くらいの間、ずっと迷走してしまい、結局は未完成のままの応募になってしまいました。テーマ「ぷち」の回収方法として私が選んだのは、過去10回の「ぷち」コンのテーマを全部使う!明らかに盛りすぎですね。間に合うわけもありません。審査結果発表会では軽くご紹介いただきましたが(動画2:15:00くらいから)、もちろん落選です。プロとして恥ずかしい限りです。鋭意作成中...(どうなることやら)この「MAGITYPE」からも、ご紹介したい事例がいくつもあるのですが、長くなってしまいそうなので、また次の機会に。「MAGITYPE」が完成した後などに記事にできればと思います。応募要項には「日本在住のUE4ユーザーなら誰でもOK!」と書いてあります。確かにズルいとは思っています。自分なりにハンデを設けて作っています。やること多くて死ねますけど。21年もゲームプログラマをやっていますと、アーティストやサウンドデザイナーとのやり取りなどで、それなりにツールの使い方や用語などは覚えるものです。箱を作ってテクスチャを貼れる程度には使い方を知っています。その程度の技量で全素材づくりに挑むのですから、十分ハンデかと。おかげさまで、2回のぷちコン参加で、SDキャラクタ作成・テクスチャ作成・アニメーション作成なども自分でできるようになりました(クオリティはともかく)。ほら、ちゃんと勉強になっているから、ズルくない!参考までに、プログラムは組めるけど絵素材や音素材がなくて困っている皆さんや、インディーズを目指している皆さんに、私が使っているツールをご紹介しておきますね。indie(月々1500円ほど)3Dモデリングツールの中では新しく、古い時代のしがらみなどが少ない分かりやすいツールです。GROUPのページにはチュートリアル動画やTIPS動画がたくさんあり、学習のしやすさもオススメしたい理由の一つです。Suite(買い切り6万円ほど)私は学生のころから論文などの図の作成に使っていました。アップデートを繰り返して使い続けています。いわゆるフォトショップやイラストレーターに相当するツールがセットになっています。CorelDRAW(イラストレーター相当)は、私や多くのアーティストでない方々のように、フリーハンドで思い通りに線が描けない人にはありがたいツールです。筆で描くのではなく、方眼紙に定規やコンパスで図を描くイメージですね。私はベジエで描いてから、ビットマップに変換する流れでテクスチャを作成しています。Pro(買い切り2.5万円ほど)いわゆるDTMソフト、音楽編集ソフトです。当時は5.5万円ほどしていたのが、今では1.7万円ですね!驚愕です。私が音楽の世界に足を踏み入れたのは、ボカロ(なぜかミクさんではなくルカさん)の影響です。www.apple.comC-Deck(540円×3種)トランプ大のカードにコード進行が書かれた作曲ツールです。Aメロ、Bメロ、サビカードをランダムに選ぶだけでコード進行が完成です!私はこれがないと作曲できません。古いツールのなので、今ではAmazonなどでも欠品してますね...。再販してほしいものです。(Blueprintに限る)前置きが長くなってしまいました。ここからは具体的なUE4プログラミングやTIPSの話を書いていきましょう。以下、Blueprintのスクリーンショットが多く登場します。紙面の都合上、どうしても画像が小さくなってしまいますが、クリックすると大きく表示されますので、その機能をご活用ください。ブラウザを複数立ち上げて、片方では文章、片方では画像の拡大を表示する、などの小技を使えば、より見やすくなるでしょう。残念ながら、Blueprintには定数という概念がありません。接頭辞や接尾辞を付けるなど、命名規則を工夫して対処しているかと思います。256;Blueprintではそうはいきません。ここでマクロの出番です。C言語の時代を知っている人は、マクロは危険という認識から、UE4でも避けてしまっているのではないでしょうか。(256)こんな風に書いちゃった日には、確実に先輩にドヤされます。C/C++言語のマクロとは、その数値が整数型なのか実数型なのか、ましてやそれが数値であるかどうかすら、コンパイラは全く気にせず、単なる文字列の置き換えで対応してしまうからです。ところが、ご存知の通り、UE4のマクロはきっちり型を意識してくれます。いうマクロを作ると、これは間違いなくInteger型の256となってくれます。Title」の欄にノード名を書くことです。これを書くことで、「いかにも定数です」みたいな見た目になってくれます。ゲーム用定数マクロライブラリを用意する。上記の例はアクタの中で作っていましたが、ゲーム全体で使う定数はどうしましょうか。答えは簡単、マクロライブラリを作れば解決します。Library」といった名前のマクロライブラリを作り、ゲーム全体で使う種々の定数を入れています。これで、このマクロライブラリを編集するだけで、ゲーム中の様々な状態を変更することができるようになりますね。バランス調整用の定数マクロライブラリなどがあっても良いかもしれません。(ゲームエンジンの時代に定数でバランス調整って、時代遅れな気もしますが...)なお、定数を変更したらコンパイルしなくてはなりません。ここはご注意ください。「False」と書くだけ。マクロも用意しておきましょう。これらは、作成者の意図を明示するだけでなく、ノードグラフをサクサク組むための助けにもなってくれます。Falseマクロがサクっと引っぱり出せるようになります。これらもマクロライブラリを作って、便利そうなものはどんどん入れておきましょう。参考までに、私のマクロライブラリに入っている便利定数をご紹介します。UE4/Blueprintライフが向上すること請け合いです。-1」などを用意してます。検索して、(あの小さい枠に)0を入力して、の手間がまるっと解消されます。ちなみに上記は軸との内積の正負で、回転角度のプラスマイナスを決めるような、比較的よくありそうなノードグラフですね。Identity」ノード。ちなみにIdentityとは「単位行列」の意味。これも右クリックのノード検索メニューで「Identity」と入力するだけで出てきます。1)を一発で書くためのものです。マクロ内ローカル変数を活用する。One」に登場するザコ敵です。「プレドニゾローン」という、とても覚えられない名前がついてます。このプレドニゾローン、キノコ状の「フタ(Flap)」が一定時間ごとに上がったり下がったりします。これをBlueprintで書いてみるとどうなるでしょうか。使っているメンバ変数に初期値をセットしています。UpdateFlap(カスタムイベント)を呼び出しています。ザコ敵とは言え、弾を撃つなど、もっとたくさんの処理がぶら下がるはずですが、上の図はあくまでサンプルだととらえてください。Tickから呼び出され、「フタ(Flap)」の回転や上下動を行うカスタムイベントです。FlapHeight)を決めています。FlapYaw変数の値を算出しています。RotationSpeedで、次の角度を求めています。Component)の相対位置と相対角度をセットしています。UpdateFlapから呼び出され、フタ(Flap)の上下動を行います。ElapsedSeconds)を算出しています。Duration)で開け閉めの割合(Alpha)を求ています。CloseFlag)を渡しています。FlapHeightに格納します。Duration)を越えたら、経過時間をゼロクリアし、開け閉め状態のフラグ(CloseFlag)を反転します。使い方がちょっとだけトリッキーなので注意してください。WaitDurationを考慮に入れていないため、1を超えてしまいます。Alphaの値を0~1にクランプしています。Duration秒数だけ開いたまま/閉じたまましばらく待つ、という状態を作ってます。Alpha)を0~1の範囲にクランプしています。Close)に応じて、OpenHeightからCloseHeightまでのをEaseするのか、CloseHeightからOpenHeightまでをEaseするのかを切り替えています。Easeで求められた高さをNewHeightとして出力します。多少トリッキーな書き方をしているのは認めますが、考え方は至って普通です。その経過時間から、フタの高さを求める。一定時間経過したら、開け/閉めを切り替える。ここで話題に挙げたいのは、この「フタの開け閉め」で使われている4つのメンバ変数です。このフラグがTrueの時は閉め、Falseの時は開け、の動作を行う。状態切り替えのためのフラグ。フタを開け始めてから/あるいは閉め始めてからの経過時間(秒)。フタの回転角度(Yaw値)さて、この、至って普通のノーディング、20年オヤジは何が気に食わないのでしょうか。これらの変数は、単にフタを開け閉めするだけのための用意されました。フタの開け閉めなんて、このActorにとっては影響度/重要度はかなり低いです。私としては、重要度の低い変数(や関数)は、できる限り重要度の高いものとは分けて置いておきたいのです。本音を言うと、メンバ変数にすらしたくない。ないと、クラスに機能が増えていくにつれ、メンバ変数の欄はどんどん肥大化し、重要度の高い変数と低い変数が同レベルでゴチャっと並んでしまうのです。実はこの問題、マクロ内ローカル変数を使うことで解消できます。(Modified)まずは簡単にできるところから。フタの回転角度として使っていたメンバ変数FlapYawをなくしてしまいました。Macroというマクロを作りました。Macroの中身はこうです。Floatノードが「マクロ内ローカル変数」です。普通に「+」ノードなどに挿して、Floatとして使えます。いわゆるSETノードに相当するののが「Assign」ノードです。上の図では「マクロ内ローカル変数に、YawAdderを足して、マクロ内ローカル変数にAssign(セット)する」「マクロ内ローカル変数をNewYawとして出力する」が行われています。マクロ内ローカル変数の制限などについて。変数名がつけられませんので、複数のマクロ内ローカル変数を使うときは混乱しがちです。Floatから必ずラインを伸ばす必要があります。Floatノードから、相手のノードに直接つなげる必要があります。したがって、マクロ内ローカル変数をたくさん使うと、非常にたくさんのラインが飛び交うスパゲッティコードになりがちです。Graph内に限り、常に値は保持される」という特徴があります。と一つずつ増えてくれます。このアクタが破棄されるまで、この値がクリアされることはありません。Upマクロの実装ただし、イベントグラフ内ではなく、関数内でマクロ内ローカル変数を使った場合、関数呼び出しのたびに値がクリアされますので注意してください。マクロを使って、思ったように動かなかった経験のある方はたくさんいらっしゃると思います。これもマクロ内ローカル変数のこの性質が原因です。(どちらかというと、イベントグラフが特殊で、関数が普通の挙動をしているのですが...それはさておき)興味のある方は、UE4標準の種々のマクロの実装を見てみてください。ダブルクリックするだけで見られます。マクロ内ローカル変数を使って実装されていますよ。Flap関数がどう変わったか見てみましょう。こちらは比較的トリッキーです。戸惑われた方もいらっしゃるかもしれません。マクロが2か所あるのは良いとして、恐るべきことに(?)1つのグラフにカスタムイベントが3つ繋がっています。それでは個々に見ていきましょう。Secondsをこのマクロで置き換えています。ここまでに紹介してきたマクロとほぼ同じような形ですが、InputsノードにあるResetピンで経過時間をゼロクリアできるようにしてあります。(Modified)のグラフをもう一度見てみてください。1の、時間経過後のOpen/Close切り替え時に呼び出されています。ここで、ElapsedTimeにゼロをセットするのと同等の処理を行っているわけです。これは「普通版」の同名マクロを変更して、メンバ変数CloseFlagを置き換えました。Macroと見比べていただくと分かると思いますが、CloseFlagの代わりにマクロ内ローカル変数を用意。ピンを新設して、CloseFlagの役割をするBoolean型のマクロ内ローカル変数のTrue/Falseを切り替え。Open/Closeを繋げ、時間経過でのOpen/Close切り替えのタイミングでこのカスタムイベントを呼び出し。いう仕組みになっています。CloseFlag、ElapsedSeconds、FlapYawがメンバ変数から消えて、まさに必要な部分だけに登場する適材適所なグラフになりました。(その代償として、初心者お断りなトリッキーなグラフになっていますが...)次はさらにマニアックな技です。ご注意を!さて、重要度の低い4つの変数のうち3つを「適材適所」な位置に移すことが出来ました。なると、最後の1つFlapHeightもメンバ変数から外してしまいたくなります。ここから先はマニアックな使い方になります(ここまでも十分マニアックかもしれませんが)。他人がノードグラフを見ると、頭の上にクエスチョンマークを浮かべてしまうかもしれません。先輩に「やりすぎだ!可読性を上げろ!」と怒られてしまうかもしれません。UpdateFlapのマニアック版です。・ここまでに登場した同名イベントと同様、算出された高さと回転角度をフタ(Flap)モデルにセットしています。Flapのマニアック版です。・ここまでに登場した同名イベントと同様、経過時間を計算し、そこからフタ(Flap)の高さを算出しています。Rotation引数をバラすのが面倒になったので、マクロを作って見た目をシンプルにしています。Heightを、Float型のマクロ内ローカル変数に格納しています。Heightとして出力しています。Graph内に限り、マクロ内ローカル変数の値は保持され続ける」特性を利用して、変数のGETとSETの両方の機能を持たせたものです。(Maniac)が呼び出されると、その引数の値をマクロ内ローカル変数にSETする。(Maniac)を呼び出します。・SET(Assign)された値は、再びSET(Assign)されるまで、変更されることはありません。通じて、マクロ内ローカル変数に格納された値をGETする。Graph内であれば、いつでもGETすることができます。Height経由で、マクロ内ローカル変数に格納された値(現時点のフタ(Flap)の高さ)をGETしています。(Maniac)イベントを使って、マクロ内ローカル変数にSETしています。Graph内の必要なところでのみGETあるいはSETされる「適材適所」な形に整理することができました。Stringなどのログ出力を使う必要があります。マクロ内変数が増えるたびに、おびただしい数のラインが増えてしまい、可読性が非常に下がります。簡潔に言うと、気を付けないとバグの温床になりやすい、ということです。いう意味では、UE4やプログラミングにある程度慣れた人以外は、多用しない方が良いかもしれません。小さなサンプルを作って試し、正しく動くことを確認出来たら本使用に移すなど、守備的な方法で運用するように注意してください。チームで作業している場合は、チーム全員でマクロ内ローカル変数をどう使うかの意思統一してから使うべきでしょう。弾幕で分かるBlueprintの限界さて、次はBlueprintの最適化とプロファイリングの話をしましょう。One」は弾幕シューティングを目指しました。弾が多いと処理落ちしてしまうのです。アクタで作ってしまいました。結果、本当に重くなってしまい、ボス戦などでは60FPSをキープできていません。いうか、40FPSくらいです。ホント、プロとしてお恥ずかしい限りです。この弾幕の最適化、今までずっと放置していたのですが、今回のブログのネタとしても面白そうだと思ったのでやってみました。Blueprint信者としての信念を曲げてのC++化もやっています。ここではそのあたりのお話をさせていただこうと思います。当初から重くなるのは覚悟してました。弾幕を出すつもりでしたので、作り始めた当初から重くなるのは想定していました。弾のActorはできる限りシンプルに組んだつもりです。Tickの仕事を最小限にするように気を付けました。Object.Update)。Rotationに渡している。使って、時間に応じて色を変化させる。一定時間で自滅させる。コンポーネントの構成も非常にシンプルです。ルートコンポーネントとして球コリジョンを使っています。メッシュですらありません。コリジョンプロファイルも限定的にしました。「Block」は一切使っていません。セッションフロントエンドでCPU負荷をチェックしてみる。セッションフロントエンド、使ったことのない方は、これを機にぜひ使ってみてください。使い方は、UE4公式にあります。わかりやすく書かれているのでご安心を。UE4ドキュメントでは、ボス戦をDevelopmentパッケージで調べてみた結果を見てみましょう。画像をクリックすると拡大して見られますが、それでも見づらいと思いますので要点をまとめます。(BP_EnemyBullet01)がダントツで重い。弾幕がボトルネックになっていた。814.3となっています。16.667(9割弱!)使っていることになります。最初からシンプルになるように組んだことが功を奏しています。Rotation)が挙がっており、自作の関数たちは次点以下になっているからです。自作の関数BP_BallisticObject.Updateが次点ですので、ここはもちろん考察しておくべきですね。自作関数を見てみましょうか。ボトルネック次点となった自作関数BP_BallisiticObject.Updateから。正直なところ、この関数もとてもシンプルで、これを最適化しろと言われると困ってしまいます。やっていることは、1フレーム前の「弾を地球中心から見たベクトル」を、今回の移動量分だけ地球の中心で回転しているだけです。この関数については、最適化方針が見出せなかったので見送ります。これ以上軽くするには「とんち」(試行錯誤の労力、あるいは天才的な閃き)が必要そうです。後述しますが、結局は、こんなシンプルな関数でも大量に呼び出されるとボトルネックとなってしまうということですね。ボス戦では700~1000個の弾が動いているわけですから。RotationのC++コードにテコを入れるという話ではありませんよ。ここで問題視したいのは、コール回数の多さです。調べてみたところ700~1000回の呼び出しがありました。呼ばなくていい時は呼ばないということにしてみます。Transform系と呼びます)が重いということを知らない人が意外と多いようです。やっていることをざっくり確認してみましょう。見づらいでしょうから、要約します。エンジンのC++コードを開いて詳しく調べたわけではなく、関数名から想像した話でしかありませんので、ご注意を。814.3関数名から、コリジョンのSweep形状を作っていると想像できます。Transform系の「Sweep」パラメータが関連するのでしょう。いうことは、Sweepしない方が軽いのでしょうが、さすがにSweep処理なしでシューティングゲームを作るのは至難の業ですね。814.3関数名から、そのアクタに付随するコンポーネントのトランスフォームをワールド系に変換していると想像できます。コンポーネントが多ければ多いほど重くなるのでしょう。NavMesh系の処理だと想像できます。NavMeshが不要なら切りましょう。どちらもコリジョンのOverlap系の処理だと想像できます。これらをまとめると、下記のようになるでしょうか。Sweepが不要なら、積極的にOFFにする。コンポーネントの数を必要最小限にする。NavMeshが不要なら、積極的にOFFにする。Transform系の呼び出しは、Tick1回の流れで1回だけにとどめるべき。ついても留意するようにしましょう。カリング処理を作ってみる。上の画像は、地球を非表示にした状態でのボス戦です。見ての通り、実は地球の裏側でも弾幕が動いていたのです。しようもなく無駄ですね。このような見えないところにあるオブジェクトの処理を省くことを、カリング処理といいます。Oneを実装していた当初から、気にしつつも放置してきた部分です。言いますか、プロとしてカリング処理をしていないこと自体お恥ずかしい。それくらい基本中の基本です。当時の私はなぜカリング処理を実装しなかったのか。1番の理由は、やることが多すぎてそれどころじゃなかったからですが、実際のところ他にも躊躇する理由があります。重いと言われているBlueprintでカリング処理を組んだ場合、逆にそのカリング処理が重くてボトルネックになってしまう可能性がある。Blueprintでは関数コールは重い処理の一つです(関数名で検索してから呼び出す仕組みとの話です)。ノード1個1個が関数に相当しますから、ノードの数が増えると比例して重くなる、ということです。したがって、カリング処理もできる限りシンプルに組む必要がありますが、カリング処理の多くは算術演算が比較的多くなってしまいがちです。ご存知の通りBlueprintでは「+」や「-」すら一つのノードになっています。これも、もちろん関数呼び出しです。Expressionを使って軽減することはできます)。この算術演算周りの負荷が高くなってしまった場合、せっかく作った最適化処理(カリング処理)は逆効果となってしまいます。ここを懸念していました。Blueprintでの最適化処理は、(今の私のUE4技能レベルですと)「とりあえず作ってみて、効果を確認する」の試行錯誤を繰り返すことが必要だと思います。労力がかかる上に、うまく行くかどうかが不明。いう意味では、Blueprintでの最適化に悩まずに、とっととC++へ移行した方が、費用対効果は高いかもしれません。今、このブログの執筆時点では、時間に追われているわけではありませんし、面白そうだし!ということで、やってみました。内積1発で済ますカリング処理。上記に書いた通り、Blueprintで組んだカリング処理が重くなっては意味がありません。Rotationに勝てるような、できる限りシンプルなカリング処理を選ぶ必要があります。そこで今回は「内積1発でざっくり判定」する方法を選びました。プレイヤー機や敵の弾をはじめ、すべてのアクタのUpベクトルが地球表面の法線ベクトル(球の中心から球面を垂直に突き抜けるベクトル)に一致するように作ってあります。このUpベクトル同士の内積を取れば、プレイヤー機と敵の弾の「球面に対する」位置関係が分かるはずです。内積の値が1に近ければ、球面上でプレイヤー機に近い位置にいて、-1に近ければ、球面上では反対側にいるはずです。結果、弾のアクタのTickはこうなりました。(OptTest)を用意。セットしていたところを、いったんこの変数に保存している。呼ばなくても、Tickのたびに更新される位置と回転を保持しておくため。Outsight」を呼び出している。このカスタムイベントについては後述する。その他の個所については、変更なし。プレイヤー機と敵の弾のUpベクトル同士の内積の大小を判定しているところ。cos(45度)の値。プレイヤー機のUpベクトルとの角度差が45度以内のものを可視と判定している。可視圏内/可視圏外へ切り替わった時の処理。SweepのOFFと、コリジョンのON/OFF、アクタの表示/非表示を切り替えている。可視圏内に入った直後はSweepをOFFにしておかないと、過去の可視圏内だった位置から可視圏内に戻った現在位置まで、長いSweepが作られてしまい、意図せぬコリジョンが発生してしまう。呼び出した後、SweepフラグをTrueにしている。「内積1発で済ます」と言った割には大きなノードグラフになってしまいました。これがプログラミングの怖いところですね。この修正でパフォーマンスは改善したのでしょうか。セッションフロントエンド再び。コール数が半減(814.3から429.0へ)。呼ばれなくなったため。msの軽減という、良い結果が得られました。Blueprintでも負荷の低いカリング処理が組めたようです。msというと、単純計算で弾があと234.5個出せます。これはかなり良い結果と言えます。成果が得られずに色々な手法を試行錯誤する覚悟をしていましたが、一回で結果が出てホッとしています。msも稼げれば相当頑張ったと言えます。ms稼ぐ、といったところです。msという成果は、逆に怒られる領域かもしれませんね。「こんな基本的なところを今までなぜ放置してた!」と。申し訳ありません...)C++化も試してみる。C++化も試してみましょう。C++化と言っても「Nativize」の方です。ところで「Nativize」とは日本人には非常に読みにくい綴りです。Web辞書で調べてみたところ「ネイティバイズ」と発音するようです。このNativize機能はUE4による「自動C++化」です。非常にありがたい機能が実装されたものです。プロジェクトセッティングを見てみると、Nativizeには3つのモードがあります。Nativizeなし。プロジェクトのBlueprintをまるっと一式Nativizeする。指定されたBlueprintのみNativizeする。(ただし関連するBlueprintも一緒にNativizeされる)残念ながら、Nativize機能はうまく行く場合とうまく行かない場合があるようです。Oneも、Inclusive(まるっと全部)のNativizeはエラーが出てしまい、うまく行きませんでした。今後のアップデートに期待です。今回の「敵の弾」に対してのみNativizeするように指定した、Exclusiveモードではうまく行きました。今回はこちらについてお話します。Settings」をクリックします。Nativize」にチェックマークを入れます。これをNativizeしたいすべてのBlueprintに対して行います。チェックマークを入れたBlueprintだけでなく、それと参照関係にある他の(チェックマークを入れていない)BlueprintもNativizeの対象となるようです。Viewerでみられる参照関係と同じなのか、他に法則があるのか、などは調べていないので分かりません。Methodを「Exclusive」にします。(意外とこの設定を忘れがち)あとは、パッケージングするだけです。Logで「NativizedAssets.cpp」を検索すると良いでしょう。NativizedAssets.cppの付近には、NativizeされたBlueprint名に妙な数字と.cppがつけられて並んでいますので、何がC++化されたかを知ることもできます。今回は、カリング処理なし/ありの両方についてNativizeしてみました。それらのプロファイリング結果を見てみましょう。Nativizeされた弾幕はどれくらい軽いか?結果を以下に並べてみます。ms高速化できたかを表しています。ms高速化!)見ての通り、小躍りしたくなるような結果を得られました。問題はNativizeが失敗することが多々あることですが、今後のUE4アップデートに期待することにしましょう。弾幕で分かるBlueprintの限界ここまでの話をまとめます。文字ばっかりになりますが、ご容赦くださいね。Blueprintをできるだけ軽く組むために。Blueprintは非常にサクサク組めて、イテレーションサイクル(試行錯誤の繰り返し)も速いので、UE4でのゲーム開発では積極的に取り入れるべきものだと思います。一方で、Blueprintは所詮スクリプトに過ぎないという一面もありますので、CPUパフォーマンスに問題が出やすいのも事実です。大事なことは、Blueprint/Nativize/手動C++の境界をどこに置くかで、これを見極めることができると、サクサク作れて高パフォーマンス、という夢のような環境を手に入れることも不可能ではないでしょう。その見極めの基準の一例として、Blueprintで注意するべき項目を並べてみようと思います。これはあくまで私個人の見解で、セガのUE4エンジニアの総意ではありませんので、その辺はご注意ください。この数は純粋にCPU負荷に影響します。今回の弾幕のようにアクタ数が多いと、明確に分かりやすく処理落ちし始めます。アクタの数を必要最低限に絞ることです。Enabledなどを使って、不要なTickは切ってしまいましょう。前述したとおり、一見トランスフォームをセットするだけのように見えて、その中ではコリジョンのSweep処理や、コンポーネントの座標変換など多くの処理が行われています。Transform系を呼び出すようにしましょう。不要なSweepは行わないこと、コンポーネントの数を絞ることも大事です。今回の記事では取り上げていませんが、Blueprintのループ処理も重い処理の一つです。試しに、256回回るForLoopを2重にして(つまり256x256=65536回ループ)実行してみてください。劇的に重いことが分かるかと思います。これは、パッケージ化すると改善はされますが、劇的に軽くなるわけではありません。ループはエディタでの実行とパッケージでの実行との速度差が大きく、開発中にCPU負荷を見積もるのが難しいので、ループを多用している場合は、パッケージでの動作チェックを頻繁にすべきでしょう。Blueprintの関数呼び出し、イベント呼び出しは、比較的重い処理のようです。できる限りシンプルなノードグラフを組んで、関数呼び出しそのものを減らす工夫をしましょう。UE4標準で用意されている関数は、たいていは内部がC++化されています。似た処理を複数のBlueprintノードで自作するよりは、UE4標準関数を積極的に使いましょう。UE4アップデートのたびに便利関数がこっそり増えていたりします。UE4リリースノートや右クリックの検索ウィンドウなどを活用して、新しいノードや機能をマメにチェックしましょう。何を基準にNativize/手動C++化に踏み切るか。個人的には、上記4項目がそこそこ出来ているならば、最適化処理をBlueprintで組んで試行錯誤するより、Nativizeを試すべきだと思っています。いう意味では、上記4項目がBlueprintの限界点だと言えます。今回例に挙げたカリング処理は幸いにも成果を得られましたが、一方で、Blueprintで最適化を模索するのは、Blueprintそのものの重さが災いして、うまく行かない可能性も高いと思っています。その試行錯誤にかけた手間暇に対して、得られる効果が見合ったものかどうか、いわゆるコストパフォーマンスは、私のUE4技能レベルではまだまだ謎の領域にあります。Blueprintが一定のレベルまで組めているなら、最適化の模索より先にNativizeを試すほうが建設的かと思います。前述したとおり、得られる効果は絶大です。Nativizeでエラーが出てしまうようなら、そこで初めて、Blueprintでの最適化を模索するか、手動でC++を組むかを悩むべきでしょう。ここで、Blueprintでの最適化と、手動でのC++化が、同レベルで天秤に掛かっていることを不思議に思う方もいらっしゃるでしょう。手動C++化で決まりだと思えます。私が手動によるC++化を避けている理由は、関連するゲームプログラム周りの設計を再構成する必要がでてしまいやすい点にあります。ビルドが必要になり、作業スピードが落ちてしまいます。アーティストやレベルデザイナーが頻繁に触っているBlueprintをC++化するわけにもいきません。そのためには、基底クラスをC++で作って、そのBlueprintの親にする等、何を表(Blueprint)に出して、何を裏(C++)に隠すかを設計しなおさなくてはならないのです。一方のNativizeはパッケージングにのみ影響する機能ですから、その辺の心配はいりません。手動C++化については、もっと気楽な方法もあります。Blueprintでゲーム全体を組むと決めてしまい、C++はそのためのツールを提供するためのものと割り切ってしまうことです。基本機能を充実させた、そのゲーム専用の基底クラスをC++で作っておいて、Blueprint側はその基底クラスを派生して使うようにする、他には便利関数や便利クラスなどの小さいが高速なモジュールをC++で用意しておくなどです。これらはBlueprint信者の妄信かもしれません。参考にしていただきつつも、皆さんは皆さん流のBlueprint/C++使い分け術を見出していただければと思います。おわりに夢中になって書いてしまった結果、非常に長くなってしまいました。楽しんでいただけましたでしょうか?とは言え、これでも書こうと思っていたトピックの4分の1だったりします。現時点でもあと6つくらいトピックがありますし、今後もUE4を使う限りどんどん増えていくでしょう。社内の他のUE4エンジニアたちも、あれこれたくさんトピックを持っているようです。今回紹介できなかったトピックも、また機会を作って紹介できればと思っています。今後もUE4のトピックをどんどん増やしていきたいと思います。インディーズのススメゲームエンジンの時代が到来して久しいですね。ゲームの素材を作る環境もどんどん安価に・身近になってきています。冒頭でもいくつかツールを紹介しましたが、今やゲーム制作環境の大部分が一般に降りてきています。何ならフリーのツールだけでも全部作れてしまいます。やる気さえあれば、誰でもゲームを作れる時代が到来しました。One」も、未完ながら「MAGITYPE」も、概ね全部の素材を私一人で作っています(もちろん、ものすごく大変でしたけど)。一昔前なら、チームを組まなくては作れない規模のゲームも、いまや個人や少人数グループの頑張りで作れてしまいます。明らかに時代は変わってきています。ゲームエンジンが台頭する前は「特定の分野一つに強い職人」を集め、チームを組んで、リーダーが全体を統括しながら作る時代でした。それゆえに、企業が強い分野でもありました。昨今では、高度な/専門的な知識はあらかじめゲームエンジンに内包されており、ゲーム開発者は「その使い方と効能」を理解してさえいれば良くなりました。その結果、ゲーム開発者は、特定の分野一つを専門にして深く理解/応用する労力から解放され、複数の分野に渡って広く知る余裕が出来てきました。今後は、「複数の分野を知っていて、それらを上手く組み合わせてコンテンツを作れる人」同士がチームを組んで、その相乗効果でより面白いものを作る時代になるのでしょう。ゲーム開発者はより「面白さ」に専念できるようになりました。皆さんも、小規模で良いので、「一つのパッケージを自分一人で作り上げる」を試してみてはいかがでしょうか。他人の評価を得ることは何にもまして勉強になりますし、その成果を何らかの形で発表すると、なお良いでしょう。ゲーム制作の全部の流れを何となくでも知っておく(体に通しておく)と、非常に視野が広がり、例えば、プログラマがアーティストの作業を知ると、以後、お互いの作業領域に重なりができることで、お互いにカバーしあえる体制が出来上がります。これは非常に良い信頼関係となります。ゲームエンジンの台頭によって、ゲーム開発者の価値が変わりつつあります。今はまだ「UE4を上手く使える」「Unityを上手く使える」という技能面だけで、それなりのステータスを得られますが、将来は、ゲームエンジンを上手に使えることよりも、「どんなテイストのゲームが作れるか」「どんな触り心地のゲームが作れるか」といった「クリエイティブ力」が、今まで以上に、ゲーム開発者の価値となる時代が来るでしょう。いわゆる「絵師さん」。そのテイストや画風が人々に受け入れられ、その絵師さんの価値となるように、あなたの作ったゲームの「テイスト」や「触り心地」が人々に受け入れられ、あなたの価値となる、そういう時代になるのでしょう。セガ・インタラクティブではUE4エンジニアを募集しています。長いうえに説教臭い話でしたね。私も年を取ったもんです。我ら「セガ・インタラクティブ」は、アーケードゲームをはじめ、スマホ、テーマパーク、ショッピングモール、はたまたeスポーツなどなど、様々なマーケットにエンタメを投入する、セガの中でも一風変わったオモシロカンパニーであります。弊社では、UE4エンジニアがまだまだ足りません。弊社にご興味を持っていただけると嬉しいです。採用情報などはこちらに記載されています。Ltd.】また、UE4インターンも「画策」しています。「開催」や「予定」と書かず「画策」と書いたのは、まだいつ開催できるかが不明だからですが、弊社のUE4エンジニアと、イケてるUE4遣い(とその候補)の皆さんとで、一緒にゲーム開発を体験できれば!と思っています。開催された折にはぜひご参加くださいませ。弊社では、もちろんUnityタイトルも出しています。Animation初めまして。セガゲームス開発サポート部テクニカルアーティストの清水と申します。新卒からテクニカルアーティスト(以後TA)業務に積極的に関わらせてもらい、今年で社会人歴TA歴共に3年目になります。今回は、弊社で使われてる内製ツールHNDViewerにコマンドライン実行を組み込み、アセットのモーションGIF画像を自動生成できるようにした時の対応について紹介させていただきます。独自の内製ビューアに動画撮影機能を実装し、「モーションプレビュー一覧を半自動的に作成する環境を構築する」という目的のもと、以下のようなコマンドをJenkinsで自動定期実行することにより、内製ビューアがGif画像を自動で生成できるようにしてみました。(C)SEGA今回紹介する事例で取り組んだ内容は、3つの内容から成り立っています。・内製3DCGモデルビューアHNDViewerにモデルのモーションに関するGIF画像を生成する機能を追加した。・HNDViewerにコマンドライン実行機能を追加して、モデルのモーションに関するGIF画像を生成する機能をコマンドライン実行できるようにした。・実装したコマンドラインをJenkinsから実行することで、モデルのモーションに関するGIF画像の生成を自動化した。今回紹介するアプリケーションについて、触れておきましょう。CGツールのデータをエクスポートして格納するための中間構造を扱うHNDというシステムがあります。HNDViewerとは、このHNDを格納した「HNDファイル」のビューアツールです。格納されている3DCGデータの表示・再生はもちろん、各ポリゴンやノードのパラメータを一覧することもできます。HNDViewerJenkinsとは?Jenkinsとは、ソフトウェアの実行等の一連の作業を自動化できる自動実行ツールです。jenkins.io高い汎用性を持った自動実行ツールで、事前に設定した条件を満たすたびに指定したコマンドを自動で実行してくれます。自動実行に指定できるのは基本的にbat処理などのコマンドライン実行可能な処理になります。ここからは少し実装の話に入っていきます。今回はImageMagickを使用してgif画像を作成する方法を採用しました。www.imagemagick.orgImageMagickは、幅広い画像ファイルフォーマットに対応している、画像を操作したり表示したりするためのソフトウェアです。コマンドラインツールを含んでおり、バッチ処理での画像の変換・編集などに必要な機能が揃っています。ImageMagickを使用して指定した連番画像からGif画像を生成することができます。HNDViewerには下記の3つの機能はすでに搭載されています。・3DCGモデルを表示する・モデルのモーションを再生する・モデルを表示している画面のスクリーンショットを作成する従ってGif画像を作成するために追加する必要のある機能は下記の2つです。・ImageMagickに連番画像を受け渡してGIF画像を作成してもらう機能まず、読み込んだモデルを1フレームずつ動かして表示している画面をキャプチャし、画像として一時フォルダへ保存します。これをモーションの最終フレームまで行い、モデルのモーションの連番画像を作成します。連番画像の作成モデルのモーションの連番画像の生成が完了したら、ImageMagickを利用してGIF画像を生成します。キャプチャした連番画像をImageMagickのコマンドラインツールであるconvert.exeの引数に渡してGIF画像を作成します。キャプチャした画像.gifこれでGIF画像の生成は完了です。GIF画像の生成処理が終了したことを確認したら、一時フォルダに保存してあるGIF画像の生成に使用した連番画像はすべて削除します。これでモデルのモーションに関するGIF画像を作成する機能ができました。コマンドライン実行の追加モデルのモーションに関するGIF画像を作成する機能を実装したHNDViewerは、GUIツールでコマンドラインから処理を実行する機能は持たないため、次にHNDViewerにコマンドライン実行機能の追加をしていきます。コマンドライン実行時の引数の入力方法について入力する引数については以下のようなルールを採用しました。・引数はキーとなる文字列とパラメータを「=」で接続したものを一つの引数として入力する。・キーとなる文字列の頭には「/」もしくは「-」を付ける。このような引数をプログラム側でパースしてパラメータを読み込みます。以下の2種類のうち、いずれかの引数を入力するルールとします。/height=画像の縦幅そして、次のようにプログラム側で引数を=でパースし、辞書にします。}この引数の入力方法は以下のような利点があります。320capturegifはコマンド名であることは推測できます。2つあるパスは入力先と出力先を表していると推測できます。どちらが入力でどちらが出力かは読み取ることはできません。残り2つの数値については何を表すのかは推測することすら困難です。-height=320-exec=capturegifによって実行したい処理がcapturegifであることがわかる。-outと-openで指定されていることによって入力と出力が一目でわかる。-widthと-heightによってそれぞれの数値が幅と高さを表していることがわかる。・アプリケーション側からのユーザーへ対しての通知内容を分かりやすくできる。コマンドラインに渡す引数の順番を間違えるなどといったミスを事前に防ぐことができる。各パラメータとパラメータが示すキーが対になっているため、アプリケーション側からどのパラメータに問題があったのかをユーザーに通知できる。・アプリケーションに関連付けられたファイルを開く処理を明確に分けることができる。第1引数に「-cmd」のようなコマンドライン実行であることを表すキー文字列が存在することによって、プログラム側は今回の実行がコマンドライン実行であるか否かを明確に判定することができます。実行時の引数を確認する処理を追加します。コマンドラインモードで起動できるようにします。この「コマンドラインモードで起動するか否か」の判定は、引数の有無で判断してしまうと、関連付けられたファイルを開くことができなくなってしまいますので、必ず引数の内容を確かめるようにします。これは、アプリケーションが関連付けられたファイルから起動される際に、そのファイルのフルパスが引数1に入るためです。アプリケーションに関連付けられたファイルがダブルクリックなどで開かれる場合、一般的に起動するアプリケーションには関連付けられたファイルのパスが第1引数に渡されます。このパスの情報をもとにアプリケーションはファイルを開いた状態で起動することができます。そのため、コマンドライン実行か否かの判定は引数の有無だけで判断しないようにします。引数が「-?」または「/?」であった場合もコマンドラインモードに遷移するようにして最終的にユーザー対してヘルプが表示されるようにします。//-cmdまたは/cmdの場合はコマンドライン実行用の処理に遷移するようにする。//-?または/?の場合もコマンドライン実行用の処理に遷移するようにする。//その後ヘルプを表示するようにする。}実行コマンドの確認コマンドライン実行であることが確定した後に、実行しようとしているコマンドがアプリケーションに登録されたコマンドであるかを確認します。コマンド名が指定されていない場合やアプリケーションに登録されていないコマンド名の場合は、ヘルプを表示して終了させます。//コマンドが無い場合はヘルプを表示する。//execが無いということはコマンドが指定されていないということなのでヘルプを表示する。実行するコマンドが確定した後に実行に必要な引数が全てそろっているか、引数に入力されている値は有効かを確認します。引数が足りていない場合や引数の内容に問題がある場合は、その旨エラーを出力し、最後にヘルプを表示して終了させます。以下のコードは私が実装した「capturegif」コマンドの引数確認の例です。//入力ファイルを確認する。Console.WriteLine("引数[open]がありません。//入力ファイルが存在するかを確認する。Console.WriteLine("指定されたファイルmodelpathが存在しません。//出力フォルダを確認する。//出力フォルダが存在するかを確認する。Console.WriteLine("指定されたフォルダoutputDirectoryが存在しません。//生成するgif画像の大きさを確認する。//widthとheightが数値に変換できるかを確認する。Console.WriteLine("widthとheightが数値に変換できませんでした。Console.WriteLine("引数[width]、[height]がありません。}処理の実行・アプリケーションの終了ここまでの手順で、実行するコマンドが決まり、引数に問題ないことが確認できたので、処理を実行します。処理が終了したら、アプリケーションを終了します。これでGUIツールだったHNDViewerにコマンドライン実行機能を追加することができました。設定したコマンド名が実行されたら、対応する既存の機能を実行するように処理を実装することで、コマンドラインからツールの任意の機能を実行できるようになります。一例として、モデルのモーションに関するGIF画像の生成機能について、コマンド名と引数は以下のように設定しました。画像の高さ複数の作業をバッチ処理にまとめることもできるようになりました。jenkinsを用いた処理の自動実行ここまでで、コマンドライン実行でモデルのモーションに関するGIF画像を作成することができました。この処理をjenkinsから実行してもらうことで、自動でモデルのモーションに関するGIF画像を作成できるようにします。jenkinsを立ち上げて新規のジョブを作成し、Windowsバッチコマンドの実行に、実装したモデルのモーションに関するGIF画像を作成するコマンドを設定します。自動実行するタイミングは好きなタイミングを指定します。jenkinsのジョブが実行するコマンドを設定する。jenkinsの導入についてはCEDEC2017で講演された以下のセッションの資料がわかりやすくてオススメです。cedil.cesa.or.jpこれで自動でモデルのモーションに関するGIF画像を作成することができるようになりました。最後にいかがでしたでしょうか。振り返ってみると実装した各処理の内容自体は、特別優れた技術が使われているわけでもなく、普通な実装だなぁと自分でも感じる部分があります。その普通な実装の積み重ねで、「アセットのアニメーションGIF画像の自動生成」という目的を達成することができました。手作業を必要とせずに、常に最新のモデルのモーションに関するGIF画像を生成できるようになりました。生成されたGIF画像を用いて、手軽にモデルのモーションを確認できるようになり、作業の効率化に貢献できました。社内での反響も上々です。実際の業務経験を通して、作業の効率化というのは、案外小さな普通の技術でできている「ちょっとした便利」の組み合わせで成り立っているんだなぁと感じました。これからもこうした作業の効率化にどんどん取り組んでいき、クリエイターがより快適にゲーム制作に注力できる環境の実現を目指して、頑張っていきたいと思います。快適なゲーム制作環境の実現や快適な環境でのゲーム制作に興味がある方は、ぜひセガゲームスの採用情報にアクセス!自己紹介(補足)新卒からTAという比較的珍しいキャリアパスを広めるべく過去2回CEDECで登壇などもいたしました。https://2018.cedec.cesa.or.jp/session/detail/s5aafcb42e41b7参加してくださった方はありがとうございます。上記セッションについて興味を持たれた方には以下の記事がオススメです。小村仁美様にはこの場を借りて感謝申し上げます。「大量のアセットも怖くない!~HTTP/2による高速な通信の実装例~」講演と壇上では語られなかった6つのこと。月別アーカイブスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。