【Unity道場スペシャル 2017博多】Unityと歩んだCC2アプリ開発の舞台裏

89
Unityと歩んだ CC2アプリ開発の舞台裏 (公開版)

Transcript of 【Unity道場スペシャル 2017博多】Unityと歩んだCC2アプリ開発の舞台裏

Unityと歩んだCC2アプリ開発の舞台裏

(公開版)

注意事項

― 2 ―

本スライドは

講演で使用したスライドを

編集・再構成したものになります

!

はじめに

― 3 ―

講演者紹介

― 4 ―

●入社:2012年 ●東京スタジオ勤務

テクニカルアーティスト 松尾 隆志

株式会社サイバーコネクトツー

プロフィール Unityを使用したタイトルとして「フルボッコヒーローズX」、

「.hack//NewWorld」などに携わる。

描画表現の開発やアーティスト向けツールの開発を行いつつ、

パイプライン構築、ゲームエンジンサポートなどの

技術的なサポートも担っている。

開発部

― 5 ―会社概要

商号

本社

東京スタジオ

モントリオールスタジオ

設立日

従業員数

資本金

事業内容

株式会社サイバーコネクトツー

福岡県福岡市博多区博多駅前1丁目

東京都品川区大井1丁目

カナダ・モントリオール

平成8年2月16日

福岡本社 :180名 (※うちアルバイト25名)

東京スタジオ:33名 (※うちアルバイト11名)

40,000,000円

家庭用・スマートフォン向けゲームソフト企画・開発

CC2開発のスマートフォンタイトルとUnity

― 6 ―

2011 2012 2013 2014 2015 2016

2011.11検証開始(Unity 3.5 beta)

2012.11ギルティドラゴン

2013.02シャドウエスケイパー

2013.10死神メサイア

2014.02フルボッコヒーローズX

2014.03リトルテイルストーリー

2014.11FINAL FANTASY VII G-BIKE

2016.01.hack//NewWorld

2017

※サービス終了タイトルを含む、年月はグランドオープン時

本講演について

― 7 ―

開発の舞台裏として

過去の開発タイトルで行った

Unityの機能を活用した

テクニックを紹介いたします

アジェンダ

― 8 ―

1 キャラクターカスタマイズ編

2 フェイシャルアニメーション編

3 タウンマップ編

4 開発効率化編

キャラクターカスタマイズ編

― 9 ―

キャラクターカスタマイズとは

― 10 ―キャラクターカスタマイズ編

複数のパーツを合成して

多様なキャラクターを

表現できるようにする機能

キャラクターカスタマイズとは

― 11 ―キャラクターカスタマイズ編

キャラクターカスタマイズの要素

• 分割したパーツを読み込んで合成する

• ひとつのモデルを複数の体格で利用する

• 複数のバストサイズに対応する

• 肌色, 髪色, 目色などを変更する

分割したパーツを読み込んで合成する

― 12 ―キャラクターカスタマイズ編

1 パーツの合成

2 パーツの接続先指定

3 パーツの可視性指定

キャラクター生成の基本機能

分割したパーツを読み込んで合成する

― 13 ―キャラクターカスタマイズ編

1 パーツの合成

2 パーツの接続先指定

3 パーツの可視性指定

キャラクター生成の基本機能

1 パーツの合成

― 14 ―キャラクターカスタマイズ編

任意のモデル&マテリアルを読み込んで合成

1. 髪

2. 顔

3. 上半身

4. 下半身

5. 頭装飾(任意)

6. 胴装飾(任意)

7. 武器 (任意)

パーツの種類

モデル

マテリアル A

マテリアル B

パーツ

A

パーツ

B

1 パーツの合成

― 15 ―キャラクターカスタマイズ編

SkinnedmeshRenderer

単一のスキンメッシュに結合

(髪、顔、上半身、下半身)

MeshRenderer

任意のボーン(Transform)に接続

(頭装飾、胴装飾、武器)

分割したパーツを読み込んで合成する

― 16 ―キャラクターカスタマイズ編

