How do I use InstancedStaticMeshes?

I created a maze generator and I’m currently trying to figure out how to use an InstancedStaticMeshs in c++.
Currently it spawns blueprints extended from a StaticMeshActor and I can only get about 10201 static meshes blueprints before i hit some heavy performance decrease, this is just on a maze alone

So when trying to make a rougelike maze dungeon with rooms and floors there are about ten to twenty times the static meshes. That’s allot of static mesh blueprints. Anyone have example usage ?

#Instanced Static Mesh

You can make a new class, InstancedStaticMeshActor

and add a Instanced Static Mesh Component

Then you spawn that actor

and to add additional instances you use this function in the Instanced Static Mesh Component Class

UFUNCTION(BlueprintCallable, Category="Components|InstancedStaticMesh")
virtual void AddInstance(const FTransform& InstanceTransform);

That’s pretty much all you need to do!

Here’s my code from the beta, that I used for my own tests, here’s a pic of my tests

In my case I extended a regular SMA so I would see the actor when it spawned :slight_smile:

#Spawning

//Spawninfo
	FActorSpawnParameters SpawnInfo;

	//SET NO COLLISION FAIL TO TRUE
	SpawnInfo.bNoCollisionFail = true;
		
	SpawnInfo.Owner = VictoryEngine->VSelectedActor;
	
	AVictoryVertex3D* NewVertex = 
		GetWorld()->SpawnActor<AVictoryVertex3D>(
			AVictoryVertex3D::StaticClass(),
			Pos,
			FRotator::ZeroRotator,
			SpawnInfo 
	);
	if(!NewVertex) 							return NULL;
	if(!NewVertex->InstancedStaticMeshComponent) 	return NULL;
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	//Mesh
	NewVertex->InstancedStaticMeshComponent->SetStaticMesh(VictoryEngine->AssetSM_EngineCube);
		
	//Add Core Instance
	FTransform newT = NewVertex->GetTransform();
	newT.SetLocation(FVector(0,0,0));
	NewVertex->InstancedStaticMeshComponent->AddInstance(newT);
	
	//Scale
	NewVertex->SetActorRelativeScale3D(CurrentVerticiesScale);

#.h

// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.

//Power

#pragma once

#include "VictoryVertex3D.generated.h"


/**
 * An instance of a StaticMesh in a level
 * Note that PostInitializeComponents() is not called for StaticMeshActors
 */
UCLASS()
class AVictoryVertex3D : public AStaticMeshActor
{
	GENERATED_UCLASS_BODY()
			
	UPROPERTY()
	TSubobjectPtr<UInstancedStaticMeshComponent> InstancedStaticMeshComponent;
	
	
	UPROPERTY()
	UStaticMesh* SMAsset_Cube;
	
};

#.cpp

// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.

#include "VictoryGame.h"

//////////////////////////////////////////////////////////////////////////
// VictoryVertex3D

//MAKE SEPARATE CLASSES OF THIS IF YOU WANT TO CHANGE THE MESH
//
AVictoryVertex3D::AVictoryVertex3D(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	//Mesh
	static ConstructorHelpers::FObjectFinder<UStaticMesh> StaticMeshOb_torus(TEXT("StaticMesh'/Engine/EngineMeshes/Cube.Cube'"));
	SMAsset_Cube = StaticMeshOb_torus.Object;
	
	//create new object
	InstancedStaticMeshComponent = PCIP.CreateDefaultSubobject < UInstancedStaticMeshComponent > (this, TEXT("InstancedStaticMeshComponentCOMP"));
	InstancedStaticMeshComponent.AttachTo(RootComponent);
	
	//Not Made some reason?
	if (!InstancedStaticMeshComponent) return;
	//~~~~~~~~~~~~~~~~~~~~~~~~
	
	//Set to Asset
	InstancedStaticMeshComponent->SetStaticMesh(SMAsset_Cube);
		
	InstancedStaticMeshComponent->bOwnerNoSee = false;
	InstancedStaticMeshComponent->bCastDynamicShadow = false;
	InstancedStaticMeshComponent->CastShadow = false;
	InstancedStaticMeshComponent->BodyInstance.SetObjectType(ECC_WorldDynamic);
	
	//Visibility
	InstancedStaticMeshComponent->SetHiddenInGame(false);
	
	//Mobility
	InstancedStaticMeshComponent->SetMobility(EComponentMobility::Movable);
	
	//Collision
	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);
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	
	if (!StaticMeshComponent) return;
	
	//Mobility
	StaticMeshComponent->SetMobility(EComponentMobility::Movable);
	
	//Collision
	StaticMeshComponent->BodyInstance.SetCollisionEnabled(ECollisionEnabled::QueryOnly);
	StaticMeshComponent->BodyInstance.SetObjectType(ECC_WorldDynamic);
	StaticMeshComponent->BodyInstance.SetResponseToAllChannels(ECR_Ignore);
	StaticMeshComponent->BodyInstance.SetResponseToChannel(ECC_WorldStatic, ECR_Block);
	StaticMeshComponent->BodyInstance.SetResponseToChannel(ECC_WorldDynamic, ECR_Block);
}

