How to get part of a texture in blueprint?

Hello, I have a 2048x2048 Perlin noise texture that I’m trying to use to create procedurally generated terrain. My goal is to get a random 256x256 portion of that texture, get a reference to that in my terrain generation function in blueprint, and then have the shade of the pixels determine the height of the mesh’s vertices. However, I’m really struggling with getting a portion of the texture, as I’m not very experienced with materials in Unreal. Is there a way to sample just a part of a texture and get a reference to it in blueprint?

1- Open your texture in editor. you will see a property for X and Y as “Wrap”. Convert it to “Clamp”

2- After that in materials, use these nodes
TextCoord > Multiply > Add > Texture > You Main Material

B inputs of both Multiply and Add should be “Make 2 Components” and you have to attach totally 4 scalar parameter to them. (2 for multiply and 2 for add)
Multiply’s will be Tilling_X and Tilling_Y
Add’s will be Move_X and Move_Y

tilling should be 0.125. It will zoom at 8x (it will get 256x256 portion)

Move_X and Move_Y should be random. you can use clamp for min and max values.

//
If you know c++ you can use FImageUtils::CropAndScaleImage function

1 Like

Thanks! That seems to be working. Looks like I have a 256x256 part of the texture. I have a reference to it in blueprint now as well. How can I return the color of a pixel at a given (x, y) or UV location on that texture in the blueprint?

There is no blueprint node for that. If it is Texture2D you have to read buffer from Texture with C++

Create a TArray(FColor) Array_Colors

copy bulk data with FMemory::Memcpy to Array_Colors.GetData()

After that you can use Get() function to get your pixel color. Index should be Pixel - 1

1 Like

I think I understand. I’ve written this function in a new C++ class, but I’m not sure what to put into the second argument in Memcpy. Also, the texture I’m using is a Texture, I don’t think it’s a Texture2D.

1 Like

Completely wrong. First of all, don’t use memcpy without proper target allocation. This is not about Unreal but C/C++'s itself.

Create a BlueprintFunctionLibrary plugin from plugins section.

Create a proper UFUNCTION.

You won’t use material for reading pixel. you said texture. it should be like this

bool UYourPlugin::GetColorAtPixel(UTexture2D* TargetTexture, FVector2D TargetPixel, FColor& OutColor)
{

if(!IsValid(TargetTexture)
{
return false;
}

if (TargetPixel.X == 0 || TargetPixel.Y == 0)
{
return false;
}

size_t PixelCount = TargetTexture-> GetSizeX * TargetTexture-> GetSizeY;
size_t BufferSize = PixelCount * sizeof(FColor);

TArray Array_Colors;
Array_Colors.SetNum(PixelCount);

FTexture2DMipMap& Texture_Mip = TargetTexture->GetPlatformData()->Mips[0];
void* Texture_Data = Texture_Mip.BulkData.Lock(LOCK_READ_WRITE);

FMemory::Memcpy(Array_Colors.GetData(), Texture_Data, BufferSize);
Texture_Mip.BulkData.Unlock();

int32 PixelLocation = (TargetPixel.X - 1) + ((TargetPixel.Y - 1) * TargetTexture->GetSize.X));

OutColor = Array_Colors[PixelLocation];
return true;
}

1 Like

If you need to read material’s pixel location, draw material to a canvas render target

Create same function but your target texture will be UCanvasTextureRenderTarget2D*

Use this instead of that BulkData and Memcpy things. You don’t need Array_Colors.SetNum() (allocation) in here because you don’t use memcpy. That ReadRenderTarget will cover it for you.

TArray Array_Colors;
UKismetRenderingLibrary::ReadRenderTarget(GEngine->GetCurrentPlayWorld(), InCRT, Array_Colors, true); // or false. I don’t remember what normalize means. read its comments and compare results.

And use same int32 PixelLocation line to create index type location.

After that
OutColor = Array_Colors[PixelLocation];

1 Like

Also you can use this.

Probably it can use CanvasRenderTarget, too.
Just draw your material on it and use this.

But as it say, it is slow operation. don’t use it with Event Tick

1 Like

Thank you for your help! I’ll give this all a try.

I’ve come across another issue with the GetColorAtPixel function. It’s not visible in blueprint, so I’m trying to turn the class into a proper UCLASS. However, I’m having a strange compilation error. On the function declaration on line 21 in the following screenshot, it says that it “Found ‘(’ when expecting ‘;’ while parsing class ‘ProcGenStuff’”:


Why might it be having these errors?

I’m having another issue now as well. I regenerated the project files and added ‘include “ProcGenStuff.generated.h”’ at the top of the file, but it’s throwing an error saying that it “cannot open source file “ProcGenStuff.generated.h””. Is this because it hasn’t created the generated.h file yet?

Fixed those compilation errors. I was calling UPROPERTY instead of UFUNCTION above my function declaration.