Slide 1

Slide 1 text

クライアントエンジニア / 呪術廻戦 ファントムパレード 『呪術廻戦ファントムパレード』 ストーリー制作を支えるグラフィックシステム 1 二宮 章太 Ninomiya Shota

Slide 2

Slide 2 text

自己紹介 - 名前 - 二宮 章太(Ninomiya Shota) - 経歴 - 2015年新卒でサイバーエージェントに入社 - ゲーム事業にていくつかの新規開発を担当 - 『呪術廻戦 ファントムパレード』 - クライアントのテックリードとして開発に従事 - 特に, 演出周りの仕組みを多く担当 2

Slide 3

Slide 3 text

呪術廻戦 ファントムパレードとは 3

Slide 4

Slide 4 text

4 『呪術廻戦 ファントムパレードは、 2018年より「週刊少年ジャンプ」 (集英社)にて連載中の芥見下々(あ くたみげげ)氏による人気漫画を原作 としたTVアニメ『呪術廻戦』を元に した、作品初のスマートフォンゲーム です。 TVアニメ『呪術廻戦』の第1期の物語 を追体験できるだけでなく、福岡を舞 台にした『ファンパレ』オリジナルの ストーリーが楽しめるコマンドバトル RPGとなっています。

Slide 5

Slide 5 text

ストーリーパートの紹介 5

Slide 6

Slide 6 text

はじめに ファンパレのストーリーパートは大きく2種類あります。 - Live2Dによる会話劇 - より動きのある表現が可能なシネマティックシーン 6

Slide 7

Slide 7 text

はじめに この発表では『呪術廻戦ファントムパレード』のストーリー制作を行う上で鍵となっ たグラフィックシステムについて, 作例を交えながら紹介します。 1. 陰影/光の表現 2. キャラライティング 3. レイヤー指定ポストエフェクト 4. Live2Dの半透明描画に関するチューニング 7

Slide 8

Slide 8 text

陰影/光の表現 8

Slide 9

Slide 9 text

陰影/光の表現 9

Slide 10

Slide 10 text

陰影/光の表現 10

Slide 11

Slide 11 text

陰影/光の表現 11

Slide 12

Slide 12 text

陰影/光の表現 要望/要件 - 光彩やグラデーションを手軽にかけたい - 加算/乗算/アルファブレンドで元絵と合成したい - 対象はLive2D, Spine, SpriteRenderer - 共通化したい - 応用の効きやすい手法を取りたい シルエットのキャプチャを加工して、上から載せる方法をとることに 12

Slide 13

Slide 13 text

陰影/光の表現 1. 対象のRendererからシルエットを抽出 2. シルエットをShaderで加工, 色付け 3. 元絵を重ねて表示する 13 キャプチャ シルエット化 加工 重ねる

Slide 14

Slide 14 text

現在使用している加工方法 - ブラー - 光彩 - グラデーション 陰影/光の表現 14 加工前 ブラー 光彩 グラデーション

Slide 15

Slide 15 text

- 背景に合わせて影を付与 - シルエット x グラデーション x アルファブレンド 作例:影 効果あり 15

Slide 16

Slide 16 text

- 背景に合わせて影を付与 - シルエット x グラデーション x アルファブレンド 作例:影 効果なし 16

Slide 17

Slide 17 text

- 背景に合わせて影を付与 - シルエット x グラデーション x アルファブレンド 作例:影 17

Slide 18

Slide 18 text

作例:影2 - 明るさをキャラごとに調整 - シルエット x グラデーション x アルファブレンド 18 効果あり

Slide 19

Slide 19 text

作例:影2 - 明るさをキャラごとに調整 - シルエット x グラデーション x アルファブレンド 19 効果なし

Slide 20

Slide 20 text

作例:ライティング1 - 共鳴りの呪力の光を表現 20 効果あり

Slide 21

Slide 21 text

作例:ライティング1 - 共鳴りの呪力の光を表現 21 効果なし

Slide 22

Slide 22 text

作例:ライティング1 - 共鳴りの呪力の光を表現 - シルエット x グラデーション x 加算 22

Slide 23

Slide 23 text

作例:内側光彩 - 内側に光を漏らす - 光彩 x 加算 23 効果あり

Slide 24

Slide 24 text

作例:内側光彩 - 内側に光を漏らす - 光彩 x 加算 24 効果なし

Slide 25

Slide 25 text

- 内側に光を漏らす - 光彩 x 加算 25 作例:内側光彩

Slide 26

Slide 26 text

26 作例:オーラ表現 (バトル) - 外側に禍々しい光を纏う表現 - ぼかし x 乗算 をキャラの下に敷く 効果あり

Slide 27

Slide 27 text

- 外側に禍々しい光を纏う表現 - ぼかし x 乗算 をキャラの下に敷く 27 作例:オーラ表現 (バトル) 効果なし

Slide 28

Slide 28 text

- 外側に禍々しい光を纏う表現 - ぼかし x 乗算 をキャラの下に敷く 28 作例:オーラ表現 (バトル)

