[Unity] GPUスケルトンアニメーションレンダリングパフォーマンス、チートアニメーションバッチレンダリング、武器マウントサポート

GPU スケルトン アニメーションのビデオ紹介:

GPU頂点アニメーションとGPUスケルタルアニメーションの実装原理、長所と短所の比較、パフォーマンスの最適化

数千人で同じ画面を実現するにはGPUアニメーションが必須です GPU頂点アニメーションの実装方法は以前の記事で紹介しています: 【Unity】レンダリングパフォーマンス攻略 GPUアニメーション、アニメーションレンダリングバッチ GPU Instance_skinmeshrenderバッチ - CSDN Blog

GPU 頂点アニメーションの長所と短所:

GPU 頂点アニメーションは、アニメーションの各フレームのメッシュの頂点/法線をテクスチャに保存し、シェーダーで頂点/法線を直接読み込んで使用します。

メリット:余分な計算がないのでパフォーマンスが高い。

欠点: モデルに複数の SkinnedMeshRenderer がある場合、最初にメッシュをマージする必要があります。生成されるアニメーション/法線マップは大きくなります。搭載された武器の切り替えはサポートされていません。

GPU スケルタル アニメーションの長所と短所:

GPU スケルタル アニメーションは、アニメーションの各フレーム内のすべてのボーンのマトリックス情報をテクスチャに保存します。各頂点は最大 4 つのボーンの影響を受けます。シェーダーでは、これら 4 つのボーンのマトリックスと、4 つのボーンに対応するスキン ウェイトが使用されます。位置と法線を変換して、ボーンの影響を受ける頂点/法線の値を取得します。

利点: アニメーション化されたテクスチャは非常に小さい; メッシュをマージする必要がない; 搭載武器の切り替えをサポート; 特定のアタッチメント ポイントの位置をリアルタイムで取得できる

短所: ある程度の計算が必要なため、頂点アニメーションよりもパフォーマンスが若干低くなります。

GPU スケルトン アニメーションの実装:
1. スケルトンデータを読み込み、アニメーションマップ、メッシュを生成

 1. スキン アニメーションのボーン情報を取得します。

ルート ボーンは、SkinnedMeshRenderer の rootBone を通じて、または SkinnedMeshRenderer に関連付けられたすべてのボーンの Transform 配列であるボーン フィールドを直接使用して見つけることができます。

2. アニメーション カーブから各アニメーション フレームに記録されたボーンのトランスフォーム値を取得します。

例として、アニメーションの各フレームのボーン位置を取得します。

private Vector3 GetBonePositionAtTime(string bonePath, AnimationClip clip, float animTime)
{
    var localPosXCurve = EditorCurveBinding.FloatCurve(bonePath, typeof(Transform), "m_LocalPosition.x");
    var localPosYCurve = EditorCurveBinding.FloatCurve(bonePath, typeof(Transform), "m_LocalPosition.y");
    var localPosZCurve = EditorCurveBinding.FloatCurve(bonePath, typeof(Transform), "m_LocalPosition.z");

    Vector3 pos = Vector3.zero;
    pos.x = AnimationUtility.GetEditorCurve(clip, localPosXCurve).Evaluate(animTime);
    pos.y = AnimationUtility.GetEditorCurve(clip, localPosYCurve).Evaluate(animTime);
    pos.z = AnimationUtility.GetEditorCurve(clip, localPosZCurve).Evaluate(animTime);
    return pos;
}

3. ボーン マトリックスをアニメーション マップに書き込みます。

ボーンの数をオフセットとして、行列の最初の 3 行の値をアニメーション マップにそれぞれ書き込みます。

for (int boneIdx = 0; boneIdx < bones.Length; boneIdx++)
                {
                    var bone = bones[boneIdx];
                    bool noBone = bone.GetComponent<MeshRenderer>() != null;
                    if (!noBone && bone.TryGetComponent<SkinnedMeshRenderer>(out var sMeshRender) && sMeshRender.rootBone == null)
                    {
                        noBone = true;
                    }
                    var boneMatrix = bone.localToWorldMatrix;
                    if (!noBone)
                    {
                        boneMatrix *= bonesW2LMatrices[boneIdx];
                    }

                    animBoneTex.SetPixel(boneIdx, curFrameIndex, boneMatrix.GetRow(0));
                    animBoneTex.SetPixel(bonesCount + boneIdx, curFrameIndex, boneMatrix.GetRow(1));
                    animBoneTex.SetPixel(bonesCount * 2 + boneIdx, curFrameIndex, boneMatrix.GetRow(2));
                }

4. 各アニメーションの開始フレーム/終了フレーム、アニメーションの長さ、およびアニメーションがループで再生されるかどうかに関する情報を、アニメーション マップのピクセルの最後の列に書き込みます。 

生成されたスケルトンアニメーションマップ

 5. メッシュグリッドを生成します。

ボーン情報のアニメーション マップでは、シェーダーで対応するボーン情報を取得して頂点と法線を変換できるように、どのボーンが各頂点の影響を受けるかを知る必要もあります。

リソースを節約し、読み取りを容易にするために、頂点に関連付けられた 4 つのボーンと各ボーンのウェイトをメッシュの UV2 チャネルと UV3 チャネルにそれぞれ直接接続できます。

 2. GPU スケルトン アニメーション シェーダーの実装:

 1. アニメーション マップから現在のアニメーションの開始/終了フレームを解析し、ループされているかどうかに基づいて現在のアニメーション フレームを計算します。

 2. 現在のフレームをアニメーション マップ サンプリングの V 座標として使用し、すべてのボーン マトリックスの各行の値をサンプリングして取得し、ボーン マトリックスを構築して頂点/法線を計算します。

3. カスタム関数を通じて変換された頂点座標と法線を取得し、GPU スケルタル アニメーション シェーダーに適用します。

 これで GPU スケルタル アニメーション機能が完成しました。アニメーションを切り替えるときに、アニメーション Index と現在時刻 Time.time を渡すと、アニメーション クリップは自動的に開始フレームから再生を開始し、アニメーションがループするかどうかを完全にサポートします。ボーンにマウントされた武器の場合、MeshRenderer と SkinnedMeshRenderer の両方が完全にサポートされます。これは、マウントされた武器のノード Transform 自体もボーンとしてアニメーション マップに書き込まれ、Shader がボーンの Local2WorldMatrix を通じて頂点を自動的に変換するためです。武器は自然に骨と一緒に動きます。

3. 吊り下げ点の位置を取得する 

たとえば、GPU アニメーション キャラクターは手に銃を持っています。弾丸を発射するとき、銃口に弾丸を作成して発射する必要があります。GPU アニメーションにはボーン トランスフォームがなくなったため、その位置を取得する方法銃口は?

GPU アニメーションは純粋な Shader 実装であるため、アニメーションの切り替えにはマテリアルの ClipId プロパティを変更するだけで済みます。ここで、x はアニメーション インデックス、y はアニメーション再生の開始時間 (Time.time) です。

アニメーション インデックスと再生開始時刻を使用すると、現在のアニメーションの再生時間を取得できます。再生時間に基づいて、アニメーションがどのフレームで再生されたかを計算できます。どのフレームを通じて、任意のアニメーションのマトリックスを読み取ることができます。アニメーション マップからボーンを取得するため、いつでもマウント ポイントの位置、回転、スケーリングを高パフォーマンスで取得できます。

おすすめ

転載: blog.csdn.net/final5788/article/details/135219200