「いけにえと雪のセツナ」グラフィック解説(第1回・フロー編)

By | 2016年7月20日

はじめに

本日より弊社が関わったタイトルで、(ご紹介できるものだけですが)そこで使った技術を紹介するブログを公開することになりました!

記念すべき初回ですが、7/19に英語版が発売になった「いけにえと雪のセツナ(I am Setsuna)」(Tokyo RPG Factory)で、弊社が関わったグラフィック処理を4回(予定)に分けて紹介していきます。
初回は「フロー編」です。

※去る2016/4/5にもUnite2016にて一部公開致しましたが、本編はそれも含めつつの内容になっています。
そちらの資料動画も合わせてご覧いただくのをオススメします。


ゲーム概要

「いけにえと雪のセツナ」自体の紹介は割愛致します。
公式HPを是非ご覧ください。)

今後の回にも関わる、グラフィック処理面での重要なポイントを挙げていきます。

・Unity5を利用していること。
・見下ろし型のRPGであること。(カメラの回転などはない)
・PS4とPS Vitaのマルチプラットフォームであること。

90年代のRPGをモチーフにしており、それは見下ろし型が主体になりますので、描画の設計でそれを活用するところが多々ありました。

そしてPS4とPS Vitaのマルチプラットフォームというのも大きく、(その時点では)この2機種だけを考えれば良かったですが、負荷などの面からPS Vitaに主観をおいて描画設計を行いました。


描画フローについて

まず「いけにえと雪のセツナ」でのおおまかな描画フローがどのようになっているかをご紹介します。

Unityを利用しているので、Cameraを複数置いてそれぞれに固有の役割を果たして〜という形態になっています。
こちらではそのCameraを、depth(描画)順に列挙してみます。

depth 名称 Target Texture
(※RT=RenderTexture)
動作
-30 シャドウマップカメラ RT:シャドウマップ ・シャドウ描画の為のシャドウマップに描く為のカメラ。
-25 マップ特殊処理用カメラ RT:マップテクスチャ ・雪面凹み、高さフォグ等を行う為のカメラ。
・各マップに入った瞬間だけ動作。
-23 足跡描画用カメラ ・雪面凹みを行う為にマップテクスチャに描く為のカメラ。
-22 画面歪み用カメラ RT:歪み量バッファ ・画面歪みの時にピクセル毎にどれだけ歪むかを指定する為のバッファを描く為のカメラ。
・画面が歪む時だけ動作。
-20〜-10 写り込み用カメラ RT:写り込み用バッファ ・水面や氷の床などに写り込み為のバッファに描く為のカメラ。
-2 キャラクター半透明用カメラ RT:半透明描画用カメラ ・キャラクターを半透明にする時用のカメラ。
-1 メインカメラ RT:メインバッファ ・キャラクターなどの3Dモデルを描くカメラ。
7 エフェクト用カメラ ・一部エフェクト用のカメラ。
9 デフォルトコピー用カメラ デフォルトターゲット ・メインバッファに描いていた3D部分をデフォルトターゲットにコピー。
・各種フィルタもここで行う。
50 UIレイヤー(後方) ・UIを描く為のカメラ。
・全画面ぼかし時にぼかし対象となるUI。
51 ぼかし用カメラ ・画面全体をぼかす為のカメラ。
・ぼかす時だけ動作。
52 UIレイヤー(前方) ・UIを描く為のカメラ。
・全画面ぼかしが掛かってもこのUIはぼけない。
100 レターボックスカメラ ・画面が16:9ではない時に上下もしくは左右に黒帯を付けるためのカメラ。
・PS4やPS Vitaでは動作しません。

本作ではUnityのRenderTextureを活用しており、利用しているものを全て挙げます。
(作業用の一時利用的なものは除く。)

名称 イメージ 基本サイズ 内容
 メインバッファ setsuna_RT_mainbuffer スクリーンサイズと同一

(1920×1080(PS4)
960×544(PS Vita))

