How do you change a material's color on a mesh at runtime in Unreal Engine?
Recolor a single mesh at runtime without affecting other meshes that share the same base material. Create the dynamic material instance once in BeginPlay, then change its color in SetHighlightColor.
Constraints:
- Use a
UMaterialInstanceDynamicviaCreateDynamicMaterialInstance— never edit the base asset. - Create and cache the instance once (in
BeginPlay), not per frame. - Set a named vector parameter (e.g.
"BaseColor") exposed by the material.
void AHighlightActor::BeginPlay()
{
Super::BeginPlay();
// your code here
}
void AHighlightActor::SetHighlightColor(const FLinearColor& Color)
{
// your code here
}
Write the implementation.
Create a UMaterialInstanceDynamic with CreateDynamicMaterialInstance on the component, then call SetVectorParameterValue with a named parameter. Editing the base material asset directly would affect every mesh that uses it.
- ✗Editing the shared base material asset, which changes the color on every mesh using it
- ✗Forgetting the material must expose a named vector parameter for the call to work
- ✗Creating a new dynamic instance every frame instead of caching one and reusing it
- →When should you create the dynamic material instance —
BeginPlayor on demand? - →How does
SetScalarParameterValuediffer fromSetVectorParameterValue?
Problem
You need to recolor a mesh during gameplay — for example, to highlight an object on hover. The base material cannot be edited directly: it is shared, and editing it would affect every mesh that uses it.
Solution
Create a UMaterialInstanceDynamic (MID) — a lightweight instance that reuses the base material's compiled shader and lets you change exposed parameters.
// In the actor header:
UPROPERTY()
UMaterialInstanceDynamic* DynMaterial = nullptr;
void AHighlightActor::BeginPlay()
{
Super::BeginPlay();
// Create the MID once and cache it. Index 0 is the material slot on the mesh.
DynMaterial = MeshComponent->CreateDynamicMaterialInstance(0);
}
void AHighlightActor::SetHighlightColor(const FLinearColor& Color)
{
if (DynMaterial)
{
// "BaseColor" is the vector parameter name exposed in the material graph.
DynMaterial->SetVectorParameterValue(TEXT("BaseColor"), Color);
}
}
Key points
- The base material must expose a named parameter (a
VectorParameternode namedBaseColor) — otherwiseSetVectorParameterValuefinds nothing to set. CreateDynamicMaterialInstanceis called once (inBeginPlay), not every frame — otherwise objects pile up and burden the garbage collector.- The MID applies only to this component; other meshes sharing the same base material are unaffected.
- Changing a parameter is cheap: no shader recompile happens — only a value in a constant buffer changes.