Gregory Igehy

Dancing at hemisphere coordinate

Notes of RenderToTexture in UE4

Construction Script

デリゲート

マテリアル

float4 RayStartClip =
mul(float4(WorldPos, 1), View.WorldToClip);

float3 RayStartScreen =
RayStartClip.xyz / RayStartClip.w;

float2 UV = RayStartScreen.xy;

UV = UV * float2( 0.5f, 0.5f) + float2(0.5f, 0.5f);

UV.y = 1.0f - UV.y;

return UV;

Qoocam

UE4 GearVR

GearVR プロジェクト設定

  • [Project] の [Maps & Modes] セクションの中の [Default Maps] で、[Editor Start Up] と [Game Default Map] に保存したばかりレベルを入力します。
  • [Engine] > [Input] を開きます。[Mobile] セクションで、[Default Touch Interface] を [None]
  • Minimum SDK Version: 19
  • Target SDK Version: 19
  • [Enable FullScreen Immersive on KitKat and above devices]: True

パッケージング

プロジェクト設定;最適化

    • サポート状況
      • For Gear VR, Multi-View is supported on Note5, S6, S7, S8, and S9 (and later) phones using ARM Exynos processors and running Android M or N. It is also supported on S7, S8, and S9 (and later) phones using Qualcomm processors and running Android N.
      • Oculus Go and all supported Samsung phones support Multi-View with OpenGL ES 2.
      • Oculus Go, S8, and S9 phones also support Multi-View with OpenGL ES 3.1.
      • For Exynos devices, verify that Support OpenGL ES2 is checked in the Build section in Platforms > Android, and that Support OpenGL ES3 is not selected.
  • [Monoscopic Far Field] を有効

止まり

  • Mobile Multi-View] を有効, Mobile Multi-View Direct を有効, Monoscopic Far Field を有効にすると, Galaxy S7 Edge だと止まる。Traslucency の描画あたり.
  • Mobile Multi-View] を有効, Mobile Multi-View Direct を有効にすると, 画面が出ないことがある。メモリ不足?
  • ProfileGPU をすると, 下のようなデバッグ出力後にハングしてアプリ終了

