2016年5月10日

UE4 で 360 度ステレオスコピックのスクリーンショットとムービーをキャプチャーする

作成 Gavin Costello Lead Programmer Ninja Theory Ltd

はじめに

Hellblade のバーティカル スライスのレビュー以前から 360 度の動画をキャプチャーする作業をしてきました。エンジン内のシネマティックスで、360 度のステレオスコピックを初めて完全にキャプチャーしました。これが初のプレイ可能なビルドのシネマティックスのイントロ ムービーになりました。

当初、社内で独自のモノスコピック 360 度キャプチャー システムを作っていました。キュービック キャプチャーを使って、球体に投影してワーピングし最終画像にしました。

このやり方はうまくいきましたが、モノスコピックの性質に起因して何もかも大きく感じられ、うまく表現できず動画の対象に一体感を得られません。囲まれているにも関わらずシーン内にいるという感覚はなく、遠くにいる傍観者のように感じられたのです。

(モノスコピックのフッテージがスケール感覚を失い、大きく感じられがちであるのは、脳の無意識の評価によるのではと私は思います。ステレオスコピックのコンバージェンスがなく、頭の動きからの視差がなく、オブジェクトは非常に遠くにあります。こうした情報と、オブジェクトがビューの大部分を占めているという事実とを合わせると、オブジェクトがとてつもなく大きく遠くにあるように感じます。)

ステレオとモノスコピックのフレームをキャプチャーして試してみてください。前後に切り替えると、深度の感覚を失うだけでなく、スケール感も失います。そのため、オブジェクトは非常に大きくなりがちです。

この時点で、適切なオフセットの左右の目で真のステレオスコピック画像を生成できるかを検討しました。その過程で Kite and Lightning のデベロッパーが提供するステレオスコピック 360 度キャプチャーに出会いました。

このとき、基本的にこれは GitHub にあるだけで、UE4 にはありませんでした。しかし、最近は UE4 ですぐに使える状態になっています。是非、これをチェックすることをお勧めします。

この記事の以下の部分では、パブリック ビューイング用にローンチした Ninja Theory での 360 度のステレオ ムービー キャプチャー用の特別な設定とワークフローについて説明します。

360 度ではないオリジナル トレーラー:

360 度ステレオスコピック版:

この記事では、UE4 の最新版 (この記事の執筆時点では 4.11.2) を使っていることを前提とします。ただし、4.9 当時からこのプラグインを使っているため、ほとんどの内容は該当します (最後のトラブルシューティングのセクションで説明するいくつかのコードの修正が追加で必要になるかもしれません)。

"Stereo Panoramic Movie Capture" プラグインを有効にし、簡単なテスト キャプチャーをします。:

最初にやるべきことは、適切なプラグインを有効にすることです。

エディタを開いた状態で、 [Edit -> Plugins] の順序で進みます。次に、左側の [Movie Capture] 設定を選択します。[Stereo Panoramic Movie Capture] で [Enabled] にチェックを入れるようにします。

その後、エディタをシャットダウンして再起動します。

注意:ブランチでローカルの変更をしたかに応じてただちに再度ビルドをする必要があるかもしれません。出荷されたプラグインのダイナミック リンクライブラリが古い可能性があるからです。

エディタが再起動したら [Editor -> Plugins -> Movie Capture] に戻って、チェックが入っているか再確認してください。

このプラグインにはコンソール コマンドで切り替え可能ないくつかの設定があります。ただし、その前にデフォルト設定で期待どおりに機能することを確かめるためにテスト キャプチャーしてください。

コマンド コンソールを開き、出力画像をダンプする適切なフォルダに SP.OutputDir を設定します。例えば、以下のようになります。

SP.OutputDir F:/StereoCaptureFrames

注意:これは持続性がないため、エディタやゲームをロードするたびに毎回 行わなければなりません。

次に、シングル フレームのキャプチャーを行います。例えば、以下のようになります。

SP.PanoramicScreenshot

