2017-04-12 17 views
3

ピクセルデータにアクセスし、ゲーム内のカメラからディスクに画像を保存しようとしています。最初は、レンダリングターゲットとその後のRenderTarget-> ReadPixels()を使用するのが簡単でしたが、ReadPixels()のネイティブ実装ではFlushRenderingCommands()の呼び出しが含まれていたため、画像が保存されるまでゲームスレッドがブロックされていました。計算集中的な操作で、これは私のFPSの方法をあまりにも低くしていました。Unreal Engine 4:マルチスレッドフレームワークにReadPixels()を適用する

この問題を解決するために、CaptureComponentとしてカメラにアクセスできる専用のスレッドを作成しようとしていますが、同様のアプローチに従ってください。しかし、FlushRenderingCommands()ブロックはゲームスレッドからしか呼び出せないので、その呼び出しなしでReadPixels()を書き直さなければなりませんでした。(ブロックのない方法で、https://wiki.unrealengine.com/Render_Target_Lookupのチュートリアルに触発されています)。画像が保存されるたびに私のゲーム中のFPSがぎくしゃくする問題に直面しています(これは実際にディスク操作に保存されたものではなく、ピクセルデータアクセスによるものであることを確認しました)。書き直したReadPixels()関数は以下のように見えますが、ここで何がうまくいかないかについていくつかの提案を得ることを望んでいました。私はENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETERがゲーム以外のスレッドから呼び出せるかどうか、それが私の問題の一部であるかどうかはわかりません。

APIPCamera* cam = GameThread->CameraDirector->getCamera(0); 
USceneCaptureComponent2D* capture = cam->getCaptureComponent(EPIPCameraType::PIP_CAMERA_TYPE_SCENE, true); 
if (capture != nullptr) { 
    if (capture->TextureTarget != nullptr) { 
     FTextureRenderTargetResource* RenderResource = capture->TextureTarget->GetRenderTargetResource(); 
     if (RenderResource != nullptr) { 
      width = capture->TextureTarget->GetSurfaceWidth(); 
      height = capture->TextureTarget->GetSurfaceHeight(); 
      // Read the render target surface data back.  
      struct FReadSurfaceContext 
      { 
       FRenderTarget* SrcRenderTarget; 
       TArray<FColor>* OutData; 
       FIntRect Rect; 
       FReadSurfaceDataFlags Flags; 
      }; 

      bmp.Reset(); 
      FReadSurfaceContext ReadSurfaceContext = 
      { 
       RenderResource, 
       &bmp, 
       FIntRect(0, 0, RenderResource->GetSizeXY().X, RenderResource->GetSizeXY().Y), 
       FReadSurfaceDataFlags(RCM_UNorm, CubeFace_MAX) 
      }; 
      ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(
       ReadSurfaceCommand, 
       FReadSurfaceContext, Context, ReadSurfaceContext, 
       { 
        RHICmdList.ReadSurfaceData(
        Context.SrcRenderTarget->GetRenderTargetTexture(), 
        Context.Rect, 
        *Context.OutData, 
        Context.Flags 
       ); 
      }); 
     } 
    } 
} 

編集:私は気づいたもう一つは、私は私のレンダーターゲットの設定でHDRを無効にします(これは、低品質画像につながる)場合吃音が消えるということですので、それはもっともらしく思われる画像の大きさおそらく、私はそれを実装している方法のために、コアスレッドの1つをまだブロックしています。

答えて

0

タスクグラフの基本呼び出しがあるので、任意のスレッドからENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETERを呼び出すことが可能です。このマクロが生成するどのようなコードanalizeときは、それを見ることができます。

if(ShouldExecuteOnRenderThread()) 
{ 
    CheckNotBlockedOnRenderThread(); 
    TGraphTask<EURCMacro_##TypeName>::CreateTask().ConstructAndDispatchWhenReady(ParamValue1); 
} 

あなたは異なるスレッドから(USceneCaptureComponent2Dのような)UObjectsへのアクセスについては慎重でなければなりませんこれらはゲームスレッドによってガベージコレクタと自身によって管理されている原因となります。

(...)それでも、私はイメージがあなたがstat unitかとFPSの低下を引き起こしているものを糸確認しました

を保存するたびに、私のゲーム内でのFPSというぎくしゃくとの問題に直面しています stat unitgraphコマンド? profiling toolsを使用してより詳細な洞察を行い、他の原因がないことを確認することもできます。

編集: もう一度method of accessing pixel dataが見つかりました。 forループ内のデータを実際にコピーせずにこれを試してください.FPSに改善があればチェックしてください。これは、ピクセル操作/変換の間に何もないため、少し速くなる可能性があります。

+0

また、プロファイリングツールを使って(単一カメラのHDRの場合)見てみました。時間の点で最大のヒットだったイベントの大部分は、「CPUストール:イベント待ち」、「CPUストール:スリープ」私は彼らがGPUが追いつくのを待っていたと推測しています。 – HighVoltage

+0

コメントをいただきありがとう:私がstat unitgraphを実行すると、これは私が見つけたものです:いいえHDR:まともなレートのすべてのスレッド。 HDR:レンダリングスレッドのスパイクが大きくなり、フレームタイミングが急上昇する。時折GPUスレッドの遅れもあります。 i.imgur.com/S1YVGaz.png – HighVoltage

+0

レンダリングスレッドでも 'ReadSurfaceData'メソッドが時間がかかりすぎているようです。 read関数を複数回呼び出すなど、他の間違いがないと仮定すると、ピクセルデータを読み取るこの特定のメソッドを使用すると、マルチスレッドの最適化が不可能になります。生のDirectXを使用することを考えましたか?RHIオブジェクトから直接アクセスすることはできますが、プロジェクトのプラットフォーム依存性は非常に高くなります。 – JKovalsky

関連する問題