目前项目中由于 cook 生成的 *.ushaderbytecode 文件体积过大,对于某些低端机不是非常友好,所以希望将低端机使用的 shadercode 单独拆分出来形成更小的 ushaderbytecode 文件。
但是我目前将 ushaderbytecode 中的 shadercode 按照 material quality 拆分之后,会发现加载 shadermap 时有shader 不完整的情况,从而导致渲染读取 shadercode 的时候会报错。
目前我这边看到 unreal engine 对于 shadercode 的组织形式是以 shadermap 为单位进行区分的,我必须保证一个 shadermap 下包含完整的 shadercode 才能在加载的时候正确创建 shadermap,
这就导致我没有办法单独把某个 material quality 的 shadercode 单独保存出来。也就解决不了低端机的 ushaderbytecode 文件过大加载过慢的问题。
所以想知道现有或者未来版本的 unreal engine 有没有什么机制能够按照 material quality 拆分 ushaderbytecode 文件呢?
下面是拆分的具体方法的说明:
`static bool SpliteShaderCodeWithQuality(
FName& FormatName,
const FString& LibraryName,
const FString& LibraryDir,
const FString& OutputDir,
const FShaderToQualityMap& ShaderToQualityMap,
bool bNeedsDeterministicOrder)
{
// load old library
FEditorShaderCodeArchive* OldLibrary = new FEditorShaderCodeArchive(FormatName, bNeedsDeterministicOrder, false);
OldLibrary->OpenLibrary(LibraryName);
if (!OldLibrary->LoadExistingShaderCodeLibrary(LibraryDir, false))
{
return false;
}
OldLibrary->LoadExistingShaderAssetInfo(LibraryDir);
TSet allShaderHashSet;
OldLibrary->GetShaderSet(allShaderHashSet);
// create new library
FEditorShaderCodeArchive VeryLowQualityLibrary(FormatName, false);
FString VeryLowQualityLibraryName = LibraryName + “_VeryLow”;
VeryLowQualityLibrary.OpenLibrary(VeryLowQualityLibraryName);
// create new library
FEditorShaderCodeArchive HighQualityLibrary(FormatName, false);
FString HighQualityLibraryName = LibraryName + “_High”;
HighQualityLibrary.OpenLibrary(HighQualityLibraryName);
for (int OtherShaderMapIndex = 0; OtherShaderMapIndex < OldLibrary->SerializedShaders.ShaderMapHashes.Num(); ++OtherShaderMapIndex)
{
const FShaderMapEntry& PrevShaderMapEntry = OldLibrary->SerializedShaders.ShaderMapEntries[OtherShaderMapIndex];
FSHAHash MapHash = OldLibrary->SerializedShaders.ShaderMapHashes[OtherShaderMapIndex];
FString StrMapHash = MapHash.ToString();
StrMapHash.ToUpper();
TSet AllQuality;
TArray VeryLowShaderIndices;
TArray HighShaderIndices;
TArray NumShaderIndices;
for (uint32 i = 0; i < PrevShaderMapEntry.NumShaders; ++i)
{
const int32 OtherShaderIndex = OldLibrary->SerializedShaders.ShaderIndices[PrevShaderMapEntry.ShaderIndicesOffset + i];
const FSHAHash& ShaderHash = OldLibrary->SerializedShaders.ShaderHashes[OtherShaderIndex];
uint8 QualityFlags = 0;
if (const uint8* pFindQualityFlags = ShaderToQualityMap.Find(ShaderHash))
{
QualityFlags = *pFindQualityFlags;
AllQuality.Add(QualityFlags);
}
else
{
continue;
}
if (QualityFlags & (1 << 4)) // EMaterialQualityLevel::VeryLow
{
VeryLowShaderIndices.Add(i);
}
if (QualityFlags & (1 << 6)) // EMaterialQualityLevel::Num
{
NumShaderIndices.Add(i);
}
if (QualityFlags & 0xAF) // Except VeryLow and Num;
{
HighShaderIndices.Add(i);
}
}
if (VeryLowShaderIndices.Num() > 0)
{
VeryLowQualityLibrary.AddShaderCode(OtherShaderMapIndex, *OldLibrary);
}
if (HighShaderIndices.Num() > 0)
{
HighQualityLibrary.AddShaderCode(OtherShaderMapIndex, *OldLibrary);
}
}
VeryLowQualityLibrary.Finalize(OutputDir, “”, false);
HighQualityLibrary.Finalize(OutputDir, “”, false);
return true;
}`