Is it possible to assign a UTexture2D to a material at runtime?

I’m trying to generate a UTexture2D in code and then assign this texture to a material. I think I’ve managed to create the UTexture2D, but I cannot find a way to assign this texture to the material associated with my Blueprint component in C++ or in the editor.

If the UTexture2D is a UPROPERTY() in my component, is it possible for the material to this texture and use it in the material editor?

#Dynamic Material Instance

Step 1:

In editor, make a material that has a Texture as a propety.

a. hold down T and left click in material space to make a new texture sample

b. right click and convert to parameter

c. Give it the name “T2DParam”

d. save this new material as your master material

Step 2:

Copy the reference into a constructor

or create a MaterialInterface* UPROPERTY to set from editor on a class BP (like your player controller BP)

//~~~ BP Referenced Materials ~~~
UPROPERTY(EditDefaultsOnly, Category=Materials)
UMaterialInterface * MasterMaterialRef;

Step 3:

In code, make a material Instance of this master material. Do NOT do this in the constructor, only after post init.

UMaterialInstanceDynamic* RV_MatInst = UMaterialInstanceDynamic::Create(MasterMaterialRef, this);

Step 4:

After you make your custom T2D, assign it as a texture parameter to your material

RV_MatInst->SetTextureParameterValue(FName("T2DParam"),YourCustomT2DRef);

UMateriaInstanceDynamic.h:

/** Set an MID texture parameter value */
UFUNCTION(BlueprintCallable, Category="Rendering|Material")
ENGINE_API void SetTextureParameterValue(FName ParameterName, class UTexture* Value);

#Enjoy!

Enjoy!

I’m not sure how to make the MasterMaterialRef, can you please provide an example of how to do this in the constructor?

//~~~ Materials ~~~
static ConstructorHelpers::FObjectFinder materialOb_PinkPlasma(TEXT(“Material’/Game/Materials/PinkPlasma.PinkPlasma’”));

MasterMaterialRef = materialOb_PinkPlasma.Object;

the name of the object finder doesnt matter, as long as each new use has a unique name

the path, inside of TEXT is something you get by right clicking on your chosen material in the editor and select “copy reference”

:slight_smile:

Hello, this tutorial is great, but i don’t understand how i can use it later in the editor. How can i use it to put this new dynamic material on an object like a cube. I try so hard to get it work but i have no idea. Please help me.
And please tell me somebody what i have to do with this in step 4:

UMateriaInstanceDynamic.h:

/** Set an MID texture parameter value */
UFUNCTION(BlueprintCallable, Category="Rendering|Material")
ENGINE_API void SetTextureParameterValue(FName ParameterName, class UTexture* Value);

Thanks alot!
Dennis

Hey Boke-

The lines of code under UMaterialInstanceDynamic.h is part of the source code that controls changing the dynamic material. You don’t have to do anything with this code yourself, it’s posted here for reference.

As for using the dynamic material in the editor, that is slightly different than applying the material during runtime. Using the above code, if you declare RV_MatInst as a UPROPERTY() then it should show up inside the editor for any blueprint that inherits from the class where you created your dynamic material instance.

Cheers

I’m trying to get this to work, but with no results so far. Here is my code:

VirtualDisplayActor.h:

UCLASS()
class HDS_API AVirtualDisplayActor : public AActor
{
	...

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Mesh)
	class UStaticMeshComponent *Mesh;

	class UTexture2D *LeftEyeTexture;

	class UTexture2D *RightEyeTexture;

	class UMaterialInterface * MasterMaterialRef;

	class UMaterialInstanceDynamic* RV_MatInst;

	...
};

(See reply for cpp)

My Material blueprint:

I have my custom actor placed in the scene with a cube mesh and the material I created assigned to it.

This set up should, in theory, turn the cube red when on the left side of the screen and green when on the right side of the screen, but the UTexture2D textures do not get applied - there is no result in the rendered game.

What am I missing here?

VirtualDisplayActor.cpp:

AVirtualDisplayActor::AVirtualDisplayActor()
{
 	...
	LeftEyeTexture = UTexture2D::CreateTransient(256, 256, PF_B8G8R8A8);
	if (LeftEyeTexture)
	{
		LeftEyeTexture->AddToRoot();
		LeftEyeTexture->UpdateResource();
	}

	RightEyeTexture = UTexture2D::CreateTransient(256, 256, PF_B8G8R8A8);
	if (RightEyeTexture)
	{
		RightEyeTexture->AddToRoot();
		RightEyeTexture->UpdateResource();
	}

	static ConstructorHelpers::FObjectFinder<UMaterial> materialOb_Perspective(TEXT("Material'/Game/VirtualDisplay/Perspective.Perspective'"));
	MasterMaterialRef = materialOb_Perspective.Object;
}
 
void AVirtualDisplayActor::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	const size_t Size = 256 * 256 * sizeof(uint32);

	uint32* Src = new uint32[65536];
	for (int i = 0; i < 65536; i++)
	{
		Src[i] = 0xff0000ff;
	}
	uint32* Dest = (uint32*)LeftEyeTexture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
	FMemory::Memcpy(Dest, Src, Size);
	LeftEyeTexture->PlatformData->Mips[0].BulkData.Unlock();
	LeftEyeTexture->UpdateResource();

	for (int i = 0; i < 65536; i++)
	{
		Src[i] = 0x00ff00ff;
	}
	Dest = (uint32*)RightEyeTexture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
	FMemory::Memcpy(Dest, Src, Size);
	RightEyeTexture->PlatformData->Mips[0].BulkData.Unlock();
	RightEyeTexture->UpdateResource();
	delete[] Src;

	RV_MatInst = UMaterialInstanceDynamic::Create(MasterMaterialRef, this);
	RV_MatInst->SetTextureParameterValue(FName("LeftEyeTexture"), LeftEyeTexture);
	RV_MatInst->SetTextureParameterValue(FName("RightEyeTexture"), RightEyeTexture);
}

Hey -troke-

Seeing the “LeftEye Texture” and “RightEye Texture” nodes makes me wonder if you are doing this for HMD / VR? The code you posted seems to be from an actor class yet the blueprint that uses those variables appears to be a material, correct? Also, can you explain exactly what’s happening in the PostInitializeComponents function?

Cheers

Hi -troke,

We have not heard back from you in a few days, so we are marking this post as Resolved for tracking purposes. If you are still experiencing the issue you reported, please respond to this message with additional information and we will offer further assistance.

Thank you.