Setting Dynamic Material Instance for Skeletal/Static meshes using C++?

Could you please paste your updated code?

1 Like
	static ConstructorHelpers::FObjectFinder<UMaterialInterface> MaterialSource(TEXT("/Game/Assets/Characters/FCharacter/Char_01/DynMaterials/DM_FH_01"));
	ReturnDynamicMaterial = UMaterialInstanceDynamic::Create(MaterialSource.Object, this);
	//if (MaterialSource.Object == nullptr)  return;
	//{
	//	GetMesh()->SetMaterialByName("F_Head_01_A", ReturnDynamicMaterial);
	//}

	if (MaterialSource.Succeeded())
	{
		int MatIndex = GetMesh()->GetMaterialIndex("F_Head_01_A");
		GetMesh()->SetMaterial(MatIndex, ReturnDynamicMaterial);
	}

I googled a bit, try to change ReturnDynamicMaterial = UMaterialInstanceDynamic::Create(MaterialSource.Object, this); to ReturnDynamicMaterial = UMaterialInstanceDynamic::Create(MaterialSource.Object, GetWorld()); (change second parameter, maybe InOuter parameter means world context, not actor).

1 Like

image_2022-05-09_023526703
it runs compiled successfully, but the material is not effecting the head

I suggest you leave it as is was, comment every line, and start testing one by one compiling until you get to the crash.

This is working for me:

void ADynamicMatTest::SetDynamicMat()
{
	static ConstructorHelpers::FObjectFinder<UMaterialInterface>Material(
		TEXT("/Game/Blueprints/Misc/M_ToCreateInstance.M_ToCreateInstance")
	);
	UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(
		Material.Object, 
		this,
		FName("M_CreatedInstance")
	);

	if (Material.Succeeded())
	{
		StaticMesh->SetMaterial(0, DynamicMaterial);
	}
}

Your problem could easily be a bad path to the material.

2 Likes

This works fine, but it deletes the base material didn’t override it, But the main thing is we found an internal engine bug, we can’t set material by name using C++, and setting it by blueprint working fine as I shown in the image.

Thank You very mush for helping and Solving this Issue. Sir thank You very very much. I was struggling with this from 3 days.
The above solutions from mnelenpridumivat should also work logically but because of the engine bug they don’t work.

image_2022-05-09_025314919
Perfectly working.

1 Like

ik it’s marked as solved, just wanted to share these… they also work:

void ADynamicMatTest::GetMaterialFromPath(FString MatPath) // Use in Constructor
{
	const TCHAR* Dir = *MatPath;
	// Find existing material
	static ConstructorHelpers::FObjectFinder<UMaterial>NewMaterial(Dir);

	// Store in UMaterial* variable
	if (NewMaterial.Succeeded())
	{
		MyMaterial = NewMaterial.Object;
	}
}

void ADynamicMatTest::CreateAndApplyNewDynMatInst(
	UMaterial* Mat, 
	UStaticMeshComponent* Mesh,
	FName SlotName,
	FName DynInstName
) // Use in or after BeginPlay
{
	// Check for nullptr
	check(Mat);
	check(Mesh);

	// Create dynamic material instance
	UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(
		Mat,
		this,
		DynInstName
	);

	// Search material slot by name
	int MatIndex = Mesh->GetMaterialIndex(SlotName); // 0

	// Check for valid slot
	if(MatIndex != -1)
	{
		// Apply material at index
		Mesh->SetMaterial(MatIndex, DynamicMaterial);
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("SlotName not found."));
	}
}

void ADynamicMatTest::CreateAndApplyNewDynMatInst(
	UMaterial* Mat,
	UStaticMeshComponent* Mesh,
	int MatIndex,
	FName DynInstName
) // Use in or after BeginPlay
{
	// Check for nullptr
	check(Mat);
	check(Mesh);

	if (MatIndex >= Mesh->GetMaterialSlotNames().Num())
	{
		UE_LOG(LogTemp, Error, TEXT("MatIndex out of scope."));
		return;
	}

	// Create dynamic material instance
	UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(
		Mat,
		this,
		DynInstName
	);

	// Apply material at index
	Mesh->SetMaterial(MatIndex, DynamicMaterial);
}
1 Like

Sir , Thank You very much for this, I saved it in my disk in a text document, in the near time I will working on a big workflow with materials and I will post many problems , I hope You will look into them. Thank You very much for these Solutions.

Sir, For some reasons the materials is not working from today again, I didn’t modify the code and everything is the same as before… I don’t know what is the reason. The game compiles and logs ā€œthe material found successfullyā€ but not effecting the head.

Could you share both .h and .cpp?

Sure, I will share them now in a minute

MyCharacter.h (12.5 KB)
MyCharacter.cpp (25.3 KB)

The Function InitSkeletalMesh is responsible to set materials.

Don’t see anything wrong with that specifically and its not giving you any errors… my old project is also having same issue… :rofl:

Found a quick solution though. You could implement this and run the function there: AActor::OnConstruction | Unreal Engine Documentation

Tested and it works.

From Actor.h:

/**
	 * Called when an instance of this class is placed (in editor) or spawned.
	 * @param	Transform			The transform the actor was constructed at.
	 */
	virtual void OnConstruction(const FTransform& Transform) {}

1 Like

and when I implement the initskeletalmeash using blueprint, everything works fine… the same way calling it under constructor using blueprints.
There is some difference between the constructor of blueprints and C++.
I think this is because the blueprint constructor is running after the editor starts and the c++ constructor is running before the editor starts. :smiley:

1 Like

This :point_up_2:.

1 Like

I tried to make the function blueprintcallable to call it under blueprint constructor, but the editor crashed on this approach.

Changing this to NULL (Material_H.Object, NULL, FName("Material_Instance")); works and I have no Idea what is going on but I am sure at some point it will also stop working as before you know the situation … already my head is burning :frowning: … looking like the situation is forcing me to build the game with blueprints…