DefaultMaterialName

DefaultMaterialName

#Overview

name: DefaultMaterialName

The value of this variable can be defined or overridden in .ini config files. 1 .ini config file referencing this setting variable.

It is referenced in 6 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of DefaultMaterialName is to specify the default material used by the Unreal Engine when no other material is assigned or available. This setting is primarily used in the rendering system to ensure that objects always have a valid material to render with, even if one hasn’t been explicitly set.

Based on the Callsites section, this variable is used in several Unreal Engine subsystems and modules:

  1. DatasmithCADImporter plugin
  2. CoreUObject module
  3. MeshMergeUtilities module
  4. ReplicationSystemTest program

The value of this variable is typically set in the engine configuration files (GEngineIni). In the provided code snippets, we can see it being set in test environments or mock scenarios:

GConfig->SetString(TEXT("/Script/Engine.Engine"), TEXT("DefaultMaterialName"), TEXT("/Engine/Transient.MockDefaultMaterial"), GEngineIni);

This variable interacts with other default material-related variables, such as DefaultLightFunctionMaterialName, DefaultDeferredDecalMaterialName, and DefaultPostProcessMaterialName.

Developers should be aware that:

  1. This variable is crucial for ensuring all objects have a valid material to render.
  2. Changing this value can affect the entire rendering pipeline.
  3. It’s used as a fallback in various scenarios, such as mesh merging and CAD importing.

Best practices when using this variable include:

  1. Avoid changing it unless absolutely necessary, as it can have wide-ranging effects on the engine’s rendering.
  2. When setting a custom default material, ensure it’s compatible with all potential use cases in the engine.
  3. In test environments, use a mock or transient material to avoid dependencies on actual assets.
  4. Be cautious when merging meshes or importing CAD files, as this default material may be used for undefined or empty material slots.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseEngine.ini:148, section: [/Script/Engine.Engine]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/CADInterfaces/Private/TechSoftUtils.cpp:296

Scope (from outer to inner):

file
namespace    CADLibrary
namespace    TechSoftUtils
function     void RestoreMaterials

Source code excerpt:

