Engine & platform

バージョン管理に重点を置いたシーンとプレハブのオーサリング方法

ADRIAN WOODS / UNITY TECHNOLOGIESContributor
Jul 15, 2024|16 分
UnityシーンとPrefabsのバージョン管理
このウェブページは、お客様の便宜のために機械翻訳されたものです。翻訳されたコンテンツの正確性や信頼性は保証いたしかねます。翻訳されたコンテンツの正確性について疑問をお持ちの場合は、ウェブページの公式な英語版をご覧ください。
Unityでコンテンツを作成するためのベストプラクティス(バージョン管理を中心に)

このガイドの目的は、バージョン管理で動作するUnityでコンテンツをオーサリングするためのベストプラクティスを提供することです。バージョン管理の使用に関する詳細については、Unityのブログ「Take on version control for stronger collaboration」や、より詳細な「Best practices for version controle-book」をご覧ください。これらのリソースはどちらもバージョン管理で作業するための良い一般的な情報を含んでいますが、このブログの焦点は、コンテンツがバージョン管理とどのように統合されるか、そして多くのクリエイターが同じ、または隣接するコンテンツで同時に作業している場合にマージの衝突をどのように避けるかにあります。

メタファイル

ネット上では、.metaファイルとバージョン管理について多くの混乱がある。.metaファイルは常に バージョンコントロールにチェックされるべきです。アセット間のすべての参照をつなぐファイルGUIDなど、重要な情報が含まれています。これらはソースファイルと同期していなければならない(名前も場所も、関連するソースファイルと常に一致していなければならない)。この目的のために特別なツールが作られているか、.metaファイルの機能を完全に理解している場合を除き、Unityエディタ以外でアセットファイルを移動したり名前を変更したりしないでください。

デフォルトのバージョン管理.metaファイルのモードは、可視ファイル(Visible Files)で、ディスク上の.metaファイルを隠すのではなく、オペレーティングシステムに表示します。Perforceを使用している場合は、Perforceモードを選択します。

スマートマージ

Unityとバージョン管理で作業するとき、どのチームも最初にすべきことは、スマート・マージ(Smart Merge)を設定することだ。デフォルトでは、UnityはYAMLファイルをテキストとして保存します。アセット・シリアライゼーション・モードをバイナリに変更すると、バージョン管理によってこれらのファイルをマージする機能がなくなります。

UnityのYAMLファイルはテキストベースなので、多くのバージョン管理マージソフトウェアはテキストもしくはコーディングルールを使ってマージしようとします。Smart MergeはYAML構造を考慮してマージするようにUnityによって構築されています。すべての YAML ファイルのデフォルトのマージツールとして Smart Merge の使用を強制することを推奨します。

Smart Merge はマージ競合による作業ロスを大幅に削減しますが、作業ロスの可能性を許容できないチームでは、ファイルロックを使用し、YAML ファイルのマージ競合を手動で解決することを推奨します。


ファイルロック

ファイルロックは、複数のコンテンツクリエイターが同じバイナリファイル(またはYAMLファイル)で同時に作業する可能性がある大規模なスタジオでは一般的なプラクティスです。Unityのバージョン管理はロックされたファイルを誰かがチェックアウトするのを防ぎます。Perforceはロックされたファイルを誰も投稿できないようにします。

Gitでは、ファイル・ロックをサポートするためにGit LFSを初期化する必要がある。大きなコンテンツファイルを持ち、バージョン管理にGitを使っているプロジェクトには、Git LFSを使うことをお勧めします。

優れたガイドラインとツール

成功するチームには、命名規則、フォルダ構造、アセットの配置場所、アセットの編集方法に関する厳格なガイドラインがあることが多い。チームごとに異なるため、普遍的なガイドラインは存在しない。自分のチームに合ったシステムを選び、それが機能する限りそれを続けることが最も重要だ。

具体的で厳格なガイドラインは、コンテンツを検証するツールの開発をよりシンプルにする。これにより、バグがゲームに入り込む前に防ぐことができる。アセットの位置と命名が明確であれば、コードとツールによるコンテンツの検証ははるかに容易になる。アセットポストプロセッシングと プリセットを使って、Unityのインポート基準をより簡単に適用できます。

懸念の分離