1 パーツの合成

2 パーツの接続先指定

3 パーツの可視性指定

キャラクター生成の基本機能

2 パーツの接続先指定

― 17 ―キャラクターカスタマイズ編

頭装飾・胴装飾のパーツは

あらかじめ設定したダミーの

ボーン(Transform)に接続する

3. 空中系(周囲を浮遊するもの)

4. 羽系 (背中に背負うもの)

5. 胸元系

6. 尻尾系

胴装飾

頭装飾

1. 帽子系

2. めがね系

分割したパーツを読み込んで合成する

― 18 ―キャラクターカスタマイズ編

1 パーツの合成

2 パーツの接続先指定

3 パーツの可視性指定

キャラクター生成の基本機能

3 パーツの可視性指定

― 19 ―キャラクターカスタマイズ編

装備に合わせて可視性を変更する

• 帽子を装備した際にツインテールが突き抜ける場合– ツインテール部分をあらかじめ分離しておき、非表示にする

• フルフェイスのようなもので髪が突き抜ける場合

– 髪全体を非表示にする

可視性の変更例

など

ひとつのモデルを複数の体格で利用する

― 20 ―キャラクターカスタマイズ編

1 男女各8段階の体格対応

2 単一パーツでの複数体格対応

複数体格への対応方法

ひとつのモデルを複数の体格で利用する

― 21 ―キャラクターカスタマイズ編

1 男女各8段階の体格対応

2 単一パーツでの複数体格対応

複数体格への対応方法

1 男女各8段階の体格対応

― 22 ―キャラクターカスタマイズ編

体格違いの素体モデルを用意する男女それぞれ8段階の素体モデル(体格)を用意

パーツ結合時のボーン構造として利用

男性用 女性用

ひとつのモデルを複数の体格で利用する

― 23 ―キャラクターカスタマイズ編

1 男女各8段階の体格対応

2 単一パーツでの複数体格対応

複数体格への対応方法

2 単一パーツでの複数体格対応

― 24 ―キャラクターカスタマイズ編

スケール用のボーンを素体に入れておき

モデルの大きさを体格ごとに調整

最小体格 中間体格 最大体格

複数のバストサイズに対応する

― 25 ―キャラクターカスタマイズ編

1 女性のみ S, M, L の3サイズ

2 揺れる揺れないの変更

複数バストサイズの対応方法

複数のバストサイズに対応する

― 26 ―キャラクターカスタマイズ編

1 女性のみ S, M, L の3サイズ

2 揺れる揺れないの変更

複数バストサイズの対応方法

1 女性のみ S, M, L の3サイズ

― 27 ―キャラクターカスタマイズ編

素体のスケール用ボーンを使用する胸のサイズ毎に “Position”, “Rotate”, “Scale” を微調整

Sサイズ Mサイズ Lサイズ

複数のバストサイズに対応する

― 28 ―キャラクターカスタマイズ編

1 女性のみ S, M, L の3サイズ

2 揺れる揺れないの変更

複数バストサイズの対応方法

2 揺れる揺れないの変更

― 29 ―キャラクターカスタマイズ編

ボーン名が異なると

アニメーションしない仕様を利用し

結合時にボーン名を変更する

揺らさない場合 揺らす場合

肌色, 髪色, 目色を変更する

― 30 ―キャラクターカスタマイズ編

1 顔以外のパーツの色指定

2 顔のパーツの色指定

色替えの対応方法

肌色, 髪色, 目色を変更する

― 31 ―キャラクターカスタマイズ編

1 顔以外のパーツの色指定

2 顔のパーツの色指定

色替えの対応方法

1 肌、目、髪色の変更

― 32 ―キャラクターカスタマイズ編

マスクテクスチャを使用肌色・髪色・目色などを変更

ベーステクスチャ

マスクテクスチャ

カラー

1 肌、目、髪色の変更

― 33 ―キャラクターカスタマイズ編

R:カラー。 色を変更する箇所の指定

G:ライト。 ライトの影響を受けない箇所の指定