この時点では、ある程度の長さの ( 1 分程度) 処理落ちがあるかもしれません。その後、2 つの画像が SP.OutputDir で上記で指定したディレクトリにダンプされます (実際には、そのディレクトリ内の日付と時間のディレクトリ)。ひとつは左目用、もうひとつは右目用です。

ざっと見て、期待したとおりに全てがそこにあるかを確認します。この時、バンディングのようなアーティファクトがないかについてあまり気にしないでください。こうした問題には後で対処します (ただし、スクリーン空間のエフェクトであるライトシャフトなどの一部のエフェクトは機能しません。これについては後述します)。

左右の目を単一画像に自動的に結合するためにコード変更します。

内部でのワークフロー用に、フレーム毎にひとつの完全なトップ / ボトムの画像をダンプします。これにより、プロセスの一部として左右の目を手作業で結合する必要なく、はるかに簡単に「すべてのフレームをムービーにビルドする」ことができます。

これが該当し、コードを本格的に操作するのに抵抗がない場合、以下は画像出力前に左右の眼を結合する簡単なコードです (特に最適化されていません) 。

1.SceneCapturer.cpp を開きます。

2.結合したものと結合しないものとの間の切替を可能にするコントロール変数を定義します。内部的には常に結合した画像を出力します。そのため、我々は単に const global bool にしました。

- const bool CombineAtlasesOnOutput = true;

3.条件付きで、USceneCapturer::SaveAtlas の下で現在の片目の出力を無効にします (CombineAtlasesOnOutput のチェックだけが唯一新しい部分です)。

IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper( EImageFormat::PNG );

if (!CombineAtlasesOnOutput) //*NEW* - Don't do this here if we're going to combine them. (結合するつもりであれば、これを行わないでください)

{

ImageWrapper->SetRaw(SphericalAtlas.GetData(), SphericalAtlas.GetAllocatedSize(), SphericalAtlasWidth, SphericalAtlasHeight, ERGBFormat::BGRA, 8);

const TArray& PNGData = ImageWrapper->GetCompressed(100);

FFileHelper::SaveArrayToFile(PNGData, *AtlasName);

}

これを行うと "GenerateDebugImages->GetInt() != 0" ブランチ内のすぐ下にエラーがあるのがわかります。この場合、PNGData を出力していましたが、PNGDataUnrpojected...を 出力すべき であるため、これも修正します。

4.次にいくつかの新しいコードを追加して、目を結合して単一画像をUSceneCapturer::Tick で出力します。以下の行を見つけます。

"TArray SphericalLeftEyeAtlas = SaveAtlas( TEXT( "Left" ), UnprojectedLeftEyeAtlas );"

以下のコードを挿入します (適切な位置になるように、周囲のコードも含めました)。

TArray SphericalLeftEyeAtlas = SaveAtlas( TEXT( "Left" ), UnprojectedLeftEyeAtlas );

TArray SphericalRightEyeAtlas = SaveAtlas(TEXT("Right"), UnprojectedRightEyeAtlas);

//*NEW* - Begin (開始)

if (CombineAtlasesOnOutput)

{

TArray CombinedAtlas;

CombinedAtlas.Append(SphericalLeftEyeAtlas);

CombinedAtlas.Append(SphericalRightEyeAtlas);

IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG);

ImageWrapper->SetRaw(CombinedAtlas.GetData(), CombinedAtlas.GetAllocatedSize(), SphericalAtlasWidth, SphericalAtlasHeight * 2, ERGBFormat::BGRA, 8);

const TArray& PNGData = ImageWrapper->GetCompressed(100);

// Generate name (名前を生成します)。

FString FrameString = FString::Printf(TEXT("Frame_%05d.jpg"), CurrentFrameCount);

FString AtlasName = OutputDir / Timestamp / FrameString;

FFileHelper::SaveArrayToFile(PNGData, *AtlasName);

ImageWrapper.Reset();

}

//*NEW* - END

// Dump out how long the process took (どれくらい長くプロセスがかかるかを出力します)。

FDateTime EndTime = FDateTime::UtcNow();

FTimespan Duration = EndTime - StartTime;

UE_LOG( LogStereoPanorama, Log, TEXT( "Duration: %g seconds for frame %d" ), Duration.GetTotalSeconds(), CurrentFrameCount );

