6
1

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 3 years have passed since last update.

UnrealC++でアセットのエクスポート機能を拡張する

Posted at

#はじめに
皆さんはアセットのエクスポート機能は使っていますか?テクスチャアセットとかだと比較的使う機会があったりするのかもしれません。
そんなアセットのエクスポート機能ですが、実は結構お手軽に拡張できます。
今回はアセットのサムネイルを画像ファイルに出力するプラグインを見ながらご紹介したいと思います。

#つくってみる
「はじめに」に埋め込んだtweetにある通り、必要な作業はUExporterクラスを継承して、出力する部分の処理を作るだけです。

ThumbnailExporter.h

ThumbnailExporter.h
// Copyright 2020 Naotsun. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Exporters/Exporter.h"
#include "ThumbnailExporter.generated.h"

/*
 * Class for exporting asset thumbnails.
 */
UCLASS()
class ASSETTHUMBNAILEXPORTER_API UThumbnailExporter : public UExporter
{
	GENERATED_BODY()

public:
	UThumbnailExporter(const FObjectInitializer& ObjectInitializer);

	// UExporter interface.
	virtual bool SupportsObject(UObject* Object) const override;
	virtual bool ExportBinary(UObject* Object, const TCHAR* Type, FArchive& Ar, FFeedbackContext* Warn, int32 FileIndex = 0, uint32 PortFlags = 0) override;
	// End of UExporter interface.
};

まずはヘッダーですが、UExporterクラスを継承して、このプラグインでは画像ファイルへ出力するためUExporter::ExportBinary関数をオーバライドします。
3.PNG
また、このプラグインでは画像のようにエディタ設定で指定した任意のクラスをサポートするようにしたいため、UExporter::SupportsObject関数もオーバライドします。もし単一のアセットのみをサポートするのであればこの関数はオーバライドする必要はありません。

ThumbnailExporter.cpp

ThumbnailExporter.cpp
UThumbnailExporter::UThumbnailExporter(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	SupportedClass = UObject::StaticClass();
	PreferredFormatIndex = 2;
	BatchExportMode = true;
	CancelBatch = true;

	FormatExtension.Add(TEXT("EXR"));
	FormatDescription.Add(TEXT("Export Thumbnail As EXR"));
	FormatExtension.Add(TEXT("JPEG"));
	FormatDescription.Add(TEXT("Export Thumbnail As JPEG"));
	FormatExtension.Add(TEXT("PNG"));
	FormatDescription.Add(TEXT("Export Thumbnail As PNG"));
}

次にソースファイルです。まずはコンストラクタで各種設定を行います。

SupportedClass関数はサポートするアセットのクラスです。このプラグインでは複数のアセットを対象としたいためUObjectのクラスを設定します。単一のアセットをサポートする場合はここでクラスを指定すればOKです。

PreferredFormatIndexはコメントを読む限り「追加する拡張子がプルダウンメニュー上のどのインデックスに挿入されるか」を決める変数のようですが、どんな値にしても結果は変わりませんでした。(原因がわかる方はコメントなどで教えて頂けると嬉しいです!)

BatchExportModeは複数のアセットを一括でエクスポートできるかを決めます。CancelBatchBatchExportModetrueの時にtrueにすると一括エクスポート中にキャンセルできるようになります。

FormatExtensionには追加する拡張子を、FormatDescriptionにはその拡張子の説明を追加します。プルダウンメニューにはFormatDescriptionの文字列が表示されます。

ThumbnailExporter.cpp

ThumbnailExporter.cpp
bool UThumbnailExporter::SupportsObject(UObject* Object) const
{
	auto* Settings = GetDefault<UAssetThumbnailExporterSettings>();
	if (Super::SupportsObject(Object) && IsValid(Settings) && IsValid(Object))
	{
		bool bIsSupportsOrChildClass = false;
		UClass* ObjectClass = Object->GetClass();
		for (const auto& SupportsAssetClass : Settings->SupportsAssetClasses)
		{
			if (SupportsAssetClass == ObjectClass || ObjectClass->IsChildOf(SupportsAssetClass))
			{
				bIsSupportsOrChildClass = true;
				break;
			}
		}

		return (Object->IsAsset() && bIsSupportsOrChildClass);
	}

	return false;
}

