Pixel search on a TextureRenderTarget

Hi all,

I implemented this c++ function to check if at least one pixel of this color is on the TextureRenderTarget :

bool ASceneCaptureManager::ReadTextureRenderTargetPixels(UTextureRenderTarget2D  * TextureRenderTarget, FColor TestColor) { 

	if (TextureRenderTarget == nullptr) { return false; }

	TArray<FColor> l_ColorsPixelsArray;
	FColor l_PixelColor;
	FRenderTarget *l_RenderTarget = TextureRenderTarget->GameThread_GetRenderTargetResource();
	l_RenderTarget->ReadPixels(l_ColorsPixelsArray);

	for (int32 i = 0; i < TextureRenderTarget->SizeX; i++) {
		for (int32 j = 0; j < TextureRenderTarget->SizeY; j++) {

			l_PixelColor = l_ColorsPixelsArray[i + j * TextureRenderTarget->SizeX];

			if (l_PixelColor.R == TestColor.R && l_PixelColor.G == TestColor.G && l_PixelColor.B == TestColor.B) {
				return true;
			}
		}

	}

	return false;

}

Here is the Blurprint :

The CaptureScene function calls USceneCaptureComponent2D->CaptureSceneDeferred();

RenderTarget texture size is 512 x 512

The problem is that this function returns true 20% of the time when it should return true everytime (after each call i opened the RenderTarget texture and there was pixels of this color).

Do you have any idea how to solve this please ?

Are you sure that you’re rendering a perfect, 100% red, that’s not tone mapped or lit or fogged or shaded?
You could test whether it matches the color with a little slop through something like:

    int difference = Abs(int(l_PixelColor.R) - TestColor.R) + Abs(int(l_PixelColor.G) - TestColor.G) + Abs(int(l_PixelColor.B) - TestColor.B);
    if (difference < 7) {
        ... same ...
    }

Also, reading back a render target to the CPU is a good way to ensure that you will never get parallelism between the CPU and the GPU, which will limit your maximum possible FPS. Maybe that’s OK for you – just making sure it’s called out, because it’s a common cause of low frame rates.

jwatte , thanks for your answer.

Are you sure that you’re rendering a perfect, 100% red, that’s not tone mapped or lit or fogged or shaded?

Yes i’m 100% positive, because i opened the RenderTarget texture on Photoshop after every function call , and i used the colorpicker which displayed the exact RGB value

Also, reading back a render target to the CPU is a good way to ensure that you will never get parallelism between the CPU and the GPU, which will limit your maximum possible FPS

Thanks a lot :wink: i’m gonna explore this way

Ok Solved, finally i rendered the strict minimum of Actors i need into the scene (roads spline mesh components). So in SceneCaptureComponent2D > Scene Capture > Primitive Render Mode, i chose “UseShowOnlyList”. This list stores an array of references (Actors or/and components) to render in the TextureRenderTarget.

Since rendering is much cheaper, maybe it has time to finish everytime before my C++ function ReadTextureRenderTargetPixels() call

Oh, you’re not calling FlushRenderingCommands somewhere? You need to do that before you read back the texture.

See the docs:

More information about the threaded rendering in Unreal: Threaded Rendering | Unreal Engine 4.27 Documentation

Thanks again, i will take a look

Hi jwatte,

I had to render more actors in the texture render target so i tried FlushRenderingCommands() at the beginning of my function ReadTextureRenderTargetPixels() which comes just after CaptureScene() function, but it doesnt work : the TextureRenderTarget doesn’t have time to be updated.

The only way to make it work is to call these 2 function inside my PlayerController blueprint and put a delay node (0.08 seconds) between the two. But it’s not a clean workaround because i wanted to call these functions from another blueprint.

Any idea please ?