StartTime = EndTime;

以上です!(エピックまたは K&L がこれをプラグインにするかもしれません)

注意:上記では、出力を JPEG にも設定しました。60 fps での PNG での 4096x4096 フレームは HDD 空間を多く消費するからです。

上記のように、SP.OuputDir を設定しSP.PanoramicScreenshot を呼び出すと、以下のように表示されます。左右の目が単一のトップ / ボトムの画像に結合されます。

ステレオスコピックの 360 度の画像ビューアがあれば、文字通りその画像を取り込み、シーン内に入ることができるはずです。ワクワクしますね!

キャプチャーのごく簡単な説明

キャプチャーで何が起こっているか、主にフレーミング目的で以下の設定が何をするかをごく大まかに説明します。必要があれば、さらに情報がありますがこのプラグインを使ううえで知っておく必要はありません。

ステレオスコピック情報を 2D の左右の目の画像から正しい方法でキャプチャーすることを理解するうえで重要なのは、少なくともキャプチャー目的では任意の方向に対して正しいステレオスコピー (立体視映像) を示すシーンは、画面中央に近い部分 (つまり目と目の間の部分) になるということです。背後ではこのキャプチャーは標準のゲーム ビュー全体をレンダリングしてから (ときには、異なるFOV (Field of View:視野角)があればそれを使って) そのほとんどを廃棄しています。

現実には、使う領域の幅は HorizontalAngularIncrement と CaptureHorizontalFOV 次第ですが、ハイクオリティのキャプチャー設定では、極めて小さいものになってしまいます。

そのため、このプラグインが 360 度のビューをレンダリングする場合、実際には多数の異なるキャプチャーを撮っています。毎回カメラを少しづつ回転させて、後で使うためにその真ん中の部分だけを抽出します。ひとつの考え方として、サンプルを数多く集めるほど任意のポイントに対してステレオスコピー情報が詳細なものになります。

これを制御する変数として以下の 2 つがあります。

- SP.HorizontalAngularIncrement は、キャプチャー間で何度水平方向に回転するかを制御します。

- SP.VerticalAngularIncrement は、完全に 360 度水平方向に回転する度に、何度垂直方向 (極から極) に回転するかを制御します。

この 2 つの中では HorizontalAngularIncrement は低い値での微調整が必要です。例えば、10 度に設定すると (360 度の回転で合計で 36 回のレンダリングになります)、深度がオフになることがわかります。認識された深度情報では、カラーバンドではなく実際にバンド (縞模様) が生じます。

最高レベルのクオリティにするためにプラグインを設定する

SP.OutputDir 以外に、このプラグインにはキャプチャーのクオリティを上げるための CVar 制御の設定があります。こうした設定には、フレームを生成するために水平ビューと垂直ビューをいくつレンダリングするか (これにより、ステレオスコピーが一段と正確になります) 、ターゲット出力の大きさ、個々のビューの大きさ (これは出力解像度とは別のものです) などがあります。

ここでは特定の設定をするものだけを説明します。完全なリストは StereoPanoramaManager.cpp の上部にあります。

ここで使う設定は以下の通りです。

SP.OutputDir F:/StereoCaptureFrames

SP.HorizontalAngularIncrement 2

SP.VerticalAngularIncrement 30

SP.CaptureHorizontalFOV 30

SP.ConcurrentCaptures 6

SP.CaptureSlicePixelWidth 720

SP.ShouldOverrideInitialYaw 0

And then for 4096x4096 captures (4096*2048 per eye)

SP.StepCaptureWidth 4096

Or for 6144x6144 captures

SP.StepCaptureWidth 6144

ご覧になってわかるように、HorizontalAngularIncrement に対して非常に小さな値を使って 360 度回転する毎にシーンを (片目につき) 180 回レンダリングしました。さらに低くすればクオリティは上がりますが、ひとつのフレームをレンダリングするためにかかる時間が増えます。我々の経験上、2 という値が最適で、それ以上低くしてもクオリティの改善はみられません。

