1.8K Views
June 20, 17
スライド概要
2017/6/3に開催されたUnity道場スペシャル 2017博多の講演スライドです。
講師:松尾 隆志(株式会社サイバーコネクトツー)
サイバーコネクトツーのスマートフォン向けネイティブアプリはUnityを使用しています。このセッションでは、過去の事例を元に、サイバーコネクトツーならではの表現を実現する技術的なアプローチや、長期間の開発および運用に対しての効率化のテクニックといった、開発の裏側をお話いたします。
Unityのイベント資料はこちらから:
https://www.slideshare.net/UnityTechnologiesJapan/clipboards
リアルタイム3Dコンテンツを制作・運用するための世界的にリードするプラットフォームである「Unity」の日本国内における販売、サポート、コミュニティ活動、研究開発、教育支援を行っています。ゲーム開発者からアーティスト、建築家、自動車デザイナー、映画製作者など、さまざまなクリエイターがUnityを使い想像力を発揮しています。
Unityと歩んだ CC2アプリ開発の舞台裏 (公開版)
注意事項 ! 本スライドは 講演で使用したスライドを 編集・再構成したものになります ―2―
はじめに ―3―
講演者紹介 株式会社サイバーコネクトツー 開発部 テクニカルアーティスト 松尾 ●入社:2012年 プロフィール 隆志 ●東京スタジオ勤務 Unityを使用したタイトルとして「フルボッコヒーローズX」、 「.hack//NewWorld」などに携わる。 描画表現の開発やアーティスト向けツールの開発を行いつつ、 パイプライン構築、ゲームエンジンサポートなどの 技術的なサポートも担っている。 ―4―
商号 株式会社サイバーコネクトツー 本社 福岡県福岡市博多区博多駅前1丁目 東京スタジオ モントリオールスタジオ 設立日 従業員数 東京都品川区大井1丁目 カナダ・モントリオール 平成8年2月16日 福岡本社 :180名 (※うちアルバイト25名) 東京スタジオ:33名 資本金 事業内容 会社概要 ―5― (※うちアルバイト11名) 40,000,000円 家庭用・スマートフォン向けゲームソフト企画・開発
CC2開発のスマートフォンタイトルとUnity 2014.02 フルボッコヒーローズX 2011.11 検証開始(Unity 3.5 beta) 2014.03 リトルテイルストーリー 2012.11 ギルティドラゴン 2014.11 FINAL FANTASY VII G-BIKE 2013.02 シャドウエスケイパー 2016.01 .hack//NewWorld 2013.10 死神メサイア 2011 2012 2013 2014 2015 2016 2017 ※サービス終了タイトルを含む、年月はグランドオープン時 ―6―
本講演について 開発の舞台裏として 過去の開発タイトルで行った Unityの機能を活用した テクニックを紹介いたします ―7―
アジェンダ 1 キャラクターカスタマイズ編 2 フェイシャルアニメーション編 3 タウンマップ編 4 開発効率化編 ―8―
キャラクター カスタマイズ編 ―9―
キャラクターカスタマイズとは 複数のパーツを合成して 多様なキャラクターを 表現できるようにする機能 キャラクターカスタマイズ編 ― 10 ―
キャラクターカスタマイズとは キャラクターカスタマイズの要素 • 分割したパーツを読み込んで合成する • ひとつのモデルを複数の体格で利用する • 複数のバストサイズに対応する • 肌色, 髪色, 目色などを変更する キャラクターカスタマイズ編 ― 11 ―
分割したパーツを読み込んで合成する キャラクター生成の基本機能 1 パーツの合成 2 パーツの接続先指定 3 パーツの可視性指定 キャラクターカスタマイズ編 ― 12 ―
分割したパーツを読み込んで合成する キャラクター生成の基本機能 1 パーツの合成 2 パーツの接続先指定 3 パーツの可視性指定 キャラクターカスタマイズ編 ― 13 ―
1 パーツの合成 任意のモデル&マテリアルを読み込んで合成 パーツ A マテリアル A パーツ B モデル マテリアル B キャラクターカスタマイズ編 ― 14 ― パ ー ツ の 種 類 1. 2. 3. 4. 5. 6. 7. 髪 顔 上半身 下半身 頭装飾 (任意) 胴装飾 (任意) 武器 (任意)
1 パーツの合成 Skinnedmesh Renderer 単一のスキンメッシュに結合 (髪、顔、上半身、下半身) Mesh Renderer 任意のボーン(Transform)に接続 (頭装飾、胴装飾、武器) キャラクターカスタマイズ編 ― 15 ―
分割したパーツを読み込んで合成する キャラクター生成の基本機能 1 パーツの合成 2 パーツの接続先指定 3 パーツの可視性指定 キャラクターカスタマイズ編 ― 16 ―
2 パーツの接続先指定 頭装飾・胴装飾のパーツは あらかじめ設定したダミーの ボーン(Transform)に接続する 頭 1. 帽子系 装 飾 2. めがね系 キャラクターカスタマイズ編 3. 胴 4. 装 飾 5. 6. 空中系 (周囲を浮遊するもの) 羽系 (背中に背負うもの) 胸元系 尻尾系 ― 17 ―
分割したパーツを読み込んで合成する キャラクター生成の基本機能 1 パーツの合成 2 パーツの接続先指定 3 パーツの可視性指定 キャラクターカスタマイズ編 ― 18 ―
3 パーツの可視性指定 装備に合わせて可視性を変更する 可視性の変更例 • 帽子を装備した際にツインテールが突き抜ける場合 – ツインテール部分をあらかじめ分離しておき、非表示にする • フルフェイスのようなもので髪が突き抜ける場合 – 髪全体を非表示にする キャラクターカスタマイズ編 など ― 19 ―
ひとつのモデルを複数の体格で利用する 複数体格への対応方法 1 男女各8段階の体格対応 2 単一パーツでの複数体格対応 キャラクターカスタマイズ編 ― 20 ―
ひとつのモデルを複数の体格で利用する 複数体格への対応方法 1 男女各8段階の体格対応 2 単一パーツでの複数体格対応 キャラクターカスタマイズ編 ― 21 ―
1 男女各8段階の体格対応 体格違いの素体モデルを用意する 男女それぞれ8段階の素体モデル(体格)を用意 パーツ結合時のボーン構造として利用 男性用 キャラクターカスタマイズ編 女性用 ― 22 ―
ひとつのモデルを複数の体格で利用する 複数体格への対応方法 1 男女各8段階の体格対応 2 単一パーツでの複数体格対応 キャラクターカスタマイズ編 ― 23 ―
2 単一パーツでの複数体格対応 スケール用のボーンを素体に入れておき モデルの大きさを体格ごとに調整 最小体格 キャラクターカスタマイズ編 中間体格 ― 24 ― 最大体格
複数のバストサイズに対応する 複数バストサイズの対応方法 1 女性のみ S, M, L の3サイズ 2 揺れる揺れないの変更 キャラクターカスタマイズ編 ― 25 ―
複数のバストサイズに対応する 複数バストサイズの対応方法 1 女性のみ S, M, L の3サイズ 2 揺れる揺れないの変更 キャラクターカスタマイズ編 ― 26 ―
1 女性のみ S, M, L の3サイズ 素体のスケール用ボーンを使用する 胸のサイズ毎に “Position”, “Rotate”, “Scale” を微調整 Sサイズ キャラクターカスタマイズ編 Mサイズ ― 27 ― Lサイズ
複数のバストサイズに対応する 複数バストサイズの対応方法 1 女性のみ S, M, L の3サイズ 2 揺れる揺れないの変更 キャラクターカスタマイズ編 ― 28 ―
2 揺れる揺れないの変更 ボーン名が異なると アニメーションしない仕様を利用し 結合時にボーン名を変更する 揺らさない場合 キャラクターカスタマイズ編 揺らす場合 ― 29 ―
肌色, 髪色, 目色を変更する 色替えの対応方法 1 顔以外のパーツの色指定 2 顔のパーツの色指定 キャラクターカスタマイズ編 ― 30 ―
肌色, 髪色, 目色を変更する 色替えの対応方法 1 顔以外のパーツの色指定 2 顔のパーツの色指定 キャラクターカスタマイズ編 ― 31 ―
1 肌、目、髪色の変更 マスクテクスチャを使用 肌色・髪色・目色などを変更 ベース テクスチャ キャラクターカスタマイズ編 マスク テクスチャ ― 32 ― カラー
1 肌、目、髪色の変更 顔以外のマスクテクスチャ R:カラー。 色を変更する箇所の指定 G:ライト。 ライトの影響を受けない箇所の指定 B:アルファ 透過させる箇所の指定 キャラクターカスタマイズ編 ― 33 ―
1 肌、目、髪色の変更 R:カラー G:ライト キャラクターカスタマイズ編 ― 34 ―
肌色, 髪色, 目色を変更する 色替えの対応方法 1 顔以外のパーツの色指定 2 顔のパーツの色指定 キャラクターカスタマイズ編 ― 35 ―
1 肌、目、髪色の変更 顔のマスクテクスチャ R:目カラー 目の色を変更する箇所の指定 G:肌カラー 肌の色を変更する箇所の指定 B:なし。。 キャラクターカスタマイズ編 ― 36 ―
1 肌、目、髪色の変更 R:目カラー G:肌カラー 目色 肌色 キャラクターカスタマイズ編 ― 37 ―
フェイシャル アニメーション編 ― 38 ―
フェイシャルアニメーションとは キャラクターカスタマイズで 生成したキャラクターの 表情アニメーションを 行うための機能 フェイシャルアニメーション編 ― 39 ―
フェイシャルアニメーションとは フェイシャルアニメーションの要素 • 様々な表情&アニメーションに対応する • データ容量を極力減らす • 短期間で制作できるようにする フェイシャルアニメーション編 ― 40 ―
様々な表情&アニメーションに対応する フェイシャル基本機能 1 ブレンドツリーでの表情作成 2 デフォルト表情設定 3 キーフレーム設定 フェイシャルアニメーション編 ― 41 ―
様々な表情&アニメーションに対応する フェイシャル基本機能 1 ブレンドツリーでの表情作成 2 デフォルト表情設定 3 キーフレーム設定 フェイシャルアニメーション編 ― 42 ―
1 ブレンドツリーでの表情作成 各キャラ毎に表情、形状が異なる テクスチャでのアニメーションは難しい 目パチ、口パク、目線など動きが様々 アニメーションとして実装するのも手間 フェイシャルアニメーション編 ― 43 ―
1 ブレンドツリーでの表情作成 様々な表情に対応できるControllerを作成 フェイシャルアニメーション編 ― 44 ―
1 ブレンドツリーでの表情作成 レイヤーは動作するパーツ毎に分ける 目線 フェイシャルアニメーション編 目そのものの動き 口 口の開閉+口の形状 眉 左右をまとめた眉の形状 左目 まぶたの動き+目の形状 右目 まぶたの動き+目の形状 感情 頬を染めるなどの特殊表現 ― 45 ―
1 ブレンドツリーでの表情作成 基準となる表情とのブレンドを行う 各ステートに表情を設定し、ブレンドツリーでブレンド デフォルト表情 例:目を開く ブレンド表情 例:目を閉じる フェイシャルアニメーション編 ― 46 ―
1 ブレンドツリーでの表情作成 上下左右動く目線のみ2Dブレンディング フェイシャルアニメーション編 ― 47 ―
様々な表情&アニメーションに対応する フェイシャル基本機能 1 ブレンドツリーでの表情作成 2 デフォルト表情設定 3 キーフレーム設定 フェイシャルアニメーション編 ― 48 ―
2 デフォルト表情設定 基準となる表情のパラメータを設定 各パーツ毎のパラメータを実行時に表情として反映 デフォルトパラメータ概要 1. 表情の状態 2. 固定の状態 (通常/半固定/固定) 3. ブレンド率 フェイシャルアニメーション編 ― 49 ―
2 デフォルト表情設定 キャラ毎にScriptableObjectで設定 右目 • 表情の状態 :半目 • 固定の状態 :半固定 • ブレンド率 :0.9 口 • 表情の状態 :怒り • 固定の状態 :半固定 • ブレンド率 :0.9 フェイシャルアニメーション編 ― 50 ― • 通常 – 0.0~1.0の間で自由に動く • 半固定 – その値を基準に動く – 例:0.0~0.9 or 0.9~1.0 • 固定 – その位置から動かない – 目を閉じたまま など
様々な表情&アニメーションに対応する フェイシャル基本機能 1 ブレンドツリーでの表情作成 2 デフォルト表情設定 3 キーフレーム設定 フェイシャルアニメーション編 ― 51 ―
3 キーフレーム設定 表情を変えるタイミングとキーを設定 指定した内容をスクリプトで制御する 0秒 アニメーション開始 1秒 右目/左目を0.1秒で閉じる 1.1秒 右目/左目を0.1秒で開ける 2秒 アニメーション終了&ループ フェイシャルアニメーション編 ― 52 ―
3 キーフレーム設定 キーフレームはScriptableObjectで定義 キーフレームパラメータ概要 1. 再生までの待ち時間 2. 対象のパーツ 3. ブレンドする表情の状態 4. 再生時間 5. ブレンド率 フェイシャルアニメーション編 ― 53 ―
3 キーフレーム設定 アニメーションイベントをトリガーとして フェイシャルを再生 フェイシャルアニメーション編 ― 54 ―
3 キーフレーム設定 アニメーション1つで全キャラ対応 デフォルト表情を元にアニメーションするので どの表情のキャラクターにおいても対応可能 まばたきする フェイシャル アニメーション 目を閉じたままのキャラ 目を閉じたまま 半目気味のキャラ 猫目のキャラ まばたきをする アニメーション デフォルトパラメータ 結果 キーフレームパラメータ フェイシャルアニメーション編 ― 55 ―
タウンマップ編 ― 56 ―
タウンマップとは ユーザー間の コミュニケーションの場である 広域のエリア タウンマップ編 ― 57 ―
タウンマップとは タウンマップの要素 • 昼、夕、夜という3種類の時間帯がある • 時間帯間の遷移はクロスフェードする • 時間帯毎のライトマップを使用する タウンマップ編 ― 58 ―
タウンマップのクロスフェード 複数要素、リソースのフェード 変化する要素が多い 要素 1. 2. 3. 4. 5. タウンマップ編 ディレクショナルライト アンビエントライト パーティクルエフェクト 背景のテクスチャ 背景のライトマップ ― 59 ― × × × × × 1 1 複数(可変) 複数(固定) 1
各要素のクロスフェード ライト系 color, intensity, rotationを線形補間 RenderSettings.ambientLight タウンマップ編 ― 60 ―
各要素のクロスフェード 前:”emission.enabled” を false で 徐々に消えるようになる particleSystem.emission.enabled = false; パーティクル タウンマップ編 後:Prewarm を false にすることで 徐々に表示するようになる ― 61 ―
シェーダーでのクロスフェード テクスチャ系 専用のカスタムシェーダー内で線形補間 ライトマップのクロスフェード タウンマップ編 テクスチャのクロスフェード ― 62 ―
シェーダーでのクロスフェード Shader.SetGlobal~を活用 共通項目はまとめて処理する SetGlobalFloat SetGlobalTexture • フェードの進捗(0.0~1.0) • フェード前後のライトマップ 共通ではない項目は個別で差し替え (空用のテクスチャなど一部の決まった要素のみ) タウンマップ編 ― 63 ―
ライトマップ生成について ライトマップを複数用意する Unity上でベイクしたライトマップを利用する 利用する際の問題点 • ライトマップのUVは「シーン内」 のメッシュに対応 • シーンに結びついたライトマップは クロスフェードできない タウンマップ編 ― 64 ―
ライトマップUVとは ライトマップのUV Lightingウィンドウ内の “Baked Lightmap” の値 (シーンに結びついている値) タウンマップ編 ― 65 ―
ライトマップUVをどうするか UVとライトマップ3枚のみ必要 シーンにある要素は不要 UVをPrefab内に保持する ライトマップを単体で3枚用意 シェーダーでクロスフェード タウンマップ編 ― 66 ―
ライトマップUVの用意 “Renderer.lightmapScaleOffset” でUV値を取得、Prefab内に保存する 保存したUV値を シェーダー内で利用する タウンマップ編 ― 67 ―
ライトマップUVの一括設定 簡易ツールで一括設定 設定しているシェーダーを調べて ライトマップを使用するかどうか判別する コンポーネントの追加 Rendererの参照追加 UV値の反映 タウンマップ編 ― 68 ―
複数のライトマップへの対応 同じモデル(シーン)を用い ベイク後にテクスチャをリネームする ライトマップを ベイクする対象の Prefab(モデル) タウンマップ編 昼用ライト 昼用 マップ 夕用 マップ 夕用ライト 夜用ライト ― 69 ― 夜用 マップ
開発効率化編 ― 70 ―
開発効率化について 開発に用いたツールの中から 小ネタをいくつか紹介します 開発効率化編 ― 71 ―
開発効率化について 開発効率化 1 透過スクリーンキャプチャ 2 モデルインポート設定のコピペ 3 エディタ上での値の保持 開発効率化編 ― 72 ―
開発効率化について 開発効率化 1 透過スクリーンキャプチャ 2 モデルインポート設定のコピペ 3 エディタ上での値の保持 開発効率化編 ― 73 ―
スクリーンキャプチャを撮りたい 透過画像が出力できない 装備のアイコンデータ作成などに時間がかかる Unity上でモデルを配置 Unity上でキャプチャ Photoshopで切り抜き Photoshopでアイコン化 開発効率化編 ― 74 ―
スクリーンキャプチャ Texture2D.ReadPixelsの利用 スクリーン画面のピクセルデータを読み込むAPI Application.CaptureScreenshot Texture2D.ReadPixels • 一般的な方法 • 透過画像を出力できない 開発効率化編 • OnPostRender内で行う方法 • 透過画像を出力できる ― 75 ―
// エディタ上で動作するように.
[ExecuteInEditMode, RequireComponent(typeof(Camera))]
public class CaptureCamera : MonoBehaviour
{
private bool isCapture = false;
public string filePath;
public void Capture() { this.isCapture = true; }
void OnPostRender()
{
// 1フレームだけキャプチャする.
if (!this.isCapture) return;
var tex = new Texture2D(Screen.width, Screen.height, TextureFormat.ARGB32, false);
tex.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
tex.Apply();
File.WriteAllBytes(this.filePath, tex.EncodeToPNG());
this.isCapture = false;
}
}
開発効率化編
スクリーンキャプチャ取得実装例
― 76 ―
開発効率化について 開発効率化 1 透過スクリーンキャプチャ 2 モデルインポート設定のコピペ 3 エディタ上での値の保持 開発効率化編 ― 77 ―
モデルインポート設定の問題 インポート設定はコピーできない 設定に時間がかかる+同じような設定が多い • Model – Mesh Compression • Rig – Avatar Source • Animation – Avatar Mask 開発効率化編 ― 78 ―
モデルインポート設定のコピー&ペースト 多くの項目は ModelImporter ModelImporterClipAnimation で取得・設定可能 無い項目については SerializedObject. CopyFromSerializedProperty で設定可能 開発効率化編 ― 79 ―
開発効率化について 開発効率化 1 透過スクリーンキャプチャ 2 モデルインポート設定のコピペ 3 エディタ上での値の保持 開発効率化編 ― 80 ―
エディタで設定した値の問題点 永続的に値を保持できない エディタで設定したフラグをゲームで使用したい Static変数 PlayerPrefs Scriptable Object 開発効率化編 実行時に初期化される レジストリを書き換える ファイルの更新が入る ― 81 ―
エディタで設定した値を保持し続ける ScriptableSingletonを使う エディタ上でしか使わない(使えない)点を利用 ScriptableSingletonの利点 1. 単一性が保たれる 2. 実行後も値が保持される 開発効率化編 ― 82 ―
// Editorのみで使用可能にする.
#if UNITY_EDITOR
// ScriptbaleSingletonはUnityEditor名前空間内にある.
using UnityEditor;
// ScriptableSingletonを継承したクラスを用意する.
public class EditorPreference : ScriptableSingleton<EditorPreference>
{
// 設定するフラグの例.
public bool customMode = false;
}
#endif
ScriptableSingletonの定義
開発効率化編
― 83 ―
// エディタ上での操作用クラス. public static class EditorPreferenceTools { // エディタ上のメニューから操作してONにする. [MenuItem(“Tools/CustomMode On”)] public static void UseCustomModeOn() { // EditorPreferenceのインスタンスを取得して設定する. var pref = ScriptableSingleton<EditorPreference>.instance; pref.customMode = true; } // エディタ上のメニューから操作してOFFにする. [MenuItem(“Tools/CustomMode Off”)] public static void UseCustomModeOff() { var pref = ScriptableSingleton<EditorPreference>.instance; pref.customMode = false; } } 開発効率化編 エディタ拡張での使用方法 ― 84 ―
// ScriptableSingletonの使用例.
public class GameManager : MonoBehaviour
{
// ゲームの起動直後に行う処理として仮定.
void Start()
{
// Editorの機能なのでEditor上だけで動作させる.
#if UNITY_EDITOR
var pref = UnityEditor.ScriptableSingleton<EditorPreference>.instance;
if (pref.customMode == true)
{
/*! 設定した時に行う処理など
* 例:エディタでの実行時の特殊処理
*
特定の機能のON/OFF切り替え
*
AssetBundleではなくAssetDatabase経由の読み込みへの切り替え など
*/
}
#endif
}
}
ゲーム内での使用方法
開発効率化編
― 85 ―
おわりに ― 86 ―
おわりに 開発事例として いくつかのトピックを 紹介いたしました ― 87 ―
おわりに みなさまの開発の 何かしらの ヒントになれば幸いです ― 88 ―
ご清聴ありがとうございました ご質問・ご連絡は [email protected] まで