01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:862][550]LogRHI: Perf marker hierarchy, total GPU time 0.00ms
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:862][550]LogRHI: WARNING: This GPU profile was captured with v-sync enabled. V-sync wait time may show up in any bucket, and as a result the data in this profile may be skewed. Please profile with v-sync disabled to obtain the most accurate data.
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:862][550]LogRHI: Warning: Profiled range "disjoinness" could not be determined due to lack of disjoint timer query functionality on this platform.
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:862][550]LogRHI: nan% 0.00ms FRAME 68 draws 12344 prims 37032 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:862][550]LogRHI: nan% 0.00ms MobileBasePass 10 draws 5798 prims 17394 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:862][550]LogRHI: nan% 0.00ms View0 5 draws 2899 prims 8697 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:862][550]LogRHI: nan% 0.00ms View1 5 draws 2899 prims 8697 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:863][550]LogRHI: nan% 0.00ms Translucency 4 draws 2016 prims 6048 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:863][550]LogRHI: nan% 0.00ms View0 2 draws 1008 prims 3024 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:863][550]LogRHI: nan% 0.00ms View1 2 draws 1008 prims 3024 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:863][550]LogRHI: nan% 0.00ms PostProcessing 49 draws 2038 prims 6114 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:863][550]LogRHI: nan% 0.00ms View0 25 draws 1019 prims 3057 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:863][550]LogRHI: nan% 0.00ms DistortionAccumulatePass 3 draws 1008 prims 3024 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:863][550]LogRHI: nan% 0.00ms DistortionMergePass 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:863][550]LogRHI: nan% 0.00ms PostProcessBloomSetup 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:864][550]LogRHI: nan% 0.00ms PostProcessBloomDown 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:864][550]LogRHI: nan% 0.00ms PostProcessBloomDown 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:864][550]LogRHI: nan% 0.00ms PostProcessBloomDown 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:864][550]LogRHI: nan% 0.00ms PostProcessBloomDown 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:864][550]LogRHI: nan% 0.00ms PostProcessBloomUp 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:864][550]LogRHI: nan% 0.00ms PostProcessBloomUp 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:864][550]LogRHI: nan% 0.00ms PostProcessBloomUp 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:864][550]LogRHI: nan% 0.00ms PostProcessSunMerge 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:864][550]LogRHI: nan% 0.00ms Tonemapper(ES2 FramebufferFetch=0) 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:865][550]LogRHI: nan% 0.00ms View1 24 draws 1019 prims 3057 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:865][550]LogRHI: nan% 0.00ms DistortionAccumulatePass 3 draws 1008 prims 3024 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:865][550]LogRHI: nan% 0.00ms DistortionMergePass 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:865][550]LogRHI: nan% 0.00ms PostProcessBloomSetup 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:865][550]LogRHI: nan% 0.00ms PostProcessBloomDown 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:865][550]LogRHI: nan% 0.00ms PostProcessBloomDown 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:865][550]LogRHI: nan% 0.00ms PostProcessBloomDown 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:865][550]LogRHI: nan% 0.00ms PostProcessBloomDown 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:865][550]LogRHI: nan% 0.00ms PostProcessBloomUp 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12868 D UE4 : [2019.01.01-14.43.57:865][550]LogBlueprintUserMessages: [GearVR_Pawn_2] XY=-0.1190.956
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:866][550]LogRHI: nan% 0.00ms PostProcessBloomUp 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:866][550]LogRHI: nan% 0.00ms PostProcessBloomUp 2 draws 1 prims 3 verts
01-01 23:43:57.850 12851 12868 D UE4 : [2019.01.01-14.43.57:866][550]LogBlueprintUserMessages: [GearVR_Pawn_2] XY=-0.1060.956
01-01 23:43:57.850 12851 12957 D UE4 : [2019.01.01-14.43.57:867][550]LogRHI: nan% 0.00ms PostProcessSunMerge 2 draws 1 prims 3 verts
01-01 23:43:57.860 12851 12957 D UE4 : [2019.01.01-14.43.57:867][550]LogRHI: nan% 0.00ms Tonemapper(ES2 FramebufferFetch=0) 1 draws 1 prims 3 verts
01-01 23:43:57.860 12851 12957 D UE4 : [2019.01.01-14.43.57:867][550]LogRHI: nan% 0.00ms RenderFinish 2 draws 184 prims 552 verts
01-01 23:43:57.860 12851 12957 D UE4 : [2019.01.01-14.43.57:867][550]LogRHI: nan% 0.00ms View0 1 draws 92 prims 276 verts
01-01 23:43:57.860 12851 12957 D UE4 : [2019.01.01-14.43.57:867][550]LogRHI: nan% 0.00ms CanvasFlush 1 draws 92 prims 276 verts
01-01 23:43:57.860 12851 12957 D UE4 : [2019.01.01-14.43.57:867][550]LogRHI: nan% 0.00ms View1 1 draws 92 prims 276 verts
01-01 23:43:57.860 12851 12957 D UE4 : [2019.01.01-14.43.57:867][550]LogRHI: nan% 0.00ms CanvasFlush 1 draws 92 prims 276 verts
01-01 23:43:57.860 12851 12957 D UE4 : [2019.01.01-14.43.57:867][550]LogRHI: nan% 0.00ms SlateUI 2 draws 2308 prims 6924 verts
01-01 23:43:57.860 12851 12957 D UE4 : [2019.01.01-14.43.57:867][550]LogRHI: nan% 0.00ms DrawDebugCanvas 2 draws 2308 prims 6924 verts
01-01 23:43:57.860 12851 12957 D UE4 : [2019.01.01-14.43.57:867][550]LogRHI: nan% 0.00ms CanvasFlush 2 draws 2308 prims 6924 verts
01-01 23:43:57.860 12851 12957 D UE4 : [2019.01.01-14.43.57:867][550]LogRHI: Total Nodes 51 Draws 68