B:アルファ 透過させる箇所の指定

顔以外のマスクテクスチャ

1 肌、目、髪色の変更

― 34 ―キャラクターカスタマイズ編

R:カラー

G:ライト

肌色, 髪色, 目色を変更する

― 35 ―キャラクターカスタマイズ編

1 顔以外のパーツの色指定

2 顔のパーツの色指定

色替えの対応方法

1 肌、目、髪色の変更

― 36 ―キャラクターカスタマイズ編

R:目カラー 目の色を変更する箇所の指定

G:肌カラー 肌の色を変更する箇所の指定

B:なし。。

顔のマスクテクスチャ

1 肌、目、髪色の変更

― 37 ―キャラクターカスタマイズ編

R:目カラー G:肌カラー

目色

肌色

フェイシャルアニメーション編

― 38 ―

フェイシャルアニメーションとは

― 39 ―フェイシャルアニメーション編

キャラクターカスタマイズで

生成したキャラクターの

表情アニメーションを

行うための機能

フェイシャルアニメーションとは

― 40 ―フェイシャルアニメーション編

フェイシャルアニメーションの要素

• 様々な表情&アニメーションに対応する

• データ容量を極力減らす

• 短期間で制作できるようにする

様々な表情&アニメーションに対応する

― 41 ―フェイシャルアニメーション編

1 ブレンドツリーでの表情作成

2 デフォルト表情設定

3 キーフレーム設定

フェイシャル基本機能

様々な表情&アニメーションに対応する

― 42 ―フェイシャルアニメーション編

1 ブレンドツリーでの表情作成

2 デフォルト表情設定

3 キーフレーム設定

フェイシャル基本機能

1 ブレンドツリーでの表情作成

― 43 ―フェイシャルアニメーション編

各キャラ毎に表情、形状が異なるテクスチャでのアニメーションは難しい

目パチ、口パク、目線など動きが様々アニメーションとして実装するのも手間

1 ブレンドツリーでの表情作成

― 44 ―フェイシャルアニメーション編

様々な表情に対応できるControllerを作成

1 ブレンドツリーでの表情作成

― 45 ―フェイシャルアニメーション編

レイヤーは動作するパーツ毎に分ける

目線

左目

右目

感情

左右をまとめた眉の形状

まぶたの動き+目の形状

まぶたの動き+目の形状

頬を染めるなどの特殊表現

目そのものの動き

口の開閉+口の形状

1 ブレンドツリーでの表情作成

― 46 ―フェイシャルアニメーション編

基準となる表情とのブレンドを行う各ステートに表情を設定し、ブレンドツリーでブレンド

デフォルト表情例:目を開く

ブレンド表情例:目を閉じる

1 ブレンドツリーでの表情作成

― 47 ―フェイシャルアニメーション編

上下左右動く目線のみ2Dブレンディング

様々な表情&アニメーションに対応する

― 48 ―フェイシャルアニメーション編

1 ブレンドツリーでの表情作成

2 デフォルト表情設定

3 キーフレーム設定

フェイシャル基本機能

2 デフォルト表情設定

― 49 ―フェイシャルアニメーション編

基準となる表情のパラメータを設定各パーツ毎のパラメータを実行時に表情として反映

1.表情の状態

2.固定の状態 (通常/半固定/固定)

3.ブレンド率

デフォルトパラメータ概要

2 デフォルト表情設定

― 50 ―フェイシャルアニメーション編

• 表情の状態 :半目

• 固定の状態 :半固定

• ブレンド率 :0.9

• 表情の状態 :怒り

• 固定の状態 :半固定

• ブレンド率 :0.9

右目

キャラ毎にScriptableObjectで設定

• 通常– 0.0~1.0の間で自由に動く

• 半固定– その値を基準に動く

– 例:0.0~0.9 or 0.9~1.0

• 固定– その位置から動かない

– 目を閉じたまま など

様々な表情&アニメーションに対応する

― 51 ―フェイシャルアニメーション編

1 ブレンドツリーでの表情作成

