[C++] How to put a dynamic material instance on a landscape?

Hi,

I’m trying to make a grid system on a landscape, and I have only one problem, updating my landscape material to highlight the correct case. It seems like my landscape doesn’t take my dynamic material instance, here is my dynamic material instance code:

Game mode class

void ARPAGameMode::BeginPlay()
{
	ALandscape	*land = nullptr;
	for (TActorIterator<ALandscape> lit(GetWorld()); lit; ++lit)
	{
		land = *lit;
		break;
	}
	if (land != nullptr)
	{
		_landscapeDMI = UMaterialInstanceDynamic::Create(land->GetLandscapeMaterial(), land);
		_landActorPos = land->GetActorLocation();
		land->LandscapeMaterial = _landscapeDMI;
	}
		
}

Player Controller class

void ARPAPlayerController::PlayerTick(float DeltaTime)
{
	Super::PlayerTick(DeltaTime);
	currentCooldown -= DeltaTime;
	ARPAGameMode *gm = static_cast<ARPAGameMode *>(GetWorld()->GetAuthGameMode());

	// keep updating the destination every tick while desired
	if (bMoveToMouseCursor)
	{
		MoveToMouseCursor();
	}
	if (currentCooldown <= 0)
	{
		FHitResult Hit;
		
		GetHitResultUnderCursor(ECC_Visibility, false, Hit);
		if (gm && gm->getLandscapeDMI())
		{
			if (Hit.bBlockingHit)
			{
				FString vec = Hit.ImpactPoint.ToString();
				FVector zeroOutImpactPoint = Hit.ImpactPoint - gm->getLandscapeActorPos();
				float caseX = floorf(zeroOutImpactPoint.X / caseSize);
				float caseY = floorf(zeroOutImpactPoint.Y / caseSize);

				UE_LOG(LogTemp, Warning, TEXT("[WATCH] FloorSet :: Cases(X;Y) = (%f;%f)"), caseX, caseY);
				gm->getLandscapeDMI()->SetScalarParameterValue(FName("CaseX"), caseX);
				gm->getLandscapeDMI()->SetScalarParameterValue(FName("CaseY"), caseY);
				gm->getLandscapeDMI()->SetScalarParameterValue(FName("Activate"), 1);
			}
			else
			{
				gm->getLandscapeDMI()->SetScalarParameterValue(FName("Activate"), 0);
			}
		}
	}	
	currentCooldown = coolDown;
}

The log is displayed and display the right case coordinates.

So, what’s wrong? How can I set a dynamic material instance on a landscape in a way that works?

Thank you for your time.

Well, dynamic material instance on landscape doesn’t seem to work. So I tried with a material parameter collection, and that’s working really well. Here’s some code to get a Material parameter collection from content browser and set some values at runtime:

To get from content browser the asset and store it in private field:

static ConstructorHelpers::FObjectFinder<UMaterialParameterCollection> MyMaterialParamCollection(TEXT("MaterialParameterCollection'/Game/Materials/MC_MPC.MC_MPC'"));

	this->MyMaterialParamCollection = MyMaterialParamCollection.Object;

To change the value:

 #include "Runtime/Engine/Classes/Kismet/KismetMaterialLibrary.h"
    ...
    UKismetMaterialLibrary::SetScalarParameterValue(GetWorld(), MyMaterialParamCollection, FName("ParamName"), theValue);