SubstrateToonマテリアルが正しくロードされないことがある

この問題をしばらく追っていましたが、ほぼ原因と再現方法が掴めたのでご報告します。

HLSLMaterialTranslator.cppを詳しく見ると、マテリアルがロードされたあとにPostLoadからマテリアルのTranslateが行われ、マテリアルのセットアップとシェーダーコードが用意されます。

EHLSLMaterialTranslatorResult FHLSLMaterialTranslator::Translate(bool bForceDisableDDCQuery)<br/>

の中で

// Asynchronously query the DDC for results
if (!bForceDisableDDCQuery && !bDisableTranslationDDC)
{
    AsyncQueryDDC(DDCRequestOwner, EnvironmentDefinesBuffer);
}
 
// Synchronously begin translating the material
{
    SCOPE_SECONDS_COUNTER(TranslationOnlyTime);
    TranslateMaterial();
}
 
// One of the two has terminated. This will be a NOOP if DDC query task has completed.
DDCRequestOwner.Cancel();

<br/>

この部分で、AsyncQueryDDCでマテリアルをDDCから取得しつつ、TranslateMaterialでマテリアルのTranslateを実行。DDCRequestOwner.Cancel()でDDC取得をキャンセルという流れで実行されています。これはDDC取得がTranslateMaterialより時間がかかっていたらキャンセルして、終了していたら取得されたDDCからTranslateを行うという処理のようです。

<br/>

問題は、DDCから取得された場合とTranslateMaterialの結果を使う場合で処理が違うことにあると思います。

DDC取得が成功した場合は

// If we've hit the cache, deserialize the buffer read from the DDC into mater  ial translation results.
if (DDCQueryHit)
{

の処理に進みますが、こちらの処理でSubstrateTranslatorDataを構築する際にSubstrateMaterialBsdfFeaturesが設定されずNoneのままシェーダーのコンパイルが行われます。

DDCから取得しなかった場合は

else if (TranslationResult == EHLSLMaterialTranslatorResult::Success)
{

こちらの処理に進みますが、こちらではSubstrateMaterialBsdfFeaturesにToonが設定されます。

<br/>

つまり、DDCからTranslateする場合とDDCを使用せずにTranslateする場合で同じ結果にならないのが問題かと思われます。

SubstrateMaterialBsdfFeaturesがNoneのままだとこの部分を通らないため、正しいマテリアルが生成されません。

if (EnumHasAnyFlags(SubstrateTranslatorData.SubstrateMaterialBsdfFeatures, ESubstrateBsdfFeature::Toon))
{
    OutEnvironment.SetDefine(TEXT("MATERIAL_SHADINGMODEL_TOON"), TEXT("1"));
}

<br/>

結果、GBufferにToonProfileIDなどが書き込まれないシェーダーになっているようです。

<br/>

この問題は起動オプションに -nomaterialtranslationddc を指定することでDDCからのTranslateを無効化して回避することができますが、通常状態ではDDCからの取得時間がTranslateより長いか短いかで不具合が発生することになっているのではと推察します。高速なPCほど発生しにくく気づきにくいのでは無いでしょうか。

再現手順がアップロードされてないみたいなので以下に追記します。

  1. ToonBSDFをFrontMaterialに接続したマテリアルを作成し、ToonProfileを追加してToonProfileIDが0より大きくなるようにしておく
  2. 上記マテリアルを使用したプリミティブをレベルに配置する
  3. レベルを保存する​
  4. エディタを終了する​
  5. EHLSLMaterialTranslatorResult FHLSLMaterialTranslator::Translate(bool bForceDisableDDCQuery)関数内のDDCRequestOwner.Cancel();をDDCRequestOwner.Wait();に変更する
  6. エディタを再起動する
  7. 先ほどのレベルに配置したマテリアルのToonProfileIDが0になっていることを確認する​

レポートありがとうございます。本件を UE-388460 MATERIAL_SHADINGMODEL_TOON macro is not propagated to the substrate tool BSDF material on a DDC hit としてバグ登録させていただきました。 数営業日ののちにIssuesに公開予定です。

単純なワークアラウンドとしては該当変数をコピーすることが機能しますが、潜在的に他の変数が同様に復元されていない可能性もありえるそうなので正規の修正をお待ちいただければと思います。

 		else
		{
			MaterialCompilationOutput = DDCMaterialCompilationOutput;
			// workaround : SubstrateTranslatorData.SubstrateMaterialBsdfFeatures is refenrenced in GetMaterialEnvironment
			SubstrateTranslatorData.SubstrateMaterialBsdfFeatures = MaterialCompilationOutput.SubstrateMaterialCompilationOutput.SubstrateMaterialBsdfFeatures;