2 デフォルト表情設定

3 キーフレーム設定

フェイシャル基本機能

3 キーフレーム設定

― 52 ―フェイシャルアニメーション編

表情を変えるタイミングとキーを設定指定した内容をスクリプトで制御する

右目/左目を0.1秒で閉じる1秒

右目/左目を0.1秒で開ける1.1秒

アニメーション開始0秒

アニメーション終了&ループ2秒

3 キーフレーム設定

― 53 ―フェイシャルアニメーション編

キーフレームはScriptableObjectで定義

1.再生までの待ち時間

2.対象のパーツ

3.ブレンドする表情の状態

4.再生時間

5.ブレンド率

キーフレームパラメータ概要

3 キーフレーム設定

― 54 ―フェイシャルアニメーション編

アニメーションイベントをトリガーとして

フェイシャルを再生

アニメーション1つで全キャラ対応デフォルト表情を元にアニメーションするので

どの表情のキャラクターにおいても対応可能

3 キーフレーム設定

― 55 ―フェイシャルアニメーション編

目を閉じたままのキャラ

半目気味のキャラ

猫目のキャラ

まばたきする

フェイシャル

アニメーション

目を閉じたまま

まばたきをする

アニメーション

キーフレームパラメータ デフォルトパラメータ 結果

タウンマップ編

― 56 ―

タウンマップとは

― 57 ―タウンマップ編

ユーザー間の

コミュニケーションの場である

広域のエリア

タウンマップとは

― 58 ―タウンマップ編

タウンマップの要素

• 昼、夕、夜という3種類の時間帯がある

• 時間帯間の遷移はクロスフェードする

• 時間帯毎のライトマップを使用する

タウンマップのクロスフェード

― 59 ―タウンマップ編

複数要素、リソースのフェード変化する要素が多い

1. ディレクショナルライト × 1

2. アンビエントライト × 1

3. パーティクルエフェクト × 複数(可変)

4. 背景のテクスチャ × 複数(固定)

5. 背景のライトマップ × 1

要素

各要素のクロスフェード

― 60 ―タウンマップ編

ライト系 color, intensity, rotationを線形補間

RenderSettings.ambientLight

各要素のクロスフェード

― 61 ―タウンマップ編

パーティクル

前:”emission.enabled” を false で

徐々に消えるようになる

後:Prewarm を false にすることで

徐々に表示するようになる

particleSystem.emission.enabled = false;

シェーダーでのクロスフェード

― 62 ―タウンマップ編

テクスチャ系 専用のカスタムシェーダー内で線形補間

ライトマップのクロスフェード テクスチャのクロスフェード

シェーダーでのクロスフェード

― 63 ―タウンマップ編

Shader.SetGlobal~を活用共通項目はまとめて処理する

• フェードの進捗(0.0~1.0)

SetGlobalFloat

• フェード前後のライトマップ

SetGlobalTexture

共通ではない項目は個別で差し替え

(空用のテクスチャなど一部の決まった要素のみ)

ライトマップ生成について

― 64 ―タウンマップ編

ライトマップを複数用意するUnity上でベイクしたライトマップを利用する

• ライトマップのUVは「シーン内」のメッシュに対応

• シーンに結びついたライトマップはクロスフェードできない

利用する際の問題点

ライトマップUVとは

― 65 ―タウンマップ編

ライトマップのUV

Lightingウィンドウ内の

“Baked Lightmap” の値

(シーンに結びついている値)

ライトマップUVをどうするか

― 66 ―タウンマップ編

UVとライトマップ3枚のみ必要シーンにある要素は不要

UVをPrefab内に保持するライトマップを単体で3枚用意

シェーダーでクロスフェード

ライトマップUVの用意

― 67 ―タウンマップ編

“Renderer.lightmapScaleOffset”

でUV値を取得、Prefab内に保存する

保存したUV値を

シェーダー内で利用する

ライトマップUVの一括設定

― 68 ―タウンマップ編

簡易ツールで一括設定設定しているシェーダーを調べて

