37.1K Views
July 15, 22
スライド概要
Game Creators Conference 2019の講演で使用したスライドです。
「緻密なキャラクターの表情や破壊表現のためのコンピュートシェーダによるメッシュアニメーション」阿久澤陽菜
株式会社カプコンが誇るゲームエンジン「RE ENGINE」を開発している技術研究統括によるカプコン公式アカウントです。 これまでの技術カンファレンスなどで行った講演資料を公開しています。 【CAPCOM オープンカンファレンス プロフェッショナル RE:2023】 https://www.capcom-games.com/coc/2023/ 【CAPCOM オープンカンファレンス RE:2022】 https://www.capcom.co.jp/RE2022/ 【CAPCOM オープンカンファレンス RE:2019】 http://www.capcom.co.jp/RE2019/
緻密なキャラクターの表情や破壊表現のための コンピュートシェーダによるメッシュアニメーション 株式会社カプコン 技術開発室 阿久澤 陽菜 1
2
Take Home Message • コンピュートシェーダ(CS)によるアニメーション手法 • プログラマ:CSの活用方法、最適化のヒント • アーティスト:CSで実現できる表現の知見 3
自己紹介 阿久澤 陽菜 技術研究開発部 技術開発室 RE ENGINEの開発に従事 主にレンダリングに関する機能実装を担当 RE ENGINE 採用タイトル BIOHAZARD 7, BIOHAZARD RE:2, Devil May Cry 5 4
メッシュアニメーション 5
主なアニメーション手法 • スキニング • ブレンドシェイプ • 頂点アニメーション • etc… 6
主なアニメーション手法 • スキニング • ブレンドシェイプ • 頂点アニメーション • etc… 7
スキニング • スケルトンを構築 • ボーン • ジョイント • ジョイントを変形させてアニメーション • 影響を受けるジョイントの変形に応じて頂点を移動 • 走る、跳ぶなどの大きな動きを模倣しやすい • 省メモリ 8
ブレンドシェイプ • 変形しうる形状をあらかじめ作成 • 元形状の頂点が一致するように移動させることで アニメーション • 複数の変形のブレンドも可能 • 微細な変形も表現可能 • メモリは消費しやすい 9
主なアニメーション手法 • スキニング 併用可 • ブレンドシェイプ 10
キャラクターの表情は… カットシーンで キャラクターの表情を 見せたい 11
ブレンドシェイプ 12
ブレンドシェイプアルゴリズム 1. ベース形状とトポロジーの等しい任意個数の ターゲット形状を用意 13
ブレンドシェイプアルゴリズム 1. ベース形状とトポロジーの等しい任意個数の ターゲット形状を用意 ・・・ ベース形状S ターゲット形状T0 ターゲット形状T1 14
ブレンドシェイプアルゴリズム 1. ベース形状とトポロジーの等しい任意個数の ターゲット形状を用意 2. ターゲット形状との差分に任意のブレンド係数 を掛けてベース形状の頂点を移動 15
ブレンドシェイプアルゴリズム 1. ベース形状とトポロジーの等しい任意個数の ターゲット形状を用意 2. ターゲット形状との差分に任意のブレンド係数 を掛けてベース形状の頂点を移動 𝑁 𝐒′ = 𝐒 + 𝑟𝑖 𝐓𝑖 − 𝐒 𝑖=0 0≤𝑟≤1 r : ブレンド係数 16
ブレンド率による調整 𝑁 𝐒′ = 𝐒 + 𝑟𝑖 𝐓𝑖 − 𝐒 𝑖=0 ー r0 T0 + S S = ー r1 T1 S’ S 17
ブレンド率による調整 𝑁 𝐒′ = 𝐒 + 𝑟𝑖 𝐓𝑖 − 𝐒 𝑖=0 1.0 T0 + S ー 0.0 S = ー T1 S’ S 18
ブレンド率による調整 𝑁 𝐒′ = 𝐒 + 𝑟𝑖 𝐓𝑖 − 𝐒 𝑖=0 0.0 T0 + S ー 1.0 S = ー T1 S’ S 19
ブレンド率による調整 𝑁 𝐒′ = 𝐒 + 𝑟𝑖 𝐓𝑖 − 𝐒 𝑖=0 0.5 T0 + S ー 0.0 S = ー T1 S’ S 20
ブレンド率による調整 𝑁 𝐒′ = 𝐒 + 𝑟𝑖 𝐓𝑖 − 𝐒 𝑖=0 0.0 T0 + S ー 0.5 S = ー T1 S’ S 21
ブレンド率による調整 𝑁 𝐒′ = 𝐒 + 𝑟𝑖 𝐓𝑖 − 𝐒 𝑖=0 0.3 T0 + S ー 0.7 S = ー T1 S’ S 22
フェイシャルアニメーションへの適用例 10,000個を超える 膨大な頂点数 GPUの利用 23
Graphics Processing Unit (GPU) • 単純な計算の並列処理が得意 • CPUは複雑な計算も可能だが大量処理は苦手 • 従来はグラフィックス処理に利用されていたが、 現世代コンソール機から数値計算にも利用可能に コンピュートシェーダの利用 24
コンピュートシェーダ(CS) • 数値演算をGPU上で行うためのプログラム • プログラムは各スレッドで並列処理 • スレッドグループは最大1024個のスレッドをまとめ たもの ThreadGroup 0 x+y=? ThreadGroup 1 ・・・ ThreadGroup N 最大1024スレッド x+y=? x+y=? 25
コンピュートシェーダでブレンドシェイプ ThreadGroup 0 ThreadGroup 1 ・・・ ThreadGroup N 𝑁 𝑁 𝑁 s′s′==ss++ 𝑟𝑟 t 𝑖t −−ss s′ = s + 𝑟 𝑖t 𝑖 − s 𝑖=0 𝑖=0 𝑖=0 26
変形後の頂点 頂点の位置のみ書き換えると法線が不自然 27
変形後の頂点 頂点の位置のみ書き換えると法線が不自然 28
変形後の頂点 頂点の位置のみ書き換えると法線が不自然 変形後の頂点から法線を生成し直す必要 29
変形後の頂点 頂点の位置のみ書き換えると法線が不自然 変形後の頂点から法線を生成し直す必要 30
法線再計算アルゴリズム 1. 三角形ポリゴンの各頂点P,A,Bの位置を読み込み 2. ベクトルPA, PBを算出 3. 外積PA × PBを算出 P A B 31
法線再計算アルゴリズム 4. 頂点Pの隣接ポリゴンすべてで同様に外積を算出 5. 4の結果の総和を正規化したベクトルが 頂点Pの法線 P A B 32
法線再計算もコンピュートシェーダで ThreadGroup 0 ThreadGroup 1 ・・・ ThreadGroup N P A B 33
法線再計算もコンピュートシェーダで ThreadGroup 0 ThreadGroup 1 ・・・ ThreadGroup N P A B 34
法線再計算もコンピュートシェーダで ThreadGroup 0 ThreadGroup 1 Group Shared Memory Group Shared Memory ThreadGroup N ・・・ Group Shared Memory Group Shared Memory • スレッドグループ内のスレッドから アクセスできる共有メモリ • 高速にアクセス可能 P A B 35
法線再計算もコンピュートシェーダで ThreadGroup 0 ThreadGroup 1 Group Shared Memory Group Shared Memory ThreadGroup N ・・・ Group Shared Memory InterlockedAdd Group Shared Memory • スレッドグループ内のスレッドから アクセスできる共有メモリ • 高速にアクセス可能 P Interlocked関数 • アトミック性 • 処理の途中に他スレッドの 処理を割り込みさせない A B 36
法線再計算もコンピュートシェーダで ThreadGroup 0 ThreadGroup 1 Group Shared Memory Group Shared Memory ThreadGroup N ・・・ Group Shared Memory InterlockedAdd 最大1024スレッド P A B 37
法線再計算もコンピュートシェーダで InterlockedAdd VRAM Group Shared Memory ・・・ Group Shared Memory Group Shared Memory InterlockedAdd 最大1024スレッド P A B 38
ブレンドシェイプあり ブレンドシェイプなし 39
ブレンドシェイプあり ブレンドシェイプなし 40
InterlockedAdd • Interlocked関数はuint型(32bit)しか扱えない • 法線は[-1,1]の浮動小数点数 • 浮動小数点数をスケーリングして整数に groupshared uint3 sharedPosiNormal[MaxVertexNumPerGroup]; groupshared uint3 sharedNegaNormal[MaxVertexNumPerGroup]; const float DataScale = 1023.f; // 法線の表現に10bit(=最大1023)を使用 float3 threadNormal; // 1つの三角形ポリゴンの法線 uint3 n; // 整数で加算するための中間変数 n.x = abs(threadNormal.x)* DataScale; // y,z成分についても同様 if(threadNormal.x > 0) InterlockedAdd(sharedPosiNormal[vertexId].x, n.x); if(threadNormal.x < 0) InterlockedAdd(sharedNegaNormal[vertexId].x, n.x); 41
InterlockedAdd
• 正数と負数に16bitずつ割り当て
• 10bitの分解能があれば見た目に差がわからない
• 1つの頂点に対して2^(16-10)=64個まで安全に加算
• 1回のInterlockedAddで正負両方の加算
groupshared uint3 sharedNormal[MaxVertexNumPerGroup];
const float DataScale = 1023.f;
// 法線の表現に10bit(=最大1023)を使用
// 正の値を下位16bit 負の値を上位16bitに格納
uint shift = threadNormal.x > 0 ? 0 : 16;
n.x = abs(threadNormal.x)* DataScale << shift;
InterlockedAdd(sharedNormal[vertexId].x, n.x);
42
Shared Memoryを使用した高速化 VRAM(位置や法線などの頂点情報) ・・・ Load P 43
Shared Memoryを使用した高速化 VRAM(位置や法線などの頂点情報) Load Group Shared Memory Group Shared Memory ・・・ Group Shared Memory Load P 44
GPU処理速度 • 計測環境: PlayStation®4 • 顔: 10,455頂点、480ターゲット • 歯: 5,235頂点、2ターゲット 処理時間 ブレンドシェイプ計算 法線再計算 計 0.189 0.051 0.24 (ミリ秒) 45
ブレンドシェイプの使用メモリ削減 • 10,000頂点のターゲット形状が480個ある場合 頂点位置(Float型) × 要素数(3) × 頂点数(10,000) × ターゲット数(480) = 57.6MB 46
ブレンドシェイプの使用メモリ削減 • ターゲット形状の位置ではなく、 ベース形状との差分ベクトルをアセットに保存 • 計算時はベース形状との差分を使用するため • 必要な値域のみ保存することで、 分解能が少なくても見た目に差が出にくくなる 𝑁 𝐒′ = 𝐒 + 𝑟𝑖 𝐓𝑖 − 𝐒 𝑖=0 アセットに保存 ベクトルの表現型 必要なメモリ量 Float型x3 12Byte×頂点数 Half型x3 6Byte×頂点数 1/2 Byte型(11bit11bit10bit) 4Byte×頂点数 値域は別途保存(Float型) +12Byte×2個 1/3 47
さらなる工夫 • 非同期コンピュート • グラフィックス処理の裏でCSを処理 • CSの計算はメッシュのグラフィックス処理が始まるまでに 終了していれば良い • DirectX 12世代から。コンソール機でも使用可能 • DirectX 12における最適化事例については… 13:30~14:20 バイオハザード RE:2とデビルメイクライ5のDirectX 12最適化手法 (AMD様のスポンサーセッション) 48
大量に破壊して派手に見せるには… ゲームプレイ中に 固定アニメーションを 大量に再生したい 49
大量破壊表現 50
スキニングアルゴリズム • スケルトン • ボーン • ジョイント ←頂点の変形に関わる • メッシュの各頂点が 特定のジョイントに関連付け • 各ジョイントの変換行列を使い 頂点を変形 51
スキニングアルゴリズム • 大量破壊では破片ごとにジョイントを設定 • 数十~数百個 • 各ジョイントの変形は独立 コンピュートシェーダの利用 52
大量破壊にもコンピュートシェーダ ThreadGroup • 1スレッドは1ジョイン トの変換行列を算出 • CSでは変換行列を 書き換えるのみ • マテリアルは通常の 背景と同じものを使用 53
カリングへの対応 54
バウンディングボックスの算出 • アニメーションはあらかじめ決まっているので バウンディングボックスを手動で設定することも 可能だが、膨大な種類のアセットがあるので大変 コンピュートシェーダの利用 55
CSを利用したバウンディングボックス算出 ThreadGroup InterlockedMin InterlockedMax Group Shared Memory 個々のJointに対するBBは アセットを作成した時点で求まる Joint0 のBB Joint1 のBB Joint2 のBB 56
CPU処理速度比較 • 計測環境: PlayStation®4 • CPU処理時間はジョイント数が増えると大幅に増加 • GPU処理時間はジョイント数にほとんど依存しない GPUスキニング シーン中の設置数 1フレームの処理時間 (CPU) 1フレームの処理時間 (GPU) CPUスキニング シーン中の設置数 ジョイント数 1 10 1 10 24 4.991 5.085 5.471 5.616 255 4.916 5.524 5.867 7.721 24 3.206 3.260 3.195 3.243 255 3.212 3.270 3.205 3.273 (ミリ秒) +2.1ms 57
58
アニメーションアセットの使用メモリ削減 • スキニング表現にも膨大メモリが必要 • ジョイント数が241個、641フレームのアニメーション ( 移動ベクトル(Float3型) + 回転クォータニオン(Float4型) ) × ジョイント数(254) × フレーム数(641) = 約4.5MB • さらにゲーム中に登場する種類も豊富 59
アニメーションアセットの使用メモリ削減 • ブレンドシェイプアセットと同様にHalfやByte利用 • 単位クォータニオンとしてw成分を省略して3要素へ • 3要素にすることで1要素あたり10bitのByte表現 • フレームの間引きも有効 ( 移動ベクトル(Byte型) + 回転クォータニオン(Byte型) ) × ジョイント数(254) × フレーム数(321) = 0.65MB 60
まとめ • CSで高速にアニメーション計算 • ブレンドシェイプ、大量スキニング • 法線再計算やバウンディングボックスの算出も • Group Shared Memoryは高速アクセス可能 • Interlocked関数 • VRAMへのアクセスが必要になるときもある • 使用メモリの削減も考慮する必要あり 61