シーン

  • Precomputed Visibility を使う, Static, ライトビルド

ポストプロセス

  • AutoExposure のみ?

マテリアル

  • Main Material ノード の [Details (詳細)] パネル に [Mobile]
    • Fully Rough 有効
    • Use Lightmap Directionality 無効
  • Render in Mono を true に設定すると、Head Mounted Device (HMD) が接続されて Monoscopic Far Field レンダリングがプロジェクトに対して有効になっていれば、崖のコンポーネントが Monoscopic Near Field カメラのみでレンダリングされます。

テクスチャ

  • テクスチャ : TC_Default および TC_NormalMap 圧縮設定のみを使用してください。モバイル プラットフォームで使用できるのはこの 2 つのみとなります。
  • Android (ETC2)」か ASTC」でパッケージング
  • ETC2 : OpenGL ES 3.0,
  • ASTC : OpenGL ES 3.2 が正式

動画再生

  • Project Packaging の Exlude movie files when staging が有効だと, 動画が再生されない

描画負荷

  • シーン全体の描画コールは、すべてのビューに対して 100 以下でなければなりません。
    • stat scenerendering
    • 描画コールは PC の ES2 プレビュア stat d3d11rhi のデバイス stat openglrhi で確認することができます。
  • レベルのトライアングル総数は、どのビューでも 100,000 を超えてはいけません。
    • stat rhi
    • 描画コールは PC の ES2 プレビュア stat d3d11rhi のデバイス stat openglrhi で確認することができます。
  • GPU

コンソールコマンド

hmd stats」コマンドで、Oculus Riftの現在の設定(hmd pdの値、IPD、視野角、遅延など)を表示できます。消すには「hmd stats off」です。

ハードウェア

Galaxy S7 Edge
  • . Poweradd Pilot X7 20000mAh
Oculus Go (Galaxy S7)
  • Mobile MSAA を使うと画面が真っ暗になる

Stereo Layer

  • GearVR や Oculus Go でまともに使えるのは World 固定のもの
  • Cubemap とか使えなかった
Oculus Quest (Galaxy S8)
  • Snapdragon 835 Adreno 540
  • GFLOPS : ???

Galaxy S9

  • Snapdragon 845 Adreno 630
  • GFLOPS : 727
  • ALU : 256, 710 MHz
  • OpenGL ES 3.2, DX12.1

S7 Edge

  • r.BloomQuality (RHI)
    • 0 : 22.0msec
    • 1 : 28msec
    • 2-5 : 29msec
  • MobileMSAACount
    • 1 : 22 msec
    • 2/4 : 24 msec
  • 16.6 msec に Frame が収まらないとちらつく
  • RHI が 16.6 msec を超えやすい
  • r.RHICmdBypass 1 の方が Draw が早くなる
  • MobileHDR を有効にしたときだけ,
  • しかし GearVR では MobileHDR は非推奨。有効にすると画面が真っ黒になることも
  • AutoExposure は使えない
  • QuitMenu : 終了メニュー

Google Pixel C

iPad Pro 12.9

Stereo Pano Ue4

Unreal Japan Stream | UE4のプロファイリングと最適化のTips!Part 1

UE4 VS

Visual Studio Snippets for Unreal Engine C++ Projects
===========

How to install snippets?
===========

**Method One**
Paste .snippet files into: C:\Users\$user$\Documents\Visual Studio 2013\Code Snippets\Visual C++\My Code Snippets. Then restart VS.

**Method Two**
Open Visual Studio, navigate to TOOLS -> Code Snippets Manager… -> Import…

How to use snippets?
===========

**Method One**
Just start typing ue4... snippet list should be loaded in a form of combo box. 
Then use arrows to select snippet. Hit ENTER or TAB to insert snippet.

**Method Two**
Type all snippet name and hit TAB. You don't have to wait for VS to show snippet list.

To navigate between highlighted fields you can use TAB and SHIFT + TAB. After you enter all names, hit ENTER.