VerticalAngularIncrement に対しては大幅に大きな値を設定しました。縦方向のステレオスコピー情報では、少なくとも我々がキャプチャーするようなものでは (キャラクター モデルを含み、完全にフラットな壁ではないもの) あまり違いは見られませんでした。この場合の最適な値は、30 でした。

1 フレーム毎にレンダリングするビューの合計数はこうした 2 つのパラメータに基づきます。

実際の作業は、直接上方向を見てシーンをキャプチャーし、HorizontalAngularIncrement の度数分回転し、再度キャプチャーし、HorizontalAngularIncrement の度数分、再度回転し、再度キャプチャーするというように 360 度全体が回転するまで行うというものです。次に、VerticalAngularIncrement で、再度同じことを行います。その後、直接下方向を見るまでそれを繰り返します。

実際には、ひとつの 360 度のステレオスコピックのキャプチャーのフレームに対して、画像を生成するためのレンダリングの合計数は以下のようになります。

(360 / HorizontalAngularIncrement) * (180 / VerticalAngularIncrement) * 2 (片目ずつであるため)

上記の設定では、2520 フレームのレンダリングを行い、たったひとつのステレオスコピックの 360 度のキャプチャーのフレームを生成することを意味します。説明を加えると、 60hz ゲームの 2520 フレームをレンダリングすると、通常は 42 秒の出力を生成しますが、代わりに 1 秒の 1/60 の出力になります (60 fps のムービーをキャプチャーしている場合)。

SP.ConcurrentCaptures も、上記を考えるうえで重要です。高く設定しすぎると (デフォルトでは 30 です!)、VRAM のメモリが不足し問題が生じます。

この CVar が実際に行うのは、いくつのキャプチャー コンポーネントが作成されて、同時にレンダリングするかを制御するということです。それぞれが関連するレンダー ターゲットのメモリを必要とするため、GPU メモリのリソースを浪費してしまいます。「同時に」と言いましたが、実際には GPU は一度にその中のひとつだけを処理します。そのため、どこかのポイントで CPU でのレンダリングされたフレームの処理と GPU のフレームの処理との間で壁にぶつかります。これは 30 よりもかなり前で起こる可能性があります。「6」が最適な値であることがわかりました。これ以上増やしても (最高 30) 基本的にフレームのレンダリングを数秒カットするだけで、VRAM の量に対して適切なトレードオフではなく、複数日にわたるキャプチャーの半ばで台無しになる (メモリ不足が原因) 可能性があります。

最後になりますが、SP.CaptureSlicePixelWidth は重要です。長い間、我々は 2048 のようなデフォルトのままにしていました。この値は (フレーム毎にレンダリングする 2520 のビューの中で) レンダリングする各ビューのサイズを表します。そのため、これを減らすと全体的なレンダリング時間に大きな影響を及ぼします。実際には、最終的な出力画像とは別に垂直方向のステップがいくつになるか (180/VerticalAngularIncrement)、および最終画像に対してどれくらいマルチ サンプリングが必要かに基づきサイズを決めます。

実際には、例えばバッファが 2048 だとすると垂直方向のステップが 6 で、実際には 12,288 ピクセルの画像をレンダリングします。最終出力画像が、片目の画像に対して 4096x2048 である場合、実際には高さでそれほど多くのピクセルを必要としません。6xFSAA で十分です。ここでは垂直解像度だけを考慮します。前述の画像を見ると、画像の幅全体を使っていません。真ん中の部分だけを使っています。ですから、ここでは幅は重要ではありません (真ん中部分を引き出すための十分なピクセルを持つ十分な幅があればいいだけです)。

逆に、値を 720 に設定すると、実際には ~4320 の高さのレンダリングをし、それを 2048 にダウンサンプリングします。それでも 2xFSAA に相当しますが (これでも十分なものです)、レンダリング時間は 2520 のビューに対して 3 分ではなく 40 秒になります (直線的に比例しませんが、それでも良い結果です)。

ブループリントで全ての設定をする

上記のように、こうした設定はエンジン / エディタの実行の間に保存されません。すべて持続性がなく、起動するたびに設定しなければなりませんが、これは面倒です。