Slide 29

Slide 29 text

パフォーマンスについて 負荷対策 - シルエット画像のサイズを512 x 512に固定 - 描画用カメラを1台に絞り, カメラ増加によるコストを抑制 - 詳細: 2Dキャラをリッチに魅せる描画テクニック https://learning.unity3d.jp/9586/ RenderFeatureを駆使して, カメラを増やさずにキャプチャするテクニックについて解説しています とはいえ重めな処理ではある - 開発中, バトル画面で表示キャラ全8体のソフトシャドウを同じ仕組みで付与し ていたが, 負荷軽減のために仕組みを変更した - ストーリーパートで使用する程度なら問題なし (数が多くなりづらい) 29

Slide 30

Slide 30 text

陰影/光の表現 まとめ - シルエットを加工・配置することで, さまざまな表現が可能 - 特にアニメ風な表現と親和性が高い - パフォーマンスも, ストーリーパートで使用する分には問題なし - 今後のタイトルでも活躍が期待できる表現手法 30

Slide 31

Slide 31 text

キャラライティング 31

Slide 32

Slide 32 text

キャラライティング Live2D x NormalMap によるライティングシステム 32 効果あり

Slide 33

Slide 33 text

キャラライティング Live2D x NormalMap によるライティングシステム 33 効果なし

Slide 34

Slide 34 text

キャラライティング 背景にライトがあって, 移動すると光の当たり方が変化する 34

Slide 35

Slide 35 text

基本的には一般的な2D Lighting - 3D空間上に光源を配置 - 2D距離によって光を減衰 一般的にNormalMapの適用には, Live2Dから出力する頂点に接ベクトルを仕込む必要があるが, Live2DのSDKには存在しなかったため, 独自の工夫を凝らした Live2D x NormalMapによるライティング 35

Slide 36

Slide 36 text

- 物体の向きによって, 光が当たることでどれくらい光って見えるかが変わる - Live2Dの絵が描画される時、各ピクセルの3D空間上での向きが分かれば, 当たる光の強さを計算できる - NormalMapとは, テクスチャにピクセルごとの向き (法線) を書き込んだもの - rgb = xyzに対応 - Live2Dの絵はモーションによって回転する - 同様に, NormalMapから取り出した法線も絵に合わせて回転してあげればよい Live2D x NormalMapによるライティング 36

Slide 37

Slide 37 text

2頂点からモーションによる回転角を推定 37 パーツのMeshごとに2頂点を適当に取り出し, 位置の差分を diff_pos, UVの差分をdiff_uvとおく. 回転角は var cos = Vector2.Dot(diff_pos.normalized, diff_uv.normalized); var sin = Vector3.Cross(diff_pos.normalized, diff_uv.normalized); と推定できる. さらに, フラグメントシェーダでNormalMapから取り出した法線を回転すれば, ピクセルごとの3D空間における向き normal_wsが算出できる. const half3 normal = UnpackNormal(tex2D(_NormalMapTex, IN.texcoord.xy)); const half x = normal.x * cos - normal.y * sin.magnitude; const half y = normal.x * sin.magnitude + normal.y * cos; const half3 normal_ws = half3(x, y, -normal.z); 最後に, 3D空間におけるライトの位置とnormal_wsから反射率を求めてあげれば 光の強さを計算できて, めでたくライティングが行える

Slide 38

Slide 38 text

キャラライティング まとめ - Live2Dにライティングを適用し, キャラの魅力を大きく向上 - 2頂点から法線の回転角を推定し, Live2Dへのライティングを実現 38

Slide 39

Slide 39 text

レイヤー指定ポストエフェクト 39

Slide 40

Slide 40 text

レイヤー指定ポストエフェクト 40

Slide 41

Slide 41 text

レイヤー指定ポストエフェクト レイヤー指定をしてポストエフェクトを当てる機能を用意 - 奥/通常/手前の3レイヤーに分類 - 奥と手前レイヤーにポストエフェクトをかけられる 41

Slide 42

Slide 42 text

手前オブジェクトに対してブラーをかける 手前レイヤーポストエフェクト1 42

Slide 43

Slide 43 text

1. 手前のレイヤーを別のRenderTextureに描画 2. RenderTextureに対してアルファ含めてポストエフェクトをかける 3. 合成 ブラーを入れる際には, アルファもぼかすことが大事 手前レイヤーポストエフェクト1 43

Slide 44

Slide 44 text

手前レイヤーに対してのみ, Directionalブラーをかける 手前レイヤーポストエフェクト2 44

Slide 45

Slide 45 text

1. 手前のレイヤーを別のRenderTextureに描画 2. RenderTextureに対してアルファ含めてポストエフェクトをかける 3. 合成 手前レイヤーポストエフェクト2 45

Slide 46

Slide 46 text