{
	FMaterialUId DefaultColorName = 0;
	FMaterialUId DefaultMaterialName = 0;

#ifndef CADKERNEL_DEV
	DefaultValues->TryGetNumberField(JSON_ENTRY_COLOR_NAME, DefaultColorName);
	DefaultValues->TryGetNumberField(JSON_ENTRY_MATERIAL_NAME, DefaultMaterialName);
#endif

	BodyMesh.MaterialSet.Empty();
	BodyMesh.ColorSet.Empty();

	for (FTessellationData& Tessellation : BodyMesh.Faces)

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/CADInterfaces/Private/TechSoftUtils.cpp:313

Scope (from outer to inner):

file
namespace    CADLibrary
namespace    TechSoftUtils
function     void RestoreMaterials

Source code excerpt:


		FMaterialUId ColorUId = DefaultColorName;
		FMaterialUId MaterialUId = DefaultMaterialName;

		GetMaterialValues(CachedStyleIndex, ColorUId, MaterialUId);

		if (ColorUId)
		{
			Tessellation.ColorUId = ColorUId;

#Loc: <Workspace>/Engine/Source/Developer/LowLevelTestsRunner/Private/TestCommon/CoreUObjectUtilities.cpp:65

Scope (from outer to inner):

file
function     void InitCoreUObject

Source code excerpt:

#if WITH_ENGINE && UE_LLT_WITH_MOCK_ENGINE_DEFAULTS
		GConfig->SetString(TEXT("/Script/Engine.Engine"), TEXT("AIControllerClassName"), TEXT("/Script/AIModule.AIController"), GEngineIni);
		GConfig->SetString(TEXT("/Script/Engine.Engine"), TEXT("DefaultMaterialName"), TEXT("/Engine/Transient.MockDefaultMaterial"), GEngineIni);
		GConfig->SetString(TEXT("/Script/Engine.Engine"), TEXT("DefaultLightFunctionMaterialName"), TEXT("/Engine/Transient.MockDefaultMaterial"), GEngineIni);
		GConfig->SetString(TEXT("/Script/Engine.Engine"), TEXT("DefaultDeferredDecalMaterialName"), TEXT("/Engine/Transient.MockDefaultMaterial"), GEngineIni);
		GConfig->SetString(TEXT("/Script/Engine.Engine"), TEXT("DefaultPostProcessMaterialName"), TEXT("/Engine/Transient.MockDefaultMaterial"), GEngineIni);
#endif // WITH_ENGINE && UE_LLT_WITH_MOCK_ENGINE_DEFAULTS

		FModuleManager::Get().LoadModule(TEXT("CoreUObject"));

#Loc: <Workspace>/Engine/Source/Developer/MeshMergeUtilities/Private/MeshMergeUtilities.cpp:3206

Scope (from outer to inner):

file
function     void FMeshMergeUtilities::CreateMergedRawMeshes
lambda-function

Source code excerpt:

							{
								TargetMesh.CreatePolygonGroupWithID(PolygonGroupID);
								TargetImportedMaterialSlotNames[PolygonGroupID] = SourceMesh.PolygonGroups().IsValid(PolygonGroupID) ? SourceImportedMaterialSlotNames[PolygonGroupID] : FName(TEXT("DefaultMaterialName"));
							}
							for (FPolygonGroupID SourcePolygonGroupID : SourceMesh.PolygonGroups().GetElementIDs())
							{
								RemapPolygonGroups.Add(SourcePolygonGroupID, PolygonGroupID);
							}
						}
						else
						{
							TArray<SectionRemapPair> SectionMappings;
							InDataTracker.GetMappingsForMeshLOD(FMeshLODKey(ComponentIndex, LODIndex), SectionMappings);
							for (FPolygonGroupID SourcePolygonGroupID : SourceMesh.PolygonGroups().GetElementIDs())
							{
								// First map from original section index to unique material index
								int32 UniqueIndex = INDEX_NONE;
								// then map to the output material map, if any
								if (InOutputMaterialsMap.Num() > 0)
								{
									TArray<MaterialRemapPair> MaterialMappings;
									InOutputMaterialsMap.MultiFind(FMeshLODKey(ComponentIndex, LODIndex), MaterialMappings);
									for (MaterialRemapPair& Pair : MaterialMappings)
									{
										if (Pair.Key == SourcePolygonGroupID.GetValue())
										{
											UniqueIndex = Pair.Value;
											break;
										}
									}

									// Note that at this point UniqueIndex is NOT a material index, but a unique section index!
								}
								
								if(UniqueIndex == INDEX_NONE)
								{
									UniqueIndex = SourcePolygonGroupID.GetValue();
								}
								FPolygonGroupID TargetPolygonGroupID(UniqueIndex);
								if (!TargetMesh.PolygonGroups().IsValid(TargetPolygonGroupID))
								{
									while (TargetMesh.PolygonGroups().Num() <= UniqueIndex)
									{
										TargetPolygonGroupID = TargetMesh.CreatePolygonGroup();
									}
									check(TargetPolygonGroupID.GetValue() == UniqueIndex);
									TargetImportedMaterialSlotNames[TargetPolygonGroupID] = SourceImportedMaterialSlotNames[SourcePolygonGroupID];
								}
								RemapPolygonGroups.Add(SourcePolygonGroupID, TargetPolygonGroupID);
							}
						}
					});
					AppendSettings.bMergeVertexColor = InSettings.bBakeVertexDataToMesh;
					AppendSettings.MergedAssetPivot = InMergedAssetPivot;
					for (int32 ChannelIdx = 0; ChannelIdx < FStaticMeshOperations::FAppendSettings::MAX_NUM_UV_CHANNELS; ++ChannelIdx)
					{
						AppendSettings.bMergeUVChannels[ChannelIdx] = InDataTracker.DoesUVChannelContainData(ChannelIdx, LODIndex) && InSettings.OutputUVs[ChannelIdx] == EUVOutput::OutputChannel;
					}
					FStaticMeshOperations::AppendMeshDescription(*RawMeshPtr, MergedMesh, AppendSettings);
				}
			}

			//Cleanup the empty material to avoid empty section later
			TArray<FPolygonGroupID> PolygonGroupToRemove;
			for (FPolygonGroupID PolygonGroupID : MergedMesh.PolygonGroups().GetElementIDs())
			{
				if (MergedMesh.GetPolygonGroupPolygonIDs(PolygonGroupID).Num() < 1)
				{
					PolygonGroupToRemove.Add(PolygonGroupID);

#Loc: <Workspace>/Engine/Source/Developer/MeshMergeUtilities/Private/MeshMergeUtilities.cpp:3313

Scope (from outer to inner):

file
function     void FMeshMergeUtilities::CreateMergedRawMeshes
lambda-function

Source code excerpt:

						{
							TargetMesh.CreatePolygonGroupWithID(PolygonGroupID);
							TargetImportedMaterialSlotNames[PolygonGroupID] = SourceMesh.PolygonGroups().IsValid(PolygonGroupID) ? SourceImportedMaterialSlotNames[PolygonGroupID] : FName(TEXT("DefaultMaterialName"));
						}
						for (FPolygonGroupID SourcePolygonGroupID : SourceMesh.PolygonGroups().GetElementIDs())
						{
							RemapPolygonGroups.Add(SourcePolygonGroupID, PolygonGroupID);
						}
					}
					else
					{
						TArray<SectionRemapPair> SectionMappings;
						InDataTracker.GetMappingsForMeshLOD(FMeshLODKey(ComponentIndex, LODIndex), SectionMappings);
						for (FPolygonGroupID SourcePolygonGroupID : SourceMesh.PolygonGroups().GetElementIDs())
						{
							// First map from original section index to unique material index
							int32 UniqueIndex = INDEX_NONE;
							// then map to the output material map, if any
							if (InOutputMaterialsMap.Num() > 0)
							{
								TArray<MaterialRemapPair> MaterialMappings;
								InOutputMaterialsMap.MultiFind(FMeshLODKey(ComponentIndex, LODIndex), MaterialMappings);
								for (MaterialRemapPair& Pair : MaterialMappings)
								{
									if (Pair.Key == SourcePolygonGroupID.GetValue())
									{
										UniqueIndex = Pair.Value;
										break;
									}
								}

								// Note that at this point UniqueIndex is NOT a material index, but a unique section index!
							}
							
							//Fallback
							if(UniqueIndex == INDEX_NONE)
							{
								UniqueIndex = SourcePolygonGroupID.GetValue();
							}

							FPolygonGroupID TargetPolygonGroupID(UniqueIndex);
							if (!TargetMesh.PolygonGroups().IsValid(TargetPolygonGroupID))
							{
								while (TargetMesh.PolygonGroups().Num() <= UniqueIndex)
								{
									TargetPolygonGroupID = TargetMesh.CreatePolygonGroup();
								}
								check(TargetPolygonGroupID.GetValue() == UniqueIndex);
								TargetImportedMaterialSlotNames[TargetPolygonGroupID] = SourceImportedMaterialSlotNames[SourcePolygonGroupID];
							}
							RemapPolygonGroups.Add(SourcePolygonGroupID, TargetPolygonGroupID);
						}
					}
				});
				AppendSettings.bMergeVertexColor = InSettings.bBakeVertexDataToMesh;
				AppendSettings.MergedAssetPivot = InMergedAssetPivot;
				for (int32 ChannelIdx = 0; ChannelIdx < FStaticMeshOperations::FAppendSettings::MAX_NUM_UV_CHANNELS; ++ChannelIdx)
				{
					AppendSettings.bMergeUVChannels[ChannelIdx] = InDataTracker.DoesUVChannelContainData(ChannelIdx, LODIndex) && InSettings.OutputUVs[ChannelIdx] == EUVOutput::OutputChannel;
				}
				FStaticMeshOperations::AppendMeshDescription(*RawMeshPtr, MergedMesh, AppendSettings);
			}
		}
	}
}

void FMeshMergeUtilities::MergeComponentsToInstances(const TArray<UPrimitiveComponent*>& ComponentsToMerge, UWorld* World, ULevel* Level, const FMeshInstancingSettings& InSettings, bool bActuallyMerge /*= true*/, bool bReplaceSourceActors /* = false */, FText* OutResultsText /*= nullptr*/) const
{
	auto HasInstanceVertexColors = [](UStaticMeshComponent* StaticMeshComponent)
	{
		for (const FStaticMeshComponentLODInfo& CurrentLODInfo : StaticMeshComponent->LODData)

#Loc: <Workspace>/Engine/Source/Programs/ReplicationSystemTest/Private/ReplicationSystemTest.cpp:165

Scope (from outer to inner):

file
function     static void PreInit

Source code excerpt:

	GConfig->SetInt(TEXT("/Script/Engine.GarbageCollectionSettings"), TEXT("gc.MaxObjectsNotConsideredByGC"), 0, GEngineIni);
	GConfig->SetString(TEXT("/Script/Engine.Engine"), TEXT("AIControllerClassName"), TEXT("/Script/AIModule.AIController"), GEngineIni);
	GConfig->SetString(TEXT("/Script/Engine.Engine"), TEXT("DefaultMaterialName"), TEXT("/Engine/Transient.MockDefaultMaterial"), GEngineIni);
	GConfig->SetString(TEXT("/Script/Engine.Engine"), TEXT("DefaultLightFunctionMaterialName"), TEXT("/Engine/Transient.MockDefaultMaterial"), GEngineIni);
	GConfig->SetString(TEXT("/Script/Engine.Engine"), TEXT("DefaultDeferredDecalMaterialName"), TEXT("/Engine/Transient.MockDefaultMaterial"), GEngineIni);
	GConfig->SetString(TEXT("/Script/Engine.Engine"), TEXT("DefaultPostProcessMaterialName"), TEXT("/Engine/Transient.MockDefaultMaterial"), GEngineIni);

	// Console commands
	IConsoleManager::Get().ProcessUserConsoleInput(TEXT("Net.IsPushModelEnabled 1"), *GLog, nullptr);