UE4 SceneCaptureとRenderTargetのテスト(別カメラの絵を投影してみる)

# 概要
UnrealEngine の SceneCapture と RenderTarget を使って別カメラの映像を投影するテストです。


## 環境
Windows10
Visual Studio 2017
UnrealEngine 4.24

## 参考
以下を参考にさせて頂きました、ありがとうございます。

[【UE4】映像をレンダーテクスチャーで投影する方法](https://argonauts.hatenablog.jp/entry/2017/03/11/181911)
[UE4 別カメラで描画した映像をTexture化して使う（Scene Capture 2D、Render Target）](http://kagring.blog.fc2.com/blog-entry-397.html)
[【UE4】Scene Capture 2Dで別視点から見たものを写す](https://tubezgames.com/2017/09/ue4-scenecapture2d/)
[【UE4】FrameGrabberを用いたキャプチャの実装方法を読み解いてみる](https://isemito.hatenablog.com/entry/2018/12/09/192026)
[Frame Grabber機能を使って、レンダリング結果（フレームバッファ）をテクスチャ化する方法について](https://pafuhana1213.hatenablog.com/entry/2018/08/27/001512)


# 関連ソース

"Engine\Source\Runtime\Engine\Classes\Engine\SceneCapture2D.h"
"Engine\Source\Runtime\Engine\Classes\Components\SceneCaptureComponent2D.h"
"Engine\Source\Runtime\Engine\Classes\Engine\TextureRenderTarget2D.h"


# 別視点の映像を投影させる１
レンダーターゲットをレベル上の板アクターに反映させてみます。

## レンダーターゲットとマテリアル準備
コンテンツ右クリックから「描画ターゲット」を選択して作成します。

![create_rendertarget.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/a5becdbc-50d9-7ece-5d2b-659b9eb7853b.jpeg)

できたレンダーターゲットを右クリックし、マテリアルを作成します。

![create_material.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/da82b69e-39bb-1691-6a83-b83e277643ea.jpeg)

出来たマテリアルはテクスチャを張っただけの以下のような感じになります。

![material00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/f6d8110c-5167-4b4f-322c-af2c7f72a7db.jpeg)


## 映像を反映させるアクターを作成
レベルに投影させるスクリーンとして `Plane`を作成し置きます。

![create_plane00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/52f41d9c-2d31-9fb4-429d-cee3dbbf69c5.jpeg)

この `Plane`のマテリアル設定に先ほどレンダーターゲットから作成したマテリアルを設定します。

![plane_material.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/3196babc-a7a2-f62b-2a28-8993ddfe6691.jpeg)


## シーンキャプチャの用意

シーンキャプチャ2Dをレベルに配置し、トランスフォームを調整します。
![create_scenecapture.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/54b41bf7-8ee8-507b-7d6b-a01c9a6a1242.jpeg)

生成したシーンキャプチャの [Scene Capture] -> [Texture Target] に先ほど作成したレンダーターゲットテスクチャを設定します。


あるいはレベルブループリント等でスポーンする方法でも可。
![create_scenecaptureBP.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/33072b9e-248e-d7da-841f-6da68c29921a.jpeg)


## 結果
静止画だとわかりにくいですが、キャラクタ上空から移した映像が Plane に反映されています。

![result1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/4f7142b0-77f6-2e49-b549-8cd2773f4f6e.jpeg)

画像の解像度が荒い場合などはレンダーターゲットの `SizeX` `SizeY` のパラメータを調整すると良いです。（大きすぎると描画負荷がかかります）


# 別視点の映像を投影させる２
レンダーターゲットを EditorUtilityWidget などのUMGに反映させてみます。

## マテリアルの準備
先ほどと同様にマテリアルを準備しますが、UI用なので [Material] -> [Material Domain] が `User Intarface` になります。

![create_materialUI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/c1469185-0360-1f9a-a83f-919d8db4148c.jpeg)

テクスチャはレンダーターゲットを指定します。

## UMGの準備
EditorUtilityWidget を作成します。（通常のUMGでも可）

![create_EUW.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/58fd1791-17c1-0eac-3f4e-b6b1444a0157.jpeg)

中身は Image があるだけです。
[Appearance] -> [Brush] -> [Image] に先ほど用意したマテリアルを指定します。

![EUW_Detail.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/0e6872f3-4ec0-b46b-fba9-5039faacdf3c.jpeg)


## 結果
エディタを実行し、EditorUtilityWidget を右クリック -> [Run Editor Utility Widget]を実行すると別ウィンドウにてレンダーターゲットでの絵が反映されます。

![result2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/d88da68d-14da-e0c8-40fd-d70b00cc87da.jpeg)



# C++でシーンキャプチャアクターをスポーンする
シーンキャプチャをC++でスポーンします。通常のアクターのスポーンと引数が少し違うだけで同じように処理できます。

## 準備
シーンキャプチャアクターを用意します。
![create_a_scenecapture.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/6539e36a-13cb-6605-4355-f2e93af4559b.jpeg)

こんなアイコンになります。
![scenecapture_icon.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/b30e276c-ed58-8f68-029a-d7a2f4c51b21.jpeg)


対象のレンダーターゲットが固定の場合、予めテクスチャターゲットに設定しておくと楽です。
![scenecapture_textarget.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/29a4e38b-cfe3-6332-05d8-5e1ecd1a4c98.jpeg)

## シーンキャプチャアクターをスポーンする
キャラクターの BeginPlay にてシーンキャプチャアクターをスポーンしてみます。
以下コード例

```cpp:.cpp
#include "Engine/SceneCapture2D.h"
#include "Components/SceneCaptureComponent2D.h"
#include "Engine/TextureRenderTarget2D.h"

void AMyProjectCharacter::BeginPlay()
{
	Super::BeginPlay();

	// シーンキャプチャアクターのパス
	FString _Path = TEXT("/Game/MySceneCapture2D.MySceneCapture2D_C");
	TSubclassOf<class ASceneCapture2D> _Class = TSoftClassPtr<ASceneCapture2D>(FSoftObjectPath(*_Path)).LoadSynchronous();
	
	// トランスフォームパラメータ
	FTransform _Transform = FTransform();
	_Transform.SetLocation(FVector(-940.0f, 170.0f, 760.0f));
	_Transform.SetRotation(FRotator(-80.0f, 0.0f, 0.0f).Quaternion());
	// シーンキャプチャアクターをスポーンする
	ASceneCapture2D* SceneCap = GetWorld()->SpawnActor<ASceneCapture2D>(_Class, _Transform);
	
	// シーンキャプチャアクターのターゲットを設定する
	if(SceneCap){
		// レンダーターゲットのパス
		_Path = TEXT("/Game/NewTextureRenderTarget2D");
		auto _Tex = Cast<UTextureRenderTarget2D>(StaticLoadObject(UTextureRenderTarget2D::StaticClass(), NULL, *_Path ));
		
		SceneCap->GetCaptureComponent2D()->TextureTarget = _Tex;
	
	}
}
```

結果は一緒です。



# レンダーターゲットの表示対象の切り替え
レンダーターゲットでのアクターの表示対象切り替えをテストします。

## 準備
ボックスとスフィアのスタティックメッシュアクターを置きます。

![add_actor.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/ecdff6c2-b2ea-7243-7cd7-c7729c3b8f04.jpeg)

判別用にそれぞれアクタータグ `Sphere` `Box`を設定しておきます。
![staticactor_detail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/ba632e55-51f1-5df3-de05-7704db1b2455.png)


## レンダーターゲットで特定アクターを表示しない処理
シーンキャプチャ2Dに対し、以下のような処理を追加します。

![add_proc_scenecapture.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/ef74d8bf-c653-144f-0cd2-e6fdf86333d7.jpeg)

タグ `Box`を持っているアクターを `Hidden Actors` に追加します。


## ゲーム中で特定アクターを表示しない処理
サードパーソンキャラクターのBPに対し、以下のような処理を追加します。

![add_proc_thirdpersonchara.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/6e788ada-ef85-3d4b-c38c-44da83827614.jpeg)

タグ `Sphere` を持っているアクターに対し、`New Owner No See` フラグを立てておきます。

## 結果
エディタ上ではボックスとスフィアが置かれています。
![result3_editor.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/2df0c439-da8e-09fc-01ea-509eb10d025c.jpeg)

実行するとエディタ上ではボックスは見えて、スフィアが見えません。
レンダーターゲット上ではボックスは見えませんが、スフィアが見えます。
![result3_play.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/33dc151a-1a63-0c59-4614-6a3f0430ea22.jpeg)

レンダーターゲットの設定次第でいろいろできると思います。



# まとめ
シーンキャプチャとレンダーターゲットの基本的な使い方をテストしてみた結果、いろいろできそうな感じでした。ただ適当に使うと描画負荷の問題がでそうです。
フレームバッファをキャプチャする方法は他に FrameGrabber という機能があり、こちらのほうは既にレンダリング済のフレームを取るため比較的処理負荷が軽いようです。