・キャラクターやNPCやマップ等の3Dオブジェクトを描き込む為の基本バッファ。
 シャドウマップ  setsuna_RT_shadowmap 1024×1024(PS4)
256×256(PS Vita)
・シャドウマップ用のバッファ。
・本作ではUnityのシャドウシステムは利用していません。(詳細は後日説明予定。)
 マップテクスチャ setsuna_RT_map_texture  マップサイズで可変

(1ピクセル5cm四方(PS4)
1ピクセル20cm四方(PS Vita))

・雪面凹みなどを実現する為のバッファ。
・内容は以下の通り。
R:高さフォグ
G:未使用
B:地面高さ
A:雪面凹み量
 写り込み用バッファ  setsuna_RT_reflection  スクリーンサイズの縦横1/2ずつ

(960×540(PS4)
480×272(PS Vita))

 ・氷の床などに写り込むオブジェクトを描くバッファ。
・こちらに描いて、メインバッファにフィードバックする仕組み。
 歪み量バッファ  setsuna_RT_distortion  PS4:スクリーンサイズの縦横1/2サイズ
PS Vita:スクリーンサイズの縦横1/4サイズ
 ・画面を歪ませる際にピクセル毎にどれだけ歪ませるかの情報が描き込まれるバッファ。
・Rが横方向、Gが縦方向の歪み量。
半透明描画用カメラ (省略) PS4:スクリーンサイズと同一
PS Vita:スクリーンサイズの縦横1/2サイズ
・キャラクターを半透明にする際、こちらに不透明で描き込んで、それをメインバッファにフィードバックする。

大雑把に書きますと、「前半の3D表示部分はメインバッファ、後半のUIなどの表示はデフォルトターゲット」となります。

setsuna_main_buffer(※メインバッファ・3D部分)



setsuna_default_target(※デフォルトターゲット・UI描画)

ポーズ中の処理

RenderTextureをベースに処理を行うことの利点を挙げていきます。

本作はRPGですので、ゲーム中にメニューを開き装備などの変更を行うことが多々有ります。

setsuna_menu_off

↓(メニューボタン押下)

setsuna_menu_on

その画面を良く見てもらうと分かりますが、プレー中の背景をぼかして表示しています。

「画面をぼかす」処理を行うのは「3D部分を描く→ぼかす」となり、通常の描画に加えて重いぼかし処理が入るので避けられがちですが、3D部分を別のメインバッファに描いているので、3D部分を描かずに画面をぼかすだけで済んでいます。

3D部分をメインバッファに描画

デフォルトターゲットにコピー

UIを描画
(既にメインバッファに3D部分が描かれている!)

メインバッファをぼかしてデフォルトターゲットにコピー

UIを描画
(通常時) (メニュー画面表示時)

3D部分を更新しないので、キャラクターなどは停止した状態になっています。
ただメニュー画面ということでポーズと同じことなので、それは問題ありません。

メインバッファのコピー時

メインバッファに3Dを描くのは良いのですが、Unityの仕様としてそれだけではディスプレイに表示されないので、デフォルトターゲットにコピーすることになります。

先述のメニュー時などでメリットがありましたが、基本的にこのコピー処理が入り負荷が掛かるので、その点ではデメリットを強く感じてしまいます。
ですので、そのデメリットを穴埋めするように、コピー時に各種ポストフィルタもついでに行っています。

setsuna_post_before(※メインバッファ)

↓(コピー&フィルタ処理)

setsuna_post_after(※デフォルトターゲット)

そのポストフィルタですが種類が幾つかあり、常時掛かっているものや時折掛かるものが有ります。
それらを全て挙げます。(上から処理される順番になっています。)

フィルタ名 イメージ
(※一部誇張表示)
動作
画面歪み setsuna_post_distortion ・派手な大技などの時に発生する歪み処理。
 スクリーンオーバーレイ setsuna_screen_overlay ・常時掛かっている画面の雰囲気作りの為のフィルタ。
 ガンマ補正  setsuna_post_gamma ・色調補正の一種。