Snippets
===========

*ue4classa* – Blueprintable class that derives from an AActor. Parameters are: comment, class name and base class name.

*ue4classu* – Blueprintable class that derives from an UObject. Parameters are: comment, class name, base class name.

*ue4struct* – Simple structure. Parameters are: comment and name.

*ue4interface* – Simple ue4 interface. Parameters are: comment and name.

*ue4bpevent* – This function can be used as an event in blueprint. Parameters are: comment,
 UI category, virtual and const modifiers, function name and arguments.

*ue4bpfunc* – This function is available for blueprint logic. Parameters are: comment (parameters and return value), 
UI category, virtual and const modifiers, function name and arguments.

*ue4prop* – This read/write property is available everywhere (blueprint, instance and archetype details). 
Parameters are: comment, category, type and name.

*ue4enum* – Simple enum. Parameters are: comment, enum name, first member name and it’s comment.

*ue4enumdisplay* – Enum that can be used with blueprints.
 Parameters are: comment, enum name, first member name, it’s display name and comment.

*ue4log* – Simplest log line. Parameters are category, verbosity and message.

*ue4logdeclare* – Declaration of log category. Place this in main header of your project to allow logging. 
Parameters are: category, default verbosity and compile time verbosity.

*ue4logdefine* – Definition of log category. Place this in main code file. Parameter is category name.

*ue4logfloat* – Log line that can be used to print float value. Parameters are: category, verbosity and variable name.

*ue4logint* – This log line can be used to log an integer value. Parameters are: category, verbosity and variable name.

*ue4loguobj* – This log line is designed to log from inside of the objects. 
By default, square brackets contains a name of an object that writes the log. 
Parameters are: category, verbosity, message and name of a pointer to the object.

*ue4mark* – Can be used to mark changes in engine classes. Parameters are: 
Company symbol, task/ticket number, name and surname of a developer and short description of modification.

*ue4eve* - 9 snippets for each params combination. Can be used to create event. 
Parameters are: owning type and event type name.

*ue4del* - 9 snippets for each params combination. Can be used to create delegate. 
Parameters are: delegate type name and param type names.

*ue4delmul* - 9 snippets for each params combination. Can be used to create multicast delegate. 
Parameters are: delegate type name and param type names.

*ue4deldyn* - 9 snippets for each params combination. Can be used to create dynamic delegate.
 Parameters are: delegate type name, param type names and display values.