次に、内部での作業は呼び出し可能な単一のコンソール コマンドを用意し、すべてのものを設定しキャプチャー直前に呼び出します。

または、コンソール コマンドをブループリントに入れます。こんなレイアウトになってすみません。ひとつの画像に入るようにまとめたかったんです。

以下のような配置で "ce NTCaptureStereo" を行い、キャプチャー開始前に全パラメータを設定します。これは良い方法であるだけでなく、エラーも発生しづらくなっています。 2 日間のキャプチャーを開始したらパラメータの設定を誤って忘れたくないですよね。

ムービーをキャプチャーする

ここまでで重要な設定と、ひとつのコンソール コマンドを使ってブループリントでキャプチャーをセットアップし、トリガーする便利な方法について説明しました。

ムービーをキャプチャーする場合に 必ず覚えておくべき 重要なことは、固定タイムステップで実行するということです。

キャプチャーの 1 フレームは、40 秒より多くなります。そのため、80 秒のシネマティックスでたった 2 フレームの出力を生成したくなければ、固定タイムステップを使った時間の増分で動くようにエンジンに指示します。

これは便利で簡単です (アンリアルに感謝!)。以下のコマンドラインを入れるだけです。

-usefixedtimestep -fps=

例えば、フレームレートを 60 に設定すると、それぞれのフレーム全体が生成された後 16 ミリ秒のタイムステップで更新されます。したがって 1 秒経過するたびに 60 フレームをキャプチャーします。30hz のムービーを生成する場合、理論上は単にこれを 30 に設定します。しかし、常に 60 でキャプチャーします。これはフレームから 60hz または 30hz のムービーを生成する選択肢を持つためです。

さらに、このポイントで -notexturestreaming を使ってテクスチャのストリーミングをオフにするとよいでしょう。ムービーのキャプチャーに 1 日費やして、フロアーのテクスチャーがすべてぼやけてたらとても困りますよね。

全体的な例として、キャプチャーを行うときにゲーム / エディタのブート時に内部では以下のコマンドラインを渡します。

-usefixedtimestep -fps=60 -notexturestreaming

ムービーのキャプチャーは実際にどのように行うのでしょうか?

上記で SP.PanoramicScreenshot について説明しましたが、上のブループリントのスクリーンショットをよく見ると、多くのフレームをムービーに直接キャプチャーする方法があるのがわかります。具体的には以下のようになります。

SP.PanoramicMovie

ここでのフレーム数は文字通り「コマンド開始時からエンジンが更新ループを実行した回数」になります。例えば、fps=60 で実行し、startime を 120 にendtime を 240 に設定します。コマンドがそれを実行すると、2 秒 (120 フレーム) 待機して、次に 2 秒分のフレーム (すなわち 120 フレーム) をキャプチャーします。これを 2 秒分の動画に 60hz でエンコードするというようになります。

ここではマチネからのみキャプチャーします (結局、固定タイムステップで 40 秒で、各フレームをキャプチャーしますが、これはプレイ可能なフレームレートではありません)。そのため、SP.PanoramicMovie コマンドをトリガーすると同時に常にマチネを開始します。すると、マチネ内の何秒でキャプチャーを開始、終了したいかに基づき開始フレームと終了フレームが簡単に機能します (単純に 60 を乗算すると答えが求められます)。

フレームのキャプチャー後

キャプチャーが完了したら SP.OutputDir// フォルダーに以下のようにラベル付けされた一連のフレームがあります。Frame_00000 -> Frame_EndFrame および Frames.txt ファイル (これで終了したことがわかります!)

上記でカスタム コードを使ったら、これらは結合されたトップ / ボトムの画像であり、エンコードの準備ができます。

これをムービーにするには非常に多くの方法があります。ただし、ここでは ffmpeg を使ってフレームから h264 60hz の動画をエンコードします。注意: ffmpeg はオンラインで無料ダウンロードできます。

例えば、以下のコマンドラインは指定したディレクトリにあるすべてのフレームをエンコードし、MyMovie.mp4 と呼ばれる h264 60hz ムービーにします。

