Read Render Target Pixel returns highest value

So I’m trying to make a simple scoring system similar to Splatoon, where it’s the most area covered. I’m using a render target to do this, but whenever I try to read the pixel data, it returns 1 or 255, or whatever the highest value is for that format. It’s a simple 256x256 in R16 format and I’m trying to iterate over all pixels and find the sum of the values.

Here is how I’m doing the iteration:

What I found interesting is that if I clear the render target argument, it still gives me the same answer. And that if I change the format to RGBA8 than it works, but is a lot slower.

The reason RGBA8 works is because it and FloatRGBA are the only supported texture formats for these functions. Here’s a relevant code snippet:

FColor UKismetRenderingLibrary::ReadRenderTargetPixel(UObject* WorldContextObject, UTextureRenderTarget2D* TextureRenderTarget, int32 X, int32 Y)
{	
	TArray<FColor> Samples;
	TArray<FLinearColor> LinearSamples;

	switch (ReadRenderTargetHelper(Samples, LinearSamples, WorldContextObject, TextureRenderTarget, X, Y, 1, 1))
	{
	case PF_B8G8R8A8:
		check(Samples.Num() == 1 && LinearSamples.Num() == 0);
		return Samples[0];
	case PF_FloatRGBA:
		check(Samples.Num() == 0 && LinearSamples.Num() == 1);
		return LinearSamples[0].ToFColor(true);
	case PF_Unknown:
	default:
		return FColor::Red;
	}
}

Notice how it returns Red for unsupported formats.

As for performance, this method is going to be sloow regardless, especially if you’re doing it with just BP. If you write some custom C++, you can look at the source code and find it’s making a sample rectangle of width 1 and height 1. Maybe you can give it a bigger rect and perform 1 large sample vs tons of small 1 pixel ones? There’s probably a better way tbh.

2 Likes