前言
UE本身是提供截图功能的,但是部分情况下策划不想要当前玩家实际整个屏幕的显示,只想要UI的一部分
实现
思路就是手动创建RT,然后Draw,然后保存……(?
具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| void UTestLibrary::SaveWidgetToPNG(const FString& FileName, UWidget* Widget, const FVector2D& DrawSize) { if (!IsValid(Widget)) { UE_LOG(LogTemp, Error, TEXT("Widget is not valid")); return; }
TSharedPtr<SWidget> SWidgetPtr = Widget->GetCachedWidget();
if (DrawSize == FVector2D::ZeroVector) { UE_LOG(LogTemp, Error, TEXT("DrawSize is not valid")); return; }
const FString FilePath = FPaths::ProjectSavedDir() / TEXT("Screenshots"); FString FullFileName = FilePath / FileName; if (!FullFileName.EndsWith(TEXT(".png"), ESearchCase::IgnoreCase)) { FullFileName = FullFileName + (TEXT(".png")); }
FWidgetRenderer* WidgetRenderer = new FWidgetRenderer; WidgetRenderer->SetIsPrepassNeeded(false);
const TSharedRef<SWidget> WidgetRef = SWidgetPtr.ToSharedRef(); UTextureRenderTarget2D* RenderTarget2D = NewObject<UTextureRenderTarget2D>(); const EPixelFormat RequestedFormat = FSlateApplication::Get().GetRenderer()->GetSlateRecommendedColorFormat(); RenderTarget2D->Filter = TF_Bilinear; RenderTarget2D->ClearColor = FLinearColor::Red; RenderTarget2D->SRGB = true; RenderTarget2D->TargetGamma = 1; RenderTarget2D->RenderTargetFormat = RTF_RGBA8; RenderTarget2D->InitCustomFormat(DrawSize.X, DrawSize.Y, RequestedFormat, false); RenderTarget2D->UpdateResourceImmediate(true); WidgetRenderer->DrawWidget(RenderTarget2D, SWidgetPtr.ToSharedRef(), DrawSize, 0, false); const FString SavePath = FPaths::ProjectSavedDir() / TEXT("Screenshots"); const FString File = SavePath / FileName; UKismetRenderingLibrary::ExportRenderTarget(nullptr, RenderTarget2D, FilePath, FileName); }
|
简单解释
1. 创建RenderTarget
1 2 3 4 5 6 7 8 9
| UTextureRenderTarget2D* RenderTarget2D = NewObject<UTextureRenderTarget2D>(); const EPixelFormat RequestedFormat = FSlateApplication::Get().GetRenderer()->GetSlateRecommendedColorFormat(); RenderTarget2D->Filter = TF_Bilinear; RenderTarget2D->ClearColor = FLinearColor::Red; RenderTarget2D->SRGB = true; RenderTarget2D->TargetGamma = 1; RenderTarget2D->RenderTargetFormat = RTF_RGBA8; RenderTarget2D->InitCustomFormat(DrawSize.X, DrawSize.Y, RequestedFormat, false); RenderTarget2D->UpdateResourceImmediate(true);
|
上面的代码是创建一个UTextureRenderTarget2D
对象,然后设置一些参数,最后调用UpdateResourceImmediate()
方法立即更新资源
相关参数与方法解释
GetSlateRecommendedColorFormat()
获取Slate推荐的颜色格式, 一般是PF_B8G8R8A8
Filter
采样此纹理时要使用的纹理过滤模式,一般是TF_Bilinear
ClearColor
清除纹理时要使用的颜色,大部分情况下很多用的是透明色,我这里用红色是为了方便调试
SRGB
是否使用sRGB颜色空间
TargetGamma
用于渲染到纹理的gamma值,如果>0,将覆盖FTextureRenderTarget2DResource::GetDisplayGamma
RenderTargetFormat
纹理的格式,一般是RTF_RGBA8
InitCustomFormat()
初始化自定义格式的纹理,第四个参数是bInForceLinearGame
,如果为true,则使用线性颜色空间,否则使用sRGB颜色空间
UpdateResourceImmediate()
立即更新资源,参数是bClearRenderTarget
,如果为true,则清除纹理
需要注意色彩管理相关的参数,如果和游戏本身的色彩管理不一致,可能会导致截图的颜色不正确。
在UE4中,为了获得更好的暗部精度,线性伽马空间是指所有颜色的数学运算都发生在线性空间中的渲染管道。输入颜色纹理(漫反射,镜面反射等)存储在伽马空间中以获得更好的暗部精度。这些纹理采用sRGB读取进行采样,这样可以进行转换。
2. Draw
1
| WidgetRenderer->DrawWidget(RenderTarget2D, SWidgetPtr.ToSharedRef(), DrawSize, 0, false);
|
调用DrawWidget()
方法,将Widget绘制到RenderTarget上
相关参数与方法解释
1 2 3 4 5 6
| void DrawWidget( UTextureRenderTarget2D* RenderTarget, const TSharedRef<SWidget>& Widget, FVector2D DrawSize, float DeltaTime, bool bDeferRenderTargetUpdate = false);
|
DrawWidget()
方法的参数解释
RenderTarget
要绘制到的RenderTarget
Widget
要绘制的Widget
DrawSize
绘制的大小
DeltaTime
绘制的时间
bDeferRenderTargetUpdate
是否延迟更新RenderTarget,如果为true,则需要手动调用UpdateResourceImmediate()
方法更新RenderTarget
3. 保存
1 2 3
| const FString SavePath = FPaths::ProjectSavedDir() / TEXT("Screenshots"); const FString File = SavePath / FileName; UKismetRenderingLibrary::ExportRenderTarget(nullptr, RenderTarget2D, FilePath, FileName);
|
调用UKismetRenderingLibrary::ExportRenderTarget()
方法,将RenderTarget保存为PNG
这里需要注意,ExportRenderTarget
的内部首先是根据RenderTarget
的RenderTargetFormat
来判断要保存的格式,如果是RTF_RGBA16f
,则会直接进入HDR格式的流程,所以前面选择手动创建RenderTarget并且设置RenderTargetFormat
为RTF_RGBA8
,这样就可以保证保存的是PNG格式
参考