パージのプロセス

3、パージのプロセス

パージと参照マーカーは個別に実行できます。通常、パージはフレームごとにインクリメントして実行されます。

IncrementalPurgeGarbage(bool bUseTimeLimit、float TimeLimit)を呼び出して、2つのパラメーターを受け入れ、ガベージパージを行います。

  • bUseTimeLimit:パージの時間制限があるかどうか
  • TimeLimit:メソッドの1回の実行の時間制限

この2つのパラメーターを使用してインクリメンタルクリーニングまたはフルクリーニングを選択的に実行できます。

最初に、UnhashUnreachableObjectsメソッドが呼び出され、RF_BeginDestroyedが設定されていないすべての到達不能なUObjectに対してBeginDestroyメソッドが呼び出され、UObjectが破棄されることを通知して、UObjectが非同期パージ操作を実行できるようにします。カスタム操作を実行するために、BeginDestroyメソッドを上書き処理できます。

その後、GCロックを取得できます。

パージするオブジェクトをトラバースし、それらのオブジェクトのFinishDestroyメソッドを呼び出します。ただし、オブジェクトがBeginDestroyを終了していない可能性があります。レンダリングスレッドが使い果たされるのを待機しているグラフィックアセットなど、非同期操作があるため、これらのオブジェクトはすぐにFinishDestroyを呼び出すことはできません。代わりに、まずGGCObjectsPendingDestruction配列に配置した後に処理します。トラバーサルプロセス中に、経過時間がチェックされます。制限時間に達すると、途中で停止し、現在の進行状況を記録してから、パージプロセスを終了します。

パージするすべてのオブジェクトをトラバースした場合、つまり、それらに対してFinishDestroyメソッドを呼び出すことを試みた場合は、GGCObjectsPendingDestruction配列を再度トラバースし、FinishDestroyの実行を再試行します。このGGCObjectsPendingDestructionのトラバーサルが完了したら、TimeLimitを使用するかどうかを確認する必要があります。 TimeLimitを使用すると、次のロジックが直接実行され、GGCObjectsPendingDestruction内のオブジェクトが次回処理されます。使用しない場合は、この場所でブロックされ、それらのUObjectがBeginDestroyの実行を終了することを強制的に待機し、主にレンダリングスレッドを待機します。GGCObjectsPendingDestruction内のすべてのオブジェクトがFinishDestroyを実行した後、次のパージ操作が実行されます。

次は、実際のパージプロセスです。これは主に、パージされるオブジェクトをトラバースし、UObjectのデストラクタを実行し、メモリスペースを解放します。この手順では、リリースがTimeLimitを超えていることも確認し、超過分は次のフレームで引き続きパージされます。


 

3.1 UObjectへのポインタがどのようにNULLに更新されるか

これは、拡張された質問です。UobjectのDestroy()関数の呼び出しを表示して、UObjectが次のガベージコレクションでリサイクルされるようにすることができますが、UObjectのUPropertyポインター、またはコンテナー内のポインターはどうなりますか。ダングリングポインタということが引き起こされるか?答えはノーです。UE4を使用した後、UPropertyポインターが有効かどうかを判断するには、それが空かどうかを判断するだけでよいことがわかります。これにより、C++の開発に非常に便利です。オブジェクトが破棄されると、UE4はオブジェクトを指すUPropertyポインターを自動的にNullに更新します。UPropertyではないポインターは更新されず、ダングリングポインターの問題が発生します。 UE4の公式ドキュメントに詳細な説明(Automatic Updating of References)があります。

3.2ポインターの自動更新の実現原理

到達可能性分析フェーズでは、各オブジェクトのtokenstreamを解析して、現在のオブジェクトによって参照されている他のオブジェクトを見つけます。他のオブジェクトがPendingKillとしてマークされている場合、そのオブジェクトへのポインターはNULLに設定されます。したがって、ポインタの更新プロセスでは、最初に破棄するオブジェクトへのすべてのポインタをNULLに設定し、次にオブジェクトを破棄して、ダングリングポインタの問題が発生しないようにします。


 

UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式QAコミュニティ(中国語注意)https://answer.uwa4d.com

UE4GCプロセス

2、UE4GCプロセス

エントリは、UObjectGlobals.hで定義されているCollectGarbage()関数であり、次のようになります。

 

void CollectGarbage(EObjectFlags KeepFlags, bool bPerformFullPurge)
{
	// No other thread may be performing UObject operations while we're running
	AcquireGCLock();

	// Perform actual garbage collection
	CollectGarbageInternal(KeepFlags, bPerformFullPurge);

	// Other threads are free to use UObjects
	ReleaseGCLock();
}

このプロセスは、GCロックの取得、CollectGarbageInternalの実行、およびGCロックの解放の3つの部分で構成されています。


 

2.1GCロックの取得

GCはマルチスレッドであるため、GCロックを設定する必要があります。他のスレッドでUObject関連の操作が実行されると、GCと競合します。これを防ぐために、GCロックが設定されています。この設定は主に非同期ロードプロセスを保護するために使用されます。

1つの機能は、オブジェクトがロードされると、格納された変数には参照を追加する時間がなく、到達不能なガベージコレクションとして扱われることを防ぐということです。次のコードで、FGCScopeGuardはGC操作を防ぐ役割を果たします。

2.1.1FGCSyncObject

GCロックは広い概念です。実際、これはFGCSyncObjectのシングルトンクラスであり、ロックと同期のために複数の変数をカプセル化します。GCの実行中に他のnon-gameスレッドをブロックするために使用することも、non-gameスレッドが重要な操作を実行する時にGCスレッドをブロックするために使用することもできます。もちろん、すべてのケースがブロックされるわけではありません。GCロックをすぐに取得できない場合、各スレッドは特定のロジックに従って他のことを実行することもできます。

主なメンバー変数は次のとおりです。

FThreadSafeCounterAsyncCounter:スレッドセーフカウンターです。スレッドがキーAsync操作を実行する時に、この値を増減させることに使用されています。

FThreadSafeCounter GCCounter:GCロックとして使用されます。0でない場合は、スレッドがGCロックを取得し、GCの実行中であることを意味します。

GCFThreadSafeCounter GCWantsToRunCounter:このカウンターは、スレッドがGCを実行しようとしているが、GCロックがまだ取得されていないことを示します。Asyncスレッドは自動・強制というロジックがありません。この変数へのサポートを手動で実装する必要があります。FCriticalSectionCritical:スレッドがGC関連の操作を実行する重要エリアを保護し、他のユーザーの入りを防ぎます。

FEvent *GCUnlockedEvent:スレッドのsignalと類似し、non-gameスレッドにGCが実行中のevent、実行できるWait()、Trigger()を知らせます。

基本的にGCロックを理解した後、GCロックの取得プロセスを紹介しましょう:


 

2.2CollectGarbageInternalを実行する

CollectGarbageInternalを実行し、ガベージコレクションを実行し、マークを付けてパージします。

この関数は、KeepFlags、bPerformFullPurgeの2つのパラメーターを受け入れます。KeepFlagsは、このようにマックされたobjectが、参照されているかどうかに関係なく保留されることを意味します。bPerformFullPurgeは、フレームごとに段階的にパージするのではなく、マーキング後に完全なパージを実行するかどうかを示します。

実行プロセスは次のとおりです。

いくつかの注意点があります。

(1)このプロセスはスキャンオブジェクトの到達可能性操作を確実に実行します。黄色の四角い枠の部分は特定のプロセスを示し、後で分析します。状況に応じてパージ操作を行いますが、必要がある限りオブジェクトのパージを行い、しかも完全にパージします。それ以外の場合は、World tickでインクリメンタルパージを行います。

(2)UE4はマルチスレッド環境で実行され、GCはすべてのUObjectで操作するため、ロックの使用に注意してください。

(3)GC自体をマルチスレッド化して、マーキングプロセスを高速化できます。

2.2.1プロセスをマークする

FRealtimeGCのPerformReachabilityAnalysisメソッドを使用して、uobject到達可能性分析を実行します。FRealTimeGCはFGarbageCollectionTracerを継承します。マルチスレッドおよびリアルタイムでオブジェクト参照関係を分析できます。

キーコードは次のとおりです。

 

// Make sure GC referencer object is checked for references to other objects even if it resides in permanent object pool
if (FPlatformProperties::RequiresCookedData() && FGCObject::GGCObjectReferencer && GUObjectArray.IsDisregardForGC(FGCObject::GGCObjectReferencer))
{
    ObjectsToSerialize.Add(FGCObject::GGCObjectReferencer);
}

{
    const double StartTime = FPlatformTime::Seconds();
    MarkObjectsAsUnreachable(ObjectsToSerialize, KeepFlags, bForceSingleThreaded);
    UE_LOG(LogGarbage, Verbose, TEXT("%f ms for Mark Phase (%d Objects To Serialize"), (FPlatformTime::Seconds() - StartTime) * 1000, ObjectsToSerialize.Num());
}

{
    const double StartTime = FPlatformTime::Seconds();
    PerformReachabilityAnalysisOnObjects(ArrayStruct, bForceSingleThreaded);
    UE_LOG(LogGarbage, Verbose, TEXT("%f ms for Reachability Analysis"), (FPlatformTime::Seconds() - StartTime) * 1000);
}

ここでは、FGCArrayStructタイプのデータ構造ArrayStructを使用して、シリアル化ためのuobjectのarrayとweak referenceを格納します。

第一歩として、FGCObject :: GGCObjectReferencerをObjectsToSerializeに追加できます。

FGCObject :: GGCObjectReferencerは、非UObjectオブジェクトでAddReferencedObjectsメソッドを呼び出すために使用できる静的UGCObjectReferencerです。

第二歩は、MarkObjectsAsUnreachableメソッドを呼び出して、KeepFlagsおよびEInternalObjectFlags :: GarbageCollectionKeepFlagsのないすべてのオブジェクトを到達不能としてマークすることです。

まず、GUObjectArrayという変数は、ObjObjects配列がすべてのUObject(FUObjectItemを通してカプセル化します)を格納するグローバルUobject allocatorです。UObjectBase :: InternalIndexプロパティは、配列内でのオブジェクトが対応するFUObjectItemの添え字であるため、添え字に従ってUObjectを検索するか、UObjectを介して対応する添え字を検索すると便利です。

GCに含まれていないobjectは、GUObjectArrayの前部に格納されるため、前のobjectはスキャンされたobjectリストから削除され、後者のobjectのみを考慮し、MaxNumberOfObjectsが取得られます。GCで考慮されない特定のオブジェクトについては、FUObjectArrayの実装を確認できます。

次に、これらのuobjectを到達不能としてマークする必要があります。ここでは、マルチスレッドバージョンのForループが使用されています。マルチスレッド実行の原理は複雑ではありません。まず、現在利用可能なワーカースレッドを取得し、次にマークするobjectをこれらのスレッドに均等に分散してトラバーサルします。マルチスレッドの最下層では、UEのGraphTaskフレームワークを使用します。uobjectをマークする場合、通常の状況で対応するFUObjectItemのプロパティが読み取られ、特別な場合にのみuobjectが読み取られます。FUObjectItemは構造体であり、GUObjectArrayに密接に配置されているため、シーケンシャルトラバーサルでキャッシュに適しています。

UEはクラスター(Cluster)を使用して効率を改善し、その改善方法を以下に紹介します。objectがRootSetに属している場合は、ObjectsToSerializeListに直接追加します。objectがClusterRootまたはClusterに属している場合は、KeepClusterRefsListリストにも追加します。ObjectのClusterRootIndex<=0(ClusterまたはClusterRootにない)の場合は、KeepFlagsがあるかどうかに応じて、到達不能としてマークするかどうかを判断します。マークしない場合は、objectをObjectsToSerializeListに追加し、さらにClusterRootの場合はKeepClusterRefsListに追加します。マークする場合は、objectをClustersToDissolveListに追加し、しかもObjectItemにUnreachableマークを設定します。いくつかの追加処理がClusterで実行されます。詳しくは、コードを参照してください。

第三歩は、PerformReachabilityAnalysisOnObjectsを呼び出して、uobjectの到達可能性を判別します

ここでは、FGCReferenceProcessor、TFastReferenceCollector、およびFGCCollectorクラスが使用され、これらはすべてシングルスレッドとマルチスレッドの両方をサポートします。

まずReferenceTokenの概念を紹介します。

UObjectシステムでは、各クラスにクラスのリフレクション情報を記述するためのUClassインスタンスがあります。UPropertyを使用して各クラスのメンバー変数を記述することができますが、GCではUPropertyを直接トラバースする場合オブジェクト参照関係をスキャンすると、効率が低下します(オブジェクト以外の参照プロパティが多数あるため)。そのため、UEはReferenceTokenを作成しました。これは、クラス内のオブジェクトへの参照を記述する1セットのtokeのストリームです。次の図に、参照のタイプを示します。

 

/**
 * Enum of different supported reference type tokens.
 */
enum EGCReferenceType
{
	GCRT_None			= 0,
	GCRT_Object,
	GCRT_PersistentObject,
	GCRT_ArrayObject,
	GCRT_ArrayStruct,
	GCRT_FixedArray,
	GCRT_AddStructReferencedObjects,
	GCRT_AddReferencedObjects,
	GCRT_AddTMapReferencedObjects,
	GCRT_AddTSetReferencedObjects,
	GCRT_EndOfPointer,
	GCRT_EndOfStream,
};

2.2.2 FGCReferenceTokenStream

このクラスは、tokenstreamを作成し、tokenstreamからobject参照を解析するために使用されます。これは、GCのコアコンセプトと言えます。ReferenceTokenは、TArray <uint32>の形式で格納されます。この形式はなぜですか。ReferenceTokenの動作原理を分析してみましょう。FGCReferenceInfoこのクラスは、参照に必要な情報を記述し、unionンメンバー変数を持ちます。

 