*ue4deldynmul* - 9 snippets for each params combination. Can be used to create dynamic multicast delegate.
 Parameters are: delegate type name, param type names and display values`.

UE4 Console variables

static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.VSync"));
// Limit framerate on console if VSYNC is enabled to avoid jumps from 30 to 60 and back.
if( CVar->GetValueOnGameThread() != 0 )
{
   // do something
}

----------------------------------------------------
// Use CommandLine command
// optionally set the vsync console variable
if( FParse::Param(FCommandLine::Get(), TEXT("vsync")) )
{
	new(GEngine->DeferredCommands) FString(TEXT("r.vsync 1"));
}

Windows10にアップグレード、Wi-Fiが途切れる場合に試してみること

UE4.18 ソースのノート

FDeferredShadingSceneRenderer::Render( ) をざっくり

// DeferredShadingRenderer.cpp

// プリパスの前の処理 : DepthRendering.cpp
RenderPrepass()

// 半透明ライティング用のライトグリッド : LightGridInjection.cpp
ComputeLightGrid()

// オクルージョンクエリ
RenderOcclusion()
FinishOcclusion()

// デプスシャドウ : ShadowDepthRendering.cpp
RenderShadowDepthMaps()

// ボリューメトリックフォグ : VolumetricFog.cpp
ComputeVolumetricFog()

if ( forward )
{
  // フォワードシャドウ投影 : 
  RenderForwardShadingShadowProjections()

  // カプセルシャドウ Indirect : CapsuleShadows.cpp
  RenderIndirectCapsuleShadows()
}

// GBuffer クリア
SetAndClearViewGBuffer()

// ベースパスの描画 : BaseRendering.cpp
RenderBasePass()

// カスタムデプス 
RenderCustomDepthPassAtLocation()

// 速度の描画 : VelocityRendering.cpp
RenderVelocities()

// ベースパス後のポストプロセス : CompositionLighting.cpp
GCompositionLighting.ProcessAfterBasePass()

// ディファードのライティング処理
if ( deferred )
{
    // カプセルシャドウ Indirect : CapsuleShadowRendering.cpp
    RenderIndirectCapsuleShadows()

   // DFAO
   RenderDFAOAsIndirectShadowing() 

   // ライティング : LightRendering.cpp 
   RenderLights(): 

   // ライトグリッドのフィルタリング : TranslucentLighting.cpp
   FilterTraslucentVolumeLighting()

   //  動的スカイライト : DistanceFieldAmbientOcclusion.cpp
   RenderDynamicSkyLighting()

    // リフレクション : ReflectionEnvironment.cpp
    RenderDeferredReclections()
   
   // スクリーンスペース SSS とか : CompositionLighting
   GCompositionLighting.ProcessAfterLighting()
}
    // ライトシャフトのオクルージョン : LightShaftRendering.cpp
    RenderLightShaftOcclusion()

   // 大気散乱フォグ : AtmosphericRendering.cpp
   RenderAtmosphere()

   // フォグ : FogRendering.cpp
   RenderFog()

   // 半透明の描画 : TranslucentLighting.cpp
   RenderTranslucency()

   // 屈折 : DistortionRendering.cpp
   RenderDistortion()

   // ブルーム付きライトシャフト : LightShaftRendering.cpp
   RenderLightsShaftBloom()

   // DistanceField
   RenderDistanceFieldLighting()

   // ポストプロセス : PostProcessing.cpp
   GPostProcessing.Process()  
}

FDeferredShadingSceneRenderer::RenderLights() : LightRendering.cpp

	if (bAllowSimpleLights)
	{
		GatherSimpleLights(ViewFamily, Views, SimpleLights); // LightRendering.cpp
	}

	// Build a list of visible lights.
	for (TSparseArray<FLightSceneInfoCompact>::TConstIterator LightIt(Scene->Lights);
               LightIt; ++LightIt)
	{
            ...
        }

       // ソート
       SortedLights.Sort( FCompareFSortedLightSceneInfo() );

      // Iterate over all lights to be rendered and build ranges for tiled deferred and unshadowed lights
     for (int32 LightIndex = 0; LightIndex < SortedLights.Num(); LightIndex++)
     {
            ...
      }

      if(ViewFamily.EngineShowFlags.DirectLighting)
      {
         	if (ShouldUseTiledDeferred(SupportedByTiledDeferredLightEnd, SimpleLights.InstanceData.Num()) && !bAnyUnsupportedByTiledDeferred && !bAnyViewIsStereo)
                {
                        RenderTiledDeferredLighting();    
                }

               	if (bRenderSimpleLightsStandardDeferred)
		{
			RenderSimpleLightsStandardDeferred(RHICmdList, SimpleLights);
		}

		// Draw non-shadowed non-light function lights without changing render targets between them
		for (int32 LightIndex = StandardDeferredStart; LightIndex < AttenuationLightStart; LightIndex++)
		{
			const FSortedLightSceneInfo& SortedLightInfo = SortedLights[LightIndex];
			const FLightSceneInfo* const LightSceneInfo = SortedLightInfo.LightSceneInfo;

			// Render the light to the scene color buffer, using a 1x1 white texture as input 
			RenderLight(RHICmdList, LightSceneInfo, NULL, false, false);
		}

		if (GUseTranslucentLightingVolumes && GSupportsVolumeTextureRendering)
		{
			if (AttenuationLightStart)
			{
				// Inject non-shadowed, non-light function lights in to the volume.
				SCOPED_DRAW_EVENT(RHICmdList, InjectNonShadowedTranslucentLighting);
				InjectTranslucentVolumeLightingArray(RHICmdList, SortedLights, AttenuationLightStart);
			}
				
			if (SimpleLights.InstanceData.Num() > 0)
			{
				SCOPED_DRAW_EVENT(RHICmdList, InjectSimpleLightsTranslucentLighting);
				InjectSimpleTranslucentVolumeLightingArray(RHICmdList, SimpleLights);
			}
		}
      }
    
 	// Draw shadowed and light function lights
	for (int32 LightIndex = AttenuationLightStart; LightIndex < SortedLights.Num(); LightIndex++)
	{
                 if (bDrawShadows)
		{
                 	RenderShadowProjections(RHICmdList, &LightSceneInfo, ScreenShadowMaskTexture, bInjectedTranslucentVolume);


                }

		// Render light function to the attenuation buffer.
		if (bDirectLighting)
		{
			if (bDrawLightFunction)
			{
				const bool bLightFunctionRendered = RenderLightFunction(RHICmdList, &LightSceneInfo, ScreenShadowMaskTexture, bDrawShadows, false);
				bUsedShadowMaskTexture |= bLightFunctionRendered;
			}

			if (bDrawPreviewIndicator)
			{
				RenderPreviewShadowsIndicator(RHICmdList, &LightSceneInfo, ScreenShadowMaskTexture, bUsedShadowMaskTexture);
			}
                }

		// Render the light to the scene color buffer, conditionally using the attenuation buffer or a 1x1 white texture as input 
		if(bDirectLighting)
		{
			RenderLight(RHICmdList, &LightSceneInfo, ScreenShadowMaskTexture, false, true);
		}
        }
FSceneRenderer::GatherSimpleLights( )
void FSceneRenderer::GatherSimpleLights(const FSceneViewFamily& ViewFamily, const TArray<FViewInfo>& Views, FSimpleLightArray& SimpleLights)
{
	TArray<const FPrimitiveSceneInfo*, SceneRenderingAllocator> PrimitivesWithSimpleLights;

	// Gather visible primitives from all views that might have simple lights
	for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
	{
		const FViewInfo& View = Views[ViewIndex];
		for (int32 PrimitiveIndex = 0; PrimitiveIndex < View.VisibleDynamicPrimitives.Num(); PrimitiveIndex++)
		{
			const FPrimitiveSceneInfo* PrimitiveSceneInfo = View.VisibleDynamicPrimitives[PrimitiveIndex];
			const int32 PrimitiveId = PrimitiveSceneInfo->GetIndex();
			const FPrimitiveViewRelevance& PrimitiveViewRelevance = View.PrimitiveViewRelevanceMap[PrimitiveId];

			if (PrimitiveViewRelevance.bHasSimpleLights)
			{
				// TArray::AddUnique is slow, but not expecting many entries in PrimitivesWithSimpleLights
				PrimitivesWithSimpleLights.AddUnique(PrimitiveSceneInfo);
			}
		}
	}

	// Gather simple lights from the primitives
	for (int32 PrimitiveIndex = 0; PrimitiveIndex < PrimitivesWithSimpleLights.Num(); PrimitiveIndex++)
	{
		const FPrimitiveSceneInfo* Primitive = PrimitivesWithSimpleLights[PrimitiveIndex];
		Primitive->Proxy->GatherSimpleLights(ViewFamily, SimpleLights);
	}
}

FPostProcessing::Process( ) をざっくり

// PostProcessing.cpp

FRenderingCompositePassContext CompositeContext(RHICmdList, View);
FPostprocessContext Context(RHICmdList, CompositeContext.Graph, View);
...
if (AllowFullPostProcessing(View, FeatureLevel))
{
   AddPostProcessMaterial(Context, BL_BeforeTranslucency, SeparateTranslucency);
 
   ....

   // ガウシアン DOF の場合
   if(VelocityInput.IsValid())
   {
 	bSepTransWasApplied = AddPostProcessDepthOfFieldGaussian(Context, DepthOfFieldStat, VelocityInput, SeparateTranslucency);
    }
    else
    {
	FRenderingCompositePass* NoVelocity = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessInput(GSystemTextures.BlackDummy));
	FRenderingCompositeOutputRef NoVelocityRef(NoVelocity);
	bSepTransWasApplied = AddPostProcessDepthOfFieldGaussian(Context, DepthOfFieldStat, NoVelocityRef, SeparateTranslucency);
	}
       ....
  
      if(SeparateTranslucency.IsValid() && !bSepTransWasApplied)
      {
		// separate translucency is done here or in AddPostProcessDepthOfFieldBokeh()
    	        FRenderingCompositePass* NodeRecombined = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessBokehDOFRecombine(bIsComputePass));
		NodeRecombined->SetInput(ePId_Input0, Context.FinalOutput);
		NodeRecombined->SetInput(ePId_Input2, SeparateTranslucency);

		Context.FinalOutput = FRenderingCompositeOutputRef(NodeRecombined);
       }

	AddPostProcessMaterial(Context, BL_BeforeTonemapping, SeparateTranslucency);      

        // テンポラル AA
	if( AntiAliasingMethod == AAM_TemporalAA && ViewState)
        {
   	   if(VelocityInput.IsValid())
	    {
		AddTemporalAA( Context, VelocityInput );
	    }
	   else
	    {
		FRenderingCompositePass* NoVelocity = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessInput(GSystemTextures.BlackDummy));
		FRenderingCompositeOutputRef NoVelocityRef(NoVelocity);
		AddTemporalAA( Context, NoVelocityRef );
		}
	}

       // 自動露出のヒストグラム

       // ダウンサンプリング

       // 自動露出補正

       // ブルーム

      // トーンマッパー
				auto Node = AddSinglePostProcessMaterial(Context, BL_ReplacingTonemapper);

				if(Node)
				{
					// a custom tonemapper is provided
					Node->SetInput(ePId_Input0, Context.FinalOutput);

					// We are binding separate translucency here because the post process SceneTexture node can reference 
					// the separate translucency buffers through ePId_Input1. 
					// TODO: Check if material actually uses this texture and only bind if needed.
					Node->SetInput(ePId_Input1, SeparateTranslucency);
					Node->SetInput(ePId_Input2, BloomOutputCombined);
					Context.FinalOutput = Node;
				}
				else
				{
					Tonemapper = AddTonemapper(Context, BloomOutputCombined, AutoExposure.EyeAdaptation, AutoExposure.MethodId, false, bHDRTonemapperOutput);
				}
      // FXAA 
}
else
{
}
// 可視化
...

if ( dbDOScreenPercentage )
{
    // アップスケール
    FRenderingCompositePass* Node = Context.Graph.RegisterPass(new(FMemStack::Get()) 
                                                            FRCPassPostProcessUpscale(View, UpscaleQuality, PaniniConfig));
    Node->SetInput(ePId_Input0, FRenderingCompositeOutputRef(Context.FinalOutput)); // Bilinear sampling.
    Node->SetInput(ePId_Input1, FRenderingCompositeOutputRef(Context.FinalOutput)); // Point sampling.
    Context.FinalOutput = FRenderingCompositeOutputRef(Node);				
}

Context.FinalOutput = AddPostProcessMaterialChain(Context, BL_AfterTonemapping, SeparateTranslucency, PreTonemapHDRColor, PostTonemapHDRColor);


// グラフを実行
// execute the graph/DAG
CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("PostProcessing"));
....

Notes of RenderThread

f:id:gregory-igehy:20180315172222j:plain

  • WindowsRunnableThread.cpp
    • (0) uint32 FRunnableThreadWin::GuardedRun()
    • (1) uint32 FRunnableThreadWin::Run()
  • RenderingThread.cpp
    • (2) virtual uint32 RenderingThread::Run(void) override
    • (3) void RenderingThreadMain( FEvent* TaskGraphBoundSyncEvent )
  • TaskGraph.cpp
    • (4) virtual void FNamedTaskThread::ProcessTasksUntilQuit(int32 QueueIndex) override
    • (5) void FNamedTaskThread::ProcessTasksNamedThread(int32 QueueIndex, bool bAllowStall)
  • TaskGraphInterfaces.h
    • (6) virtual void TGraphTask::ExecuteTask(TArray& NewTasks, ENamedThreads::Type CurrentThread) final override
  • SceneRendering.cpp
    • (7) static void RenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneRenderer* SceneRenderer)
  • DeferredShading.cpp
    • (8) void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)

Forward shading

f:id:gregory-igehy:20180315180024j:plain

Game 側

UWorld
  • https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/Engine/UWorld/
  • The World is the top level object representing a map or a sandbox in which Actors and Components will exist and be rendered.
  • A World can be a single Persistent Level with an optional list of streaming levels
  • that are loaded and unloaded via volumes and blueprint functions or it can be a collection of levels organized with a World Composition.
  • In a standalone game, generally only a single World exists except during seamless area transitions
  • when both a destination and current world exists. In the editor many Worlds exist:
  • The level being edited, each PIE instance, each editor tool which has an interactive rendered viewport, and many more.
ULevel
  • http://api.unrealengine.com/INT/API/Runtime/Engine/Engine/ULevel/index.html
  • The level object. Contains the level's actor list, BSP information, and brush list.
  • Every Level has a World as its Outer and can be used as the PersistentLevel,
  • however, when a Level has been streamed in the OwningWorld represents the World that it is a part of.
  • A Level is a collection of Actors (lights, volumes, mesh instances etc.).
  • Multiple Levels can be loaded and unloaded into the World to create a streaming experience.
UPrimitiveComponent : 描画や物理と相互作用する基底クラス, カリングの単位
  • https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/Components/UPrimitiveComponent/index.html
  • PrimitiveComponents are SceneComponents that contain or generate some sort of geometry,
  • generally to be rendered or used as collision data.
  • There are several subclasses for the various types of geometry,
  • but the most common by far are the ShapeComponents (Capsule, Sphere, Box),
  • StaticMeshComponent, and SkeletalMeshComponent.
  • ShapeComponents generate geometry that is used for collision detection but are not rendered,
  • while StaticMeshComponents and SkeletalMeshComponents contain pre-built geometry that is rendered, but can also be used for collision detection.
  • ULightComponent : ライト用のクラス
  • FSceneView : FScene を描画する 1 視点

RenderThread 側

  • FScene : UWorld のレンダースレッド版
USceneComponent : FScene に追加する要素の基底クラス
FPrimitiveSceneProxy : UPrimitiveComponent の RenderThread 版
FPrimitiveSceneInfo : レンダラーの内部状態,UPrimitiveComponent と FPrimitiveSceneProxy
FViewInfo : FSceneView のレンダースレッド版
FSceneViewState : 複数フレームに渡るビューの情報を保存するもの
FSceneRenderer : 毎フレーム作られる一時状態

マテリアル

FMaterial : 描画用のマテリアルのインターフェース
FMaterialResource : FMaterial の実装
UMaterialInstance : マテリアルのインスタンス
UMaterialInstanceConstant : マテリアルの定数
UMaterialInstanceDynamic : ランタイムで変えられる

DebugPrint

#include "Engine.h"

if ( GEngine != nullptr )
{
FString str = FString::Printf( TEXT( "last_render_time = %f" ), render_time );
GEngine->AddOnScreenDebugMessage( 2, 1.0f, FColor::Red,
str );
}

UE4 RenderTask

  • class FRenderBasePassDynamicDataThreadTask : public FRenderTask
  • class FRenderPrepassDynamicDataThreadTask : public FRenderTask
  • class FDrawShadowMeshElementsThreadTask : public FRenderTask
  • class FRenderDepthDynamicThreadTask : public FRenderTask
  • class FDrawSortedTransAnyThreadTask : public FRenderTask
  • class FRenderVelocityDynamicThreadTask : public FRenderTask