[Tutorial] Pixel and Compute Shaders in UE4

Hi, I’m so puzzled with compute shader recently, And I don’t know how to copy the result calculated from compute_shader. I try to copy the TextureRHI resource to a render target. But operation is always failed. could you give me some help? thank you very much.

static void UseComputeShader_RenderThread(
FRHICommandListImmediate& RHICmdList,
FTextureRenderTargetResource* OutputRenderTargetResource,
ERHIFeatureLevel::Type FeatureLevel
)
{
check(IsInRenderingThread());

TShaderMapRef<FMyComputeShader> ComputeShader(GetGlobalShaderMap(FeatureLevel));
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());

//ComputeShader->SetSurfaces(RHICmdList,)
int32 SizeX = OutputRenderTargetResource->GetSizeX();
int32 SizeY = OutputRenderTargetResource->GetSizeY();
FRHIResourceCreateInfo CreateInfo;

FTexture2DRHIRef Texture = RHICreateTexture2D(SizeX, SizeY, PF_A32B32G32R32F, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
FUnorderedAccessViewRHIRef TextureUAV = RHICreateUnorderedAccessView(Texture);
ComputeShader->SetSurfaces(RHICmdList, TextureUAV);

DispatchComputeShader(RHICmdList, *ComputeShader, SizeX/32, SizeY/32, 1);
ComputeShader->UnbindBuffers(RHICmdList);

// Resolve render target.
RHICmdList.CopyToResolveTarget(
Texture,
OutputRenderTargetResource->TextureRHI,
true, FResolveParams());

//create a bitmap
TArray<FColor> Bitmap;

//To access our resource we do a custom read using lockrect
uint32 LolStride = 0;
char* TextureDataPtr = (char*)RHICmdList.LockTexture2D(Texture, 0, EResourceLockMode::RLM_ReadOnly, LolStride, false);

for (uint32 Row = 0; Row < Texture->GetSizeY(); ++Row)
{
uint32* PixelPtr = (uint32*)TextureDataPtr;

//Since we are using our custom UINT format, we need to unpack it here to access the actual colors
for (uint32 Col = 0; Col < Texture->GetSizeX(); ++Col)
{
uint32 EncodedPixel = *PixelPtr;
uint8 r = (EncodedPixel & 0x000000FF);
uint8 g = (EncodedPixel & 0x0000FF00) >> 8;
uint8 b = (EncodedPixel & 0x00FF0000) >> 16;
uint8 a = (EncodedPixel & 0xFF000000) >> 24;
Bitmap.Add(FColor(r, g, b, a));

PixelPtr++;
}

// move to next row:
TextureDataPtr += LolStride;
}

RHICmdList.UnlockTexture2D(Texture, 0, false);

// if the format and texture type is supported
if (Bitmap.Num())
{
// Create screenshot folder if not already present.
IFileManager::Get().MakeDirectory(*FPaths::ScreenShotDir(), true);

const FString ScreenFileName(FPaths::ScreenShotDir() / TEXT(“VisualizeTexture”));

uint32 ExtendXWithMSAA = Bitmap.Num() / Texture->GetSizeY();

// Save the contents of the array to a bitmap file. (24bit only so alpha channel is dropped)
FFileHelper::CreateBitmap(*ScreenFileName, ExtendXWithMSAA, Texture->GetSizeY(), Bitmap.GetData());

UE_LOG(LogConsoleResponse, Display, TEXT(“Content was saved to “%s””), *FPaths::ScreenShotDir());
}
else
{
UE_LOG(LogConsoleResponse, Error, TEXT(“Failed to save BMP, format or texture type is not supported”));
}

}