/** Mapping to exactly one uint32 */
union
{
    /** Mapping to exactly one uint32 */
    struct
    {
        /** Return depth, e.g. 1 for last entry in an array, 2 for last entry in an array of structs of arrays, ... */
        uint32 ReturnCount	: 8;
        /** Type of reference */
        uint32 Type			: 4;
        /** Offset into struct/ object */
        uint32 Offset		: 20;
    };
    /** uint32 value of reference info, used for easy conversion to/ from uint32 for token array */
    uint32 Value;
};
  • Type:参照のタイプを表します。ここではEGCRefenceTypeOffsetです。
  • Offset:クラス内のこの参照に対応する属性のアドレスオフセットを意味しています。
  • ReturnCount:返されるネストの深さです。

UEは、これら3つの情報を巧みにuint32にエンコードするため、FGCReferenceTokenStreamはTArray<uint32>形式を通してtokensを保存します。

TokenStreamを処理するとき、まずreferencetokenを解析し、それからOffsetを介して属性を直接取得できます。これにより、処理が簡単になるだけでなく、キャッシュを効果的に使用して速度を上げることができます。 TokenStreamの特別な使用法もあります。これは、2つの連続するtokenを使用してポインター(64ビット)を格納することです。たとえば、実行時に、AddReferencedObjectsを実行することで参照オブジェクトを動的に追加でき、この関数のポインターはTokenStreamに保存されます。

2.2.3UClass :: AssembleReferenceTokenStream(bool bForce)メソッド

リアルタイムでトークンストリームを作成できます。一度実行するだけで、結果を保存してCLASS_TokenStreamAssembledを介してClassFlagsに反映し、計算の繰り返しを回避できます。TokenStreamが以前に作成されている場合は、古いものを置き換えます。

具体的なプロセスは次のとおりです。

(1)独自のUProperty(親クラスを除く)をトラバースし、UPropertyのEmitReferenceInfoメソッドを順番に呼び出します。これは仮想関数です。さまざまなUPropertyがそれを実装し、主にClass内の独自のメモリオフセット、ReferenceType情報をUClassに送信し、UClassはEmitObjectReferenceを通してこの参照情報をtokenにエンコードしてReferenceTokenStreamに追加します。異なるUProperty処理方法は非常に異なります。一般的なUObjectPropertyは処理が簡単ですがUArrayPropertyとUMapPropertyは、内部データ型もTokenStreamを生成する必要があるため、比較的に複雑です。structが検出されると、再帰も含まれます。

(2)このクラスに親クラスがある場合、親クラスのAssembleReferenceTokenStreamメソッドが再帰的に呼び出されて、親クラスのReferenceTokenStreamが生成され、親クラスのstreamが自分のstreamの前に追加されます。この手順は、UObjectBaseクラスまで続きます。UObjectBaseは特別な方法で処理されます。streamに追加されるのはClassPrivateとOuterPrivateのみです。

(3)自身のAddReferencedObjects()関数がUobject :: AddReferencedObjectsを指していない場合は、この関数ポインターに対応するtokenをTokenStreamに追加または更新したら、到達可能性分析を実行するときに呼び出すことができます。

(4) TokenStreamを追加したら、「EndOfStream」tokenをTokenStreamに追加し、tokens arrayにshrinkを実行し、アイドルなarray slackを削除します。これは、toneks配列の長さが次に固定される必要があるためです。 (5)ClassFlagsでCLASS_TokenStreamAssembledをtrueに設定します。

2.2.4 TFastReferenceCollector

CollectReferencesメソッドは、到達可能性分析に使用されます。シングルスレッドの場合、ProcessObjectArrayメソッドが直接呼び出され、uobjectのtoken streamをトラバースして、参照関係を見つけます。マルチスレッドの場合、uobjectリストは複数のスレッドに分割して処理され、各スレッドはProcessObjectArrayも呼び出します。

ProcessObjectArrayメソッドは、ObjectsToSerializeのUObjectをトラバースし、参照関係を見つけて、到達可能性を判断します。プロセスには、すべてがトラバースされるまで、ObjectsToSerializeは増加し続けることに注意してください。再帰的方法は内部で使用されますが、スタックを使用してシミュレートします。

(1) シングルスレッドであり、tokenstreamの自動生成がオンになっている場合、objectに対応するUClassにtokenstreamがない場合、UClassのAssembleReferneceTokenStreamsをリアルタイムで呼び出して、tokenstreamを作成します。

(2) 現在uobjectのtokenstreamを取得し、FGCReferenceInfoを解析して、参照されているUObjectを見つけます。

tokenのReferenceInfoはさまざまなタイプがあり、状況に応じて処理する必要があります。GCRT_ObjectやGCRT_ArrayObjectのように扱いやすくて、uobjectオブジェクトをObjectsToSerializeに追加するだけで済みます。 GCRT_ArrayStructはより厄介で、再帰的な処理が必要です。ここでの「struct」は、C ++のstruct構造体だけでなく、UEdGraphPinなどのUObjectシステムに属していない一部のclassも指します。GCRT_ArrayStructを処理するときは、最初に再帰スタックをインクリメントしてから、Array内の「Struct」を1つずつ処理する必要があります。 GCRT_AddStructReferencedObjectsは、structやFGCObjectから継承しないclassがUOBjectへの参照も追加できることを示します。UStructProperty:: EmitReferenceInfoのコードは、structpropertyが参照を追加できることも示しています。しかし、コードとコメントを見ると、UE4は将来これらの特別なstructとclassをFGCObjectから継承させ、AddReferencedObjects関数を使用して参照を追加するかもしれないと思います。 GCRT_AddReferencedObjectsは、参照を追加するためにこのオブジェクトのAddReferencedObjects関数を呼び出す必要があることを意味します。 FGCObjectを回想すると、このクラスはUObjectを継承しませんが、AddReferencedObjects関数を介してUObjectに参照を追加することもできます。同時に、この関数はUClassによってのみTokenStreamに追加できます。FGCObjectはどのように機能しますか?実際、UEにはUGCObjectを管理するための特別なUObjectインスタンスがあります。これはUGCObjectReferencerです。このクラスのAddReferencedObjects関数を見てください。

 

void UGCObjectReferencer::AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector)
{	
	UGCObjectReferencer* This = CastChecked<UGCObjectReferencer>(InThis);
	// Note we're not locking ReferencedObjectsCritical here because we guard
	// against adding new references during GC in AddObject and RemoveObject.
	// Let each registered object handle its AddReferencedObjects call
	for (FGCObject* Object : This->ReferencedObjects)
	{
		check(Object);
		Object->AddReferencedObjects(Collector);
	}
	Super::AddReferencedObjects( This, Collector );
}

このクラスのインスタンスが参照・マークの段階で収集されると、FGCObjectのAddReferencedObjectsメソッドを1つずつ呼び出してUObject参照を収集し、それによってFGCObjectをGCシステムに組み込みます。

(3) 参照されたUObjectを取得した後、通常はUObjectへの参照を追加し、ObjectsToSerialize配列に追加します。

UObjectがすでにisPendingKillとマークされている場合、それが参照されていても無視されます。

マーキングは複数のスレッドで実行できるため、2つのスレッドが同時にオブジェクトを到達可能としてマークし、ObjectsToSerialize配列に追加して参照チェックを続行することができますが、これは明らかな無駄です。したがって、オブジェクトをマークするとき、オブジェクトが現在Unreachableであるかどうかをチェックするだけでなく、Unreachableフラグをパージするには、2つのスレッドが誤って同時に設定するのを防ぐために、アトミックな「比較と置換」操作も必要です。

UObjectがCluster内にある場合は、それをReachableInClusterとしてマークし、必要に応じてそのClusterOwnerを到達可能としてマークし、後続の処理のためにObjectsToSerializeに追加します。

(4) ObjectsToSerialize配列のスキャンはラウンドごとに実行され、1ラウンドのスキャン中にスキャンされた新しいUObjectは一時的にNewObjectsToSerialize配列に格納されます。このラウンドのスキャンが完成すると、NewObjectsToSerializeにある要素の数がMinDesiredObjectsPerSubTaskというしきい値に達すると、マルチスレッドが始まります。しきい値に達していない場合、現在のスレッドで新しいラウンドの処理が続行します。

2.2.5パージするUobjectのリストを取得する

まずClusterの概念を紹介します。

複合論理オブジェクトに対し、内部Objectは親オブジェクトの状態で管理されるので、ClusterでGC管理をすることができます。Clusterは、GCプロセスで単一のユニットとして扱われ、GCを高速化できるUObjectのグループです。パーティクルシステムでは、1組のパーティクルオブジェクトはClusterとしてマークされます。Actorは、「can be in Cluster」を設定することで、自分自身をあるClusterに追加することができます。

プログラムで、Cluster はFUObjectClusterというクラスとして表示されます。 ObjectsのプロパティはCluster内のすべてのObjectsで、ReferencedClustersはこのObjectsによって参照される他のObjectsです。

 

Clusterによって参照される他のClusterルートオブジェクトがPendingKillとしてマークされている場合、他のpendingkill参照を処理するには、このCluster内のすべてのオブジェクトをObjectsToSerialize配列に追加する必要があります。同時に、Cluster間の参照関係が保証されなくなったため、Clusterは分解が必要であるとマークされます。

到達可能なオブジェクトを分析した後、分解のマークが付けられたClusterを分解する必要があります。

その後、すべてのUObjectを再度スキャンして、到達不能なすべてのオブジェクトを収集する必要があります。この操作は、複数のスレッドで並行して処理することもできます。到達不能オブジェクトの場合、それらがCluster内にない場合、それらはGUnreachableObjects配列に直接追加されます。 ClusterRootの場合は、含まれているすべてのObjectsを分析する必要があります。ObjectにClusterの外部からの参照がない場合も、到達不能であるため、GUnreachableObjects配列に追加する必要があります。これまでのところ、GUnreachableObjects配列のUObjectは、このスキャンから得たパージする必要があるオブジェクトです。


 

2.3 GCロックを解放する

GCロックを削除し、他のスレッドがUObjectを使用できるようにします。解放プロセスは取得プロセスよりもはるかに簡単です。

(1)GCUnlockedEvent-> Trigger()を呼び出して、このeventを待機しているスレッドをウェイクアップします。

(2)GCCounterがデクリメントされます GC状態を終了します。


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式QAコミュニティ(中国語注意)https://answer.uwa4d.com

UE4GCの概要

1、UE4GCの概要

UE4には、一連のUObjectオブジェクトシステムが構築され、ガベージコレクションメカニズムも追加されました。これにより、ゲーム開発にC ++を使用しやすくなり、ゲーム自体でメモリリークの問題を大幅に回避できます。

UE4は、従来のガベージコレクション方式である「マーク・パージ」というガベージコレクション方式を採用しています。ガベージコレクションは2つの段階に分かれています。第一段階はあるルートコレクションから始まり、到達可能なすべてのオブジェクトをトラバースします。トラバースが完了すると、到達可能なオブジェクトと到達不可能なオブジェクトにマークを付けることができます。このステージは1フレームで完了します。第2段階では、これらの到達不能なオブジェクトを徐々にパージします。到達不能なオブジェクトにはアクセスできないため、一度に多くのUObjectがパージされ(例えば、mapがアンロードされると、明らかなフリーズが発生します。)ないように、フレーム内でパージできます。

GCはゲームスレッドで発生し、UObjectをパージし、マルチスレッドGCをサポートします。

ゲーム内で最大のUObjectオブジェクトを指定するMaxObjectsInGameなど、いくつかのパラメーターをGCに設定できます(エディターでは有効になりません)。モバイルプラットフォームのデフォルト設定は131072です。UObjectの数がこのしきい値を超えると、ゲームがクラッシュします。その他の詳細なパラメーター関連するプロパティは、UGarbageCollectionSettings、GarbageCollection.cpp、およびUnrealEngine.cppで確認できます。

次の図は、マークパージの動作原理を示しています。


 

1.1GCの開始時期:

UE4のGCは、アクティブトリガーと自動トリガーの2つの方法に分けることができます。

1.1.1アクティブトリガー

ある操作を実行する同時に手動で呼び出せます。例えば、アセットをアンロードするとすぐにGCを呼び出してパージすることができます。

そして、多くの方法があります。例えば、ゲームはForceGarbageCollectionを呼び出して、Worldに次のtickでガベージコレクションを実行させることができます。また、CollectGarbageを直接呼び出すこともできます。エンジンのほとんどの状況は、この方法でアクティブにトリガーされます。

1.1.2自動トリガー

ゲームでは、ほとんどのガベージコレクション操作はUE4によって自動的にトリガーされます。通常の状況では、手動でGCを呼び出す必要はありません。これは、GCを使用するための理想的な方法でもあります。

World tickが発生すると、UEngine::ConditionalCollectGarbage()関数が呼び出され、関数でいくつかの判断が行われます。GC条件が満たされると、GCが実行されます。ConditionalCollectGarbageの実行ロジックを分析してみましょう。


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式QAコミュニティ(中国語注意)https://answer.uwa4d.com

sRGBのテクスチャチェックに関する疑問

1)sRGBのテクスチャチェックに関する疑問

2)ライティングをオンにすると、メッシュ数が増える

3)UGUI Imageの材質属性を修正する質問

4)UniWebViewインターフェイスがUnityインターフェイスの後に表示されるのはどすればよいのか

5)TimelineのInternal_CreatePlayableはコストが高い


 

Rendering

Q:UWAある回答を見つけました(中国語注意)

