GPU Skinningで指定されたボーンを回転させる

1）GPU Skinningで指定されたボーンを回転させる
2）UGUIキャンバスの再構築と動静分離について
3）フラッシュバックがないようにゲームメモリのピーク値を設定する方法
4）UsePassを使用してKeywordが見つからないという問題に遭遇する
5）Unity Shader Built-inでのマクロの定義

---
 

##Rendering

Q：GPU Skinningを使用するオブジェクトの場合、キャラクターに面する必要がある頭と同様に、指定されたボーンを回転させる方法は？現在のアイデアは、Matrixとボーン番号を渡し、それをShaderで処理することですが、計算はすべて0ポイントです。同じく実現されたプロジェクトを逆コンパイルし、ボーン位置float3とボーン回転float4の変数を渡しました（この名前を参照してください）。
 
>A：実現のアイデアは、ボーンマトリクスの計算中にLookAtの回転をNeck BoneとそのChild Boneに適用することです（ボーンMatrixの計算がオフラインで事前に計算されるのではなく、Shaderでも実現されている場合 、Child Boneを考慮しません）。
問題主のGPU Skinningがどのように実現されているかわかりませんが、簡単なテストを行うために、例としてchengkehan / GPU Skinningのオープンソースライブラリを取り上げました。
ボールの回転マトリクスをShaderに渡します。

>![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/c8135951-a955-2add-7895-a1694559ef20.png)

>事前に計算されたボーンマトリクスをサンプリングする時に、Neckのボーンの下にあるすべてのボーンノードの計算に回転を適用します（boneindex> 21）（PS：マトリクスには可換法則がないため、子ボーンノードの計算には問題があります。自分で処理してください。）
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/084a64d0-5562-dc96-4563-e906e21fbd3f.png)


>効果は次のとおりです。

>![3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/7f4af938-133a-83e0-e26e-34e2389a3df5.gif)

 
##UGUI

**Q：UGUIキャンバスの再構築と動静分離に関して、UI要素のサイズと位置の変更がキャンバスメッシュの再構築の問題を引き起こさないと確認しました。**
 
**UI要素のサイズと位置がリファクタリングを引き起こすというUWAの回答をたくさん見ましたが、UGUIの調査の結果、そうではないことがわかりました。以下に示すように、UGUIによって再描画される要素はCanvasUpdateRegistryクラスにあります。**


**反射によってメッシュの再描画リストをプリントした後、位置、サイズ、および回転は再構築リストに入力されないことがわかりますが、Anchors、Pivot、およびコンポーネントのColorと幅と高さの変更により、メッシュの再構築が発生します。それはどういうことでしょうか。**
 
>A1：OnRectTransformDimensionsChange関数、VertexHelperクラスのコード、位置とRectサイズなどを確認できます。これらの変更はsetDirtyになります。
VertexHelperのいくつかのListは、実際には対応するマテリアルプロパティと頂点位置プロパティです。これらの変更がsetdirtyになるのは当然ですが、RectTransformの一部のプロパティの観点からは、UnityはPivot、SizeDelta、AnchorMin、AnchorMaxという4つのプロパティが変更された場合のみにSetdirtyは発生します。
 

>---

 
>A2：以下に示すように、A1に従って検証を行い、Imageから継承するMyImageを記述してから、OnRectTransformDimensionsChangeをOverrideします。


>シーンでMyImageを使用すると、Anchorの位置またはRectの幅と高さを変更すると、OnRectTransformDimensionsChange（このメッセージはNativeレイヤーから返送されます）がトリガーされ、これをトリガーするとSetVerticesDirtyがトリガーされることを確認できます。PositionとScaleを変更してもSetVerticesDirtyはトリガーされず、色を変更するとSetMaterialDirtyがトリガーされます。これらの2つのタイプのSetDirtyは、対応する要素をGraphicRebuildQueueに追加し、最後の時間消費はCanvas.SendWillRenderCanvasesでカウントされます。この部分の「リファクタリング」は、メッシュの再構築を指すものではなく、UI要素自体の更新として理解できます。
別の種類のメッシュ再構築は、UIの変更によって引き起こされるCanvasの再構築を指します。つまり、メッシュステッチはNativeレイヤーで実行され、Canvas.BuildBatchの呼び出しがトリガーされます。

