Download

How to create textures at runtime and assign them to a mesh?

Unfortunately I cannot find proper documentations around this question. I want to create a texture of custom size at runtime, assign colors to pixels of the texture, and then assign that texture to a plane mesh to be displayed at runtime.

I only want to use C++.

Can anyone help me?

You’re going to set pixel values on a UTexture2D and assign that to a material, then apply that material onto your plane mesh.

https://docs.unrealengine.com/4.26/en-US/API/Runtime/Engine/Engine/UTexture2D/

UTexture2D::CreateTransient() creates an empty UTexture2D for you to modify.
You get the first mipmap of this newly created texture, then need to get and lock the image data.

// Create custom texture and retrieve raw image data

UTexture2D CustomTexture = UTexture2D::CreateTransient(1024, 1024);
FTexture2DMipMap* MipMap = &CustomTexture->PlatformData->Mips[0];
FByteBulkData* ImageData = &MipMap->BulkData;
uint8* RawImageData = (uint8*)ImageData->Lock(LOCK_READ_WRITE);

RawImageData is formatted as such:
[Pixel1 B][Pixel1 G][Pixel1 R][Pixel1 A][Pixel2 B][Pixel2 G][Pixel2 R][Pixel2 A] …
You can iterate this like a 2D array with a nested for-loop, keeping in mind that each pixel takes up four elements.

Once you’ve set your colors, unlock the image data and update the texture.

ImageData->Unlock();
CustomTexture->UpdateResource();

In editor, you must have a material with an image texture parameter.
Call CreateDynamicMaterialInstance() in your plane mesh and pass in the material.

Finally, SetTextureParameterValue() with your custom texture in the Dynamic Material Instance you just created and set the plane mesh’s material to the Dynamic Material Instance.

https://docs.unrealengine.com/4.26/en-US/API/Runtime/Engine/Materials/UMaterialInstanceDynamic/

2 Likes

Thank you for your detailed explanation. It helped a lot.

I successfully created the texture. But I’m having trouble assigning it to the material. This is the code that I have:

	RuntimeTexture = UTexture2D::CreateTransient(100, 100);
	FTexturePlatformData** PlatformData = RuntimeTexture->GetRunningPlatformData();
	FTexture2DMipMap FirstMip = (*PlatformData)->Mips[0];
	FByteBulkDataOld ImageData = FirstMip.BulkData;
	uint8* RawImageData = (uint8*)ImageData.Lock(LOCK_READ_WRITE);

	int ArraySize = 100 * 100 * 4;
	for(auto i = 0; i < ArraySize; i += 4)
	{
	    RawImageData[i] = 255;
	}
	
	ImageData.Unlock();
	RuntimeTexture->UpdateResource();

	UMaterialInstanceDynamic* DynamicMaterial = Mesh->CreateDynamicMaterialInstance(0, Mesh->GetMaterial(0));
	DynamicMaterial->SetTextureParameterValue("Texture", RuntimeTexture);

RuntimeTexture is a field which I can see in the Details panel. I can see that the texture is being generated but it doesn’t get applied to the material. What am I doing wrong?

The code block shows you created the dynamic material and set the texture parameter, but you haven’t actually set the mesh’s material with SetMaterial().