合成可能な手前レイヤーには制約があり, 背景に対して加算またはアルファブレンドする絵 にしか対応していない - 手前レイヤーのRenderTextureは, 事前乗算テクスチャ (RGBにあらかじめ Aを乗算した値が格納してあるテクスチャ) となる必要がある - ファンパレではストーリーパートで使用するほぼ全てのシェーダーのブレ ンドモードを Blend One OneMinusSrcAlpha にすることで対応している 合成可能な手前レイヤーの制約について 46

Slide 47

Slide 47 text

奥レイヤーにのみブラーをかける 奥レイヤーポストエフェクト 47

Slide 48

Slide 48 text

1. 奥のレイヤーを描画 2. フレームバッファにポストエフェクトをかける 3. 通常レイヤのオブジェクトを描画 奥レイヤーポストエフェクト 48

Slide 49

Slide 49 text

ファンパレでは, 手前レイヤー/奥レイヤーのサポートを行うため, RenderFeatureを 使って処理の挿入を行った レンダリングパイプラインの実装 49

Slide 50

Slide 50 text

各レイヤーの描画を行う際には, Renderer.renderingLayerMaskによるカリングを 行った描画コマンドの発行を行っている パフォーマンスの観点から, レイヤー指定ポストエフェクトの設定がない時には自動 的に描画処理をまとめたかったため, ポストエフェクトの設定情報から動的に描画するレイヤーを切り替えるようにした レンダリングパイプラインの実装 50 ポストエフェクトがな ければ, 通常の半透明 描画にマージ

Slide 51

Slide 51 text

レイヤー指定ポストエフェクト まとめ - レイヤーを手前/通常/奥の三層に分離してポストエフェクトをかける手法 - 手前レイヤーの合成は, 背景に対して加算またはアルファブレンドする絵のみ対応 - 疑似的な被写界深度やスピード感の表現など, キーとなる演出で活用 51

Slide 52

Slide 52 text

Live2Dの半透明描画に関するチューニング 52

Slide 53

Slide 53 text

Live2Dの半透明描画に関するチューニング Live2D x 半透明描画を綺麗に出すための従来手法 - Live2Dを半透明で描画すると、関節が重なってしまって汚れる - よくある解決手法 - 専用カメラを用意 - キャラをそれぞれRenderTextureに焼き込み <メモリ増> - RenderTextureを描画する際に一律透明化する ファンパレではこのコストを許容できずチューニングを行った. 53

Slide 54

Slide 54 text

Live2Dの半透明描画に関するチューニング 従来のフロー 1. Live2D全体が映るようにRenderTextureを用意 (1体につき約10MB) ※ キャラ全体を映してQuadに差して描画するため, 1800pix * 1500pix * 32bit ※ 簡単に実装する場合を想定すれば, 出てくるキャラ x 10MB. 頑張っても同時表示数 x 10MB. 2. 専用カメラを用意してLive2Dを撮影 (描画コスト高) 54

Slide 55

Slide 55 text

Live2Dの半透明描画に関するチューニング ファンパレの描画フロー 1. 1枚だけ半透明のRenderTextureを用意 ※ フルスクリーン 2. 透明オブジェクトの描画を開始 3. Live2Dの描画順の直前に, 対象のLive2DをRenderTextureに書き込む 4. 1で利用したフレームバッファにRenderTextureを合成 5. まだ描画すべきオブジェクトがあれば2に戻る 55 すぐにFrameBufferに移すため RenderTextureが1枚で済む

Slide 56

Slide 56 text

Live2Dの半透明描画に関するチューニング 主なメリット - 何体同時表示してもRenderTextureが1枚で済む - しかも手前レイヤーのポストエフェクトに使うバッファの使い回し = 何体出しても実質タダ - 描画用カメラを1台に絞り, カメラ増加によるCPUコストを抑制 デメリット - 実装コスト大 - 全オブジェクトの描画順コントロールが必要. - レンダリングパイプラインの拡張が必要 - 半透明の合成が必要なので, Live2DのShaderも Blend One OneMinusSrcAlpha でブレンドするという制約がつく 56

Slide 57

Slide 57 text

Live2Dの半透明描画に関するチューニング まとめ Live2Dの綺麗な半透明化を実現する上で, Live2Dパートの専用描画フローを作成す ることで, メモリ使用量とCPU負荷を抑制できた - 何体出してもRenderTextureは追加せずに済む - 描画用カメラを1台に絞り, カメラ増加によるCPUコストを抑制 ※ 陰影/光の表現のチューニングと同じアイデア 57

Slide 58

Slide 58 text

まとめ 58

Slide 59

Slide 59 text

まとめ 呪術廻戦ファントムパレードで広く活用しているグラフィックシステムについて紹介 しました. - 陰影/光の表現 - キャラライティング - レイヤー指定ポストエフェクト - Live2Dの半透明描画に関するチューニング どの手法も使い勝手がよく, クオリティをぐっと引き上げる仕組みなので, 今後のタイ トルにも活用されていくと思います. 皆様の開発するプロジェクトにとっても良いノウハウとなっていたら幸いです. 59

Slide 60

Slide 60 text

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