コンテンツを構築する際には、懸念事項の分離原則を活用することが重要だ。コンテンツをどのように分割し、どこに置くべきかを考えることで、プロジェクトをクリーンな状態に保ち、ほとんどのコンテンツ制作者がマージのコンフリクトに陥るのを防ぐことができる。また、個々の機能が特定のサブシーンやPrefabsに存在する場合、発見しやすく、機能のエキスパートにオンボードするのに役立ちます。コンテンツをファイルに分けるために使用できる主なビルディングブロックは、シーンプレハブ、サブグラフです。

ボスルームのキャラクターにおける懸念の分離。
ボスルームのシーンにおける懸念の分離。
シーン

シーンはUnityアプリケーションのマクロ構成要素です。各シーンはファイルにシリアライズ(保存)されるため、ソース管理や同時編集に適した方法でコンテンツを整理することができる。Additive Scene Loadingは、非常に大きなシーンや、ストリーミングコンテンツ、あるいは複数のコンポーネントを持つ非常にシンプルなシーンの作成に効果的に使用されます。

一般的に、シーンに依存するデータはシーンに保存することをお勧めします。例えば、ベイクド・ライティングの場合、ライト、ライトマップ、環境設定はすべて、どのシーンにあるかに依存する。それ以外のほとんどのものはプレハブに収納できる。シーンが小さく、そのシーン内でしか編集されない特定のコンテンツがある場合、そのデータをすべて1つのシーンに保存することは理にかなっているかもしれない。ただし、シーン内に2つのGameObjectがある場合、片方のオブジェクトを変更すると、シーンファイルも変更されることに注意しましょう。

Smart Mergeは、2人のコンテンツ制作者がシーン内の2つの異なるオブジェクトを同時に変更するシナリオを処理することができますが、より精巧な変更は、解決できないコンフリクトを引き起こす可能性があります。この問題を軽減するために、プレハブを利用することをお勧めします。

明示的なシーン構造に関しては、Unity Netcode Demoに、シンプルなプロジェクトの標準的なシーンレイアウトの有用なフローチャートがあり、多くのシナリオで見てきたものと似ている。


プレハブ

プレハブは、モジュール化された独立したコンテンツを構築するために使用できる。詳しくは、プレハブとネストされたプレハブについてのチュートリアルをご覧ください。そのチュートリアルの中で最も重要なセクションは、ベストプラクティスのセクションである。プレハブを使ってコンテンツを作ることについて、明確なルールはない。各チームは、自分たちのプロジェクトに基づいて、自分たちに最適な方法を決めなければならない。しかし、守るべきガイドラインはいくつかある:

  • プレハブは、あなたの家、あるいはプロジェクトの積み木だと思ってください。一般的に、家の基礎を表すプレハブの根元がある。その中に、家の残りの部分を構成する再利用可能な各コンポーネントのプレハブがある。窓辺のような粒状のものから、窓のある壁のような広いものまである。必要な粒度のレベルは、コンテンツ制作者がどのようにプレハブを編集したいかによって異なります。
  • プレハブは入れ子にできる。つまり、上記の例では、家のプレハブがあり、家を構成する壁、屋根、窓、ドアのプレハブがあるかもしれない。プレハブの入れ子で注意すべき重要な点は、階層が深くなればなるほど、プロジェクトにパフォーマンスの問題が発生する可能性が高くなるということだ。通常、プレハブの階層は5~7レベル以下にすることをお勧めします。
  • プレハブを入れ子にする場合、プレハブモードで編集するのが一般的です。これにより、プレハブのプロパティやオーバーライドが適切な場所に設定されていることが保証される。シーンビューでPrefabのプロパティを編集すると、間違ったPrefabやシーン自体にオーバーライドされてしまうことがあります。これは意図しない結果をもたらし、マージの衝突を引き起こす可能性がある。時々、親Prefabの子Prefabプロパティをオーバーライドする必要があります。これは標準的なワークフローですが、適切なプレハブやシーンで変更を加え、オーバーライドを適用するように注意することが重要です。
  • Prefabに含まれる全てのものは、Prefabがロードされインスタンス化された時に、実行時にメモリにロードされインスタンス化されます。つまり、ビジュアルエフェクトや常に存在しない付属オブジェクトがプレハブの中にある場合、それらのオブジェクトはメモリにインスタンス化されます。Prefabをインスタンス化するたびに、その中にあるすべてのものがインスタンス化されるため、メモリの肥大化を招く可能性がある。オブジェクトに視覚効果やモデルが付随している場合は、プーリング・システムと、実行時にそれらのコンポーネントを追加するアタッチメント・マネージャーを用意したほうがよい。プーリング・システムにあるものは、一般的にプレハブの中に入れるべきではない。
  • すべてがプレハブである必要はない。より小さなビルディングブロックは、Prefabやシーン内のGameObjectになります。オブジェクトがシーンやPrefabに固有のものであれば、そのためのPrefabを作成する必要はありません。
  • プレハブのバリエーションは慎重に使用すべきである。一般的に、プレハブのバリアントの最も良い使い方は、オブジェクトのコアとなるビルディングブロックが同一で、単純な違いしかない場合です。例えば、機能は同じだがビジュアルが異なるゲームコンポーネントにPrefabのバリアントを使うと便利かもしれない。このシナリオでは、コアの機能を変更すると、Prefabとそのバリアントの両方の機能に影響を与えますが、ビジュアルはオーバーライドされたままになります。ルートPrefabへの変更がオーバーライドされたPrefabに意図しない影響を与える可能性があるので、複雑すぎるPrefabのバリアントを作ることに注意してください。一般的な経験則として、キャラクターバリエーションシステムやその他の複雑なビジュアルスキニングシステムのようなものは、システムが非常に単純でない限り、プレハブバリエーションをベースにすべきではありません。

