ボーンの数と骨格階層のアート規範

今回の主な話題：ボーンの数と骨格階層のアート規範、最適化前のすべてのボーンの名前を取得する方法、パッケージ化時にコードからSVNバージョン番号を取得する方法、Gitの2つの分かれたPrefabの衝突問題の回避または解決する方法、今でもETC1形式を使用する必要がありますか？

---
###FBX
Q1：質問したいのですが、ボーンの数と骨格階層は本当にパフォーマンスに大きな影響を与えますか（ある文章がそう言っています）？簡単なテストの結果、影響はそれほど大きくないことがわかりました。

面が3,000のキャラクターに対して、100のボーン、7つのレイヤーは妥当な指標ですか？ まだたくさんの浪費がありますか？
>問題主のテスト方法は分かりません。GPU skinがデフォルトでオンになっていないか、特別な処理方法が使用されている場合、この部分は主にCPUのパフォーマンスに影響します。したがって、より科学的な方法は、ボーンの数が異なる状況でCPUのアニメーションモジュールの時間コストを統計して判断できます。
たとえば、ターゲットシーンにn人のキャラクターがいる場合、60本のボーンと100本のボーンに従ってn人のキャラクターを置いて、時間のかかる違いを比較します。
>
そして、100本のボーンが最大化ボーンであるかどうか、またはすべてのキャラクターのスキニングに参与するボーンの数が100本であるかどうかによって、ここのパフォーマンスが異なる可能性があります。私も簡単なテストを行いました。最終的にAnimator.Updateのパフォーマンスを影響するのは、スキニングに参加するボーンの数です。最大化ボーン方案を採用すれば、最大化ボーンの数を特に制限する必要はありませんが、各キャラクターがスキニングに参加するボーンの数を制限する必要があります。
たとえば、PCでアニメーションに関するモジュールのパフォーマンス消費の比較は次のとおりです。
>
100人のキャラクター、300本のボーンがすべてスキニングに参与します。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/49064693-09b8-7a3a-dae3-f6310656991f.png)
100人のキャラクター、300本のボーンがありますが、スキニングに参与するのはそのうちの60本だけです。（更新：確認しました、Unityがエクスポートするときに、スキニングに参与しないボーンはエクスポートしなくなります。ここの300本のボーンの概念はMaxにのみ存在し、Unityではもう60本に最適化されました。）
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/52a54e42-80f4-5c09-c895-c786cbc8a250.png)
100人のキャラクター、60本のボーンはすべてスキニングに参与します。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/496acfb7-279a-4fd7-d1dc-cc3e15abfa38.png)
もちろん、これではパフォーマンスの違いのみをテストします、より現実的なデータがターゲットモデルで実行必要があります。
>
また、骨格階層の深すぎは良くないかもしれません。しかし、GameObject最適化オプションがオンになっていると仮定すると、7層と10層のパフォーマンスに大きな違いはないと思います。この部分にはあまり知っていませんが、ただアニメーション計算の過程から推測します。レイヤーごとに計算する場合、通常、エンジンが子ノードで直接使用するために変換行列をルートノードに格納します。ですから、ここでの余分なコストはあまり多くないです。ただし、これにはいくつかのテストが必要であり、Unityのソースコードを読んでいませんから確定できません。
>
単純にパフォーマンスから規範を考えると、成立されたばかりのプロジェクトに対して、100本のボーンと7レイヤーはOKって感じます。3000面は少し保守的で、具体的にはゲームタイプによって異なります。もちろん、ボーンの数もゲームタイプに応じて判断する必要があります。例えば、アクションゲームではより多くのボーンが必要になる場合があります。
>
PS：テストデータは人型モードを使用します。
>
PPS：この実験についてもう一度説明します。＠xin さんと相談した後、この実験はあまり意味がないことがわかりました。
>
以前の自社開発エンジンでは、モデルをエクスポートした後、スキニングに参加しなかったボーンもモデルにエクスポートされていたため、アニメーションを更新する際に、スキニングに参与しないボーンを削除するために一つの最適化操作があります。この実験を通じて私が最初に検証したかったのは、Unityがそのような最適化を行うかどうかであり（より基本的であるため、行われると思います）、結果もそのようです。しかし、Unityはエクスポート部分ですでにそのような最適化を行っていることがわかりました。つまり、Maxにボーンが300本ある場合にも、60本のみがスキニングに参与し、Unity内にインポートされるのは60本のボーンだけです。
この意味は、前に述べた最大化ボーン数に対する制限にあります。以前のボーン数の制限は、最大化ボーンのレイヤーにありますが、今から見ると最終モデルのボーン数のレイヤーにあるはずです。

---
###FBX
Q2: アニメーションシステムでOptimize Game Objectオプションをオンにすると、不要なボーンが消えます。私たちがボーンの下に多くの特殊効果の吊り下げポイントをぶら下げました。Extra Transforms to Exposeでぶら下げポイントを公開できで、後にエディターツールを使用してバッチ処理を行えることもよくわかります。

