将SceneCapture2DActor的SceneCaptureComponent2D的RenderTarget格式设为PF_A16B16G16R16格式, 将captureSource类型设为SceneColorSceneDepth,(SceneCaptureComponent2D->CaptureSource = ESceneCaptureSource::SCS_SceneColorSceneDepth),但生成的RenderTarget的a通道被截取到了1,无法获取到深度信息。
查看源码,用到的shader是MobileSceneCapture.usf文件。看不出来啥问题。
然后把SceneCaptureComponent2D的captureSource类型改为SCS_SceneDepth:
/** Specifies which component of the scene rendering should be output to the final render target. */
UENUM()
enum ESceneCaptureSource
{
SCS_SceneColorHDR UMETA(DisplayName="SceneColor (HDR) in RGB, Inv Opacity in A"),
SCS_SceneColorHDRNoAlpha UMETA(DisplayName="SceneColor (HDR) in RGB, 0 in A"),
SCS_FinalColorLDR UMETA(DisplayName="Final Color (LDR) in RGB"),
SCS_SceneColorSceneDepth UMETA(DisplayName="SceneColor (HDR) in RGB, SceneDepth in A"),
SCS_SceneDepth UMETA(DisplayName="SceneDepth in R"),
SCS_DeviceDepth UMETA(DisplayName = "DeviceDepth in RGB"),
SCS_Normal UMETA(DisplayName="Normal in RGB (Deferred Renderer only)"),
SCS_BaseColor UMETA(DisplayName="BaseColor in RGB (Deferred Renderer only)")
};
发现RenderTarget的R通道是有深度信息的。
查看shader发现如下代码:
#elif SOURCE_MODE_SCENE_DEPTH
OutColor.r = float4(EncodedColor.a,0,0,0);
#endif
而SCS_SceneColorSceneDepth下的a通道获取代码
OutColor.r = SceneW;
可以看出区别,一个是float直接赋过去,一个是写成float4(floatVal, 0, 0, 0),再赋过去。可能前一种方式会导致位数太低,截断了。
所以,进行修改,然后RenderTarget的a通道终于有深度了。
关于SceneCapture渲染相关代码在MobileSceneCaptureRendering.cpp文件中:
FRendererModule.BeginRenderingViewFamily( )
{
...
if (!SceneRenderer->ViewFamily.EngineShowFlags.HitProxies)
{
USceneCaptureComponent::UpdateDeferredCaptures(Scene);
}
...
}
UpdateDeferredCaptures函数里调用子类(SceneCaptureComponent2D和SceneCaptureComponentCube)的UpdateSceneCaptureContents函数;
void USceneCaptureComponent::UpdateDeferredCaptures(FSceneInterface* Scene)
{
UWorld* World = Scene->GetWorld();
if (!World || SceneCapturesToUpdateMap.Num() == 0)
{
return;
}
// Only update the scene captures associated with the current scene.
// Updating others not associated with the scene would cause invalid data to be rendered into the target
TArray< TWeakObjectPtr > SceneCapturesToUpdate;
SceneCapturesToUpdateMap.MultiFind(World, SceneCapturesToUpdate);
SceneCapturesToUpdate.Sort([](const TWeakObjectPtr& A, const TWeakObjectPtr& B)
{
if (!A.IsValid())
{
return false;
}
else if (!B.IsValid())
{
return true;
}
return A->CaptureSortPriority > B->CaptureSortPriority;
});
for (TWeakObjectPtr Component : SceneCapturesToUpdate)
{
if (Component.IsValid())
{
Component->UpdateSceneCaptureContents(Scene);
}
}
// All scene captures for this world have been updated
SceneCapturesToUpdateMap.Remove(World);
}
USceneCaptureComponent2D的update函数里里又调用了Scene的update函数:
void USceneCaptureComponent2D::UpdateSceneCaptureContents(FSceneInterface* Scene)
{
Scene->UpdateSceneCaptureContents(this);
}
这个函数代码:
void FScene::UpdateSceneCaptureContents(USceneCaptureComponent2D* CaptureComponent)
static void UpdateSceneCaptureContent_RenderThread()
void UpdateSceneCaptureContentMobile_RenderThread( )
{
...
// Render the scene normally
{
SCOPED_DRAW_EVENT(RHICmdList, RenderScene);
if (bNeedsFlippedFinalColor)
{
// Hijack the render target
SceneRenderer->ViewFamily.RenderTarget = &FlippedRenderTarget; //-V506
}
SceneRenderer->Render(RHICmdList);
if (bNeedsFlippedFinalColor)
{
// And restore it
SceneRenderer->ViewFamily.RenderTarget = Target;
}
}
...
}
上面UpdateSceneCaptureContentMobile_RenderThread函数里又渲染了一遍场景,开销很大。爲了避免在不需要sceneCapture时候的这些开销,可以在USceneCaptureComponent中定义bSceneCaptureEnable变量,SetSceneCaptureEnabled(bool SceneCaptureEnable)函数。在子类的UpdateSceneCaptureContents函数中判断该变量为true的情况下,才执行场景渲染相关操作。如下面代码所示,先判断bCaptureSceneEnabled是否为true,再执行更新:
void USceneCaptureComponent2D::UpdateSceneCaptureContents(FSceneInterface* Scene)
{
if (bCaptureSceneEnabled)
{
Scene->UpdateSceneCaptureContents(this);
}
}