>---

 
>A3：メッシュの再構築（Canvas.BuildBatch）はNativeレイヤーで行われ、内部のコンテンツはRiderでは表示できません。Positionを変更すると、再構築がトリガーされます。これは、Unityの公式ドキュメントに明確に記載されています。
 
##Memory

**Q：メモリが異なるAndroidとApple（1G、2G、3G、4G …）で、フラッシュバックが発生しないように、ゲームメモリのピーク値はどれくらいにしたら良いでしょうか？**
 
>A1：このリンクにはiOSのメモリピークが更新し続けられ、さらにピーク値をテストするためのツールを投稿されました：
https://stackoverflow.com/questions/5887248/ios-app-maximum-memory-budget
 
>---


>A2：このリンクにはテストデータが提供してくれました。みやすくために、それを転送しました。
device: (crash amount/total amount/percentage of total)
iPad1: 127MB/256MB/49%
iPad2: 275MB/512MB/53%
iPad3: 645MB/1024MB/62%
iPad4: 585MB/1024MB/57% (iOS 8.1)
iPad Mini 1st Generation: 297MB/512MB/58%
iPad Mini retina: 696MB/1024MB/68% (iOS 7.1)
iPad Air: 697MB/1024MB/68%
iPad Air 2: 1383MB/2048MB/68% (iOS 10.2.1)
iPad Pro 9.7″: 1395MB/1971MB/71% (iOS 10.0.2 (14A456))
iPad Pro 10.5”: 3057/4000/76% (iOS 11 beta4)
iPad Pro 12.9” (2015): 3058/3999/76% (iOS 11.2.1)
iPad Pro 12.9” (2017): 3057/3974/77% (iOS 11 beta4)
iPad Pro 11.0” (2018): 2858/3769/76% (iOS 12.1)
iPad Pro 12.9” (2018, 1TB): 4598/5650/81% (iOS 12.1)
iPad 10.2: 1844/2998/62% (iOS 13.2.3)
iPod touch 4th gen: 130MB/256MB/51% (iOS 6.1.1)
iPod touch 5th gen: 286MB/512MB/56% (iOS 7.0)
iPhone4: 325MB/512MB/63%
iPhone4s: 286MB/512MB/56%
iPhone5: 645MB/1024MB/62%
iPhone5s: 646MB/1024MB/63%
iPhone6: 645MB/1024MB/62% (iOS 8.x)
iPhone6+: 645MB/1024MB/62% (iOS 8.x)
iPhone6s: 1396MB/2048MB/68% (iOS 9.2)
iPhone6s+: 1392MB/2048MB/68% (iOS 10.2.1)
iPhoneSE: 1395MB/2048MB/69% (iOS 9.3)
iPhone7: 1395/2048MB/68% (iOS 10.2)
iPhone7+: 2040MB/3072MB/66% (iOS 10.2.1)
iPhone8: 1364/1990MB/70% (iOS 12.1)
iPhone X: 1392/2785/50% (iOS 11.2.1)
iPhone XS: 2040/3754/54% (iOS 12.1)
iPhone XS Max: 2039/3735/55% (iOS 12.1)
iPhone XR: 1792/2813/63% (iOS 12.1)
iPhone 11: 2068/3844/54% (iOS 13.1.3)
iPhone 11 Pro Max: 2067/3740/55% (iOS 13.2.3)
また、もっとマクロのまとめがここをクリックして確認できます。具体的には以下の通りになります。
device RAM: percent range to crash
256MB: 49% – 51%
512MB: 53% – 63%
1024MB: 57% – 68%
2048MB: 68% – 69%
3072MB: 63% – 66%
4096MB: 77%
6144MB: 81%
Special cases:
iPhone X (3072MB): 50%
iPhone XS/XS Max (4096MB): 55%
iPhone XR (3072MB): 63%
iPhone 11/11 Pro Max (4096MB): 54% – 55%
 
##Shader