Prefabsやシーンの中で、何をPrefabsにし、何をGameObjectにするかを決めるために、一貫した戦略を立てることをお勧めします。


FBXとプレハブ

FBXファイルから直接Prefabを作成する場合、モデルPrefabと呼ばれる特殊なPrefabが作成されます。結果は、FBXファイルのPrefabバリアントです。追加や変更はPrefabファイルにオーバーライドとして保存されます。しかし、ほとんどのデータはFBXファイルに保存されているため、プレハブの変更や追加はモデルのプレハブには適用できません。Prefab バリアントモデルのワークフローを使用する場合、構造的な変更を最小限に抑えることが重要です。

モデル・プレハブに変更を適用することはできません。

FBXモデルとプレハブの間の結合をより密にしない構造を可能にする2つの代替ワークフローがある:

FBXファイルをシーンに直接追加し、シーン内のGameObjectにコンポーネントや構造変更を追加する。このシナリオでは、すべての変更がシーンファイルに保存されます。これは、同じシーンで多くの人がこのワークフローを使用している場合、マージの競合を引き起こす可能性があります。このワークフローを推奨するのは、変更をシーンに反映させる必要があり、コンフリクトが問題にならない場合のみです。

分解モデルから標準的なUnity Prefabを作成する。この方法では、FBXモデルをシーンにドラッグしてから、完全に解凍します。これはプレハブの作成に使われる。この方法は、FBXファイルをプレハブから完全に切り離す。これは、FBXファイルとPrefabの間に非常に緩やかな結合が必要な場合に便利です。元のFBXファイルに加えられた構造的な変更は継承されなくなります。結合は、メッシュ、マテリアル、アニメーションの名前の間だけになる。それ以外はすべてプレハブファイル自体にある。これは、FBXモデルのまったくユニークなバリアントを作成するのに便利です。例えば、2つのキャラクターが同じモデルを使用しているが、全く異なるメッシュ、マテリアル、あるいは異なる階層が必要な場合、この方法は、余分なメモリとディスクスペースを消費する複数のFBXファイルを作成するよりも良いかもしれません。この方法で注意すべき点は、元のFBXファイルでメッシュやマテリアルの名前が変更された場合、オブジェクトは消えずに、代わりに、欠落したメッシュやマテリアルを参照することです。これは、非常に複雑なコンポーネントのセットアップが必要な場合に便利である。GameObjectが消えてすべてのコンポーネントが失われるのではなく、オブジェクトが残っていて、コンポーネントを新しいオブジェクトに転送したり、名前を変更したメッシュやマテリアルを、消えたメッシュやマテリアルを参照しているGameObjectに戻すことができます。

下の2つの画像では、FBXファイルに変更を加え、再インポートしています。ボールのUnityロゴの周りの円は削除された。メインスタンドの名称を変更。メインボールの素材が黒から緑に変更され、スタンドロゴの上に新しい親玉が導入され、モデルよりも高くなるように変形が施されている。


前