・RGBに対し任意のガンマ補正を掛ける。
コントラスト調整  setsuna_post_contrast ・色調補正の一種。
・画面全体のコントラストを調整。
明るさ調整  setsuna_post_brightness ・色調補正の一種。
・画面全体の明るさを調整。
ブレンドカラー  setsuna_post_blend_color ・色調補正の一種。
・画面全体にアルファブレンドでカラーを乗せる。
モノクロ化  setsuna_post_monochrome ・イベントなどの際に、画面全体をモノクロ階調にする。
セピア化  setsuna_post_sepia ・イベントなどの際に、画面全体をセピア階調にする。

これらはメインバッファをデフォルトターゲットにコピーする際に行われていますが、常時ではなくたまにしか行わないものもあります。(画面歪みなど)
それも常に処理していると負荷的に重いので、それはUnityのShaderの「multi_compile」で適宜切り替えながら処理しています。

色調補正マトリクス

デフォルトターゲットコピー時にポストフィルタを行いますが、後半の色調補正系も多く、やはり負荷が高くなると予想されます。
そこで、幾つかの色調補正は特殊な方法で高速化を行っています。

ここで一般的なカラー計算の話に入ります。
上記の「ブレンドカラー」は通常のアルファブレンドですが、そのカラー計算は以下の通りです。

・元々のカラーを(Rd, Gd, Bd)とし、ブレンドするカラーを(Rs, Gs, Bs, As)とする。
・その場合、最終的なカラー(R, G, B)は以下の通りになる。

R = Rd×(1-As) + Rs×As
G = Gd×(1-As) + Gs×As
B = Bd×(1-As) + Bs×As

これを普通にシェーダに書いてもいいのですが、以下の様なマトリクス(3行4列)を用意し、(Rd, Gd, Bd, 1)を乗算する事で(R, G, B)を得る様な仕組みにしました。

| (1-As) 0   0   Rs×As |
| 0   (1-As) 0   Gs×As |
| 0   0   (1-As) Bs×As |

上記に(Rd, Gd, Bd, 1)を乗算すると同一の結果が得られます。

ここからが肝ですが、ブレンドカラー以外のコントラスト調整、明るさ調整などもマトリクス化し、事前にCPUでマトリクスをまとめておくことで、シェーダ側ではマトリクス計算1回分で済み、尚且つフィルタの掛かる順番も乗算順で制御できるようになっています。
(ポストフィルタ表の赤色部分がその対象となっています。)

(流れ)
・コントラスト調整のマトリクス = Mc
・明るさ調整のマトリクス = Mbr
・ブレンドカラーのマトリクス = Mbc
・モノクロ化のマトリクス = Mm
・セピア化のマトリクス = Ms


・CPUで事前にまとめる。(M = Ms × Mm × Mbc × Mbr × Mc)


・まとめたマトリクスMをシェーダに渡し、フラグメントシェーダで乗算。

メリットとして「シェーダ内でマトリクス1回分の計算で済む」「フィルタを掛ける順番もマトリクスの乗算順で制御できる」ことがありますが、ガンマ補正などの複雑な処理は行えないというデメリットがあります。

上記のポスト処理以外でも、派手な連携技などで利用されます。


PowerVR考慮について

「いけにえと雪のセツナ」はPS Vita向けにもリリースしていますが、PS VitaではGPUにPowerVR系を採用しています。

PowerVRでは固有の特徴があり、それを考慮した処理を少しだけ行っています。
ここではそれらを一部紹介します。
(Androidの一部や、iOSデバイスでも採用されていますので、活用の場面があるかもしれません。)

Cutoutシェーダについて

オブジェクトは不透明と半透明の部分に分かれると思いますが、半透明は描画順の問題や負荷の観点で利用に躊躇する場面が出てきます。
その際に半透明の代わりとして「カットアウト」を利用することもあると思います。

