Dynamic Materials doesn't work after calling SetMaterial()

Hello!

Dynamic materials work perfectly as long as I create them in PostInitializeComponents or in the constructor. But if I at some point try to execute the same bit of code during gameplay it stops working.

Here’s what I have:

void AWBaseCharacter::PostInitializeComponents()
{
	Super::PostInitializeComponents();
	ReCreateDynamicMaterials();
}

void AWBaseCharacter::ReCreateDynamicMaterials()
{
	USkeletalMeshComponent* mesh = GetMesh();
	for (int32 i = 0; i < mesh->GetNumMaterials(); ++i)
	{
		mesh->CreateAndSetMaterialInstanceDynamic(i);
	}
}
void AWBaseCharacter::SetCharacterSkin_Multi_Implementation(const FString& aSkin)
{
	const static FString ContextString("GENERAL");
	auto rowHandle = mCharacterSkinTable->FindRow<FCharacterSkinLookupTable>(*aSkin, ContextString);
	if (!rowHandle)
	{
		UE_LOG(WLog, Log, TEXT("No character skin matching lookup: %s"), *aSkin);
		return;
	}

	auto animBluePrint = rowHandle->AnimationBlueprint;
	auto skelMesh = rowHandle->SkeletalMesh;
	auto bodyMat = rowHandle->MaterialBody;
	auto headMat = rowHandle->MaterialHead;

	GetMesh()->SetSkeletalMesh(skelMesh);
	GetMesh()->SetAnimInstanceClass(animBluePrint->GetAnimBlueprintGeneratedClass());
	GetMesh()->SetMaterial(0, headMat);
	GetMesh()->SetMaterial(1, bodyMat);
	ReCreateDynamicMaterials();
}

void AWBaseCharacter::SetCharacterColor_Multi_Implementation(int32 aTeam)
{
	USkeletalMeshComponent* mesh = GetMesh();
	for (int32 i = 0; i < mesh->GetNumMaterials(); ++i)
	{
		if (auto mat = Cast<UMaterialInstanceDynamic>(mesh->GetMaterial(i)))
		{
			mat->SetVectorParameterValue(TEXT("playerclr"), AWGameState::GetTeamColor(aTeam));
		}
	}
}

if I omitt the “GetMesh()->SetMaterial()” it works fine as it did before, but I desperately need to be able to set the materials. Any idea how to fix this?

PS: This isn’t the entire code as it would bloat the entire page, but I call SetCharacterColor_Multi elsewhere, which works fine as long as I haven’t called SetMaterial beforehand.

What is the behavior when you do that code? A little more info could help!

BTW, auto keyword can be very useful but it also is harder to understand code. I’d say not to use it like you do, but that’s only my opinion :wink:

The code I posted were only touching the relevant bits, I’ll update with the SetVectorParameter I use as well. Basically I’m trying to switch mesh, animation blueprint and materials on a character during runtime.

Solved it.

if (ParameterValue->ParameterValue != Value)
{
	ParameterValue->ParameterValue = Value;
	// Update the material instance data in the rendering thread.
	GameThread_UpdateMIParameter(this, *ParameterValue);
	CacheMaterialInstanceUniformExpressions(this);
}

this tidbit of code inside MaterialInstance.cpp made sure that my new parameter was never getting set. It compared my old value to my new one, and found no differences. I now first change the value to a random one, and then reset it to what I want it to be - this forces the material to update its’ cached parameter references.

Nice one! Will keep that in my if it ever happens to me.