ライトマップを使用するかどうか判別する

コンポーネントの追加Rendererの参照追加

UV値の反映

夜用

マップ

夕用

マップ

昼用

マップ

複数のライトマップへの対応

― 69 ―タウンマップ編

同じモデル(シーン)を用い

ベイク後にテクスチャをリネームする

昼用ライト

夕用ライト

夜用ライト

ライトマップを

ベイクする対象の

Prefab(モデル)

開発効率化編

― 70 ―

開発効率化について

― 71 ―開発効率化編

開発に用いたツールの中から

小ネタをいくつか紹介します

開発効率化について

― 72 ―開発効率化編

1 透過スクリーンキャプチャ

2 モデルインポート設定のコピペ

3 エディタ上での値の保持

開発効率化

開発効率化について

― 73 ―開発効率化編

1 透過スクリーンキャプチャ

2 モデルインポート設定のコピペ

3 エディタ上での値の保持

開発効率化

スクリーンキャプチャを撮りたい

― 74 ―開発効率化編

透過画像が出力できない装備のアイコンデータ作成などに時間がかかる

Unity上でモデルを配置

Unity上でキャプチャ

Photoshopで切り抜き

Photoshopでアイコン化

スクリーンキャプチャ

― 75 ―開発効率化編

Texture2D.ReadPixelsの利用スクリーン画面のピクセルデータを読み込むAPI

• 一般的な方法

• 透過画像を出力できない

Application.CaptureScreenshot

• OnPostRender内で行う方法

• 透過画像を出力できる

Texture2D.ReadPixels

― 76 ―開発効率化編

// エディタ上で動作するように.

[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;

}

} スクリーンキャプチャ取得実装例

開発効率化について

― 77 ―開発効率化編

1 透過スクリーンキャプチャ

2 モデルインポート設定のコピペ

3 エディタ上での値の保持

開発効率化

モデルインポート設定の問題

― 78 ―開発効率化編

インポート設定はコピーできない設定に時間がかかる+同じような設定が多い

• Model– Mesh Compression

• Rig– Avatar Source

• Animation– Avatar Mask

モデルインポート設定のコピー&ペースト

― 79 ―開発効率化編

多くの項目は

ModelImporter

ModelImporterClipAnimation

で取得・設定可能

無い項目については

SerializedObject.

CopyFromSerializedProperty

で設定可能

開発効率化について

― 80 ―開発効率化編

1 透過スクリーンキャプチャ

2 モデルインポート設定のコピペ

3 エディタ上での値の保持

開発効率化

エディタで設定した値の問題点

― 81 ―開発効率化編

永続的に値を保持できないエディタで設定したフラグをゲームで使用したい

PlayerPrefs レジストリを書き換える

Static変数 実行時に初期化される

Scriptable

Objectファイルの更新が入る

エディタで設定した値を保持し続ける

― 82 ―開発効率化編

ScriptableSingletonを使うエディタ上でしか使わない(使えない)点を利用

1. 単一性が保たれる

2. 実行後も値が保持される

ScriptableSingletonの利点

― 83 ―開発効率化編

// Editorのみで使用可能にする.

#if UNITY_EDITOR

// ScriptbaleSingletonはUnityEditor名前空間内にある.

using UnityEditor;

// ScriptableSingletonを継承したクラスを用意する.

public class EditorPreference : ScriptableSingleton<EditorPreference>

{

// 設定するフラグの例.

public bool customMode = false;

}

#endif

ScriptableSingletonの定義

― 84 ―開発効率化編

// エディタ上での操作用クラス.

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;

}

} エディタ拡張での使用方法

― 85 ―開発効率化編

ゲーム内での使用方法

// 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

}

}

おわりに

― 86 ―

おわりに

― 87 ―

開発事例として

いくつかのトピックを

紹介いたしました

おわりに

― 88 ―

みなさまの開発の

何かしらの

ヒントになれば幸いです

ご清聴ありがとうございました

ご質問・ご連絡は[email protected] まで