Dynamic Material Instance inconsistent behavior

Hi there, I’m coming from unity so it’s possible that I am simply missing something simple, as a checkbox.

In my setup I have 4 materials, applied to three meshes. I create dynamic instances, and assign color. Two of those material instances, both belonging to mesh A are behaving consistently for client and server. Two others, belonging to mesh B and mesh C have a variety of strange behavior:

I am unable to assign them properly, after creation using :

BaseMaterial = BipedBody->GetMaterial(0);
BaseMaterialInstance = UMaterialInstanceDynamic::Create(BaseMaterial, this);
BipedBody->SetMaterial(0, BaseMaterialInstance);

the parent material in created material instance is null. If I create them using:

	BaseMaterialInstance = BipedBody->CreateAndSetMaterialInstanceDynamicFromMaterial(0, BipedBody->GetMaterial(0));

They are fine, for the local player, and If I create them with:

BipedBody->SetMaterial(0, nullptr);  
BaseMaterial = BipedBody->GetMaterial(0);
BaseMaterialInstance = UMaterialInstanceDynamic::Create(BaseMaterial, this);
BipedBody->SetMaterial(0, BaseMaterialInstance);

They are also fine.

Also, I replicate the colors for all of these materials. I do not think my replication logic is wrong, as I am able to get it to work correctly on the two materials from mesh A, but the two problematic, from mesh B and C, are just very strange - they are correct on Listen Server, consistent with clients, client A only sees itself in the correct color, and client B only sees itself and client A in correct color, but not the listen server. However, the mesh A have all correct colors assigned on all clients and server.
Since material shows the correct color always in some case, I don’t think it’s the fault of the material setup, and since the code is the same for all, I don’t think it’s a code issue? That would leave the mesh, but that seems strange?

Full Implementation, and I call GenerateRandomColors in BeginPlay:

void ABipedPawn::GenerateRandomColors()
{
	if (!IsLocallyControlled())return;
	ServerGenerateRandomColors();
}

void ABipedPawn::ServerGenerateRandomColors_Implementation()
{	
		float r = FMath::RandRange(0, 100) / 100.f;
		float g = FMath::RandRange(0, 100) / 100.f;
		float b = FMath::RandRange(0, 100) / 100.f;

		float Hr = FMath::RandRange(0, 100) / 100.f;
		float Hg = FMath::RandRange(0, 100) / 100.f;
		float Hb = b * 1.3f;

		ReplicatedColors.Main = FLinearColor(r, g, b);
		ReplicatedColors.Highlight = FLinearColor(Hr, Hg, Hb);

		CreateMaterialInstances();
		ApplyColors();

	 
}
void ABipedPawn::OnRep_ColorChange()
{
	CreateMaterialInstances();
	if (BaseFeatherMaterialInstance == nullptr || BaseMaterialInstance == nullptr || WingPlaneMaterialInstance == nullptr || WingFeatherMaterialInstance == nullptr)
	{
		return;
	}
	ApplyColors();
}
void ABipedPawn::ApplyColors()
{
	FVector4 HCol = FVector4(ReplicatedColors.Highlight.R, ReplicatedColors.Highlight.G, ReplicatedColors.Highlight.B, 1.0f);
	BaseFeatherMaterialInstance->SetVectorParameterValue(FName("HighlightColor"), HCol);
	BaseMaterialInstance->SetVectorParameterValue(FName("HighlightColor"), HCol);
	WingPlaneMaterialInstance->SetVectorParameterValue(FName("HighlightColor"), HCol);
	WingFeatherMaterialInstance->SetVectorParameterValue(FName("HighlightColor"), HCol);

	FVector4 MCol = FVector4(ReplicatedColors.Main.R, ReplicatedColors.Main.G, ReplicatedColors.Main.B, 1.0f);
	BaseFeatherMaterialInstance->SetVectorParameterValue(FName("BaseColor"), MCol);
	BaseMaterialInstance->SetVectorParameterValue(FName("BaseColor"), MCol);
	WingPlaneMaterialInstance->SetVectorParameterValue(FName("BaseColor"), MCol);
	WingFeatherMaterialInstance->SetVectorParameterValue(FName("BaseColor"), MCol); 
}
void ABipedPawn::CreateMaterialInstances()
{	 
 	if (WingFeatherMaterialInstance == nullptr)
	{	 
		WingFeatherMaterialInstance = BipedWings->CreateAndSetMaterialInstanceDynamicFromMaterial(0, BipedWings->GetMaterial(0));
	}
	if (WingPlaneMaterialInstance == nullptr)
	{	 
		WingPlaneMaterialInstance = BipedWings->CreateAndSetMaterialInstanceDynamicFromMaterial(1, BipedWings->GetMaterial(1));
	}
	if (BaseMaterialInstance == nullptr)
	{ 
		BaseMaterialInstance = BipedBody->CreateAndSetMaterialInstanceDynamicFromMaterial(0, BipedBody->GetMaterial(0));
	}
	if (BaseFeatherMaterialInstance == nullptr)
	{	 
		BaseFeatherMaterialInstance = BipedFur->CreateAndSetMaterialInstanceDynamicFromMaterial(0, BipedFur->GetMaterial(0));
	}
}

There was a reported bug with player colors not working as intended - you should search for that.

It isn’t the first time I hear of it, but it is the first time I see it with c++ code. Which is odd - these bugs are generally due to blueprint.

Anyway, try having a look :wink:

Thank you! I will search for it.

I have to say I have also discovered that the material instance on that mesh on simulated proxy is different than the material instance I create and edit colors of, and if I simply reapply the material a bit later, it works as expected - which could point to material instance being applied somewhere in between, which would naturally be my dumb mistake. Although atm I can’t find it, I think it’s much more likely than an engine bug

Update:
If I apply the offending material instances, either anytime before, or after they are created and assigned, it works - so in BeginPlay:

BipedBody->SetMaterial(0, BaseMaterialInstance);
BipedFur->SetMaterial(0, BaseFeatherMaterialInstance);

GenerateRandomColors();

I have no idea why, so I’m reluctant to mark this post as answered, but maybe it helps someone with a similar issue later.

I think it may go back to the bug issue?

Either way, it is unusual to create and assign right away.

The proper pathway would be create, store, change a variable on it, then apply.

If values are meant to change at runtime then it wouldn’t matter when values are changed - if at all - in that process.

But the point of using the material pathway is that you are able to store and manipulate the material via code more so than you can by other means (material parameter collection or just instances).

That said - if the engine is bugged and you can’t fix it, just define the color(s) inside of an MPC. The downside is you need a different material for each different player or some other idea behind how it should work.