Unable to assign material to InstancedStaticMeshComponent

I have been unable to get a material on an InstancedStaticMeshComponent, and unable to find any code examples on the forums or AnswerHub showing how it might be done. I have tested my code by putting in both a StaticMeshComponent and an InstancedStaticMeshComponent. The material applies to the SMC, but not the ISMC. I’m sure there’s something obvious I’m missing. Please advise.

Block.cpp

AArchBlock::AArchBlock(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	PrimaryActorTick.bCanEverTick = true;

	// capsule component for root
	CapsuleComponent = PCIP.CreateDefaultSubobject<UCapsuleComponent>(this, "MyCapsuleComponent");
	CapsuleComponent->InitCapsuleSize(100.0f, 200.0f);
	CapsuleComponent->BodyInstance.bEnableCollision_DEPRECATED = true;
	static FName CollisionProfileName(TEXT("Pawn"));
	CapsuleComponent->SetCollisionProfileName(CollisionProfileName);
	
	RootComponent = CapsuleComponent;

	//-----------------------------------------------------------------------

	// staticmeshcomponent, called blockstaticmeshcomponent here
	static ConstructorHelpers::FObjectFinder<UStaticMesh> StaticMeshFinder(TEXT("StaticMesh'/Game/Shapes/Shape_Cube.Shape_Cube'"));	
	AssetSM_BlockStaticMesh = StaticMeshFinder.Object;

	BlockStaticMeshComponent = PCIP.CreateDefaultSubobject < UStaticMeshComponent >(this, TEXT("BlockStaticMeshComponent"));
	BlockStaticMeshComponent->SetStaticMesh(AssetSM_BlockStaticMesh);

	SetupSMComponentsWithCollision(BlockStaticMeshComponent);
	BlockStaticMeshComponent->AttachParent = CapsuleComponent;

	BlockStaticMeshComponent->SetMobility(EComponentMobility::Movable);

	BlockStaticMeshComponent->BodyInstance.SetCollisionEnabled(ECollisionEnabled::QueryOnly);
	BlockStaticMeshComponent->BodyInstance.SetObjectType(ECC_WorldDynamic);
	BlockStaticMeshComponent->BodyInstance.SetResponseToAllChannels(ECR_Ignore);
	BlockStaticMeshComponent->BodyInstance.SetResponseToChannel(ECC_WorldStatic, ECR_Block);
	BlockStaticMeshComponent->BodyInstance.SetResponseToChannel(ECC_WorldDynamic, ECR_Block);

	//-----------------------------------------------------------------------

	// instancedstaticmeshcomponent
	static ConstructorHelpers::FObjectFinder<UStaticMesh> StaticMeshOb(TEXT("StaticMesh'/Game/Shapes/Shape_Cube.Shape_Cube'"));
	SMAsset_Cube = StaticMeshOb.Object;

	InstancedStaticMeshComponent = PCIP.CreateDefaultSubobject<UInstancedStaticMeshComponent>(this, TEXT("InstancedStaticMeshComponentCOMP"));
	InstancedStaticMeshComponent->AttachParent = RootComponent;

	InstancedStaticMeshComponent->SetStaticMesh(SMAsset_Cube);

	InstancedStaticMeshComponent->bOwnerNoSee = false;
	InstancedStaticMeshComponent->bCastDynamicShadow = false;
	InstancedStaticMeshComponent->CastShadow = false;
	InstancedStaticMeshComponent->BodyInstance.SetObjectType(ECC_WorldDynamic);

	InstancedStaticMeshComponent->SetHiddenInGame(false);

	InstancedStaticMeshComponent->SetMobility(EComponentMobility::Movable);

	InstancedStaticMeshComponent->BodyInstance.SetCollisionEnabled(ECollisionEnabled::QueryOnly);
	InstancedStaticMeshComponent->BodyInstance.SetObjectType(ECC_WorldDynamic);
	InstancedStaticMeshComponent->BodyInstance.SetResponseToAllChannels(ECR_Ignore);
	InstancedStaticMeshComponent->BodyInstance.SetResponseToChannel(ECC_WorldStatic, ECR_Block);
	InstancedStaticMeshComponent->BodyInstance.SetResponseToChannel(ECC_WorldDynamic, ECR_Block);

	//-----------------------------------------------------------------------

	// find and apply materials
	static ConstructorHelpers::FObjectFinder <UMaterial>MaterialFinder(TEXT("Material'/Game/Materials/M_Brick_Clay_Beveled.M_Brick_Clay_Beveled'")); 
	if (MaterialFinder.Object != NULL)
	{
		MyMaterial = (UMaterial*)MaterialFinder.Object;
	}
	MyMaterialDynamic = UMaterialInstanceDynamic::Create(MyMaterial, this);
	InstancedStaticMeshComponent->SetMaterial(0, MyMaterialDynamic);
	BlockStaticMeshComponent->SetMaterial(0, MyMaterialDynamic);
}

And Block.h

UCLASS()
class ARCH_API AArchBlock : public AActor
{
	GENERATED_UCLASS_BODY()

	UPROPERTY()
	TSubobjectPtr<UInstancedStaticMeshComponent> InstancedStaticMeshComponent;

	UPROPERTY()
		UStaticMesh* SMAsset_Cube;

	TSubobjectPtr<UStaticMeshComponent> BlockStaticMeshComponent;
	UStaticMesh * AssetSM_BlockStaticMesh;

	TSubobjectPtr<UCapsuleComponent> CapsuleComponent;

	UMaterial* MyMaterial;
	UMaterialInstanceDynamic* MyMaterialDynamic;
}

And the code from which it the spawning is called

	FActorSpawnParameters MySpawnParams;
	MySpawnParams.bNoCollisionFail = true;

	AArchBlock* NewBlock = GetWorld()->SpawnActor<AArchBlock>(AArchBlock::StaticClass(), FVector(0, 0, 0), FRotator(0, 0, 0), MySpawnParams);

	FTransform newT = NewBlock->GetTransform();
	newT.SetLocation(FVector(-300, -300, -300));
	NewBlock->InstancedStaticMeshComponent->AddInstance(newT);

	newT.SetLocation(FVector(300, 300, 300));
	NewBlock->InstancedStaticMeshComponent->AddInstance(newT);

Aha!

Materials have an attribute:
bUsedWithInstancedStaticMeshes

Toggle that to TRUE and it works.

The same thing applies to many other types of meshes. We had the same issue with SplineMeshComponent not being able to recieve materials in runtime; turns out it’s a bool you need to enable in the material. Thank you :slight_smile: