UE4 ComputeShader Write, Material Read (GPGPU)

エンジンバージョン:4.24 (4.25がリリースされたら対応予定)

ComputeShaderで計算した結果を、RWテクスチャを利用してダイレクトにマテリアルで利用する。↓はサンプルコードの実行の様子。

はじめに

前回の記事ではComputeShaderでメッシュ情報を直接生成する方法を紹介した。前回記事の手法では頂点カラー等を利用することでComputeShaderからマテリアルへ追加情報を渡すことができる。しかし頂点データの一部を間借りすることから渡せる情報に制限がある。
当記事ではComputeShaderが書き込みをしたRWテクスチャをそのままマテリアルで利用することで頂点データ利用に比べてより自由に情報を受け渡す方法を検証してうまくいったので公開。そもそもこんな面倒なことしなくても可能な方法があるかもしれないので注意。
(GlobalShader利用, エンジン改造無し)

サンプルコード

uprojectファイルを右クリック→Generate Visual Studio project files でプロジェクトコード生成.
github.com

説明

RWテクスチャ定義

マテリアルで利用可能且つComputeShaderで書き込みが可能なUAVリソースとしてのテクスチャが必要であるため、UTextureRenderTarget2Dを継承したRWテクスチャを定義する。
bCanCreateUAVにtrueを指定することでリソース自体がUAV利用可能な設定で作成される。ただしこの設定だけではUAVが作成されないため(メンバ変数uav_)、RWテクスチャとして利用するComputeShader処理側で必要なときに生成する(後述)。
また、UAVの破棄はRenderThreadで処理する必要があるのでデストラクタでRenderThreadのコマンドとして発行している。

// UavTextureSampleComponent.h
UCLASS(BlueprintType)
class UNglRWTextureRenderTarget2D : public UTextureRenderTarget2D
{
	GENERATED_UCLASS_BODY()

public:
	virtual ~UNglRWTextureRenderTarget2D();

	FUnorderedAccessViewRHIRef uav_;
};
// UavTextureSampleComponent.cpp
UNglRWTextureRenderTarget2D::UNglRWTextureRenderTarget2D(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	bNeedsTwoCopies = false;
	// リソース生成時にUAV利用可能な設定で作成することを指示
	bCanCreateUAV = true;
}

UNglRWTextureRenderTarget2D::~UNglRWTextureRenderTarget2D()
{
	if (uav_.IsValid())
	{
		// UAVの破棄
		// 破棄は描画スレッドで実行する必要があるのでコマンドをキューに積む.
		auto rhi_resource = uav_;
		ENQUEUE_RENDER_COMMAND(UpdateResourceImmediate)(
			[rhi_resource](FRHICommandListImmediate& RHICmdList)
		{
			rhi_resource->Release();
		}
		);
	}
}

RWテクスチャのUAV生成

本来ならUTextureRenderTarget2Dの初期化フローの中で生成するのが理想だが、今回はUAV利用する側が生成することにした。

// UavTextureSampleComponent.cpp 252行目
if (!rw_tex->uav_.IsValid())
{
	rw_tex->uav_ = RHICreateUnorderedAccessView(rw_tex->Resource->TextureRHI);
}

ComputeShaderによるRWテクスチャへの書き込み

生成したUAVはComputeShaderパラメータに設定することで利用可能。

// UavTextureSampleComponent.cpp 271行目
SetUAVParameter(RHICmdList, rhi_cs, cs->rw_tex, rw_tex->uav_);

RWテクスチャのマテリアルでの利用

UNglRWTextureRenderTarget2Dは通常のUTextureオブジェクトと同様にマテリアルパラメータに設定可能。これでComputeShaderで書き込みをしたRWテクスチャをそのままマテリアルで利用できる。
f:id:nagakagachi:20200319232634p:plain

サンプルコードの概要

サンプルではComputeShaderで簡易な波の計算をして128x128のRWテクスチャに書き込み、マテリアルでその情報を利用して多数配置した三角錐メッシュを揺らしている。サンプルではComputeShaderは2つあり、一つは波の計算をして構造化バッファを更新するもの、もう一つは構造化バッファをもとにRWテクスチャへマテリアルで利用する情報を書き込むもの。マテリアルではRWテクスチャの値を読み取って頂点を動かしている。

f:id:nagakagachi:20200320001630p:plain

テクスチャから取得した波の高さの可視化

ComputeShaderとMaterial連携サンプル動画1

テクスチャから取得した波の高さの勾配ベクトルの可視化

ComputeShaderとMaterial連携サンプル動画2

テクスチャから取得した波の高さと勾配ベクトルを利用して頂点オフセットで揺れ表現をした様子

ComputeShaderとMaterial連携サンプル動画0


手記はここで途切れている