Change character's material at runtime using c++

I am having issues changing my character’s material at runtime using only c++. I am following the BatteryCollector tutorial and in the 14th video, we change the material depending on the character’s power level. In the video, the material change is done with blueprint, so as a challenge for myself I wanted to try it in c++. From what I understand, to change a material at run time we need to create a UMaterialInstanceDynamic and set it’s VectorParameterValue to the desired value.

Here is the function that I have that is called every Tick :

void ABatteryCollectorCharacter::PowerChangeEffect()
{
	/* Create a dynamic material instance from the character's material */
	UMaterialInstanceDynamic* DynamicMaterial = GetRootPrimitiveComponent()->CreateDynamicMaterialInstance(0, GetMesh()->GetMaterial(0));
	/* Change the color to Black */
	DynamicMaterial->SetVectorParameterValue("BodyColor", FLinearColor::Black);
}

The issue is the second line of code makes the editor crash as soon as I start the game. I am probably doing something wrong, but I can’t figure it out. (I was setting it to black just to see if it was working)

I did search quite a bit on the forums, but for this topic I find mostly blueprint answers and not much for c++ code. I would assume that it is doable in code but I am not 100% sure.

Any help would be greatly appreciated !

Thanks a lot all !

I debugged my code and found out that the CreateDynamicMaterialInstance was returning a null value, so I changed my code to this :

void ABatteryCollectorCharacter::PowerChangeEffect()
{
    /* Create a dynamic material instance from our mesh's material 0 */
    UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(GetMesh()->GetMaterial(0), this);
    /* Change color to yellow */
    DynamicMaterial->SetVectorParameterValue("BodyColor", FLinearColor::Yellow);
    /* Set the mesh's material to the new one */
    GetMesh()->SetMaterial(0, DynamicMaterial);
}

Now this seems to work, the only problem I have now is that when setting back the material (not sure if this is the best way of doing it) it seems to sometimes set it successfully on the first frame. The rest of the time, the character appears gray (the same gray as when the editor is compiling shaders) and flickers a lot when the camera is turning or the character jumping (as if something had trouble keeping up).

Also, while looking to the DynamicMaterial in debug, there seems to be a lot of null values :

Any help appreciated, Thanks !

I found the issue last week and I thought I would let you guys know in case someone have a similar issue. On every frame I was creating a new dynamic material instance and setting it as the new material for that mesh. That worked for the first frame, but on the second frame it was complaining because the parent material (which is now a dynamic material) is not a valid parent for a dynamic material. The solution was to put the code to create the material in BeginPlay and then set the material each frame, so now the dynamic material is only created once, but change each frame.

Here is the BeginPlay function:

void ABatteryCollectorCharacter::BeginPlay()
{
	Super::BeginPlay();
	DynamicMaterial = UMaterialInstanceDynamic::Create(GetMesh()->GetMaterial(0), this);
}

And here is my function that is called every frame:

void ABatteryCollectorCharacter::PowerChangeEffect()
{
	float PowerRatio = FMath::Clamp((CharacterPower / InitialPower), 0.0f, 1.0f);
	FLinearColor PowerRatioColor = FMath::Lerp(Teal, Orange, PowerRatio);
	DynamicMaterial->SetVectorParameterValue("BodyColor", PowerRatioColor);
	GetMesh()->SetMaterial(0, DynamicMaterial);
}

Change this to GetMesh() in target, otherwise it will crash(?)
In BeginPlay():

DynamicMaterial= UMaterialInstanceDynamic::Create(GetMesh()->GetMaterial(0), GetMesh());
GetMesh()->SetMaterial(0, DynamicMaterial);

then in PowerChangeEffect you don’t have to re-set Material to mesh