12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Unreal Engine (UE)Advent Calendar 2023

Day 5

【UE5】ウィジェットを画像として出力する(プラグイン配布あり)

Last updated at Posted at 2023-12-05

はじめに

生粋の Unrealer の皆さんは、Photoshop などの画像編集ソフトではなく、使い慣れた UMG でデザインしたくなることが稀によくあるかと思います。(?)
そこで本記事では、UMG で作成したウィジェットを PNG 等の画像ファイルとして出力する方法を説明します。

説明とかどうでもいいからプラグイン使わせろ!という方はこちらへどうぞ。

UE 4.27 - 5.3 で動作確認済みです。

実装例

上記のプラグインで実装している内容です。
UE 5.3 時点では、C++ が必須です。

WidgetToImageFunctionLibrary.h
#pragma once

#include "CoreMinimal.h"
#include "Engine/Texture.h"
#include "ImageWriteTypes.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "WidgetToImageFunctionLibrary.generated.h"

class SWidget;

UCLASS()
class WIDGETTOIMAGE_API UWidgetToImageFunctionLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

public:
	static void ExportWidgetAsImage(
		TSharedRef<SWidget> Widget,
		const FString& Filename,
		const FVector2D& DrawSize,
		const float Scale = 1.f,
		const EDesiredImageFormat Format = EDesiredImageFormat::PNG,
		const bool bOverwriteFile = true,
		const bool bAsync = true,
		const TextureFilter Filter = TF_Bilinear,
		const bool bUseGammaCorrection = true);

	UFUNCTION(BlueprintCallable, Category = "WidgetToImage", meta = (AdvancedDisplay = 4))
	static void ExportWidgetAsImage(
		UUserWidget* Widget,
		const FString Filename,
		const FVector2D DrawSize,
		const float Scale = 1.f,
		const EDesiredImageFormat Format = EDesiredImageFormat::PNG,
		const bool bOverwriteFile = true,
		const bool bAsync = true,
		const TextureFilter Filter = TF_Bilinear,
		const bool bUseGammaCorrection = true);
};
WidgetToImageFunctionLibrary.cpp
#include "WidgetToImageFunctionLibrary.h"
#include "Blueprint/UserWidget.h"
#include "Engine/TextureRenderTarget2D.h"
#include "ImageWriteBlueprintLibrary.h"
#include "RenderingThread.h"
#include "Slate/WidgetRenderer.h"

void UWidgetToImageFunctionLibrary::ExportWidgetAsImage(TSharedRef<SWidget> Widget, const FString& Filename, const FVector2D& DrawSize, const float Scale /*= 1.f*/, const EDesiredImageFormat Format /*= EDesiredImageFormat::PNG*/, const bool bOverwriteFile /*= true*/, const bool bAsync /*= true*/, const TextureFilter Filter /*= TF_Bilinear*/, const bool bUseGammaCorrection /*= true*/)
{
	FWidgetRenderer* WidgetRenderer = new FWidgetRenderer(bUseGammaCorrection, false);

	if (UTextureRenderTarget2D* RenderTarget = FWidgetRenderer::CreateTargetFor(DrawSize, Filter, bUseGammaCorrection))
	{
		if (bUseGammaCorrection)
		{
			RenderTarget->bForceLinearGamma = true;
			RenderTarget->UpdateResourceImmediate();
		}

		WidgetRenderer->DrawWidget(RenderTarget, Widget, Scale, DrawSize, 0.f);

		::FlushRenderingCommands();

		FImageWriteOptions Options;
		Options.Format = Format;
		Options.bOverwriteFile = bOverwriteFile;
		Options.bAsync = bAsync;

		UImageWriteBlueprintLibrary::ExportToDisk(RenderTarget, Filename, Options);
	}

	::BeginCleanup(WidgetRenderer);
}

void UWidgetToImageFunctionLibrary::ExportWidgetAsImage(UUserWidget* Widget, const FString Filename, const FVector2D DrawSize, const float Scale /*= 1.f*/, const EDesiredImageFormat Format /*= EDesiredImageFormat::PNG*/, const bool bOverwriteFile /*= true*/, const bool bAsync /*= true*/, const TextureFilter Filter /*= TF_Bilinear*/, const bool bUseGammaCorrection /*= true*/)
{
	ExportWidgetAsImage(Widget->TakeWidget(), Filename, DrawSize, Scale, Format, bOverwriteFile, bAsync, Filter, bUseGammaCorrection);
}

CreateWidget ノードで作成したウィジェットを、上記で作成した ExportWidgetAsImage ノードに渡すことで、ウィジェットを画像ファイルとして出力できます。
勿論ウィジェットに変更を加えてから出力することも可能です。

image.png

出力するウィジェットがエンジンの標準ではない独自の Slate Widget を使用している場合は、SWidget::OnPaint をオーバーライドして FSlateElement での描画処理を記述しないと画像が正しく出力されないため、注意。

解説

ウィジェットを画像ファイルとして出力する際の流れは、下記の通りです。

  1. UUserWidget から SWidget を取得する
  2. SWidget を UTextureRenderTarget2D に描画する
  3. UTextureRenderTarget2D を画像として出力する

1. UUserWidget から SWidget を取得する

UWidget::TakeWidget を使います。

Widget->TakeWidget()

2. SWidget を UTextureRenderTarget2D に描画する

エンジンの FWidgetRenderer というクラスに、このための関数 (FWidgetRenderer::DrawWidget) が用意されているので、これを利用します。

FWidgetRenderer* WidgetRenderer = new FWidgetRenderer(bUseGammaCorrection, false);

描画先の UTextureRenderTarget2D は、FWidgetRenderer::CreateTargetFor を使って作成すると楽です。
なお、ガンマ補正を使用する場合は個別に設定と更新が必要です。

if (UTextureRenderTarget2D* RenderTarget = FWidgetRenderer::CreateTargetFor(DrawSize, Filter, bUseGammaCorrection))
{
	if (bUseGammaCorrection)
	{
		RenderTarget->bForceLinearGamma = true;
		RenderTarget->UpdateResourceImmediate();
	}

作成した UTextureRenderTarget2D に対して、FWidgetRenderer::DrawWidget を実行します。
実行後は ::FlushRenderingCommands でレンダリングスレッドを待機する必要があります。

WidgetRenderer->DrawWidget(RenderTarget, Widget, Scale, DrawSize, 0.f);

::FlushRenderingCommands();

FWidgetRenderer は FDeferredCleanupInterface を継承しているので、破棄する際は ::BeginCleanup を使用します。

::BeginCleanup(WidgetRenderer);

WidgetRenderer の生成は、RenderTarget を作成する前に行う必要があります。
順番が逆になると、たまに画像が正しく出力されなくなります。どうして。

3. UTextureRenderTarget2D を画像として出力する

UImageWriteBlueprintLibrary::ExportToDisk で UTexture を画像ファイルとして出力できます。
オプションとして、ファイル形式 (PNG, JPG, BMP, EXR)、上書き保存するかどうか、非同期実行するかどうかを選択できます。
ちなみに、この関数は Blueprint でも使用可能です。

FImageWriteOptions Options;
Options.Format = Format;
Options.bOverwriteFile = bOverwriteFile;
Options.bAsync = bAsync;

UImageWriteBlueprintLibrary::ExportToDisk(RenderTarget, Filename, Options);

おわりに

ここまで説明した内容が実装されているプラグインは、こちらからダウンロード可能です。

また、UE マーケットプレイスにて無料のプラグインを他にも公開しているので、こちらもぜひ。

これであなたも脱フォトショ!(?)

12
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?