How to get material from mesh instance?

In general, an actor needs to be created with material exactly the same as material appeared in object of UInstancedStaticMeshComponent.

Instanced static mesh has multiple instances with material properties tweaked for every instance via PerInstanceCustomData. Few floats are passed as custom parameters to define how specific mesh instance should look like. So far so good. Now it is needed to “extract” color and other material properties of specific instance and apply those to different actor. Within approaches that I’ve tried (unsuccessfully) the questions can be formulated as:

  1. How to acquire or generate material from specific mesh instance?

  2. How to pass floats to PerInstanceCustomData into material to get desired looking material?

I don’t get an option to retrieve this data on a per instance value. You may have to keep it in a Map <int, parameter> where int would be the index of the instance and parameter be the passed variable type. Then set the TMap in parallel when adding the instance.

In c++ there is a TArray PerInstanceSMCustomData that maybe can be accessible (would have to dive into the docs to see it’s visibility)

Update: Yes it does seem to be accessible from c++ though it’s seems to be a little cumbersome having to pass in an index then multiplying the this by the NumCustomDataFloats to get the correct variables.

Thanks for reply. And sorry for possible ill formulation of the question.

Right, custom data can be accessed. From c++, for any instance. I get stumbled on how to apply these custom data to new material. New material is what needed to make a copy.

A copy of material is needed to make an actor, of different mesh, but of the same color (and all material properties).

InstancedLibrary.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "InstancedLibrary.generated.h"

/**
 * 
 */
UCLASS()
class YOUR_API UInstancedLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
	
public:
	UFUNCTION(BlueprintCallable)
	static TArray<float> GetData(UInstancedStaticMeshComponent* passedComponent);

	UFUNCTION(BlueprintCallable)
		float GetDataAtIndex(UInstancedStaticMeshComponent* passedComponent, int32 InstanceIndex, int32 CustomDataIndex);
};

InstancedLibrary.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "InstancedLibrary.h"
#include "Components/HierarchicalInstancedStaticMeshComponent.h"
#include "Components/InstancedStaticMeshComponent.h"

TArray<float> UInstancedLibrary::GetData(UInstancedStaticMeshComponent* passedComponent)
{
	return passedComponent->PerInstanceSMCustomData;
}

float UInstancedLibrary::GetDataAtIndex(UInstancedStaticMeshComponent* passedComponent, int32 InstanceIndex, int32 CustomDataIndex)
{		
	return passedComponent->PerInstanceSMCustomData[InstanceIndex * passedComponent->NumCustomDataFloats + CustomDataIndex];
}

GetDataAtIndex will return your custom value, pass in the instancestaticmeshcomponent, index and custom data index and you will get the saved value

Take into account that it’s the raw value without the vertex convert needed for vector colors.

Right. The next (unknown) part is how to make a material from custom data retrieved. An actor on which these custom data to be applied is NOT InstancedStaticMeshComponent. I could implement another material, or use existing with PerInstanceCustomData, but how to apply custom data, see my question 2. These PerInstanceCustomData seems to require instanced mesh, which is not what exists per se.

Again, from more general perspective. Suppose, there are 1000 instanced mesh “actors”, each having the same mesh but different positions, sizes and material properties, like color, emissivenes, etc. What I need is to replace one instanced mesh “actor” by another (completely different and true) actor. Say, there are one thousand goblins marching on battlefield. Merlin comes and converts one goblin into a dragon. This dragon should preserve parent-goblin’s color. How should it be done?

You would need to extract the materials from the custom variable and pass it to a dynamic material instances internal parameters.

The whole material would need to expose each variable

No easy way of doing this conversion

Finally I got it. It is so simple and to the lack of my understanding of UE materials.

  1. Duplicate material and replace PerInstanceCustomData float by scalar parameter. Name the latter.

  2. Get static mesh of new actor and call “Create Dynamic Material Instance” with material duplicated in step 1.

  3. Extract custom data from original instanced mesh “actor”. (here on c++ side)

  4. Apply custom data to scalar parameter, as named in step 1.

I close the question as resolved. Thanks to 3dRaven!

1 Like