"ffmpeg.exe -framerate 60 -i F:/StereoCaptureFrames/2016.04.26-13.04.34/Frame_%%5d.jpg -c:v libx264 -profile:v high -level 4.2 -r 60 -pix_fmt yuv420p -crf 18 -preset slower MyMovie.mp4"

ここでは ffmpeg の詳細には踏み込みません。沢山のドキュメントがあり、私の知る限りではほとんどの人は他の編集ソフトウェアを使ってエンコードするからです。

出荷前にオーディををミックスするでしょうが、出力されたムービーは基本的に使用の準備が整っています。

以上です!

これで終わりです。... これでGearVR で再生したり、YouTube や Facebook にアップロード可能なフル ステレオスコピック 360 度のシーンをキャプチャーするセットアップと方法をご理解いただけたかと思います。

YouTube にアップロードするうえでの注意事項: メタデータをアタッチし、適切な解像度 / アスペクト比で出力する必要があります。例えば、以下のようになります。この場合は 4096x4096 ではなく、"4K/UHD/(3840x2160, 16:9)" です。そうでなければ、それをストリーミングすると非常にぼやけます。ムービーをエンコードする場合 (どのようなプログラムを使う場合でも)、ソース フレームが 4096x4096 なのは問題ありません。4096x4096 で 1:1 のアスペクト比の画像ではなく (ただし、これは GearVR / Oculus360 の再生ではうまく機能します)、標準の UHD 解像度と 16:9 のアスペクト比で出力するようにしてください。

その他の陥りやすいミスと注意事項

共有したほうがよいと思われるいくつかの陥りやすいミスがあります。その一部は普遍的なものであり、4.11 で修正されましたがアンリアル エンジンのそれ以前のバージョンには該当します。

1.すべてのエフェクトが機能するとは限りません。

これは注意すべき重要なことです。上記の情報でご理解いただければと思います。シーンは実質上、「タイル」(ズームインの FOV (視野角) で) でキャプチャーされています。一連の水平ステップを実行してから、一連の垂直ステップに対してこうした水平ステップのすべてを繰り返します。そのため、シーン全体に適用されることを前提としたスクリーン空間のエフェクト (例、ビネット) は機能しないためオフにしてください。

ライトシャフトも機能しないことを意味します。シャフトのソースが画面上にある一連のタイルになってしまいます。その後のタイルでシャフトのソースが画面上に全くないため、そのタイルに対してシャフトは生成されません。その結果、最終画像ではライトシャフトのブロックがオン、オフし、希望に沿った外観になりません。こうした理由から、(素晴らしいエフェクトなので) 残念ですがライトシャフトも機能しません。

ライトシャフトが我々の例でなぜ機能しているのか疑問に感じられるかもしれませんが、メディアのソリューションに加わっているカスタムのワールド空間を持っているため、ワールド空間のエフェクトが問題なく機能しているからです。

同様にスクリーン空間の歪みがあれば、それも機能しません。各ポイントで画面の真ん中部分だけを取り出しています。そのため、ラップされて画面の真ん中部分だけの歪みになります。

ワールド空間の歪みはまだ機能します。そのため、パーティクルなどの歪みの見栄えは良いままです。

一般的に、スクリーン空間のエフェクトは機能しません。それを念頭にコンテンツのビューをとってください。

2.全てが固定タイム ステップに従うわけではありません

垂直スライス シーン中に早い段階で陥りやすいミスです。カットシーン中にインゲームの顔のムービーを再生した部分がありますが、何らかの理由で 2 フレームの映像にしかなりません。動画は我々が必要とする 1 レンダリングあたり 16 ミリ秒の固定レートではなく、「通常」の速度で進行しているからです。つまり、キャプチャーしたフレーム毎に約 40 秒、映像をジャンプしています。

同様に、実際の差分を使って (ゲーム時間ではなく) 各フレームで GPU で計算されるものもこれに従いません。過去に面白いケースがありました。通常のマテリアルを使った見栄えのよい炎があり、GPU のパーティクルの燃えさしが炎の中にあり、信じられない速さで動いていました。これは更新が適切にバインドされていなかったからです。こうしたことに対処するために固定の更新時間の設定がパーティクル システムにあります。

