什么是DDC?
可以直接看Unreal的官方文档。
https://docs.unrealengine.com/en-US/Engine/Basics/DerivedDataCache/index.html
为何要局部清理DDC
在我们将Shader修改之后,如果不对DDC进行清理的话会产生Shader找不到的Crash。
所以我们在Shader修改之后都会清理一下DDC。但是如果我们将全部DDC进行清理的话打包时间会远远超出我们的预期,所以我们需要进行局部清理DDC。
快速找到问题解决点
我们可以先观察DDC目录下的文件:
我们可以发现DDC目录文件的一个特点:
有固定的前缀,我们可以搜索这些前缀所在的位置,例如MATSM
我们发现以下代码:
static FString GetMaterialShaderMapKeyString(const FMaterialShaderMapId& ShaderMapId, EShaderPlatform Platform)
{
FName Format = LegacyShaderPlatformToShaderFormat(Platform);
FString ShaderMapKeyString = Format.ToString() + TEXT("_") + FString(FString::FromInt(GetTargetPlatformManagerRef().ShaderFormatVersion(Format))) + TEXT("_");
ShaderMapAppendKeyString(Platform, ShaderMapKeyString);
ShaderMapId.AppendKeyString(ShaderMapKeyString);
FMaterialAttributeDefinitionMap::AppendDDCKeyString(ShaderMapKeyString);
return FDerivedDataCacheInterface::BuildCacheKey(TEXT("MATSM"), MATERIALSHADERMAP_DERIVEDDATA_VER, *ShaderMapKeyString);
}
所有的DDC文件都通过BuildCacheKey进行文件名生成,根据这个特征,我们可以全局搜索BuildCacheKey的位置,我们可以看到,清理DDC完全是为了弃用旧Cache使用新Cache而对Key进行拼写的。所以Key拼写的方式意味着资源修改的关联性。
DDC前缀:
NiagaraShaderMap
FDerivedDataCacheInterface::BuildCacheKey(TEXT("NIAGARASM"),
NIAGARASHADERMAP_DERIVEDDATA_VER,
*ShaderMapKeyString);
FlattenMaterial
FDerivedDataCacheInterface::BuildCacheKey(
TEXT("FLT_MTL"),
*FString::Printf(TEXT("%s_%s"), *HashedShaderMapKey, FLATTEN_MATERIAL_VER),
TEXT(""));
ReflectionCaptureEncodedHDR
FDerivedDataCacheInterface::BuildCacheKey(
TEXT("REFL_ENC"),
*ReflectionCaptureDDCVer.ToString(),
*StateId.ToString().Append("_").Append(FString::FromInt(CubemapDimension)).Append("_").Append(FString::FromInt(REFLECTIONCAPTURE_ENCODED_DERIVEDDATA_VER))
);
MaterialShaderMap
FDerivedDataCacheInterface::BuildCacheKey(TEXT("MATSM"),
MATERIALSHADERMAP_DERIVEDDATA_VER,
*ShaderMapKeyString);
SubUV
FDerivedDataCacheInterface::BuildCacheKey(TEXT("SUBUV_"),
SUBUV_DERIVEDDATA_VER,
*KeyString);
GlobalShaderMap
FDerivedDataCacheInterface::BuildCacheKey(TEXT("GSM"),
GLOBALSHADERMAP_DERIVEDDATA_VER,
*ShaderMapKeyString);
StreamedAudio
FDerivedDataCacheInterface::BuildCacheKey(
TEXT("STREAMEDAUDIO"),
STREAMEDAUDIO_DERIVEDDATA_VER,
*KeySuffix
);
DistanceField
FDerivedDataCacheInterface::BuildCacheKey(
TEXT("DIST"),
*FString::Printf(TEXT("%s_%s%s%s%s%s%s"), *InMeshKey, DISTANCEFIELD_DERIVEDDATA_VER, *PerMeshMaxString, *VoxelDensityString, *CompressString, *FormatString, *EmbreeString),
TEXT(""));
StaticMesh
FDerivedDataCacheInterface::BuildCacheKey(
TEXT("STATICMESH"),
*GetStaticMeshDerivedDataVersion(),
*KeySuffix
);
Texture
//Texture
FDerivedDataCacheInterface::BuildCacheKey(
TEXT("TEXTURE"),
TEXTURE_DERIVEDDATA_VER,
*KeySuffix
);
//Mipmap
FDerivedDataCacheInterface::BuildCacheKey(
TEXT("TEXTURE"),
TEXTURE_DERIVEDDATA_VER,
*FString::Printf(TEXT("%s_MIP%u_%dx%d"), *KeySuffix, MipIndex, Mip.SizeX, Mip.SizeY)
);
LandscapeComponent
FDerivedDataCacheInterface::BuildCacheKey(TEXT("LS_FULL"),
LANDSCAPE_FULL_DERIVEDDATA_VER,
*StateId.ToString());
HF
FDerivedDataCacheInterface::BuildCacheKey(*KeyPrefix,
LANDSCAPE_COLLISION_DERIVEDDATA_VER,
*CombinedStateId.ToString());
ShaderCode
FDerivedDataCacheInterface::BuildCacheKey(
*(FString("Dict") + LibraryName + FormatName.ToString()),
SHADER_COMPRESS_USING_DICT_VERSION, TEXT("Dict"));
FDerivedDataCacheInterface::BuildCacheKey(
*(FString("Dict") + DictHash.ToString()),
SHADER_COMPRESS_USING_DICT_VERSION, *(Pair.Key.ToString() + ShaderName));
解决Shader修改之后清理DDC的问题
我们只需要找到在拼写BuildKey时包含Shader相关字段的DDC文件,并且进行清理即可。
只要清理对应文件即可。
后续优化
实际上Shader在修改之后会产生崩溃的问题是本身需要我们去进行解决的问题。如果能找到shader修改之后DDC未修改的原因,我们可以完全避免清理DDC。