UE 中默认材质初始化
UE 中如果发生材质丢失或者材质未指定时,会使用引擎初始化时创建的默认材质,下面时默认材质的创建流程:
默认材质的创建实现在UMaterialInterface::InitDefaultMaterials()
中:
class UMaterialInterface : public UObject, public IBlendableInterface, public IInterface_AssetUserData
{
/**
* Initializes all default materials.
*/
ENGINE_API static void InitDefaultMaterials();
};
实现如下:
void UMaterialInterface::InitDefaultMaterials()
{
// Note that this function will (in fact must!) be called recursively. This
// guarantees that the default materials will have been loaded and pointers
// set before any other material interface has been instantiated -- even
// one of the default materials! It is actually possible to assert that
// these materials exist in the UMaterial or UMaterialInstance constructor.
//
// The check for initialization is purely an optimization as initializing
// the default materials is only done very early in the boot process.
static bool bInitialized = false;
if (!bInitialized)
{
SCOPED_BOOT_TIMING("UMaterialInterface::InitDefaultMaterials");
check(IsInGameThread());
if (!IsInGameThread())
{
return;
}
static int32 RecursionLevel = 0;
RecursionLevel++;
#if WITH_EDITOR
GPowerToRoughnessMaterialFunction = LoadObject< UMaterialFunction >(nullptr, TEXT("/Engine/Functions/Engine_MaterialFunctions01/Shading/PowerToRoughness.PowerToRoughness"), nullptr, LOAD_None, nullptr);
checkf( GPowerToRoughnessMaterialFunction, TEXT("Cannot load PowerToRoughness") );
GPowerToRoughnessMaterialFunction->AddToRoot();
GConvertFromDiffSpecMaterialFunction = LoadObject< UMaterialFunction >(nullptr, TEXT("/Engine/Functions/Engine_MaterialFunctions01/Shading/ConvertFromDiffSpec.ConvertFromDiffSpec"), nullptr, LOAD_None, nullptr);
checkf( GConvertFromDiffSpecMaterialFunction, TEXT("Cannot load ConvertFromDiffSpec") );
GConvertFromDiffSpecMaterialFunction->AddToRoot();
#endif
for (int32 Domain = 0; Domain < MD_MAX; ++Domain)
{
if (GDefaultMaterials[Domain] == nullptr)
{
FString ResolvedPath = ResolveIniObjectsReference(GDefaultMaterialNames[Domain]);
GDefaultMaterials[Domain] = FindObject<UMaterial>(nullptr, *ResolvedPath);
if (GDefaultMaterials[Domain] == nullptr
#if USE_EVENT_DRIVEN_ASYNC_LOAD_AT_BOOT_TIME
&& (RecursionLevel == 1 || !GEventDrivenLoaderEnabled)
#endif
)
{
GDefaultMaterials[Domain] = LoadObject<UMaterial>(nullptr, *ResolvedPath, nullptr, LOAD_DisableDependencyPreloading, nullptr);
checkf(GDefaultMaterials[Domain] != nullptr, TEXT("Cannot load default material '%s'"), GDefaultMaterialNames[Domain]);
}
if (GDefaultMaterials[Domain])
{
GDefaultMaterials[Domain]->AddToRoot();
}
}
}
RecursionLevel--;
#if USE_EVENT_DRIVEN_ASYNC_LOAD_AT_BOOT_TIME
bInitialized = !GEventDrivenLoaderEnabled || RecursionLevel == 0;
#else
bInitialized = true;
#endif
}
}
其中EMaterialDomain
定义如下,
/** Defines the domain of a material. */
UENUM()
enum EMaterialDomain
{
/** The material's attributes describe a 3d surface. */
MD_Surface UMETA(DisplayName = "Surface"),
/** The material's attributes describe a deferred decal, and will be mapped onto the decal's frustum. */
MD_DeferredDecal UMETA(DisplayName = "Deferred Decal"),
/** The material's attributes describe a light's distribution. */
MD_LightFunction UMETA(DisplayName = "Light Function"),
/** The material's attributes describe a 3d volume. */
MD_Volume UMETA(DisplayName = "Volume"),
/** The material will be used in a custom post process pass. */
MD_PostProcess UMETA(DisplayName = "Post Process"),
/** The material will be used for UMG or Slate UI */
MD_UI UMETA(DisplayName = "User Interface"),
/** The material will be used for runtime virtual texture (Deprecated). */
MD_RuntimeVirtualTexture UMETA(Hidden),
MD_MAX
};
在下面的这个循环中,遍历Material 的 所有的Domain,对不同类型的默认材质进行初始化
for (int32 Domain = 0; Domain < MD_MAX; ++Domain)
然后从GDefaultMaterialNames
取得默认材质的指定路径,GDefaultMaterialNames
定义如下
static const TCHAR* GDefaultMaterialNames[MD_MAX] =
{
// Surface
TEXT("engine-ini:/Script/Engine.Engine.DefaultMaterialName"),
// Deferred Decal
TEXT("engine-ini:/Script/Engine.Engine.DefaultDeferredDecalMaterialName"),
// Light Function
TEXT("engine-ini:/Script/Engine.Engine.DefaultLightFunctionMaterialName"),
// Volume
//@todo - get a real MD_Volume default material
TEXT("engine-ini:/Script/Engine.Engine.DefaultMaterialName"),
// Post Process
TEXT("engine-ini:/Script/Engine.Engine.DefaultPostProcessMaterialName"),
// User Interface
TEXT("engine-ini:/Script/Engine.Engine.DefaultMaterialName"),
// Virtual Texture
TEXT("engine-ini:/Script/Engine.Engine.DefaultMaterialName")
};
最后从指定路径中导入默认材质,并做AddToRoot
操作防止垃圾回收。
默认材质什么时候初始化需要进行断点查看,如果不使用默认材质,应该会考虑到节约内存而延迟加载的情况。