3.デフォルトでは (出荷時)、キャプチャーはポストボリュームの設定を使いません!

この回避策は、キャプチャーのビューがプレイヤーからのポストプロセスの設定を使うようにすることです。

簡単な例として、USceneCapturer::InitCaptureComponent で、以下のコードを追加します (RegisterComponentWithWorld の呼び出し前)。そうすると、プレイヤーのポストプロセス設定を使うようになります。

//*NEW* Set up post settings based on the player camera manager (プレイヤーの camera manager に基づきポスト設定をセットアップ )

if (GetWorld())

{

APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();

if (PlayerController && PlayerController->PlayerCameraManager)

{

CaptureComponent->PostProcessSettings = PlayerController->PlayerCameraManager->CameraCache.POV.PostProcessSettings;

CaptureComponent->PostProcessBlendWeight = PlayerController->PlayerCameraManager->CameraCache.POV.PostProcessBlendWeight;

}

}

// Disable effects that we don't want for capture (キャプチャーに不要なエフェクトを無効にします)

CaptureComponent->PostProcessSettings.bOverride_GrainIntensity = true;

CaptureComponent->PostProcessSettings.GrainIntensity = 0.0f;

CaptureComponent->PostProcessSettings.bOverride_MotionBlurAmount = true;

CaptureComponent->PostProcessSettings.MotionBlurAmount = 0.0f;

CaptureComponent->PostProcessSettings.bOverride_ScreenSpaceReflectionIntensity = true;

CaptureComponent->PostProcessSettings.ScreenSpaceReflectionIntensity = 0.0f;

CaptureComponent->PostProcessSettings.bOverride_VignetteIntensity = true;

CaptureComponent->PostProcessSettings.VignetteIntensity = 0.0f;

//*NEW*

注意:一部のポスト エフェクト (例、マテリアルのエフェクト) が機能するように、キャプチャー コンポーネントが ViewState を持つように強制する必要があるかもしれません。

もちろん、初期化は一回だけ起こります。そのため、様々なボリュームなどを移動したい場合、そのコードを抽出するか、フレーム毎に呼び出すか、FScene::CreateRenderer を挿入して、プレイヤーのポストのコピーを処理します (フレーム毎、キャプチャー ビュー毎に起こります)。

4.出力ファイルが緑になってしまいます! どうしたらいいですか!!

これはエンジンの古いバージョンで発生していました。これは複数のキャプチャー コンポーネントがあるため生じますが (SP.ConcurrentCaptures を思い出してください)、これらはすべて同じ名前です。そのため、ひとつめを何回も使い、次にそれぞれを連続して読み取ります。緑はクリアな色になります。そのため、目にしているのはレンダリングされていないフレームから読み取った結果になります。

この場合の修正は、USceneCapturer::InitCaptureComponent で単に一意の名前を付けることです。

4.11 では、MakeUniqueObjectName の呼び出しで行われますが、古いバージョンをご使用の場合は他の方法で行うことができます (静的なインデックスのままにして、一意の名前を生成するように増分しました)。

5.片目だけにシャドウが表れます。どうしたらいいですか!!

我々もこれを経験しましたが、4.11 で修正されたようです。しかし、これはステレオ レンダリングパスの最適化によって生じました。つまり、シャドウ バッファを一度だけ生成して次にこうしたバッファを両目に対して使います。

当時の我々の回避策は、それぞれの目に対してシャドウの再生成を強制することでした。

また、 USceneCapturer::InitCaptureComponent では CaptureComponent -> CaptureStereoPass を設定する行を単にコメントアウトし、修正します。

つまり、シャドウ深度のレンダリングをさらに行うことを意味しますが、いずれにせよレンダリングは非常に遅いため、ヒットにはあまり気づかないでしょう。

6.想定していたものから 180 度シーンが回転しているようです。どうしたらいいですか!!

これも 4.11 で修正されていますが、我々もこの経験があります。回避策は単に手書きのコードで 180 度加えることです。USceneCapturer::Tick で以下の行を探します。

