UE5.1 Planar reflection과 VSM 동시 사용 시 프레임 드랍 문제

2023. 8. 3. 20:20·언리얼 엔진

서론

Unreal Engine 5.1 릴리즈 버전에서 Planar reflection과 VSM 사용 시, 프레임이 많이 하락하는 현상을 보인다.

원인은 planar reflection 렌더러 / 메인 렌더러에서 불리는 D3D12RHI::CreateD3D12Texture 콜

 

 

VSMCachemanager::SetPhysicalPoolSize 는 한번 세팅되면 그만불려야하는 함수인데,

SceneCapture에서 쓰는 VSM cache, 메인 렌더러에서 쓰는 VSM cache가 공유되고있어서

'if (!PhysicalPagePool || PhysicalPagePool->GetDesc().Extent != RequestedSize || PhysicalPagePool->GetDesc().ArraySize != RequestedArraySize)' 조건에 의해 매번 PooledRenderTarget이 만들어지고, cache invalidate가 발생하고있다.

 

TRefCountPtr<IPooledRenderTarget> FVirtualShadowMapArrayCacheManager::SetPhysicalPoolSize(FRDGBuilder& GraphBuilder, FIntPoint RequestedSize, int RequestedArraySize)
{
	if (!PhysicalPagePool || PhysicalPagePool->GetDesc().Extent != RequestedSize || PhysicalPagePool->GetDesc().ArraySize != RequestedArraySize)
	{
		FPooledRenderTargetDesc Desc2D = FPooledRenderTargetDesc::Create2DArrayDesc(
			RequestedSize,
			PF_R32_UINT,
			FClearValueBinding::None,
			TexCreate_None,
			TexCreate_ShaderResource | TexCreate_UAV,
			false,
			RequestedArraySize
		);
		GRenderTargetPool.FindFreeElement(GraphBuilder.RHICmdList, Desc2D, PhysicalPagePool, TEXT("Shadow.Virtual.PhysicalPagePool"));

		Invalidate();
		//UE_LOG(LogRenderer, Display, TEXT("Recreating Shadow.Virtual.PhysicalPagePool. This will also drop any cached pages."));
	}

	return PhysicalPagePool;
}

 

해결 방법

  • 각 렌더러가 각각의 VSMManager를 가진다.
    -> Unreal 5.2 에서 해결됨

 

 

 

5.2 릴리즈 노트 및 수정 커밋 (seperate VSM cache 사용)

 

 

https://github.com/EpicGames/UnrealEngine/commit/a4262b8a07e9e063c12586a6721057e0a5d6addd

 

해당 커밋은 UE5.1에도 이미 적용되어있었음

 

 

코드 분석

Engine/Source/Runtime/Renderer/Private/SceneCaptureRendering.cpp

FScene::UpdateSceneCaptureContents

 
if(UseVirtualShadowMaps(SceneRenderer->ShaderPlatform, FeatureLevel))
{
	// A separate VSM cache is added to the SceneCapture views. 
	// This is needed to prevent the cache being invalidated on every frame.
	// In a future iteration, it may be more efficient to share this cache with the main viewfamily.
	if (ViewStateInterface)
	{
		ViewStateInterface->AddVirtualShadowMapCache(this);
	}
	else
	{
		GEngine->AddOnScreenDebugMessage((uint64)this, 10.0f, FColor::Yellow, TEXT("SceneCapture has no viewstate. This may affect Virtual Shadow Map caching performance. Consider enabling bAlwaysPersistRenderingState or bCaptureEveryFrame."));
	}
}
else if (ViewStateInterface)
{
	ViewStateInterface->RemoveVirtualShadowMapCache(this);
}

 

해당코드는 씬캡쳐 FSceneViewState에 VSMCacheManager를 독립적으로 추가하는 코드이다.

 

PlanarReflectionRendering.cpp 의 FScene::UpdatePlanarReflectionContents

반면 Planar Reflection에서는 독립적인 VSMCacheManager를 추가하는 코드가 없다. 따라서 같은 VSMCacheManager 및 PhysicalPagePool (렌더타겟포함)을 사용하는 것으로 확인되었다.

 

