we’re using a TextureRenderTargetCube to map colors to raytraced points for our LiDAR sensor. Using UE4.27 we were able to extract each face of the TextureRenderTargetCube individually like this:
if (TextureTarget != NULL)
{
CubeResource = (FTextureRenderTargetCubeResource*)TextureTarget->GameThread_GetRenderTargetResource();
if (CubeResource->IsInitialized() && CubeResource != NULL)
{
CubeResource->ReadPixels(ColorBufferPosX, FReadSurfaceDataFlags(RCM_UNorm, CubeFace_PosX));
...
TextureTarget is a member of the USceneCaptureComponentCube class of which our sensor is derived and has the type TextureRenderTargetCube.
Now using UE5.1 this doesn’t work anymore. Casting the TextureTarget to a FTextureRenderTargetCubeResource will trigger an assertion (in D3D12RenderTarget.cpp, line 656) that a Texture2D is expected. Therefore, I checked the implementation of the ReadRenderTargetHelper in KismetRenderingLibrary.cpp from the engine and stopped casting to a cube resource and used a regular TextureRenderResource instead:
Since I’m passing the value CubeFace_PosX as an argument, I expect to recieve the data from a specific cube face. However, if I change the value to CubeFace_PosY or other sides, the result is identical.
I dug a little into the D3D12RenderTarget.cpp file and found out, that the cube faces may not be accessible at all. We have this if statement, where the cube face would be accessed if the Texture->getDesc().IsTextureCube():
Now the problem is that this will always return false, since the assertion on line 656 will make sure that the dimension of the TextureRHI always equals Texture2D.
I have no clue if it matters that the assertion (line 656) is checking a FRHITexture and the if statement (line 702) testing a FD3D12Texture, but to me it looks like this could be a bug in the engine. What do you think?
… it’s ok to cast to a FTextureRenderTargetCubeResource:
if (TextureTarget != NULL)
{
FTextureRenderTargetCubeResource* RTResource = (FTextureRenderTargetCubeResource*)TextureTarget->GameThread_GetRenderTargetResource();
if (RTResource->IsInitialized() && RTResource != NULL)
{
if (!RTResource->ReadPixels(ImageDataPosX, FReadSurfaceDataFlags(RCM_UNorm, CubeFace_PosX))) UE_LOG(LogTemp, Warning, TEXT("LiDAR: PosX failed"));
This works because in D3D12RenderTarget.cpp then the method RHIReadSurfaceFloatData is used instead of GetStagingTexture. And since they both do the same more or less (to my very limited understanding), but RHIReadSurfaceFloatData doesn’t have the stupid/broken assertion it now works. Just need to convert the results to FColor and from BGR to RGB, but otherwise now it does what it should and I’m able to access all sides of the cube … yay just a week spent for a bug in the engine.
Let me know if there’s an alternative solution or if this assertion is intentional and how to avoid it …