**Q：Shaderコードを共有するため、複数のPassを単独のShader Aに記述し、Shader BでUsePassキーワードを異なるSubShaderに組み合わせます。**
 
**PCには問題はありませんが、AssetBundleをパッケージ化した後、その中のKeywordが欠落していることがわかりました。 ShaderVariantCollectionを介してバリアントを収集し、そこに必要なKeywordが含まれていることを確認しました。コードがUsePassなしで直接記述されている場合、Keywordは失われません。**
 
**この方法でKeywordを含むShaderコードを共有することはできませんか？**
 
>A1：AssetBundleメソッドを使用する過程で、最初に共有Shader Aをロードせず、Shader BとSVCのみをロードしたため、Shaderの解析時に共有Shader AのPass情報が欠落していたと思います。すべてのShaderアセットがあるので、PCには問題はありませんでした。

>---

 
>A2：このURL（https://forum.unity.com/threads/keywords-and-usepass.324180/） で同じような質問を見つけましたが、UsePass後のPass名を大文字にする必要があると回答しました。

>---

  
>A3：参照Shaderを解析し、バリアントリストに従って参照Shaderのバリアントリストを解析し、S​​VCに追加する必要があります。
 
>---

 
>A4：テスト（exeテストにパッケージ化）後、SVCファイルとシェーダーがAssetBundleにパッケージ化されている場合、UsePassを使用するとキーワード損失の問題が発生しないことがわかりました。 SVCとシェーダーを別々にパッケージ化すると、UsePassを使用しなくても、キーワードが失われるという問題が発生します。
 
 
##Shader

**Q：Unity ShaderのUNITY_FAST_COHERENT_DYNAMIC_BRANCHINGマクロはどういう意味ですか？このマクロはいつtrueになりますか？**
 
>A：HLSLSupport.cgincで定義されています：

>```
#if (SHADER_TARGET < 30) || defined(SHADER_API_GLES3) || defined(SHADER_API_GLES) || defined(SHADER_API_N3DS)
    //no fast coherent dynamic branching on these hardware
#else
    #define UNITY_FAST_COHERENT_DYNAMIC_BRANCHING 1
#endif
```


>たとえば、次のコードでは、これらの条件付き判断により、ifがfalseの場合にUNITY_BRANCHを使用してコードをスキップするかどうかも決定されます。


>```
half UnityDeferredSampleRealtimeShadow(half fade, float3 vec, float2 uv)
{
    half shadowAttenuation = 1.0f;
    #if defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE)
        #if defined(SHADOWS_SCREEN)
            shadowAttenuation = tex2D(_ShadowMapTexture, uv).r;
        #endif
    #endif
    ++
**
#if defined(UNITY_FAST_COHERENT_DYNAMIC_BRANCHING) && defined(SHADOWS_SOFT) && !defined(LIGHTMAP_SHADOW_MIXING)
    //avoid expensive shadows fetches in the distance where coherency will be good
    UNITY_BRANCH
    if (fade < (1.0f - 1e-2f))
    {
    #endif
**
++
        #if defined(SPOT)
            #if defined(SHADOWS_DEPTH)
                float4 shadowCoord = mul(unity_WorldToShadow[0], float4(vec, 1));
                shadowAttenuation = UnitySampleShadowmap(shadowCoord);
            #endif
        #endif
        #if defined (POINT) || defined (POINT_COOKIE)
            #if defined(SHADOWS_CUBE)
                shadowAttenuation = UnitySampleShadowmap(vec);
            #endif
        #endif
    #if defined(UNITY_FAST_COHERENT_DYNAMIC_BRANCHING) && defined(SHADOWS_SOFT) && !defined(LIGHTMAP_SHADOW_MIXING)
    }
    #endif
    return shadowAttenuation;
}

---

UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、**パフォーマンス分析**と**最適化ソリューション**及び**コンサルティングサービス**を提供している会社でございます。

今なら、UWA GOTローカルツールが**15日間に無償試用**できます！！
よければ、ぜひ！

UWA公式サイト：https://jp.uwa4d.com
UWA GOT OnlineレポートDemo：https://jp.uwa4d.com/u/got/demo.html
UWA公式ブログ：https://blog.jp.uwa4d.com