Create a UMaterialInstanceDynamic in Constructor in C++

Is it possible to create a UMaterialInstanceDynamic inside an actor constructor?

if not, is there any other place that I can do it besides “BeginPlay”?

Many thanks.

Cheers,
J

Hi J,

Technically you can with:

if (ParentMaterial)
{
    BaseMaterialMID = UMaterialInstanceDynamic::Create(ParentMaterial, nullptr, FName(TEXT("Base Material Dynamic")));
   BaseMaterialMID ->SetFlags(RF_Transient);
}

However, if the ParentMaterial is set as a property in a BP child of this class then the above won’t work as the C++ construction happens first prior to any of the BP vars being set.

In this case, you need to make a function of the above code like so:

void AYourActorClass::SetActorMaterial(UMaterialInterface* ParentMaterial, bool bInConstructor)
{
	if (ParentMaterial)
	{
		BaseMaterialMID = UMaterialInstanceDynamic::Create(ParentMaterial, this, FName(TEXT("Base Material Dynamic")));
		if (bInConstructor) 
		{
			// Set new object flag to RF_Transient since this is being called in the BP child constructor
			BaseMaterialMID->SetFlags(RF_Transient);
		}
	}
}

THEN call this function in your BP Child Class’ Construction script. I hope that helps.

Cheers,
runeberg

Hi,

I have also tried creating an UMaterialInstanceDynamic in the Constructor in C++. I had issues by using UMaterialInstanceDynamic::Create in the constructor and the solution of RuneBerg posted on May 20 '18 helped me.

But then I had troubles when I was realoading my world (When I quit Unreal studio and relaunched later my project). The MaterialInstanceDynamics were no longer there.

So, if anyone have the same issue, here is the solution that I found.
Don’t create the the material instance dynamic in the constructor at all. Put your code inside PostActorCreated(). That way, it’s like the MID is created outside the constructor and… well I don’t know why but that don’t create the same issues that it does in the constructor.

/// Header file
/**
 *	Called after the constructor.
 *	Used to create the material instance dynamic of the cables.
 *	Can't be create directly in the contructor because it will not be created again on the reload of the world.
 */
virtual void PostActorCreated() override;

/// Cpp file
void AITPowerSupplySystem::PostActorCreated()
{
    UE_LOG(LogTemp, Warning, TEXT("[%s] PostActorCreated"), *this->GetName());
    
    Super::PostActorCreated();
    

    for (uint8 i = 0; i < this->NumberCables; i++)
    {
        if (this->PowerSupplySystemCables.IsValidIndex(i))
        {
            UCableComponent* Cable = this->PowerSupplySystemCables[i].Components.Cable;
            
            const FString CableMaterialRef = TEXT("Material'/Game/Materials/M_Cable.M_Cable'");
            UMaterialInterface* const CableMaterialFinder = LoadObject<UMaterialInterface>(Cable, *CableMaterialRef);
            if (CableMaterialFinder)
            {
                Cable->SetMaterial(0, UMaterialInstanceDynamic::Create(CableMaterialFinder, Cable));
                UE_LOG(LogTemp, Warning, TEXT("[%s] create Material name : %s"), *this->GetName(), *Cable->GetMaterial(0)->GetName());
            }
            else
            {
                UE_LOG(LogTemp, Error, TEXT("[%s] Impossible to find UMaterial : %s"), *this->GetName(), *CableMaterialRef);
            }
        }
    }
}
1 Like