これはすべて、FBXファイルとモデルPrefabの両方で密接に一致している。非モデルのプレハブでは、元の階層、名前、素材はそのままです。削除されたメッシュは行方不明のメッシュになりましたが、GameObjectはまだ存在しています。リネームされたメッシュは、もうモデルに存在しないメッシュ名を参照しているため、表示されません。GameObjectはまだ元の素材を参照しているため、変更された素材は更新されない。さらに、階層の変更は尊重されず、親が変更されていないため、メッシュは同じ場所にとどまる。

その後

下のビフォー・アフター画像では、上記の変更結果がシーン階層に表示されている。シーンで直接参照されるFBXファイルと標準モデルのPrefabは、元のFBXファイルに加えられた変更に反応します。解凍されたPrefabは元の階層を保持し、削除や名前の変更には反応しない。

ビフォー・アフター

あるシナリオにおいて、どの方法論を用いるかを慎重に決定することが重要である。エディターとFBXファイルの間に緊密な結合が必要な場合は、標準モデルのPrefabが最適でしょう。非常にゆるいカップリングが必要な場合(たとえば、メッシュやマテリアルが頻繁に入れ替わるような、非常に柔軟なキャラクタシステムなど)は、FBXファイルのコンポーネントへのソフトリファレンスを持つ、モデル以外のPrefabsを作成する方がうまくいきます。

サブグラフ

シェーダー・グラフや ビジュアル・エフェクト・グラフのようなグラフ・ツールの場合、シェーダー・グラフ・サブグラフや ビジュアル・エフェクト・グラフ・サブグラフを使用して、再利用可能な機能ノードを作成することができます。これによって、ユーザーはプレハブやシーンと同じような方法で関心事を分けることができる。私たちは、最も理にかなっている部分グラフを利用することによって、再利用性の戦略を立てることを推奨する。

サブグラフの例
深い階層を避ける

深い階層を避けることは、Scene、Prefabs、GameObject、Animation、UIなど、あらゆるコンテンツに共通することです。一般的に、どのような種類のものであれ、深い階層はパフォーマンスの問題を引き起こす傾向がある。キャラクタのアニメーション階層が深いと、CPUのパフォーマンス上の問題から、画面に描画できるキャラクタの数が少なくなる。このため、パフォーマンスを向上させるために、すべてのアニメーション階層をシーンのルートノードに配置することをお勧めします。UGUIと Canvasを使用するときにフラットな階層を選択すると、カスケードレイアウトの更新が少なくなるため、パフォーマンスが向上します。深くネストされたPrefabsはパフォーマンスの問題を引き起こし、オーバーライドを注意深く管理しないと混乱を招く。

ソース・コンテンツ

ソース・コンテンツをネットワーク・ドライブからローカル・マシンまで、さまざまな場所に保存しているチームをよく見かける。重要なソース・コンテンツはすべて、何らかの方法でバージョン管理することをお勧めする。

最も一般的な方法は、バージョン・コントロールのAssetsフォルダ以外のフォルダにソース・コンテンツを置くことです。これは、Unityがソースファイルからコンテンツを直接インポートしようとしないことを保証します。Maya、3ds Max、Blender、Photoshopのファイルは、assetsフォルダのどこかに配置されていれば、モデルやテクスチャに自動的にインポートされます。ユニティはこれをサポートしていますが、私たちはこのやり方を推奨していません。さらに、アセットを比較的簡単に追跡できるように、ソースディレクトリをAssetsディレクトリのコンテンツにミラーリングすることをお勧めします。

ソース・コンテンツは、ユーザーにとってマスキング可能であるべきだ。ほとんどのユーザーはすべてを必要としないだろうし、ソース・コンテンツはディスク上で非常に大きくなる可能性があるからだ(テラバイトを考えてほしい)。バージョン管理ソフトウェアによっては、コンテンツ・マスクの作成はかなり簡単だ。Unityのバージョン管理では、これはクロークされたファイルで実現される。Perforce では、クライアントからコンテンツを隠すためにViews を使用します。しかし、Gitはこのように動くようには設計されていません。このため、ソース・コンテンツ用に別の Git リポジトリを作成するか、コンテンツの種類ごとに別のリポジトリを作成することをお勧めします(例えば、3D アーティストはオーディオ・ソースを完全に同期する必要はないかもしれませんし、その逆も同様です)。

バージョン管理と連動し、同じ分野で働く複数のユーザーをサポートするコンテンツを作るのは難しい仕事だ。しかし、Unityは、解決不可能なマージの衝突や作業の損失を招くことのない大規模なコンテンツを作成するために、注意深く考え、計画的に使用することができるビルディングブロックを提供します。