UE输出场景2D全景图和2D全景深度图

UE输出场景2D全景图和2D全景深度图 1 准备创建一个立方体渲染目标使用USceneCaptureComponentCube组件捕获全景图使用SCS_FinalColorHDR或者SCS_FinalColorLDR捕获深度使用SCS_SceneDepth然后通过引擎的CubemapHelpers::GenerateLongLatUnwrap函数来把渲染纹理转成2d全景图。2 说明捕获深度时候纹理我使用的PF_A32B32G32R32F这个精度够也支持在Linux平台使用其他格式可以自行探索RenderTarget-OverrideFormat PF_FloatRGBA;这一步代码是为了GenerateLongLatUnwrap函数能够正常处理成16位的结果。3 代码1 捕获2d全景图// 1. 捕获 RGB HDR SceneCapture-CaptureSource ESceneCaptureSource::SCS_FinalColorHDR; RenderTarget-Init(FaceSize, PF_FloatRGBA); SceneCapture-CaptureScene(); FlushRenderingCommands(); TArray64uint8 RGBRawData; FIntPoint RGBOutputSize; EPixelFormat RGBOutputFormat; bool bSuccess CubemapHelpers::GenerateLongLatUnwrap(RenderTarget, RGBRawData, RGBOutputSize, RGBOutputFormat); if (!bSuccess) { UE_LOG(LogTemp, Error, TEXT(RGB GenerateLongLatUnwrap Error)); return; } TArrayFLinearColor ExrPixels; int32 RGBPixelCount RGBOutputSize.X * RGBOutputSize.Y; ExrPixels.SetNum(RGBPixelCount); for (int32 i 0; i RGBPixelCount; i) { const uint8* PixelPtr RGBRawData[i * 8]; FFloat16 R16, G16, B16, A16; FMemory::Memcpy(R16, PixelPtr, 2); FMemory::Memcpy(G16, PixelPtr 2, 2); FMemory::Memcpy(B16, PixelPtr 4, 2); ExrPixels[i] FLinearColor(R16.GetFloat(), G16.GetFloat(), B16.GetFloat(), 1.0f); } { TArrayFColor Pixels; Pixels.SetNum(ExrPixels.Num()); for (int i 0; i ExrPixels.Num(); i) { Pixels[i] ExrPixels[i].ToFColor(true); } TArray64uint8 PNGData; FImageUtils::PNGCompressImageArray(RGBOutputSize.X, RGBOutputSize.Y, Pixels, PNGData); FFileHelper::SaveArrayToFile(PNGData, *SaveRGBFilePath); }2 捕获2d全景深度图// 捕获深度 UTextureRenderTargetCube* RenderTarget SceneCapture-TextureTarget; const int32 FaceSize width; SceneCapture-CaptureSource ESceneCaptureSource::SCS_SceneDepth; RenderTarget-Init(FaceSize, PF_A32B32G32R32F); SceneCapture-CaptureScene(); FlushRenderingCommands(); // 这一步代码是为了GenerateLongLatUnwrap函数能够正常处理成16位的结果 RenderTarget-OverrideFormat PF_FloatRGBA; TArray64uint8 DepthRawData; FIntPoint DepthOutputSize; EPixelFormat DepthOutputFormat; bSuccess CubemapHelpers::GenerateLongLatUnwrap(RenderTarget, DepthRawData, DepthOutputSize, DepthOutputFormat); if (!bSuccess) { UE_LOG(LogTemp, Error, TEXT(Depth GenerateLongLatUnwrap Error)); return; } TArrayfloat SceneDepths; int32 DepthPixelCount DepthOutputSize.X * DepthOutputSize.Y; SceneDepths.SetNum(DepthPixelCount); float MaxClipDepth 65504; for (int32 i 0; i DepthPixelCount; i) { const uint8* PixelPtr DepthRawData[i * 8]; FFloat16 R16; FMemory::Memcpy(R16, PixelPtr, 2); float Depth R16.GetFloat(); if (Depth 0.0f Depth MaxClipDepth) { SceneDepths[i] Depth; } else { SceneDepths[i] 0; } } { float MinDepth TNumericLimitsfloat::Max(); float MaxDepth TNumericLimitsfloat::Min(); for (int32 i 0; i SceneDepths.Num(); i) { float Depth SceneDepths[i]; if (Depth 0) { MinDepth FMath::Min(MinDepth, Depth); MaxDepth FMath::Max(MaxDepth, Depth); } } float DepthRange MaxDepth - MinDepth; if (DepthRange KINDA_SMALL_NUMBER) DepthRange 1.0f; TArrayuint16 DepthData16; DepthData16.SetNumUninitialized(SceneDepths.Num()); for (int32 i 0; i SceneDepths.Num(); i) { float Depth SceneDepths[i]; float NormalizedDepth (Depth - MinDepth) / DepthRange; NormalizedDepth FMath::Clamp(NormalizedDepth, 0.0f, 1.0f); float FlippedDepth 1.0f - NormalizedDepth; DepthData16[i] static_castuint16(FlippedDepth * MAX_uint16); } IImageWrapperModule ImageWrapperModule FModuleManager::LoadModuleCheckedIImageWrapperModule(FName(ImageWrapper)); TSharedPtrIImageWrapper ImageWrapper ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG); if (ImageWrapper-SetRaw(DepthData16.GetData(), DepthData16.GetAllocatedSize(), DepthOutputSize.X, DepthOutputSize.Y, ERGBFormat::Gray, 16)) { TArray64uint8 CompressedData ImageWrapper-GetCompressed(); if (CompressedData.Num() 0) { FFileHelper::SaveArrayToFile(CompressedData, *SaveDepthFilePath); } } else { UE_LOG(LogTemp, Error, TEXT(Depth SetRaw failed)); } }4 效果图2d全景图2d全景图深度图