カットアウトは不透明扱いなので使い勝手がよいのですが、PowerVR系では負荷の観点で注意が必要です。

Unityのドキュメントにも記載されていますが、PowerVR系はアルファテスト、つまりカットアウトもですが、それは非常に負荷が高いものとなっています。
(原理を簡単に書きますと、PowerVRでは事前デプス描画を行いますが、その際に単純な不透明はポリゴンをそのまま描けば良いのに対し、アルファテスト系はテクスチャの参照が必要になってくるので、その分負荷が高くなります。)

本作の場合、ワールドマップの樹木は当初はカットアウトで書いていましたが負荷が高く、代わりに半透明にしたところ負荷が大きく削減されました。

setsuna_VR_cutout_on setsuna_VR_cutout_off
Cutoutオン
(最初はこの状態・負荷高い)
半透明化
(こちらに変更・負荷軽い)

しかし半透明だと描画順やデプスの問題が再度発生しますので、それは「形状はなるべく木の形にしてポリゴンを作る」「ポリゴン順を奥から順に並べてもらう」としてもらいました。
特に後者は、見下ろし型でカメラも回転がしないことから、データが作りやすかったとも言えます。
(回転する場合は木の前後関係も変わってしまうので。)

setsuna_tree_polygon

(未実装)フェレームバッファのフェッチ

本作では未実装ですが、PowerVR系のユニークな機能をご紹介します。

Unityのドキュメントにもありますが、PowerVR系ではシェーダ内でフェレームバッファ、つまり描き込み先のカラーを取得することが可能です。
(これは非常に面白い機能ですが、あまり知られていないと思います。)

具体例を挙げます。
画面のRGBを全て2乗にする(簡易的なガンマ補正)ことをしたいとします。
このフレームバッファフェッチ機能の有無で処理を考えます。

★フェッチ機能なし
バッファBに普通に絵を描く

全画面描画でシェーダでバッファBを参照しながら2乗し、バッファAにコピー

★フェッチ機能あり
バッファAに普通に絵を描く

全画面描画でシェーダ内でバッファAをフェッチして2乗して戻す

フェッチ機能があることで「バッファBが不要になる」「全画面描画でテクスチャを参照しないので負荷が軽い」という強いメリットが生まれます。

本作でもメインバッファを廃止し最初からデフォルトターゲットに描画、そして色調補正などをこの機能で行う事を検討しましたが、「画面を歪ませる事がある」「それによりフローが複雑になってしまう」ことから、導入を見送りました。

Unityでは同機能の扱いは以下のようになっています。(動作未確認)

・OpenGL的には「EXT_shader_framebuffer_fetch」が有効になっていると利用可能。
・シェーダでは「UNITY_FRAMEBUFFER_FETCH_AVAILABLE」が定義されていれば使えると判断している様子。
・しかしPS Vitaでは上記定義は有効になっていない模様?
・PS Vitaでは「FRAGCOLOR」というセマンティックを利用して実現可能。(これは検証済み)

この機能を活用することでPowerVR系のデバイスで大きく負荷削減が見込めるかもしれません。


まとめ

初回として描画フロー周りを中心に「いけにえと雪のセツナ」での描画の概要を説明しました。

次回以降は各パーツの細かい話もしていけたらと思いますが、まず大枠を理解することで詳細の技術も理解しやすくなると思います。
RPG固有での考慮も含めており、それに助けられているところもありますが、ゲームジャンルに見合った設計というものが大事だと考えています。

次回は「グラフィック効果編」をお送りする予定です。
お楽しみに!


 

 

【免責事項】
本サイトでの情報を利用することによる損害等に対し、株式会社ロジカルビートならびに株式会社Tokyo RPG Factoryは一切の責任を負いません。

※「いけにえと雪のセツナ」:©2016 Tokyo RPG Factory Co., Ltd. All rights reserved.