ue4的SceneComponent2D的SceneDepthInA问题

问题描述:

将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);
	}
}

你可能感兴趣的:(UE4)