https://answer.uwa4d.com/question/5bd1724fae74300ab0497bed

結論は次のとおりです。

linear space + gamma texturesRGBを選択します

linear space + no gamma texturesRGBを選択しませんhttps://answer.uwa4d.com/question/5bd1724fae74300ab0497bed

Gamma Spaceでは、sRGBを選択することは何の影響もないようですが。

 

Player Settingのcolor space設定標識によってインポートされた画像が、Gamma Spaceで作成されたのかLinear Spaceで作成されたのかについて、ドキュメントでは明確ではありません。もう少し説明してくれませんか

 

ここでのディスカッションによると:https://forum.unity.com/threads/confusion-about-gamma-vs-linear.496053、sRGBが選択されている場合、Unityはgamma逆補正を行います。つまり、tex2Dからのvalueはbe pow(origin_color_value、2.2)、ここでgamma値は2.2と想定され、fragではRチャネルの値が逆補正され、heatmapのuの中央値は約0.5になります。それなら、上記のディスカッション最初のheatmapが示したようになりますが、実際には2番目のheatmapのように示しています

 

colorの代わりにcolorの値をdataとして使っているからだと言われていますが、やはり納得できません。dataでもcolorでもすべて数字であり、数字の比較には間違いがありませんから

 

A1:確かにGamma Spaceでは、sRGBを選択することは何の影響もないようですが。

Linear Spaceで、sRGBが選択されている場合、UnityはRemove Gamma Correctionをします。この場合、図の値は0.5階調値、つまりu = 0.5の列の階調値です。次の図に示すように、Remove Gamma Correctionすると、取得される値は0.25になります。

X軸は光の強度を表し、Y軸はグレー値を表します。

青い線のY値は、人間の目の階調、視覚的な階調値を表します。赤い線は、光の強度に比例する物理的な空間の実際の階調値を表します。

Photoのグラデーション図でu=0.5の列の階調値は0.5で、これは視覚的な階調値です。Remove Gamma Correctionの後、実際の階調値は0.25になります。Fragment Shaderの計算に参加します。したがって、2番目のheat mapが表示されます。

 

A2:この記事を参照できます:https://developer.nvidia.com/gpugems/gpugems3/part-iv-image-effects/chapter-24-importance-being-linear

個人的な理解です。通常の状況では、私たちが見る画像は「モニタースペース」にあり、画像自体がGammaCorrectionをした(つまり、元の値は 1 /2.2乗の操作をしました。)ため、モニターに表示される画像の色は正常です。このような画像の場合、非線形として理解できます。 Unityが線形空間を選択した後、そのような非線形画像の場合、正しくレンダリングするにはsRGBを選択する必要があります。画像のsRGBが選択されると、メモリ内の形式は、以下に示すように、ETC2_EAC_RGBA8_SRGBの形式になります(画像がETC2 8ビットの圧縮形式を選択すると仮定します)。

sRGBが選択されていない場合、以下に示すように、ETC2_RGB8_UNORM形式になります。

この_SRGBサフィックス形式の場合、GPUがテクスチャサンプリングを実行すると、GamaCorrectionが自動的に削除されます。つまり、値は2.2乗をしますが、元のデータは変更されません。Gamma空間では、sRGBが選択されているかどうかに関係なく、形式はETC2_RGB8_UNORMです。

問題主の質問について、Gamma空間では、レンダリングの結果は平均的な4色になります。これは、Gamma空間ではGammaCorrectionが削除されないためです。つまり、この「非線形画像」はu= 0.5の場合(uはテクスチャuv座標)、テクスチャのdata値= 0.5、Linear空間になるとdataは変化しません。相変わらずu = 0.5の場合に、data= 0.5になります。しかし、sRGBを選択した後、テクスチャサンプリングを実行する場合、GPUは値に対して2.2乗の操作をし、約0.25になります。したがって、u <= 0.5の場合、color.r <= 0.25になります。Shader がcolor.r <0.25を計算すると、赤になります。つまりu <= 0. 5の場合、すべて赤なので、色の半分が赤です。


 

Rendering

Q:Unityによって表示される面(メッシュ)数は、このフレームでGPUにアップロードされたすべての頂点データによって決定されるため、GPUがこの部分をキャッシュしないのはなぜですかライティングをオンにすると、面数が増えるため、モデルの頂点データを複数回アップロードすることになります。この部分をキャッシュすると、パフォーマンスが大幅に向上しませんかGPUがこのキャッシュを実行できない場合、GPUのキャッシュが小さすぎてそのようなスペースがないことを意味しますか、それともGPUがキャッシュする部分を確認できないことを意味しますかエンジンコードを変更すると、プロジェクト用にキャッシュできます。

 

A:ライト自体のシェーディングは、DrawCallと面数には影響しません。リアルタイムシャドウは、シャドウ用の深度マップをレンダリングする必要があります。これは、別の視点からレンダリングするのと同じであり、データは現在のカメラとは異なります。 FrameDebuggerを開いて、レンダリングプロセス全体を確認できます。


 

UGUI

 

Q:UGUIのImageはMaterialPropertyBlockを設定することでマテリアルプロパティを変更できますか設定方法はありますか。

 

A:UGUIはマテリアルブロックを使用しません。以下を参照してください。

https://forum.unity.com/threads/big-problem-with-locking-materialpropertyblock-for-ui-image.506941


 

UGUI

 

Q:Android側にWebページを表示するプラグインUniWebViewがあります。デフォルトでは、Unityインターフェースの上位層に表示され、Unityのすべての表示をブロックします。 Androidのネイティブインターフェイスをバックグラウンドにし、UnityのUIをフォアグラウンドにし、Unityのバックグラウンド自体を透明にする方法を教えてください。

 

A:UniWebViewをUnityインターフェイスの背後で実行できるようにするために、公式ドキュメントにはダメだと記載されています。

https://docs.uniwebview.com/guide/faq.html

Unityの背景の透明度の維持に関しては、Player Settingsに以下のようなオプションがあります。

 


 

Playable

Q:特殊効果はTimelineを使用して作成されています。最近のパフォーマンステストで、Internal_CreatePlayableメソッドには多くのコストがあることがわかりましたが、トラックが1つしかないなのに、このコストが何に関連していますか

 

 

 

同じオブジェクトをPCにロードし、Internal_CreatePlayableに18.55ミリ秒かかり、次にPCにCubeを作成してTimeline効果を追加してから、Internal_CreatePlayableに約4ミリ秒かかるようになります

 

A:Timlineの最初のCreatePlayableは時間がかかります。こちらの簡単なTimelineアセットでも、初めて500ミリ秒以上かかります。

ただし、シーンのロードにCreatePlayableステップを配置することで、ゲーム中のラグを回避できます。Timelineアセットを読み込んだ後、PlayableDirector.RebuildGraphを呼び出すと、Prewarmと同等のCreatePlayableが実行されます。その後、Play()を呼び出しても、CreatePlayableは実行されません。RebuildGraphを呼び出しても、キャッシュがあるため、高い時間コストも発生しません。

次の図は、RebuildGraphを初めて呼び出すのにかかる時間を示しています。

次の図は、RebuildGraphを2回呼び出すのにかかる時間を示しています。

 


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式QAコミュニティ(中国語注意)https://answer.uwa4d.com

【HDRと色彩管理】ゲームにおけるHDR

最後のセクションは初心に戻ります。ゲームでHDR表示の使用を紹介します。2016年以降、主要なゲームメーカーは、自社のゲームでHDR表示をサポートし始めています。初期のin FAMOUSシリーズからUE4で開発されたGears of War 5まで、市場に出回っている3Aゲームにおいて、HDR表示へのサポートは不可欠になっています。このセクションは、まずCOD共有の実現方法を確認し、そしてUE4のHDRへの実現と比較します。


 

5.1HDR in COD:WW II

 

ゲームのHDR表示は、ACESの多くの概念と実現、特にOutput Transform(RRT + ODT)の部分を適用しています。ただし、映画やテレビのプロセスと違い、ACESの概念の多くは実際には必要ありません。たとえば、ゲームは複雑なIDTを考慮する必要はあまりありません。基本的に、sRGBテクスチャの入Output Transformで十分です。 COD:WW IIも、ACESに基づいて独自のHDRカラーパイプラインに独自の調整を加えました。

 

CODの技術的な共有において、著者はHDR表示の実現目標は次のとおりであると述べました。

lHDRとSDRの視覚的な一貫性を維持すること

l新しいSDRパイプラインでは、元の古いSDRと同じ効果を得ることができること

lアーティストに迷惑を掛けないように、高品質で効率的なパフォーマンスがあること

 

5.1.1新しいカラーパイプライン

 

この目標を念頭に置いて、COD:WWIIの新しいカラーパイプラインは次のようになります。

Source: HDR in Call of Duty

CODの以前のパイプラインと比較して、新しいHDRパイプラインにはいくつかの重要な変更があります。

l後処理は、HDRとSDRの視覚的な一貫性を維持するために、元のsRGB gamma空間からHDR linear空間に移動された

l次に、露出パラメータを適用し、シーン全体の輝度をスケーリングして、Exposed HDR空間に入る。この空間は依然として線形空間であるが、同時に色変換マトリックスを使用して、色空間をsRGBからRec.2020色空間に変換する

lRec.2020線形色空間でColor Gradingを適用する

Tonemappingを適用する。 Tonemappingは現在2つの操作に分かれている。まず、固定のTone Curveを使用して統一的な画像変換(ACESのRRTに相当)を実行し、次にdisplay mappingを使用して特定の出力デバイス(ACESのODTに相当)に出力します。 )。これらの2つのステップは、ACESのOutput Transform、つまりRRT+ODTに相当します。

 

5.1.2 Tone Curve

 

ACESのRRT段階と同等で、著者は固定のTone Curveを使用して、HDRシーンの輝度をPQに対応する0〜10000nitの出力輝度範囲に再マッピングします。これは実にSカーブです。このSカーブの定義は、欲しい芸術的表示に決められます。このようなSカーブに依存すると、古いSDRでのfilmic tonemapと同様の効果を得ることができます。以下は、Tone Curveを適用する前後の写真の対照です。適用後の画面は、より「映画的」になっていることがわかります。

Source: HDR in Call of Duty

 

このSカーブを以下に示します。水平座標と垂直座標は、輝度のlog(対数)を取った後のstop値であり、その入力色空間はACEScg、つまりAP1空間です。

Source: HDR in Call of Duty

CODで使用されるこの曲線は、ネイティブACES RRTで使用されるtonescale曲線に非常に類似しています。このRR Ttonescale曲線自体は、セグメント化されたB-spine曲線によって定義されます(詳細については、ACESlib.Tonescales.ctlファイルのsegmented_spline_c5_fwd関数を参照してください)。ACESRRTの完全なワークフローを以下に示します。

ここまで、すべてのスタイルと効果の計算が行われ、シーン全体の輝度が0〜10,000ニットの範囲に再マッピングされています。これで、この出力輝度範囲内で実際に画像を出力できます。

5.1.3 Display Mapping

 

Display Mappingは、特定の出力デバイスに関連する後続の表示ロジックを引き継ぎます。これには、次の主な操作が含まれます。

l HDR Range Reduction:0〜10000 nitの輝度範囲は、市販の表示(ディスプレイ)デバイスには大きすぎるため、出力デバイスの輝度範囲を縮小するには、次の操作が必要になります。

l Color Space Transformation:色変換を使用して、色空間を出力デバイスの色空間に変換します

 

Display Mappingは、SDRとHDR表示の2つのラインに分けることができます。まず、HDR表示でのDisplay Mappingを見てみましょう。その2つの部分は次のとおりです。

lBT. 2390EETFとユーザーによる校正(キャリブレーション)でHDR Range Reductionを計算します

lPQ OETFを使用して、結果を出力デバイスの色空間に変換します

 

1つ目はHDR Range Reductionです。このステップの目的は、0〜10000ニットをユーザーのHDR表示デバイスの実際の黒点と白点の範囲にマッピングすることです。著者は、このマッピングを実現するためにBT.2390のEETF伝達関数を使用することを選択しました。BT.2390のEETFは、指定された最小および最大輝度値に従って、Hermite曲線をICtCp空間の輝度値に適用することにより、出力輝度範囲を調整できます。以下は、さまざまな最大輝度値と最小輝度値が与えられた場合の関数曲線です。

Source: HDR in Call of Duty

 

BT2390のEETF入力、最小および最大輝度値は、校正機能を表示する形でユーザーによって設定されています。 HDR白色点の設定インターフェースは次のとおりです。

 

Source: HDR in Call of Duty

 

HDR黒色点の設定は次のとおりです。

Source: HDR in Call of Duty

 

HDR Range Reductionを完了した後、最後のステップは、PQ OETFを直接使用して最終出力信号をエンコードします。

 

SDR表示でのDisplay Mappingは、もう1つのロジックです。 その2つの部分は次のとおりです。

l固定曲線を使用してSDR Range Reductionを計算します

l色変換行列を使用して色空間をBT.2020からBT.709に変換し、BT.1886 OETFを使用して最終結果を出力デバイスの色空間に変換します。

 

著者は、このマッピング曲線として、線形関数セグメント部分+指数shoulderのfalloff部分を使用します。

Source: HDR in Call of Duty

RGBチャンネルに異なる曲線のマッピングを適用することにより、色相のシフトが発生します。この問題を解決するために、著者は純粋な輝度曲線に対して同じ曲線マッピングを個別に実行して、色調の偏りのない結果を取得してから、2つの結果の間を補間します。SDRも以前と同様のユーザー校正パラメーターを使用しますが、黒色点の調整のみに用いられています。 最後に、BT.1886 OETFを使用して出力信号のエンコードを実行します。

 