"Rotation.Yaw = (bOverrideInitialYaw) ?ForcedInitialYaw :Rotation.Yaw;"

そして以下のように変更します。

"Rotation.Yaw = (bOverrideInitialYaw) ?ForcedInitialYaw :Rotation.Yaw + 180.0f;"

7.複数のマシンにキャプチャーを拡散する

これは、フル カットシーンをレンダリングするためにかかる時間をスピードアップするために最良の方法です。

ただし、必ずしもすべてのエフェクトが機能するわけではないことを覚えておいてください。例えば、パーティクルに変化を付けるためにランダムな開始位置を生成するノードがあるかもしれません。2 つのマシンでひとつのシーンをキャプチャーした場合、ひとつのフレーム セットをもうひとつのセットとスワップすると、ポップが生じる可能性が高くなります。こうしたエレメントは同じ場所に存在しないからです。

実行する度に同じパーティクルを生成するようにパーティクル システムのシードを設定することは可能です。ただし、あらゆるケースを考えて非常に注意深くしなければ大量のキャプチャーを行ってもひとつのエフェクトでポップが生じるかもしれません。

これを行うのではなく、これまでやってきたのはシーン内の「自然なカット」を見つけてカメラがジャンプする場所、フェードする場所、またはコンテンツのポップに気付かない任意の場所を配置し、こうしたカットのそれぞれを別のマシンでキャプチャーするというものです。

ただし、このやり方に従う場合は、カットのいずれかの側に余分なバッファを少しキャプチャーするようにします。マチネで誤ってカットのキャプチャーを早めに止めてしまったり、次のカットのキャプチャーの開始が遅すぎると、そのカット全体を再キャプチャーしなければならないかもしれません。これは大きな時間のロスです。意図的にカットを 1 秒程度余分/少なめに実行することで必要なフレームをすべて入れることができます。

ここで良い点は、ひとつの大きなマチネである場合、フレームと数が一致するということです。異なるフレームで開始および終了し、フレームの名前(Frame_StartFrame->Frame_EndFrame) がカット別に違うものになるようにします。こうすることで、個別にムービーにつなげる必要なく同じフォルダに入れることができます。

8.エディタ / キャプチャーを夜通し遅くするウィンドウがポップアップして困ります!

[Edit -> EditorPreferences -> (General)Miscellaneous] に [Use Less CPU when in Background.] という便利な設定があります。

これをオフにします... (キャプチャリング時)。こうすることで夜通しキャプチャリングし、誰かがメッセージを送ってきて一番上のウィンドウにポップアップしても、エディタが停止してキャプチャー全体をスローダウンさせることはありません。

9.両極での深度が正しくありません。

残念ながらこれは技術上の制約です。一般的に真上を見る場合、これには気づきません。しかし、地上に立っているとき、フロアー上でこれに必ず気付きます。

各フレームでそれぞれの下の方の画像の列をブラックアウトすることで回避しました。これは必ずしも望ましくない場合がありますが、実際に人々はその部分を見なかったり、誤った深度を感じない傾向があるため、問題ないでしょう。

10.一部のジオメトリに片目 / 両目がありません。

これはオクルージョンのクエリを無効にすることで回避しました。問題の詳細ははっきり覚えていませんが、エンジンが最後のフレームのオクルージョン結果をどのように使うか、「最後のフレームのオクルージョン」情報の更新前にいくつレンダリングされたかに関するものだったと思います。これはフレームの更新間の同時キャプチャー数に起因するものです。

キャプチャーを行う前に、単に r.AllowOcclusionQueries を 0 に設定しこれを解決します。

これで本当に終わりです。

とても長い記事でしたが、キャプチャリングを始めたばかりの方々やキャプチャリングしたことがあっても上記の陥りやすいミスに出くわしたことがある方々のお役にたてば幸いです。

それでは、頑張ってキャプチャリングしてください。高品質なステレオスコピックの 360 度フッテージこそ素晴らしいものになります。

~Gav

Hellblade のフレームの一部です (6K)

各画像をクリックすると、6K バージョンを見ることができます。