次にSupportsObject関数ですがこのプラグインのような特殊なことをするのでなければ不要かつ、エディタ設定で設定されているクラスかを確かめているだけなのでサラッと流します。
ちなみにベースクラスのSupportsObject関数ではコンストラクタで設定したSupportedClass及びその子クラスかを判定しています。

UnrealExporter.cpp

UnrealExporter.cpp
// Returns whether this exporter supports the specific object
bool UExporter::SupportsObject(UObject* Object) const
{
	return (SupportedClass && Object->IsA(SupportedClass));
}

どうでもいいことですが、UExporterのようにヘッダーとソースファイルの名前が違うとエクスプローラやgithubで探す時に戸惑うのでちょっと困りますね...w

ThumbnailExporter.cpp

ThumbnailExporter.cpp
bool UThumbnailExporter::ExportBinary(UObject* Object, const TCHAR* Type, FArchive& Ar, FFeedbackContext* Warn, int32 FileIndex, uint32 PortFlags)
{
	FVector2D ImageSize(512, 512);
	if (auto* Settings = GetDefault<UAssetThumbnailExporterSettings>())
	{
		ImageSize = Settings->ImageSize;
	}

	FObjectThumbnail ObjectThumbnail;
	ThumbnailTools::RenderThumbnail(
		Object,
		ImageSize.X, ImageSize.Y,
		ThumbnailTools::EThumbnailTextureFlushMode::AlwaysFlush, NULL,
		&ObjectThumbnail
	);

	if (ObjectThumbnail.IsEmpty())
	{
		Warn->Log(TEXT("The thumbnail object was empty."));
		return false;
	}

	IImageWrapperModule& ImageWrapperModule = FModuleManager::Get().LoadModuleChecked<IImageWrapperModule>(TEXT("ImageWrapper"));
	TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(ThumbnailExporterInternal::ConvertStringToImageFormat(Type));
	if (!ImageWrapper.IsValid())
	{
		Warn->Log(TEXT("Failed to get ImageWrapper."));
		return false;
	}
	
	const TArray<uint8>& RawImageData = ObjectThumbnail.AccessImageData();

	if (!ImageWrapper->SetRaw(RawImageData.GetData(), RawImageData.GetAllocatedSize(), ImageSize.X, ImageSize.Y, ERGBFormat::BGRA, 8))
	{
		Warn->Log(TEXT("Could not set data to ImageWrapper."));
		return false;
	}

	const TArray64<uint8>& CompressedData = ImageWrapper->GetCompressed();
	if (CompressedData.Num() == 0)
	{
		Warn->Log(TEXT("The compressed data was empty."));
		return false;
	}

	Ar.Serialize((void*)CompressedData.GetData(), CompressedData.GetAllocatedSize());

	return true;
}

IImageWrapperModuleを使った画像出力についてはヒストリアさんの記事や私が以前に書いた記事にあるのでそちらを読んでいただければと思います。
ImageWrapperModuleを用いて指定の拡張子でスクリーンショットを書き出す方法
UnrealC++で画像ファイルからテクスチャアセットを作成する

最後にアセットからサムネイルのデータを取得する方法ですが、ThumbnailTools::RenderThumbnailを使います。必要なヘッダーは"Misc/ObjectThumbnail.h"です。

引数にサムネイルを取得したいオブジェクト、画像サイズ、テクスチャストリームのフラッシュ設定、描画に使用するレンダーターゲットリソース、最後に結果を出力するFObjectThumbnailを渡すだけで動きます。
テクスチャストリームのフラッシュ設定ですが、ThumbnailTools::EThumbnailTextureFlushMode::NeverFlushにすると出力結果がぼやける可能性があるので特に理由がなければThumbnailTools::EThumbnailTextureFlushMode::AlwaysFlushにしておきましょう。

そしてFObjectThumbnailからTArray<uint8>型でデータが取得できるのでそれをIImageWrapperModuleを使って画像ファイルに出力します。

#おわりに
ここ最近誰得記事を量産している気がしますが、「ちょうど今エクスポート機能拡張したかったんだよぉ!!」って方の役に立てれば嬉しいです。あとは13連続でUnrealC++を使った記事なのでBPでできることの記事も書きたいですね。
このプラグインでは画像ファイルへの出力でしたが、テキストファイルへの出力などもできるのでもっといろんなことができるのではないでしょうか。

この記事で紹介したプラグインは以下でダウンロードできます。
https://github.com/Naotsun19B/TmbExporterPlugin

6
1
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
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?