COD:WW IIのこのDisplay Mappingステージは、ネイティブのACESODTステージと非常によく似ています。 ACES ODTにはRange ReductionおよびEOTFエンコード信号の適用と同等のステージもあります。ACES ODTの完全なワークフロー(例としてP3D60を取り上げます)を以下に示します。

上の図のODT tonescaleは、CODでのRange Reductionと同等ですが、その実現はCODとは異なります。このODTtonescale曲線は、セグメント化されたB-spine曲線によっても定義されます(詳細については、ACESlib.Tonescales.ctlファイルのsegmented_spline_c9_fwd関数を参照してください)。

5.1.4AAとUI

 

Temporal AAは、display mappingの後に実行されるため、AAは視覚的な線形空間で計算でき、追加の色空間変換やパラメーター調整を回避できます。

 

最後のステップは、UIをレンダリングすることです。 UIをレンダリングする方法は2つあります。

l1つは、最初にUIをoffscreen bufferにレンダリングし、次にそれを最終的な画像に合成することです。

lもう1つは、UIをbackbufferに直接レンダリングすることです。

 

COD:WW IIは2番目の方法を選択しました。ここでもSDRとHDRの2つのロジックラインに分割することもできます。

lSDR出力パスでは、ロジックは古いパイプラインと一致しています。つまり、sRGB色空間に直接混合させます。

lHDR出力パスでは、UIの輝度値が最大300 nitの範囲にスケーリングされ、色空間変換をBT. 2020色空間に変換してから、PQ曲線マッピングを適用します。

 

上記の2つのパスの結果は完全に同じではありませんが、作者にとっては十分に近いものです。さらに、Alpha Blend混合モードと比較して、Additive混合モードには、追加のfixが必要となってシェーダーの計算を増やされました。幸いに、WW IIのUIには通常の半透明の混合モードで十分です。

5.1.5 CLUT

 

実現に関しては、CODはUniversal CLUTと呼ばれるLUTを使用して、上記のパイプラインの色変換操作を完了します。これにより、パイプライン全体のパフォーマンスを大幅に向上させることができます。

Source: HDR in Call of Duty

 

このCLUT(Color LUT)の入力は、露出パラメータによってスケーリングされた線形シーンの色値であり、出力はoutput-referredの色値です。 このCLUTには、次の色彩操作が含まれています。

  • HDR Color Grading
  • HDR Tone Curve(RRT)
  • Display Mapping(ODT)

CLUTは本質的に3Dテクスチャであり、各フレーム描画の初期段階でasync compute shaderによって計算されます。著者は、log2関数を使用して、入力された露後のHDR色値をテクスチャ座標空間の0〜1の範囲に変換します。これに基づいて、この3Dテクスチャで変換された色値を検索できます。


 

5.2UE4におけるHDR

 

Talk is cheap, show me the code. CODのソースコードはありませんが、UE4があります! 次に、これまでに学んだすべての理論的知識を組み合わせて、HDR表示がUE4にどのように実現されているかを確認します。

 

一般に、UE4におけるHDRカラーパイプラインはWW IIのロジックとほぼ同じですが、一部の細部はWW IIのサポートほど良くありません。 それを段階的に見ていきましょう。

 

5.2.1 How to Use使用方法

 

UE4でHDR表示を使用するのは非常に簡単です。UE4のドキュメントには、詳しい説明があります。一般的に、次の3つのコマンドラインパラメータを使用できます。

lr.HDR.EnableHDROutput:HDR出力を有効にするかどうかを制御します。主にDXGI設定を制御して、backbufferの形式を変更し、HDR形式のbackbufferをHDR表示デバイスに送信できるようにします。

lr.HDR.Display.OutputDevice:使用する出力デバイスを制御する伝達関数。 UE4にサポートされています。

lr.HDR.Display.ColorGamut:出力デバイスの色空間として使用される色空間を制御します。

 

また、UIレンダリングに関連する2つの調整パラメーターがあります。

lr.HDR.UI.CompositeMode:UIが有効にしているかどうかを制御するHDRコンポジットモードで、SDRと同じUI視覚効果を取得しようとしています。

lr.HDR.UI.Level:UI合成のハイライト値を制御します。

 

r.HDR.EnableHDROutputコンソールパラメーターを除いて、他のパラメーターは、UE4のレンダリングロジックを制御するshaderパラメーターです。以前の開発プロセスでは、r.HDR.EnableHDROutputによってプログラムが簡単にクラッシュしたり、HDRが正常にアクティブ化されなかったりする可能性がありました。通常の状況では、r.HDR.EnableHDROutputを1に設定すると、UE4は、現在のプラットフォームでHDRを有効にしようとします。D3D12を例として、以下のようになります。

上のSetHDRTVModeおよびEnsureColorSpaceは、現在のコマンドラインパラメーターに従って対応するDXGIパラメーターを設定します。SetHDRTVMode関数は現在のr.HDR.Display.OutputDeviceおよびr.HDR.Displayのパラメータに従って、HDR metaデータに対応する色空間の三原色、白色点の値、および出力の最大および最小輝度値を設定する役割を果たします。これにより、対応するHDR metaデータが現在のHDR表示デバイスに送信されます。

EnsureColorSpace関数は、正しいbackbuffer色空間形式を設定する役割を果たします。

ユーザーが出力デバイスの最小および最大輝度値を指定できるCOD:WW IIとは異なり、UE4は現在1000または2000 nitの固定最大輝度値のみをサポートしています。つまり、UE4のODT実現はWWIIとは異なります。UE4のロジックはより簡単になります。これについては後で詳しく説明します。

 

ここまで、表示デバイスに関連するDXGI設定は完了しており、残りのロジックはレンダリングパイプラインレベルにあります。r.HDR.Display.OutputDeviceは、出力デバイスのタイプを制御します。これは、ODTステージで使用されるOETF伝達関数などのロジックに影響を与えます。 UE4は現在、合計7種類の出力デバイスをサポートしています。

このうち、r.HDR.Display.OutputDevice≥3の部分はHDR出力デバイスに対応し、残りはSDR出力デバイスに対応します。コードでも、この値でSDRロジックまたはHDRロジックが実行されているかを判定します。

r.HDR.Display.ColorGamutは、出力デバイスの色空間を制御します。これは、ODTステージで使用される色空間変換などのロジックに影響します。 UE4は現在、5種類の表示色空間をサポートしています。

 

その中で、r.HDR.Display.ColorGamut≤1の部分はSDR色空間に対応し、残りはHDR色空間に対応します。

 

これらの基本的なパラメータを理解した後、具体的なコードロジック部分を見てみましょう。

5.2.2 HDR Scene Rendering

 

この部分のロジックは一般的で、通常はsRGBテクスチャを入力して、物理の照明レンダリングを行い、シーン輝度が幅広いHDRシーン色値を取得できます。ピーク輝度は数千ニットにもなる可能性があります。次のステージに出力します。

 

この部分の色空間はsRGB線形空間です。

 

5.2.3 HDR Post Processing

 

UE4の後処理は、AAを含むHDR線形空間で計算されます。実際、UE4のAAは、DOFの直後、後処理の非常に早い段階で発生します。 以下は、PCDX11でのUE4.25のRenderdocスクリーンショットです。

 

5.2.4 Generating CLUT

 

まずは、現在フレームのCLUTを生成します。この部分のロジックは、PostProcessCombineLUTs.usfで処理されます。現在のプラットフォームに応じて、PSとCSと二つのバージョンを選択できます。このCLUTには、次の色操作が含まれています。

  • White Balance
  • HDR Color Grading
  • Output Transform(RRT + ODT)

 

(1)テクスチャ座標を線形値に変換する

 

コードは最初に、現在のLUTの座標をその位置に対応する線形シーンの色に変換します。

 