現在、問題が発生し、アーティストは１つの公開された吊り下げポイントを追加したいです。実際に、一部のFBXにはこのような吊り下げポイントがありません。ツールで処理する時にFBXにこの吊り下げポイントがアあるかどうかを検出したいです。存在しない場合、増加しません。前に処理する時にFBXのOptimize Game Objectオプションをチェックしましたから、LoadAssetの後で最適化する前のすべてのボーンポイント名を取得できませんでした。何かFBXのすべてのボーンポイント名を取得する方法はありますか？

①
>
ModelImporter.transformPathsを使用して、FBXの下のすべてのノードパスを取得できます。

②
>
ModelImporter以外に、Avatarを解析することもできます。
>
```ruby:
public static bool HasSkeleton(this GameObject gameObject, string skeletonName)
{
    Avatar avatar = gameObject.GetComponentInChildren<Animator>(true).avatar;
    SerializedObject serializedObject = new SerializedObject(avatar);
    var property = serializedObject.FindProperty("m_TOS");
    for (int i = 0; i < property.arraySize; i++)
    {
        string fullSkeletonPath = property.GetArrayElementAtIndex(i).FindPropertyRelative("second").stringValue;
        if (fullSkeletonPath.EndsWith(skeletonName))
            return true;
    }
    return false;
}
```

---
###Script
Q3: パッケージ化するときに、プロジェクトのSVNバージョン番号を取得したいのですが、どうすればいいですか？

①
>
コマンドラインのSVN infoを使用して、戻り値からバージョン番号を抽出します。

②
>
CIでパッケージ化をします。
>
```ruby:
svn log -v -r BASE:HEAD $unity_project_path
SvnVersion=`svn info | grep "Last Changed Rev" | tr -d "Last Changed Rev: "`
echo "SvnVersion:"$SvnVersion
```
Unityを起動し、パラメーターをインポートします。
>
```ruby:
$unity_path -batchmode -projectPath $unity_project_path -executeMethod BuildUi.BuildFromCI SvnVersion-$SvnVersion
```
C＃取得
>
```ruby:
public static string SvnVersion
        {
            get
            {
                //SvnVersion-$1
                foreach (string arg in System.Environment.GetCommandLineArgs())
                {
                    if (arg.StartsWith("SvnVersion"))
                    {
                        return arg.Split("-"[0])[1];
                    }
                }
                return "";
            }
        }
```

---
###バージョン管理
Q4: Gitの2つの分かれたPrefabの衝突問題の回避または解決する方法はありませんか？外部ネットワークバージョンが急速に更新されており、内部バージョンが数週間後にリリースする大きなバージョンを開発しております。しかし、この２つのバージョンが１つの同じPrefabに変更されており、合併が発生した場合はどうすればよいですか？問題主がGitを使っていますが、SVNで解決できますか？または、他に何か衝突を解決するツールがありませんか？（UnimergeとUnityYAMLMergeのどちらが優れていますか？）

①
>
アイデアを提供します。私たちは、Unimergeを参照してUnity間のプロセス比較および合併ツールを実現して、２つのUnityを開いて対応するPrefabを比較します。

②
>
Unity 2018.3でNested Prefab機能を提供しました。Prefabの粒度をさらに細かく分割できるため、衝突の発生する可能性を減らすことができます。

---
###Texture
Q5: 今でもETC1フォーマットを使用する必要がありますか？4〜5年前の解釈では、ローエンドデバイスはETC2をサポートしていないため、ETC1+Alpha分離を使用する必要があります。

今まで、数年前のハイエンドマシンは、ぎりぎり今のミッドエンドマシンと呼べます。あの時のローエンドマシンのほとんどは淘汰されています。iOSバージョンのゲームもデフォルトで5Sをサポートしていなく、ASTCフォーマットを使用している今に、ETC1+Alpha分離の方式でテクスチャフォーマットを設定することはまだ必要がありますか？デフォルトのETC2はETC1+Alphaの方式に比べて、メモリも仕様も節約し、効果もより良いです。
>国内向けのゲームであれば、チェスやカードゲームでない限り（またはローエンドの携帯電話向けの特別なサポート要件がある限り）、ETC2はAndroid端末で直接使用できます。
>
ただし、ベトナム、タイ、インドなどの海外市場向けの場合は、慎重に検討する必要があります。多くのチームからのフィードバックによると、海外の多くの地域にはまだ低品質の設備が残ってあります。この場合、設備の占有率を運用チームと検討することをお勧めします。

---
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、**パフォーマンス分析**と**最適化ソリューション**及び**コンサルティングサービス**を提供している会社でございます。

UWA公式サイト：https://jp.uwa4d.com
UWA公式ブログ：https://blog.jp.uwa4d.com