I’m only guessing here but I think a game like this would also benefit greatly from level streaming.

How would you level stream from actors spawned at run time ?

Thanks mate! You are the best :slight_smile: !

Well thats what you get when browsing this place the last hour of work :slight_smile:

Sorry, carry on!

i have a few problems when i try this solution.
my objects get spawned in the world. but it seems they dont have a material applied even if i apply it in the code.

so for me the main difference is that instead of
TSubobjectPtr MyBlock;
i use this:
TSubobjectPtr MyBlock;

and of course also in cpp for the pcip createabstractdefaul…

but then the block has no material :<

you’ll have to post your code for us to help you

also, it’d be better to post your issue as a separate topic so we can focus just on your issue :slight_smile:

:slight_smile:

Rama

I know I’m late to this party but I’m guessing this is because your material isn’t set up to work on Instanced Meshes. Open up your material in the Material Editor (by double-clicking it in the Resource Browser) and set the property. :slight_smile:

What if I needed to apply an instanced Material with a parameter wich is different for every instance? Would I just override AddInstance? And how would I get the static mesh created in there?

And also: How can I enable collision with my character??

Rama, first off, thanks for being so active and helpful in the community I swear every third post I find turns out to be from you :smiley:

I’m trying to solve this exact problem for myself as well and I have two quick(ish) questions:

  1. Does implementing this class help solve the issue of not being able to get a reference to a specific instance of a static mesh component during runtime? I’m running into that limitation, and it’s a dealbreaker because I need to be able to spawn AND destroy instances of the static mesh at runtime based on player interaction, but I can’t seem to do that via blueprints :confused:

2: If I place multiple instances of this actor into the world, do they each reference the SAME mesh, thereby helping to limit draw calls?

That’s the other huge issue I am hitting as I try to solve this with blueprints: Each instance of a BP that contains an instanced mesh isn’t inheriting or ‘grouping’/batching with the other instances even though it’s the same mesh. Functionally, that means I can’t make use of instanced meshes unless they ALL spawn from the same blueprint…and if they all spawn in the same BP, I can’t get a reference to a single instance to destroy it so it’s kind of useless for what I need to do :confused:

Your reply here was the closest thing I have found that might be a solution, I’m not a coder (yet) so I wanted to ask those Questions before I dive in and learn how to implement this :smiley:

Editing my post in regards to the first question: it would seem that in 4.4 they have JUST added the ability to do this!

“InstancedStaticMeshComponents now set the FHitResult.Item property with the index an instance hit by a collision event. This can be used with the above functions to remove a specific instance and replace it with a real StaticMeshComponent to provide interactivity with Foliage or other behavior.”

This is great news!

Still not sure how/if multiple Blueprints can have objects that are references to the same static mesh.

What is an SMA ?

Sorry, I’m not familiar with the acronyms.

Also, is this code still valid for UE 4.4 ?

Please can someone point me in the right direction or show me a sample project doing the same InstanceStaticMesh thingy…

SMA is StaticMeshActor.

I haven’t updated this project to 4.4 so im not entirely sure,but it should.

Are you making sure you are adding an instance of it ?

Hi,
I am trying to add InstancedStaticMeshComponent using the code above. It works for single component. However when I try to add three different instanced mesh componentes they all look the same. For example the first added mesh is floor, the second and the third are cubes. Everything is rendered as floor mesh.

Turns out the problem is with this line
static ConstructorHelpers::FObjectFinder StaticMeshOb_torus(TEXT(“StaticMesh’/Engine/EngineMeshes/Cube.Cube’”));
I removed static and it seems to be working.

Hi is there a way to pre-set scale of static mesh so when I call SetStaticMesh() on instanced mesh component and than AddInstance() it will automatically add scaled instances ?
I have an Actor c++ class with StaticMeshComponent instance, I’ve created a blueprint class from it so I can set properties instead of hard coding them, and now when I set StaticMesh to for example Cube than SetRelativeScale3D of that cube in construction script, when I drag and drop instance of it into editor the mesh is re-scaled prperly, but when I set this mesh as a StaticMesh of Instanced mesh component and call AddInstance the mesh instance is added but it has default scale any idea how to do this if possible ? Or can I only set the scale of instanced static mesh witch will change scale on all instances ?

Hi all,
I’m triyng to follow the examples but I’m stuck with this variable I can’t find anywhere.

if (!StaticMeshComponent) return;

 //Mobility
 StaticMeshComponent->SetMobility(EComponentMobility::Movable);
 
 //Collision
 StaticMeshComponent->BodyInstance.SetCollisionEnabled(ECollisionEnabled::QueryOnly);
 StaticMeshComponent->BodyInstance.SetObjectType(ECC_WorldDynamic);
 StaticMeshComponent->BodyInstance.SetResponseToAllChannels(ECR_Ignore);
 StaticMeshComponent->BodyInstance.SetResponseToChannel(ECC_WorldStatic, ECR_Block);
 StaticMeshComponent->BodyInstance.SetResponseToChannel(ECC_WorldDynamic, ECR_Block);

could someone help me?

thx

Davide