Create a material instance

I’ve created an importer for the editor in to load a custom 3D model format.
When loading the model I would like to apply materials based on a template material graph I prepared.

When I create a material instance from my template graph does the instance need to be dynamic? I don’t want to change anything in the material at play time, just at editing time in the editor.

Currently I am trying to use a dynamic instance but it doesn’t look right:
When I create an instance of my graph manually from the editor, everything looks fine with all the parameter groups and values set correctly.
When I create a “dynamic material instance” programmatically and apply it to the object I cannot query the default parameters and the groups are not created
UMaterial *parentMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Game/Materials/myMaterialTemplate"));
UMaterialInstanceDynamic *unrealMat = UMaterialInstanceDynamic::Create(parentMaterial, nullptr);
//set parameters from loaded model file

What should I do to achieve the same result I get when creating an instance manually in the editor?


In this case you should be able to use UMaterialInstanceConstant. It serves exactly this purpose, being able to modify parameters in the editor only but not during play time. The Set*ParameterValue functions have an EditorOnly suffix. These functions have an additional warning: “You MUST call PostEditChange afterwards to propagate changes to other materials in the chain!”

thank you! this makes sense.

do you have any sample code to show how to create a UMaterialInstanceConstant from a parent material asset?

The “Create Material Instance” menu item when you right-click another material is implemented like this in FAssetTypeActions_MaterialInterface::ExecuteNewMic so you should probably be able to apply the same process in your case. The “InitialParent” of the UMaterialInstanceConstantFactoryNew is what will be set as the parent material asset of the created UMaterialInstanceConstant.

if ( Objects.Num() == 1 )
	auto Object = Objects[0].Get();

	if ( Object )
		// Create an appropriate and unique name 
		FString Name;
		FString PackageName;
		CreateUniqueAssetName(Object->GetOutermost()->GetName(), DefaultSuffix, PackageName, Name);

		UMaterialInstanceConstantFactoryNew* Factory = NewObject<UMaterialInstanceConstantFactoryNew>();
		Factory->InitialParent = Object;

		FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
		ContentBrowserModule.Get().CreateNewAsset(Name, FPackageName::GetLongPackagePath(PackageName), UMaterialInstanceConstant::StaticClass(), Factory);
	// ... code when multiple Materials are selected ...