main renderer 의 PhysicalPagePool pointer

  PhysicalPagePool	{Reference=0x0000023cbf4d6a00 {RenderTargetPool=0x00007ff6c815c280 {MV.exe!TGlobalResource<FRenderTargetPool> GRenderTargetPool} {...} ...} }	TRefCountPtr<IPooledRenderTarget>

planar reflection renderer의 PhysicalPagePool pointer

  PhysicalPagePool	{Reference=0x0000023cbf4d6a00 {RenderTargetPool=0x00007ff6c815c280 {MV.exe!TGlobalResource<FRenderTargetPool> GRenderTargetPool} {...} ...} }	TRefCountPtr<IPooledRenderTarget>

(같음)

 

 

 

따라서 FScene::UpdatePlanarReflectionContents 함수에 View고유의 VSMCacheManager를 추가하는 코드를 추가하였음.

FScene::UpdatePlanarReflectionContents (..)
{
		...
        FSceneViewStateInterface* ViewStateInterface = CaptureComponent->GetViewState(0);
		if (UseVirtualShadowMaps(SceneRenderer->ShaderPlatform, FeatureLevel))
		{
			// A separate VSM cache is added to the SceneCapture views. 
			// This is needed to prevent the cache being invalidated on every frame.
			// In a future iteration, it may be more efficient to share this cache with the main viewfamily.
			if (ViewStateInterface)
			{
				ViewStateInterface->AddVirtualShadowMapCache(this);
			}
			else
			{
				GEngine->AddOnScreenDebugMessage((uint64)this, 10.0f, FColor::Yellow, TEXT("SceneCapture has no viewstate. This may affect Virtual Shadow Map caching performance. Consider enabling bAlwaysPersistRenderingState or bCaptureEveryFrame."));
			}
		}
		else if (ViewStateInterface)
		{
			ViewStateInterface->RemoveVirtualShadowMapCache(this);
		}
        ...
}

 

변경 후

불필요한 D3D12RHI::CreateD3D12Texture  콜이 사라지고, FPS 46 -> FPS 110 으로 평균프레임 향상

'언리얼 엔진' 카테고리의 다른 글

[Unreal Engine 5] Virtual Shadow Map  (1) 2025.07.29
[Unreal Engine 5] Nanite Basepass 분석  (5) 2025.07.25
Expert's guide to unreal engine performance  (0) 2023.09.01
[언리얼 엔진] Referencing Assets 쿠킹 테스트  (0) 2023.03.24
[언리얼 엔진] 블루프린트 String Path로 로드 시 주의할 점  (2) 2023.03.20
'언리얼 엔진' 카테고리의 다른 글
  • [Unreal Engine 5] Nanite Basepass 분석
  • Expert's guide to unreal engine performance
  • [언리얼 엔진] Referencing Assets 쿠킹 테스트
  • [언리얼 엔진] 블루프린트 String Path로 로드 시 주의할 점
jooh3444
jooh3444
게임엔진 / 그래픽스 개발 블로그
  • jooh3444
    Jooh 개발 블로그
    jooh3444
  • 전체
    오늘
    어제
    • Dev blog (18)
      • OpenGL (7)
        • CS-248 셰이더 프로그래밍 (7)
      • 언리얼 엔진 (7)
      • 기타 (1)
      • Computer Graphics (3)
  • 블로그 메뉴

    • 홈
    • About
    • github
  • 인기 글

  • 태그

    Nanite
    Shader Programming
    Unreal Engine 5
    Shader
    셰이더
    그래픽스
    Enviroment Lighting
    UE5
    Blueprint load by path
    Computer Graphics
    bDontLoadBlueprintOutsideEditor
    셰이더 프로그래밍
    twopass occlusion culling
    multi-scattering brdf
    범프 매핑
    UE5 bugfix
    Unreal Engine
    Shadow map
    Virtual Shadow Map
    OpenGL
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
jooh3444
UE5.1 Planar reflection과 VSM 동시 사용 시 프레임 드랍 문제
상단으로

티스토리툴바