float4 CombineLUTsCommon(float2 InUV, uint InLayerIndex) 
{     
...     
// construct the neutral color from a 3d position volume texture        
float4 Neutral;
{         
float2 UV = InUV - float2(0.5f / LUTSize, 0.5f / LUTSize);          
Neutral = float4(UV * LUTSize / (LUTSize - 1), InLayerIndex / (LUTSize - 1), 0);
}     
...     
float3 LUTEncodedColor = Neutral.rgb;     
float3 LinearColor;     
// Decode texture values as ST-2084 (Dolby PQ)     
if (GetOutputDevice() >= 3)     
{         
// Since ST2084 returns linear values in nits, divide by a scale factor to convert       
// the reference nit result to be 1.0 in linear.         
// (for efficiency multiply by precomputed inverse)         
LinearColor = ST2084ToLinear(LUTEncodedColor) * LinearToNitsScaleInverse;     
}     
// Decode log values     
else         
LinearColor = LogToLin( LUTEncodedColor ) - LogToLin( 0 );

 

ここには2つのブランチが含まれます。HDR出力ロジックに対応するOutputDevice(つまり、r.HDR.Display.OutputDevice)> = 3の場合、前の記事で説明したST 2084/PQ伝達関数を使用して0〜1の範囲は、0〜100ニットの変換に再マッピングされます。スケーリングにはLinearToNitsScaleInverse値が使用されることに注意してください。これは、PQ伝達関数は入力信号1を10000 nitにマッピングできるため、PQエンコーディングのLUTスペースをより有効に活用するためのものです。それに、露出スケーリング後のシーンの輝度値を大幅に越しました。つまり、シーンの最大輝度値が約100 nitの場合、LUT全体の有効なコーディング部分は50%未満しか占めないため、LUTスペースの無駄になります。UE4は、スケーリング値として100を使用することを選択したため、100nitは座標1のLUTのピクセル部分に対応します。

// Scale factor for converting pixel values to nits.  
// This value is required for PQ (ST2084) conversions, because PQ linear values are in nits.  
// The purpose is to make good use of PQ lut entries. A scale factor of 100 conveniently places  
// about half of the PQ lut indexing below 1.0, with the other half for input values over 1.0. // Also, 100nits is the expected monitor brightness for a 1.0 pixel value without a tone curve. static const float LinearToNitsScale = 100.0; static const float LinearToNitsScaleInverse = 1.0 / 100.0;

SDR出力デバイスブランチは、logを使用しエンコードします。log関数を使用して、0〜1の範囲を0からシーンの最大ピクセル値(約50)への変換に再マップします。

float3 LogToLin( float3 LogColor ) 
{     
const float LinearRange = 14;     
const float LinearGrey = 0.18;     
const float ExposureGrey = 444;      
// Using stripped down, 'pure log', formula. Parameterized by grey points and dynamic range covered.     
float3 LinearColor = exp2( ( LogColor - ExposureGrey / 1023.0 ) * LinearRange ) * LinearGrey;     
//float3 LinearColor = 2 * ( pow(10.0, ((LogColor - 0.616596 - 0.03) / 0.432699)) - 0.037584 ); // SLog     
//float3 LinearColor = ( pow( 10, ( 1023 * LogColor - 685 ) / 300) - .0108 ) / (1 - .0108); // Cineon     
//LinearColor = max( 0, LinearColor );      

return LinearColor; 
}

(2)Implement White Balance

上に変換された線形シーン値でWhite Balanceを計算します。

float4 CombineLUTsCommon(float2 InUV, uint InLayerIndex) 
{     
...     
float3 BalancedColor = WhiteBalance( LinearColor );

(3)sRGBからAP1色空間への変換

 

White Balanceを計算した後、色空間はsRGBLinearからACESAP1線形色空間に変換されます。

float4 CombineLUTsCommon(float2 InUV, uint InLayerIndex) 
{     
...     
float3 BalancedColor = WhiteBalance( LinearColor );

前回の記事で述べたことを思い出してください。AP1色空間の色域範囲はRec. 2020に非常に近く、CGおよびVFX計算に適し、得られた結果は、スペクトルレンダリングのground truth結果に近くなっています。

 

色域をsRGB空間から広色域AP1に変換しましたが、前のシーンのレンダリングはsRGB線形色空間で実行されたため、取得した色域値は常にsRGB色域の範囲内でした。ここでUE4にはtrickがあり、シーンはWide Color Spaceで計算されているように見えます。その三原色はP3とAP1の間にあり、Wide_2_AP1を使用して色変換を行い、最後にパラメーターと元のsRGB_2_AP1の変換結果を補間します。

float4 CombineLUTsCommon(float2 InUV, uint InLayerIndex) 
{     
...     // Expand bright saturated colors outside the sRGB gamut to fake wide gamut rendering.     
if (!bUseMobileTonemapper)     
{         
float  LumaAP1 = dot( ColorAP1, AP1_RGB2Y );         
float3 ChromaAP1 = ColorAP1 / LumaAP1;          

float ChromaDistSqr = dot( ChromaAP1 - 1, ChromaAP1 - 1 );         
float ExpandAmount = ( 1 - exp2( -4 * ChromaDistSqr ) ) * ( 1 - exp2( -4 * ExpandGamut * LumaAP1*LumaAP1 ) );          
// Bizarre matrix but this expands sRGB to between P3 and AP1         
// CIE 1931 chromaticities: x       y         
//              Red:        0.6965  0.3065         
//              Green:      0.245   0.718         
//              Blue:       0.1302  0.0456         
//              White:      0.3127  0.329         
const float3x3 Wide_2_XYZ_MAT =          
{             
0.5441691,  0.2395926,  0.1666943,             
0.2394656,  0.7021530,  0.0583814,             
-0.0023439,  0.0361834,  1.0552183,         
};          

const float3x3 Wide_2_AP1 = mul( XYZ_2_AP1_MAT, Wide_2_XYZ_MAT );         
const float3x3 ExpandMat = mul( Wide_2_AP1, AP1_2_sRGB );          

float3 ColorExpand = mul( ExpandMat, ColorAP1 );         
ColorAP1 = lerp( ColorAP1, ColorExpand, ExpandAmount );     
}

補間に使用されるパラメータは、後処理コンポーネントのExpand Gamutによって制御されます。デフォルトは1で

 

(4)Implement Color Grading

 

次に、AP1空間でColor Gradingを計算します。

float4 CombineLUTsCommon(float2 InUV, uint InLayerIndex) 
{     
...      
ColorAP1 = ColorCorrectAll( ColorAP1 );

UE4のColor Gradingパラメータは豊富です。一般的に、定型化された色相に関連する調整は、Color Gradingで行うことをお勧めします。 Color GradingまたはColor Correctionは、アーティストがシーンごとに照明の色相を調整する方法を提供します。UE4は、Post Process Volumeに色補正機能と同様の多数のパラメータを提供します。

 

 

これまでのところ、アーティストスタイルに関連するすべての計算と調整が完了しています。次のステップは、出力デバイスに応じてOutput Transformを計算することです。この部分では、ACESの実現ロジックを多く使用します。これは、SDRとHDRの2つのロージックパスに分けることができます。

 

(5)SDRでのOutput Transform

 

SDRでのOutput Transformは、ACESのLMT + RRT+ODT変換を使用します。 1つ目はLMTの部分です。UE4はACESLMTのBlueLightArtifact Fix部分を使用して、高輝度の青の値によって引き起こされる過飽和の問題を修正します。

float4 CombineLUTsCommon(float2 InUV, uint InLayerIndex) 
{     
...     
const float3x3 BlueCorrect =     
{         
0.9404372683, -0.0183068787, 0.0778696104,         
0.0083786969,  0.8286599939, 0.1629613092,         
0.0005471261, -0.0008833746, 1.0003362486     
};     
const float3x3 BlueCorrectInv =     
{         
1.06318,     0.0233956, -0.0865726,         
-0.0106337,   1.20632,   -0.19569,         
-0.000590887, 0.00105248, 0.999538     
};     
const float3x3 BlueCorrectAP1    = mul( AP0_2_AP1, mul( BlueCorrect,    AP1_2_AP0 ) );     
const float3x3 BlueCorrectInvAP1 = mul( AP0_2_AP1, mul( BlueCorrectInv, AP1_2_AP0 ) );      
// Blue correction     
ColorAP1 = lerp( ColorAP1, mul( BlueCorrectAP1, ColorAP1 ), BlueCorrection );
この部分は特に説明するところはありません、「標準」と言えます。補正度パラメータは、後処理コンポーネントのBlue Correction値によって制御でき、デフォルト値は0.6です。

 

次に、AP1空間でTonemappingを計算します。

float4 CombineLUTsCommon(float2 InUV, uint InLayerIndex) 
{    
...     
// Tonemapped color in the AP1 gamut     
ColorAP1 = FilmToneMap( ColorAP1 );

Tonemappingの具体的な意味は、エンジンやテクノロジーの共有によってわずかに異なることに注意してください。本質的な違いはありませんが、混乱を避けるために、もう少し説明します。 COD:WW IIの共有では、TonemappingにはTone Curve(RRT)とDisplay Mapping(ODT)の操作が含まれます。つまり、実際には2つのS曲線が含まれています。 UE4では、Tnemappingとは、RRTとODTを組み合わせた後の統合曲線マッピング部分を指します。つまり、S曲線は、Output Transformステージで直接再マッピングするために使用され、RRTステージとODTステージは厳密に区別されなくなりました。 UE4のTonemappingロジックはFilmToneMap関数で処理されます。この部分コードは比較的長く、コッピーしないようにします。要約すると、ACES RRTステージとACES SDR ODTステージの実現ロジックを組み合わせたものです。

 

UE4では、Post Process VolumeのTonemapperでこのS曲線パラメータを調整できます。これらのパラメータのデフォルト値はACESの実現と一致しているため、特別な要求がない場合は、次のパラメータをシーンやレンズごとに調整しないでください。Color Gradingパラメータを使用してすべての芸術スタイルを制御します。

最後のステップは、OETF伝達関数を適用してエンコードします。その前に、白色点の精度を確保するために、最初に前にLMTによって実行されたBlue Correction操作をオフセットし、次に色空間をsRGB色空間に再変換して、最終出力の準備をします。

float4 CombineLUTsCommon(float2 InUV, uint InLayerIndex) 
{     
...     
// Uncorrect blue to maintain white point     
ColorAP1 = lerp( ColorAP1, mul( BlueCorrectInvAP1, ColorAP1 ), BlueCorrection );   // Convert from AP1 to sRGB and clip out-of-gamut values     
float3 FilmColor = max(0, mul( AP1_2_sRGB, ColorAP1 ));

説明の便宜上、SDR出力デバイスに関連するOETF計算をまとめました。まとめて説明してみると、出力デバイスに応じて異なるOETF伝達関数を選択します。

float4 CombineLUTsCommon(float2 InUV, uint InLayerIndex) 
{     
...     
half3 OutDeviceColor = 0;     
// sRGB, user specified gamut     
if( GetOutputDevice() == 0 )     
{                
// Convert from sRGB to specified output gamut           
float3 OutputGamutColor = mul( AP1_2_Output, mul( sRGB_2_AP1, FilmColor ) );          
// Apply conversion to sRGB (this must be an exact sRGB conversion else darks are bad).         
OutDeviceColor = LinearToSrgb( OutputGamutColor );     
}     
// Rec 709, user specified gamut     
else if( GetOutputDevice() == 1 )     
{         
// Convert from sRGB to specified output gamut         
float3 OutputGamutColor = mul( AP1_2_Output, mul( sRGB_2_AP1, FilmColor ) );          
// Didn't profile yet if the branching version would be faster (different linear segment).         
OutDeviceColor = LinearTo709Branchless( OutputGamutColor );     
}     
// OutputDevice == 2     
// Gamma 2.2, user specified gamut     
else if ( GetOutputDevice() == 2 )     
{         
// Convert from sRGB to specified output gamut         
float3 OutputGamutColor = mul( AP1_2_Output, mul( sRGB_2_AP1, FilmColor ) );          
// This is different than the prior "gamma" curve adjustment (but reusing the variable).         
// For displays set to a gamma colorspace.         
// Note, MacOSX native output is raw gamma 2.2 not sRGB!         
OutDeviceColor = pow( OutputGamutColor, InverseGamma.z );     
}          

// Better to saturate(lerp(a,b,t)) than lerp(saturate(a),saturate(b),t)     
OutColor.rgb = OutDeviceColor / 1.05;     
OutColor.a = 0;      
return OutColor; 
}

さまざまなOETFによってエンコードされた情報は、対応するSDR表示デバイスに送信する準備ができています。

 

###HDRでのOutput Transform

 

SDR Output Transformと比較して、UE4のHDROutput Transformは変換がはるかに少なくなっています。Tonemappingと同様の計算は、UE4のHDR出力パイプラインでは実現されませんが、Color Gradingが計算された後、色空間はAP1からsRGBに直接再変換されます。

float4 CombineLUTsCommon(float2 InUV, uint InLayerIndex) 
{     
...     
ColorAP1 = ColorCorrectAll( ColorAP1 );      

// Store for Legacy tonemap later and for Linear HDR output without tone curve    
float3 GradedColor = mul( AP1_2_sRGB, ColorAP1 );

そのOutput Transformは基本的に直接的にODT変換を行い、その本質は、出力信号をエンコードするためにさまざまなOETF関数を使用することでもあります。

float4 CombineLUTsCommon(float2 InUV, uint InLayerIndex) 
{     
...     
if( GetOutputDevice() == 3 || GetOutputDevice() == 5 )     
{                
// 1000 nit ODT         
float3 ODTColor = ACESOutputTransforms1000( GradedColor );          

// Convert from AP1 to specified output gamut         
ODTColor = mul( AP1_2_Output, ODTColor );          

// Apply conversion to ST-2084 (Dolby PQ)         
OutDeviceColor = LinearToST2084( ODTColor );     
}      
// ACES 2000nit transform with PQ/2084 encoding, user specified gamut      
else if( GetOutputDevice() == 4 || GetOutputDevice() == 6 )     
{                
// 2000 nit ODT         
float3 ODTColor = ACESOutputTransforms2000( GradedColor );          
// Convert from AP1 to specified output gamut         
ODTColor = mul( AP1_2_Output, ODTColor );          
// Apply conversion to ST-2084 (Dolby PQ)         
OutDeviceColor = LinearToST2084( ODTColor );     
}        
else if( GetOutputDevice() == 7 )     
{             
float3 OutputGamutColor = mul( AP1_2_Output, mul( sRGB_2_AP1, GradedColor ) );             
OutDeviceColor = LinearToST2084( OutputGamutColor );     
}          
// Better to saturate(lerp(a,b,t)) than lerp(saturate(a),saturate(b),t)     
OutColor.rgb = OutDeviceColor / 1.05;     
OutColor.a = 0;      

return OutColor; 
}

最後に、エンコードされたHDR信号をHDR表示デバイスに渡すために、PQのOETF伝達関数を使用してエンコードします。

 

##CLUTを使用する

 

CLUTを使用するロジックは、PostProcessTonemap.usfで処理され、その主な関数ロジックはTonemapCommonPS関数にあります。 TonemapCommonPS関数は、最初に、Grain、Color Fringe、Sharpen、Bloom、Exposure、Vignetteなど、これまでに完了していない後処理を計算し、上記の後処理計算で得られた最終結果を3D LUTのサンプリング座標に変換して色を検索します:

float4 TonemapCommonPS() {     // Compute Grain/Color Fringe/Sharpen/Bloom/Exposure/Vignette     ...     half3 OutDeviceColor = ColorLookupTable( LinearColor );     ...     return OutColor; }

ColorLookupTableの出力は、OETFによってエンコード後の信号値です。 ここまで、UE4のHDR出力パイプラインは終了しています。

 

##UE4におけるACES

 

UE4がBlue Light Artifact FixのLMT部分と、Fake Wide Gamutのtrick部分を除いて、SDRでの実現はACES sRGBとほぼ同じです。これにより、DCCソフトウェアでUE4レンダリング効果を調整するパスが提供されます。完全にカスタムのOCIOファイルまたはその他のLUTファイルを実現したくない場合は、UE4でこれら2つの変更をオフにすることができ(後処理コンポーネントでBlue CorrectionとExpand GamutGamutの値を0に設定する)、そしてACES RRT +sRGBODTに関連するOCIOを使用します。

 

#UE4とCODのHDR実現の比較

 

次のように、UE4とCOD がHDR表示パイプラインでの実現とはまだ多少異なることがわかります。

WW IIのOutput Transformは、UE4の処理よりも複雑です。

n要するに、UE4はACESのネイティブコードロジックを直接使用し、SDRパスの下でACES RRTとODTのTonemapping計算を結合し、UE4のレンダリングパイプラインにネストします。ただし、HDRパスでは、ACESの最も基本的なOETF部分のみが保持され、1000ニットと2000ニットの2つの固定最大輝度値のみがサポートされます。つまり、HDRをオンにした後、手動でHDR Tonemappingを調整する必要があります。これ限り、SDRと同じ画像効果を得られます。

 

nWW IIは彼らのニーズに合わせてより多くの適応作業を行いましたが、それでも明確なRRTおよびODTステップを保持していました。RRTステージでは、ACES RRTと非常によく似たTone Curveを使用して調整するため、マッピングされたシーンの輝度はPQの0〜10000ニットの範囲になります。ODTステージでは、ACES ODTと同様のDisplay Mapping計算も保持されます。つまり、アプリケーションデバイスのOETFの前に、WW IIはSDRとHDRの下で相互に独立したS曲線を使用して、特別なHDR Range Reductionを実行します。このプロセスにより、ユーザーは、さまざまな表示デバイスの表示パラメーター(最小および最大輝度値など)を処理するためのパラメーターの調整に参加し、より優れた制御性を実現できます。

 

lWW IIのUI描画はbackbufferーに直接的に的に混合されますが、UE4は最初にoffscreen bufferに出力され、次にbackbufferーに混合されます

 

まとめてみると、UE4の現在の実現は、私たちに基盤を与えています。より良いHDR表示を実現するには、いくつかの二次開発が必要です。たとえば、UE4で開発されたGears of War 5のHDR表示は、ネイティブUE4と比較して、より優れています。Gears of War 5のインタビューにより、Tonemapping を使用していることを明らかにしました。それは、Microsoftのファーストパーティゲームで多数のHDR / SDR画像をトレーニングサンプルとして使用し、機械学習を使用してトレーニングして得られたものです。その上に、ゲーマーが表示デバイスに応じてゲーム内に校正することをサーポットします。


 

おわりに

 

HDR表示に関してはACESが常に言及されていますが、ACESはゲームのHDR表示のいわゆる「銀の弾丸」ではないことに徐々に気づきました。仕事でTonemappingを選択する方法にも出会ったとき、AngeloPesceは彼のブログでそのような質問をしました。 ACESTonemappingは本当にすべてのゲームに適していますか? ACESのSカーブのさまざまなパラメータは、多くの映画やテレビ業界の大物によって承認されていますが、これは、多数の画像の検証後に取得した「最も合理的な」パラメータですが、この「高度なフィルムとテレビセンス」はすべてのゲームに適しているわけではありません。視覚的な「映画感」を除いて、ACESのもう1つの大きな利点は標準化ですが、これがゲーム業界でそれほど重要であるかどうかは議論の余地があるようです。 2Dスタイルのゲームなど、一部のゲームタイプでは、開発ツールの種類が限られており、映画やテレビ業界と同じ標準を使用する必要はまったくないようです。しかし、「標準化」が開発者に安心感を与えることは否定できません。また、小さなワークショップからの工業化の重要な兆候でもあります。ACES標準に適応するか、独自の標準を開発するかが問題です。

 

UnityとUE4の両方に現在完全なACESが組み込まれていますが、HDR表示をサポートする3Aゲームの共有を見てみると、Gears of War 5使用されたML Tonemapping 、WW IIで使用されたBT2390EETF標準に基づくHDRDisplay Mappingなど、ACESのアイデアに独自の変更が加えられていることがわかります。これらの商用エンジンでの実現は、私たちに出発点を与えるだけであると言えます。PBRタイプのゲームの場合、ACESは他のDCCソフトウェアとの互換性が高くなります。しかし、現在の国内開発環境では、HDR表示は重要な位置に昇格していません。同時に、完全なACES実現は、携帯電話プラットフォームに多くの計算圧力をかけます。 簡略化されたPBRはACES標準化の重要性を弱めました。それに、柔軟性の欠如と、多数の主観的な定型化された画面開発のニーズが相まって、簡略化されたACES SDR TonemappingHDR Tonemappingなど、他のTonemappingが現在の国内ゲーム開発により適しているようです。


Reference

  1. Digital Dragons 2018: HDR in Call of Duty
  2. SIGGRAPH Asia 2018:Practical HDR and Wide Color Techniques in Gran Turismo SPORT
  3. GDC 2019: Not-So-Little Light: Bringing ‘Destiny 2’ to HDR Displays
  4. GDC 2018: Advances in the HDR Ecosystem
  5. GDC 2017: HDR Dynamic Range Color Grading and Display in Frostbite
  6. https://www.resetera.com/threads/hdr-games-analysed.23587/
  7. https://docs.unrealengine.com/en-US/Engine/Rendering/HDRDisplayOutput/index.html
  8. https://developer.nvidia.com/hdr-ue4

UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

サウンドエンジンWwiseとCriwareの違い

1)サウンドエンジンWwiseとCriwareの違い

2)Unityの読み込みシーンのフラッシュバックの問題

3)Animation Transition規則

4)Qualcomm GPU Adreno650 にあるテクスチャ表示が異常です

5)Live2Dのスムーズなグラデーションのスキーム


 

Audio

 

Q:現在、WwiseCriware2つの音声(サウンド)エンジンから選択できますが、通常の開発、熱更新、効率、およびデカップリングの観点から、どっちをすすめますか?それとも、得意な方を使われば良いでしょうか?

 

A1:実際、オーディオミドルウェアツールには、この2つだけでなく、多くのオプションがあります。たとえば、「Apex Legends」はRad Milesを使用し、「Wind Traveler and Light Encounter」はFMODを使用し、「Half-Life Alyx」はミドルウェアを使用しなく、自社エンジンのオーディオモジュールを使用しています。

Criwareは比較的長い歴史があり、有名なゲーム開発者Segaと深い関係があり、かつてSegaの公式オーディオおよびビデオ開発ツールセットに含まれていたとさえ言えます。Segaの影響を考慮すると、Criwareは今の日本でも相変わらず大規模なユーザーベースを持っています。

Wwiseの歴史は比較的に短く、その開発会社であるAudiokineticが2019年にSIE(Sony Interactive Entertainment)の子会社になったのは興味深いことです。実際にはWwiseを使ったプロジェクトがたくさんあり、毎年TGAの受賞プロジェクトの約半分はWwiseを使って開発されていますが、顧客にLogoを強制することはなく、存在感がそれほど高くなくなっています。

Wwiseを使用した例をいくつか挙げられます(順位は前後を問わず):Death Stranding、Resident Evil 123 Remake、Resident Evil 8、Monster Hunter Rise、Ghost of Tsushima、God of War、Honkai Impact 3、Genshin Impact、Honor of Kings 、CODM、ミステリアスケース、レインボーフォール、モニュメントバレー2、Gris、Quantum Break、Control、ウィッチャー3、サイバーパンク2077など。

開発の観点からもオーディオチームの観点からも、Wwiseの方がより良い選択であると思います。

開発

業界をリードする空間オーディオツールの集め、広義Object Basedのオーディオパイプラインをサポートする最初のオーディオツール:

https://www.audiokinetic.com/zh/library/edge/?source=SDK&id=spatial_audio.html

https://www.audiokinetic.com/zh/products/plug-ins/reflect/

業界をリードする自動車エンジンのサウンドデザインプラグイン:

https://www.audiokinetic.com/en/products/plug-ins/crankcase-rev/

オーディオデザイナーのクレイジーなアイデア、多数の成功したユーザーケース、テクノロジーの共有(Wwise Tour、GDCなど)を実現できる強力なクリエイティブツール:

https://www.bilibili.com/video/BV1RE411K7nT

公式ウェブサイトのQ&AとLauncherのBug reporterは、公式によってサポートされた無料の質問フィードバックと送信のチャネルです。技術サポートと創造的な技術サービスは、プロジェクトのカスタマイズしたニーズを満たせます。公式に維持されているUnity/Unreal統合では、Launcherを介してWwise SDKをプロジェクトにすぐに統合できます。

フルプラットフォームをサポートし、豊富なオーディオコーデックオプション、豊富なSDKドキュメント、明確で習得しやすいヘルプドキュメント、認定チュートリアルドキュメントにより、ユーザーは初期化設定を調整して、必要に応じてオーディオ遅延を減らすことができます。

ホットアップデート

File Packagerツールは、PCKを作成してホットアップデートを介して公開されたコンテンツを管理します。、Wwise2021.1はすでにUnity Addressablesをサポートしています。

効率

デザイナーにとって、WAQL(Wwiseオーサリングツールクエリ言語)を使用すると、プロジェクトの規模が特定のレベルに達したときに配置が必要なアセットをすばやくクエリしたり、問題の原因となるアセットを特定したりすることができます。

https://www.audiokinetic.com/en/library/edge/?source=SDK&id=waql_introduction.html

強力で柔軟な音声制限機能とProfilingツールにより、パフォーマンスの最適化とトラブルシューティングが容易になり、エンジニアの負担が軽減され、豊富なバッチ処理機能が備わっています。

エンジニア向けに、WwiseにはWAAPI(Wwise Authoring Tool API)があります。これは、開発ツールの作成に使用でき、膨大なデータ構成をすばやく処理するのに便利で、プロジェクト開発のニーズを満たすためにアセットをバッチでパッケージ化するのにも役立ちます。

https://www.audiokinetic.com/en/library/edge/?source=SDK&id=waapi.html

Wwiseは動的なメモリ管理を備えており、事前に固定サイズのメモリプールを申請する必要がないため、可能な限り使用することができます。メモリ分類システムにより、ユーザーはメモリコストに関連する問題をすばやく特定することができます。

デカップリング

Wwise APIはシンプルで使いやすく、イベント後の動作はオーサリングツール側のデザイナーが設計できるため、エンジニアはそれについて心配する必要はありません。通常、デザイナーのためにコール必要があるインターフェースは次のようなものがあります。

PostEvent

SetState

SetSwitch

SetRTPCValue

Load/Unload bank

詳細なドキュメントについては、以下を参照してください。

https://www.audiokinetic.com/en/library/edge/?source=SDK&id=workingwithsdks_integratingelements.html

Wwiseは、サウンドデザイナーに優れたクリエイティブな空間を提供します。空間オーディオデザインに関連する多くの設定は、デバッグのためのプログラムの介入を必要とせずにクリエイティブツール側に配置され、一般的なサウンドジェネレーターのように処理するだけで済みます。

デザイナーは、Profilingツールを通じてパフォーマンスの低下を明確に理解し、パフォーマンスの問題を引き起こす可能性のある設計を事前に特定し、リファクタリング処理を行うこともできます。

 

A2:技術的な観点からすると、A1は本当に良いです。簡単に私の意見を述べさせてください。

インターフェイスの見栄えが良いかどうかに関係なく、後で変更できます。どのテクノロジーでも、その市場を考慮する必要があります。現在はいうまでもなく、Wwiseのシェアは高いのです。たとえば、会社に採用される可能性が高いのは、Wwiseができるオーディオエンジニアか、またはCriwareができるオーディオエンジニアですか。

プログラムは同じで、人気があるのはWwiseのみができるの方か、Criwareのみができるの方か。この分析を通じて、どのソフトウェアを使用すべきかがわかります。

 


 

Crash

 

Q:最近、プロジェクトで非常に奇妙な問題が発生しました。あるシーンから別のシーンに切り替えると、Android 64ビットの実機でクラッシュし、シンボルテーブルを使用して最後のクラッシュがUnityil2cpp / vm/liveness.cppのファイルにあると発見ました。

 

UnityPCバージョンにはフラッシュバックはありません。

 

エンジンバージョン:Unity 2018.4.10

パッケージ化デバイス:MacOS

 

クラッシュの原因を特定するために、次のテストが実行されました。

  1. Monoを使用してパッケージ化すると、ラッシュバックしません。
  2. V8クラスライブラリを削除し、V7クラスライブラリを完全に使用すると、ラッシュバックしません。
  3. V8ライブラリを使用して、空のシーンに切り替えてフラッシュバックします。

 

3では、Application.LoadLevel、Applicaiton.LoadLevelAync、SceneManager.LoadScene、SceneManager.LoadSceneAyncのいずれを使用しても、フラッシュバックします。この問題には今のところ手がかりがありません。誰かがこの問題に遭遇したことがあるのか。

 

フラッシュバックログ:il2cpp :: vm :: LivenessState :: AddProcessObject(Il2CppObject、il2cpp :: vm :: LivenessState)

 

残念ながら、Unityをアップグレードした後でも、クラッシュは解決されません。

  

参照URL:

https://forum.unity.com/threads/il2cpp-crashes-at-garbagecollectsharedassets-and-loadlevel.316775/page-2

 

A:Unity 2018.4.35バージョンにアップグレードする必要があることがわかりました。このバグは、このバージョンで修正されています。


Animation

QAnimation Transitionについて質問させて頂きます。現在、State Aには、Aからのすべての遷移線に優先順位を付けることができます。では、Aに入るすべての遷移線にも優先順位を付ける方法はありますか?

 

たとえば、Aの場合、AnyState->AB->Aという二つの線があり、それらの条件は同じです。したがって、条件が真の場合、上記の線のいずれかの使用を指定する方法はありますか?

 

現在、公式ドキュメントには対応する方法はありません。Bに入るときに状態をDisable AnyStateに設定し、Bを出るときに元に戻すことができるという主張がありますが、より良い方法があるかどうかわかりません。

 

A1:「Aに入るすべての遷移線にも優先順位を付ける」という言い方は間違っているところがあります。ステートマシンの定義によれば、同時に2つの状態にいる状況は存在しなくて、両方ともState Aに入る必要があります。

問題を詳細に説明するとき、重要なのはAnyStateノードの存在であるとも述べられました。Unityのアニメーションステートマシンスキームでは、Entry、AnyState、Exitノードはシンタックスシュガーに似ています。Runtimeアセットを生成する場合、一連のノード拡張プロセスがあります。

この質問に戻ると、State B -> State Aの場合、「Aに入るすべての遷移線に優先順位を付ける」または「Bから出る遷移線に優先順位を付ける」ではありません。B-> Aに2つのTransition線を設定すると、優先順位を付けることができ、AnyStateは展開後にB->AのTransitionも生成します。ただし、エディターレイヤーはこの視覚化レイヤーを公開しないため、調整できず、拡張プロセスは表示されず、拡張はサポートされません(少なくとも私はそれを見つけられませんでした)。

AnimatorControllerを使用し、関数を実現する方法を見つける必要があるという前提で、次のようにします。

B-> AでAnyStateのTransitionを実行しないようにする場合は、Distable AnyStateのステートマシンスクリプトを記述し、AnyStateの条件に割り当てるパラメーターを宣言するのが最も簡単です。面倒なのは、Anystate-> Aを使用する代わりに、Sub-Smを使用して接続数を減らすことです。

AnyStateのTransitionの優先度を上げたい場合は、同じ配置の同等の遷移TransitionをB-Aに追加して調整できます。

 

A2:意味的には、AnyState->AにはB->Aが含まれます(条件が同じ場合)。つまり、B->Aはステートマシンの冗長なTransitionです。現在の状態は1つだけで、条件が満たされると次の状態に移行し、優先度の問題はありません。したがって、B->AがAnyState->Aのサブセットにならないように、B->Aを他の条件に設定する必要があります。

 


Rendering

Q:現在、Qualcomm GPU Adreno650デバイスでは、テクスチャ表示がぼやけていることがわかりましたが、解決策がありますか? (Mipmapslevelエラーのようです。)

 

Unityバージョン:2019.4.10LTS

URPバージョン:7.5.3

画像設定圧縮形式:RGB(A) astc compressed

 

Qualcomm Adreno650

 

 

他のデバイス:

 

A:おそらくGPUの問題です。Shaderの浮動小数点精度を下げてみてください。それが、当時私たちが解決した方法です。一部のHuaweiスマホにもこの精度の問題があります。

 

 


Rendering

QLive 2Dによって公式に提供されているCubismRenderControllerは、Opacityを設定することでCubismの透明度を設定できますが、以下に示すように、過渡は非常に硬く見えます。

 

 

現在の解決策は、RTを介してパネルにCubismをレンダリングし、パネルの透明度を制御することでスムーズな過渡効果を実現することです。良い解決策はありますか?

 

テスト後、イージングカーブ関数を使用してこの値を設定することはできず、中間プロセスでは相変わらずバレます。

 

A1:いわゆる透明性の「スムーズではない過渡」の本質的な理由は、元のロジックは、cubism_ModelOpacityを体の各小さな部分に個別に適用してから、各部分を混合することからです。コアコードは次のとおりです。

体は部分ずつ描かれています:

問題主の欲しい効果は次のとおりです。全体的な結果がレンダリングされた後、透明効果が全体に適用されます。したがって、「全身を描いた後、再度透明度を使用する」ことは避けられません。その本質は、ボディの各部分が描画された後、FrameBufferを取得してから、透明度を使用して1回処理する必要があるということです。したがって、「RTを介してパネルにレンダリングし、パネルの透明度を制御すること」は合理的です。

したがって、主な問題は、このプロセスを最適化するためのより直接的な方法があるかどうかです。 ここでは、より良い最適化方法を考えていません。Builtin-RenderPipelineはそれほど柔軟ではないか、最適化が必要かどうかを検討する必要があるかもしれません。


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

【HDRと色彩管理4】HDR標準とACES

前のセクションでは、古いSDR Color Pipelineと、最も一般的な2つのSDRディスプレイとそれらの色空間標準(sRGBおよびRec. 709)について説明しました。しかし、色彩管理とディスプレイには、SDRディスプレイは欠点があリます。色彩表示とストレージの需要が高まるにつれ、HDRディスプレイの時代が到来しました。これらの複雑なディスプレイと色の標準により、Pipeline全体に重大な管理上の課題が追加されました。ACESは、すべての段階で一貫した表示結果を達成するために生まれました。


 

4.1SDRの欠点

SDRの最も明らかな欠点は、非常に狭い色域をカバーし、CIE 1931色空間の約35.9%しか占めていないことです。

Source: https://nick-shaw.github.io/cinematiccolor/common-rgb-color-spaces.html

 

彩度が非常に高い一部の色は、このような低い色域では表現できないため、色表現の豊かさに影響します。同時に、低色域で照明とレンダリングを計算すると、色の値がclipされ、色の精度に影響します。

 

また、SDRのOETF関数と最終的なディスプレイの輝度の間には不確実なギャップがあります。これは、SRD OETFの出力範囲が0〜1であり、ディスプレイの最大輝度が不確であるためです。これは、特定のディスプレイモデルに関連しています。たとえば、HDTVディスプレイのピーク輝度は、通常、PCディスプレイのピーク輝度よりも大きいです。使用したSDR Tonemapping曲線は、低輝度のPCディスプレイでうまく機能する可能性がありますが、高輝度のピークを持つHDTVでは細部の表示がダメになるかもしれません。もちろん、高輝度のディスプレイに別のTonemapper曲線を使用して、強調表示の部分の詳細を増やすことができますが、色彩管理が複雑になってしまう危険性があります。

 

これらの問題に対処するために、HDR色空間標準を導入しました。


 

4.2 HDR色空間標準

 

最も一般的なHDR色空間標準はITU-R Recommendation BT.2020(REC. 2020またはBT.2020と略称する)。 REC. 2020は、HDR色空間の三原色(R(0.708,0.797)、G(0.170,0.046)、B(0.170,0.046))および白点(D65)を定義しています。色域範囲について、CIE 1931の色空間の75.8%をカバーできます。

Source: https://nick-shaw.github.io/cinematiccolor/common-rgb-color-spaces.html

Rec. 709と同様に、Rec. 2020標準も正確なOETF伝達関数を指定しています。

ここで、αとβの値は、32ビットの完全精度で1.09929682680944と0.018053968510807、12ビットの精度で1.0993と0.0181、10ビットの精度で1.099と0.018です。

 

Rec. 2020標準では、SDR表示で使用するEOTF関数を定義しています。このEOTF関数は、BT.1886で定義されているEOFT関数であるRec. 709と同じです。 Rec. 2020で使用されるより一般的な伝達関数は、HDRディスプレイで使用されるEOTF関数です。これは、ITU-RBT.2100で定義されているST2084またはHLG伝達関数です。

 

4.2.1 2084/PQ伝達関数

ST 2084はSMPTE ST 2084(Society of Motion Picture and Television Engineers、2014)と呼ばれ、Rec. 2020の3原色で使用されるEOTF関数(つまり、output-referred encoding function)です。もともとはドルビー(Dolby)によって定義されたPQ(Perceptual Quantizer)と呼ばれるエンコード関数であり、最大10000cd /m²(ニット)の高い動的輝度値をエンコードできます。PQ伝達関数の本質は、コーディングスペースを最大限に活用して、人間の視覚系が明るさへの感知に応じてデジタル信号を定量化することです。簡単に言えば、人間の目が知覚できる輝度色階(banding)が避けられる場合に、データを量子化させ、エンコードを行います。

 

以下は、人間の視覚システムから派生したBarten Rampモデルです。これは、現在の輝度値(横座標)の下で、2つの輝度値の違いが人間の目でどの程度認識できるかを示しています。輝度の差が点線より上にある場合、人間の目は明るさのコントラストを認識でき、いわゆるbanding現象が発生します。輝度の差が点線より下にある場合、人間の目はそれを区別がつかず、滑らかで且つ漸進的です。

Source: HDR in Call of Duty

Barten Rampモデルに依存して、輝度エンコーディング曲線のデータ使用率を評価できます。 たとえば、下の緑色の線は、16ビット精度(OpenEXR形式など)で輝度値を直接保存することによって生じる輝度精度の違いを表しています。その違いはすべて曲線の下にあるため、視覚的なbandingはありません。

Source: HDR in Call of Duty

以下のオレンジ線と青線は、それぞれ15ビットと10ビットの精度でガンマエンコーディングを使用した曲線を表しています。10ビットの精度のガンマエンコーディングが0〜1の輝度範囲での輝度差は、曲線の上にあります。これは、人間の目に見える色階の問題があることを意味します。 15ビットの精度のガンマエンコーディングは曲線の下にありますが、強調表示された領域でのエンコーディングはデータの無駄です。つまり、これらの領域に格納されている多数の異なる輝度値は、人間の目から見れば大きな差がありません。紫色の線は、13ビット精度のLogエンコーディングを表します。15ビットのガンマエンコーディングと比較すると、強調表示された領域のデータエンコーディングをより十分に活用しますが、低輝度領域のデータが無駄になります。

Source: HDR in Call of Duty

ドルビーが提案した12ビット精度のPQ伝達関数を用いて得られた輝度差曲線を以下に示します。PQ伝達関数のエンコーディング方法は、各輝度区間の範囲にエンコーディングデータをより有効に活用できることがわかります。

Source: HDR in Call of Duty

ITU-R BT.2100は、PQ用の特定のEOTF伝達関数を定義します。 ST 2084 EOTF伝達関数は次のとおりです。

定数値は次のとおりです:

その曲線は次のように表されます。

Source: https://nick-shaw.github.io/cinematiccolor/common-rgb-color-spaces.html

PQ OETF関数は、前に見たsRGBまたはRec. 709のEOTF関数とは大きく異なることがわかります。まず、PQ伝達関数は0から10000cd /m²の範囲の絶対輝度値を出力しますが、SDRは0から1の範囲の相対輝度値を出力します。SDRディスプレイによって表示される真の輝度値不明です。この確実性は、debug時にも役立ちます。たとえば、PQ値が0.5である時、古いLCDディスプレイのピーク輝度値である約100 nitに対応します。PQ値が0.75である時、一部のHDRTVディスプレイのピーク輝度値である約1000nitに対応します。

PQ伝達関数の視覚的な一貫性により、output-referred imageのワークスペースとして適しています。これにより、エンコードされたデータを最大限に活用して視覚的なエラーを減らすことができます。実際、多くのゲームエンジンは、最初にPQ伝達関数を使用して、HDRを表示するときにシーンの線形輝度値を0から1のエンコード値に変換し、これを使用してColor GradingおよびTonemapping操作用の3DLUTをサンプリングします。たとえば、HDR表示用の3D LUTを計算するときに、UE4はST 2084 ToLinearを使用してデコードして線形輝度値を取得し、この輝度値で後続のカラー操作を実行します。

// Since ST2084 returns linear values in nits, divide by a scale factor to convert
// the reference nit result to be 1.0 in linear. 
// (for efficiency multiply by precomputed inverse) 
LinearColor = ST2084ToLinear(LUTEncodedColor) * LinearToNitsScaleInverse;

この3DLUTをサンプリングする場合、上記の計算の逆関数を実行して、線形輝度値を0から1のテクスチャサンプル座標に変換します。

// ST2084 expects to receive linear values 0-10000 in nits. 
// So the linear value must be multiplied by a scale factor to convert to nits. 
float3 LUTEncodedColor = LinearToST2084(LinearColor * LinearToNitsScale); 

float3 UVW = LUTEncodedColor * ((LUTSize - 1) / LUTSize) + (0.5f / LUTSize); 
float3 OutDeviceColor = Texture3DSample( ColorGradingLUT, ColorGradingLUTSampler, UVW ).rgb;

上記のPQ伝達関数には、2つのpow計算と1つのrcp計算が必要です。計算するときに、コマンドの消費に注意してください。

//
// Dolby PQ transforms
//
float3 ST2084ToLinear(float3 pq) 
{
const float m1 = 0.1593017578125; // = 2610. / 4096. * .25;
const float m2 = 78.84375; // = 2523. / 4096. *  128;
const float c1 = 0.8359375; // = 2392. / 4096. * 32 - 2413./4096.*32 + 1;
const float c2 = 18.8515625; // = 2413. / 4096. * 32;
const float c3 = 18.6875; // = 2392. / 4096. * 32;
const float C = 10000.;
float3 Np = pow( pq, 1./m2 );
float3 L = Np - c1;
L = max(0., L);
L = L / (c2 - c3 * Np);
L = pow( L, 1./m1 );
float3 P = L * C;
return P;
}

PQ伝達関数は最大10,000nitの絶対輝度値をサポートできますが、ほとんどのディスプレイの輝度ピック値は2,000 nitを超えることはなく、多くのHDRディスプレイの輝度ピック値は約1,000nitであることに注意してください。もちろん、最も簡単な方法は、シーンの輝度値を線形にスケーリングして特定のディスプレイの輝度値に対応させ、ST 2084 OETF関数を使用してエンコードしてディスプレイに送信することです。しかし、SDRディスプレイで見たように、この線形から線形への対応は視覚的な線形性を満たさないため、明るい領域と暗い領域の両方でも細部が不足します。したがって、シーン内の高い動的輝度値をディスプレイデバイスがサポートできる輝度範囲に再マッピングするには、何らかのトーンマッピング操作が必要です。このトーンマッピング操作は、強調表示部と陰影部のコントラストを目立たせることができ、より良い視覚効果が得ルことができます。 ACESは、最も一般的なHDR曲線のマッピング(View Transform)のいくつかを提供します。これらは、それぞれ1000 cd /m²、2000 cd /m²、4000cd/m²の標準HDRディスプレイに使用されます。これらのマッピング機能の本来の目的は、HDRディスプレイをSDRディスプレイと可能な限り視覚的に一致させることです。これらのマッピング関数については、後でACESについて説明するときに詳しく説明します。

 

4.2.2HLG伝達関数

 

HLG伝達関数は、ゲームエンジンのHDR表示パイプラインでは一般的に使用されていません。ここでは、完全を期すために簡単に説明します。 HLGの正式名称はHybridLogGammaで、BBCとNHKは共同で設計したコーディング機能です。HLG伝達関数の設計の本来の目的は、主にHDR表示ができないSDRディスプレイと互換性を持たせることです。つまり、従来BT 1886 EOTFを使用していたSDRディスプレイにHLG信号を送信すると、表示効果を得ることができます。

 

HLGコーディング関数もITU-RBT.2100で定義されており、ここではHLGEOTFの関数曲線のみを示します。

Source: https://nick-shaw.github.io/cinematiccolor/common-rgb-color-spaces.html


 

4.3 The DominationACES

 

撮影デバイスの型番や特定のエンコーディングおよび表示標準や制作プロセスの段階(合成、CG、VFXなど)でのデータ入出力の複雑さにより、映画やテレビの制作では色彩管理が非常に難しい作業です。問題が発生しやすいリンクとして、推測や当てずっぽうの場合がよくあります。ACESは、この問題を解決するために存在する管理システムです。

ACESの定義は以下の通りです。

The Academy Color Encoding System (ACES) is a set of components that facilitates a wide range of motion picture and television workflows while eliminating the ambiguity of legacy file formats. The system is designed to support both all-digital and hybrid film-digital motion picture workflows.

—— From github

このシステムは主に次のような部分からなっています。

(1)いくつかの仕様

  • 色エンコディングとメトリックの仕様
  • ファイル形式の仕様
  • 色変換、およびオープンソースバージョン(CTL言語を使用)のコード実装を提供する

(2)ACESで色変換を使用して参照画像を処理した結果に対応する一連の参照画像と校正ターゲット画像。これはユーザーがACESシステムの実装の精度を検証するのに役立ちます。

(3)システムとソフトウェアツールのドキュメント

 

ACESのドキュメントは広範囲にわたり、その命名と有用性について非常に厳密に説明されています。これらのドキュメントは、ACESの個々の標準と実装の詳細について詳しく知りたい場合に最適なリファレンスです。たとえば、TB-2014-001は、他の各ドキュメントの一般的な使用方法を提供する概要ドキュメントです。TB-2014-002は、ACESインターフェースと概念をユーザーによりよく紹介するため、ACESをソフトウェアに統合する必要がある開発者向けのユーザー製品エクスペリエンスガイドを提供します。TB-2014-012は、ACESのさまざまなコンポーネントの詳細な名前(色空間、色変換、ファイル形式を含む)を提供します。

 

リアルタイムレンダリングの場合、私たちに最も関係のあるのは、色のコーディングと色変換に関するACESシステム仕様の一部です。

4.3.1カラーコーディング

 

ACESシステムは、映画やテレビの制作プロセスのさまざまな段階で使用するためのいくつかの色空間を定義します。これらの色空間の三原色と変換関数の定義は、それらのアプリケーションシナリオ用に特別に指定されており、次のものが含まれます。

(1)ACES2065-1:線形変換関数でエンコードされたscene-referred色空間です。主にACESプロセスでの画像交換作業に使用されます。

  • 三原色:AP0(ACES Primaries 0)という名前の三原色値を使用します。これらの値は、1931 CIE xy色度図でR(0.7347、0.2653)、G(0.0、1.0)、B(0.0001、-0.077)です。
  • 白色点:D60値と類似しているが同じではない白色点値(0.32168、0.33767)。一部の記事では直接D60と呼ばれることもありますが、これは実際には不正確です。

(2)ACEScg:線形変換機能でエンコードされたシーン参照色空間でもあり、主にCG、VFX、合成ステージの作業スペースに使用されます。

  • 三原色:AP1(ACES Primaries 1)という名前の三原色値を使用します。これらの値は、1931 CIE xy色度図でR(0.713、0.293)、G(0.165、0.830)、B(0.128)です。 、0.044)。
  • 白色点:白色点の値はACES2065-1の値と同じで、つまり(0.32168、0.33767)です。

(3)ACESproxy、ACEScc、ACEScct:これら3つのスペースの三原色と白色点の値はACEScgと同じですが、異なるコーディング深度と伝達関数が使用されます。たとえば、ACESproxyは、伝達関数の色空間としてlogを使用して、10ビットまたは12ビットの整数データエンコーディングを使用します。これらの色空間は、主に映画やテレビの制作プロセスで使用され、ゲームのリアルタイムレンダリングではほとんど触れられません。

 

AP0とAP1の原色の値は、アプリケーションシナリオのために、多数の専門家によって厳密に設計および定義されています。 AP0の3つの頂点で囲まれた領域には、スペクトルトレース全体が含まれています。

Source: https://nick-shaw.github.io/cinematiccolor/common-rgb-color-spaces.html

AP0は、AP0線形色空間で正の値を使用して、人間の目に見える色値をエンコードできるように定義されています。 AP0に対応する三原色の値は物理的に不可能ですが、つまり、現実の世界ではそのような3色を作成することはできません(1931 CIE XYZの三原色と類似している)が、これはアプリケーションシナリオ。と関わり、その広い色域は、制作プロセスでの画像転送の中間色空間として理想的であり、情報の損失を最小限に抑えます。

 

AP0と比較すると、AP1の色域範囲は非常に「保守的」であり、AP1が囲む色域範囲は、スペクトル軌跡とわずかに交差していますが、Rec. 2020に非常に近いです。

Source: https://nick-shaw.github.io/cinematiccolor/common-rgb-color-spaces.html

色情報を最大限に保持およびエンコードすることを目的とするAP0とは異なり、AP1はCGおよびVFXでのレンダリングおよび照明計算に適しています。レンダリングに使用される色空間の選択は非常に重要です。これは、照明の計算方法に影響を与え、したがって最終的なレンダリング結果、特に間接照明の計算に影響を与えます。どちらも平等であるにもかかわらず、いくつかの色空間は他の色空間よりも優れていて正確であると言えます。

 

これは、色空間の比較に言及する必要があります。コンピュータレンダリングの分野では、私たちの計算はすべて、色空間の三原色、つまり3次元空間におけるこの色空間の3つの基本ベクトルに基づいています。次の状況を考えてみましょう。sRGB空間で特定の色を使用して特定の照明計算を実行した後、結果をCIE XYZ空間に変換して結果Aを取得します。これらのsRGB空間の色をACEScg空間に変換して同じ照明計算を行なった後、その結果もCIEXYZ空間に変換して、結果Bを取得します。結果Aと結果Bが同等でないことが多いのは憂慮すべきことです。数学的には、この現象をより簡単に理解できます。さまざまな色空間の3つの基底ベクトルは、XYZ空間では正規直交基底ではありません。これらの非直交基底には、加算や減算などの操作を除いて、乗算と除算と指数などの一般的な照明計算さえも同価ではありません。では、これらの結果のどれがより正しいかをどのように比較しますか?一般に、スペクトルレンダラー(波長で色の計算を行う。Mitsubaなど。)を使用して得られた結果はground truthであり、Ward and Eydelberg-Vileshin (2002)Langlands and Mansencal (2014)Mansencal (2014)などは色空間比較の実験を行い、AndersLanglandsとThomasMansencalは、Computer Graphicsの記事で、これらの実験の結果について簡単に説明しました。比較結果は次のとおりです。

Source:https://chrisbrejon.com/cg-cinematography/chapter-1-5-academy-color-encoding-system-aces/

上記の最初の3行は、Rec. 709、Mitsuba、およびRec. 2020が同じターゲットに対するレンダリング結果です。最後の2行は、MitsubaからRec. 709とRec. 2020を差し引いた差です。色が濃いほど、差が小さいほど、結果がground truthに近く、より正確であることを意味します。Rec. 2020の全体的なパフォーマンスは、スペクトルレンダリングの結果に近いことがわかりますが、場合によっては、Rec. 709のパフォーマンスが実際に優れていることもわかります。実際、まだ胸を叩いて、コンピューターのレンダリングに最適な色空間があるとは言えませんが、ThomasMansencalは次のように述べています。

Some RGB colourspaces have gamuts that are better suited for CG rendering and will get results that overall will be closer to a ground truth full spectral rendering. ACEScg / BT.2020 have been shown to produce more faithful results in that regard.

—— From this article

以前の研究では、三原色がスペクトル軌跡に近い色域空間のレンダリング結果は、スペクトルレンダリングの正しい結果に近いことが多いことが示されています。ACEScgはそのような色空間であり、その三原色AP1はスペクトル軌跡の近くにあり、且つRec. 2020およびその他の一般的な広色域空間が含まれているため、CGやVFXなどのコンピューターレンダリングのワークスペースとして理想的です。

 

10年以上前は、sRGBとRec. 709が業界で最も一般的な規格でしたが、技術の進歩に伴い、Rec. 2020などのHDR広色域色規格が普及しており、古いSDR色域空間は、いつか歴史の舞台から撤退するのも早晩のことといえます。AP0とAP1のこれらの特性により、将来、広い色域を持つ新しい色空間がさらに提案されたとしても、それらは非常に強力な互換性を持ち、短期間で歴史によって排除されることはありません。これは、ACESの強度システムも反映しています。


 

##色変換

 

ACESはまた、映画やテレビの制作のすべての段階で、完全で強力な色変換のセットを定義しています。これらの変換には次のものが含まれます。

(1) Input Transform:Input Device Transform(IDT)とも呼ばれていました。 ACES 1.0の正式名称は、ACES Input Transform、または略してInputTransformです。入力データをscene-referred色空間に変換する役割を果たします。たとえば、別の撮影デバイスで撮影された写真は、独自のIDTを使用して変換する必要があります。

(2)Look Transform:Look Modification Transform(LMT)とも呼ばれていました。 ACES 1.0の正式名称は、ACES Look Transform、または略してLookTransformです。 LMTは、正式なカラーグレーディングステップの前に全体的な画像の外観の変換を提供します。その入力スペースと出力スペースは同じです。このような変換が別々に抽出される理由は、フィルムとテレビのプロセスを使用するためです。

(3)Output Transform:RRT(Reference Rendering Transform) + ODT(Output Device Transform)とも呼ばれ、ACES Viewing Transformです。ACES 1.0の正式名称は、ACES Output Transform、または略してOutputTransformです。その中で、RRTは画像をscene-referred空間からoutput-referred空間に変換する責任があり、ODTはRRTの結果を特定の出力デバイスの色空間に変換し続ける責任があります。 RRT + ODTは、scene-referred画像を特定のディスプレイデバイスに完全にレンダリングする変換操作であるため、Viewing Transform/Output Transformと呼ばれます。

 

映画やテレビの制作の分野では、IDTはさまざまなカメラ機器メーカーから提供されているという点で特別です。RED、Alexa、Canon、Panasonic、Sony、およびその他の主要メーカーには、独自の色空間とコーディング標準があります。ACESワークフローでは、これらのメーカーは自分の「レシピ」を公開する必要はなく、SMPTEのACES標準に従って独自のIDTを作成して、その画像データをACES色空間に均一に変換することだけで十分です。これにより、映画やテレビの制作プロセスにおける入力データの不確実性が排除され、これはACESの魅力なところといえます。もちろん、ゲームレンダリングでは、通常、IDT はsRGB画像をガンマ空間から線形空間に変換するところに使用されます。

 

LMTは、ユーザー定義のLUT変換ステージであり、その入力コントロールはscene-referredの線形シーン空間です。その機能は調色と混同されやすいです。画像の領域ごとに異なる種類のカラー操作を必要とする調色とは異なり、LMTは画像全体を変更し、「調子を設定する」役割を果たす変換操作です。それが特定の変換に分離される理由は、全体的な画像操作の一部がより複雑であり、LMTは映画やテレビのさまざまな制作パイプライン間で共有されるそのようなLUTアプローチを提供するためです。ゲームのレンダリングでは、LMTの存在は比較的薄いといえます。

 

RRTはACES委員会によって開発されたものであり、その出典は「調色されていない画像をどのように見せたいか」という質問として理解できます。ACESはこの質問に答えるために多数の業界専門家を集め、最終的にこのRRT変換を取得しました。その特定の実装は、githubでACESによって提供されたCTL実装バージョンを参照できます。ODTの特定の定義も同様です。ODTとRRTの定義には特定の主観的な要素があり、これらの業界の専門家が各ディスプレイで画像を最良の結果として表示する方法を考える方法の変化であることがわかります。ゲームレンダリングの分野では、ほとんどの場合、sRGBおよびRec. 709のODTを扱います。これらのODTには、画像を視覚的に「より良く」するためのトーンマッピングのような操作が含まれています。業界で最も目の肥えた多くの目によって検証されており、簡単に変更するべきではありません。 RRT + ODTを直接変更するのではなく、事前に調色して画像の外観を実現する必要があります。

 

ACES 1.0では、RRTとODTは2つの独立したステージであり、それぞれにTone Scale操作があります(特定の実装については、githubにあるRRTソースコードODTソースコードのセクションを参照してください)。

このTwo Stage Tone Scaleモードは非常に紛らわしく、実装はあまり直感的ではありません。これは、HDR Output Device Transformに関連する標準を策定するのに役立ちません。 したがって、ACES委員会はACES ODT改善計画を提案し、代替として統一されたSingle Stage Tone Scale(SSTS)アルゴリズムを使用することを選択しました。 統合プロセスパイプラインは次のとおりです。

新しいOutput Transformの実装から、元のRRTステージで色の計算を保持し、SSTS曲線を使用してTonemapping操作を完了することがわかります。 ネーミングでは、新しいOutput TransformはRRTODTをプレフィックスとして使用して、以前の個別のOutput Transform(ODT)ステージと区別します。

 

以下は、映画やテレビの分野でACESを使用する比較的完全なプロセスです。

Source: https://z-fx.nl/ColorspACES.pdf

映画やテレビの制作プロセスのCGおよびVFXステージでのACESの適用は、ゲームのレンダリングと非常に似ています。

Source: https://z-fx.nl/ColorspACES.pdf

ACESは、誰もが認める色彩管理の達者です。

 

4.3.3DCCのACES

現在、さまざまなソフトウェアでACESワークフローを使用する最も便利な方法は、OpenColorIOを使用することです。OpenColorIOは、SonyPicturesImageworksによって開発されたオープンソースの色彩管理システムです。Nuke、Fusion、MayaなどのソフトウェアはすでにOpenColorIOをサポートしています。色彩管理にOCIO構成ファイルを使用できます。最新のACES OCIOファイルはgithubにダウンロードできます。これらの構成ファイルは、画像のさまざまなACES色変換を行うのに役立ちます。

 

残念ながら、Substance Painterなどの一部のソフトウェアはまだOpenColorIOをサポートしていません(Substance Designerは2019年後半にサポートすることを発表しました)。ただし、これらのソフトウェアでは通常、色変換にカスタムLUTを使用でき、これらのソフトウェアに必要なLUT形式の特定のLUTファイルを生成できます。たとえば、Substance Painterでは、単一のLUTイメージを使用して、sRGB linearからACESsRGBディスプレイに変換できます。このLUTは、Nukeによって作成することも、コードによって直接生成することもできます。

 

Christophe Brejonは、彼の本の中で、さまざまなソフトウェアでACESを使用するプロセスとリファレンスを示しています。OpenColorIOとカスタムLUTを使用すると、基本的に、さまざまなDCCソフトウェアでの色の校正作業を満足させることができます。

 

映画やテレビの制作プロセスのACESとゲームのゲームにはまだいくつかの違いがあります。ゲームでHDR表示を実現するには、ACESプロセスにいくつかの変更を加え、ゲームの特定の開発作業を行う必要があります。次のセクションでは、他のゲームとエンジンについて見ていきます。


参考文献

  1. Digital Dragons 2018: HDR in Call of Duty
  2. https://nick-shaw.github.io/cinematiccolor/common-rgb-color-spaces.html
  3. https://nick-shaw.github.io/cinematiccolor/academy-color-encoding-system-aces.html
  4. https://nick-shaw.github.io/cinematiccolor/visual-effects-animation-and-games.html
  5. https://www.oscars.org/science-technology/aces/aces-documentation
  6. https://chrisbrejon.com/cg-cinematography/chapter-1-5-academy-color-encoding-system-aces/
  7. https://github.com/ampas/aces-dev/

UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com