[역] 언리얼 엔진 4.22를 위한 메시 드로잉 파이프라인 변환 가이드

2025. 4. 11. 02:13개인 공부

 

 

- 2025/04/11 (최초 작성)

- 2025/04/11 (마지막 수정)

발 번역 주의보, Figures나 예제 코드는 빠져있을 수 있습니다.

개인 공부 및 연습용으로 번역된 글입니다. 의역/오역/오타가 많을 수 있으며. 원저작권자의 별도의 허가 없이 작성되었으므로, 언제든지 삭제될 수 있습니다.

원본 아티클


언리얼 엔진 4.22를 위한 메시 드로잉 파이프라인 변환 가이드


 언리얼 엔진 4.22가 릴리즈 되면서 메시 드로잉 파이프라인이 완전히 다시 쓰였습니다. 주요 변화는 매 프레임마다 가시성이 존재하는 드로우들을 만들어내는 즉시 모드(Immediate Mode)에서, 모든 장면의 드로우들이 사전에 준비되어 있는 보존 모드(Retained Mode)로의 변경입니다. 이는 DirectX Raytracing (DXR)과 같이 전체 장면에 대한 셰이더 바인딩 테이블을 요구하거나, GPU 주도 렌더링과 같이 CPU가 가시성에 대한 정보 없이도 드로우를 준비해야만 하는 경우를 가능하게 만들어줄 아주 중요한 변화입니다.

메시 드로우 커맨드

 낣은 파이프라인에서는, 메시 패스 드로우 정책이 직접적으로 FMeshBatch에 기반하여 렌더링 하드웨어 인터페이스 (RHI) 커맨드를 직접 실행 하였었습니다. 새로운 파이프라인에서는 FMeshBatch와 RHI 사이의 인터페이스 처럼 행동하는 새로운 개념인 메시 드로우 커맨드 FMeshDrawCommand가 새롭게 추가됩니다. 메시 드로우 커맨드는 완전 독자적인 드로우 설명입니다. 이 새로운 개념은 RHI가 드로우를 하는데 필요한 모든 정보를 저장합니다. 이는 셰이더 바인딩과 함께 전체 드로우 상태를 같이 캐싱하거나 재사용하는 것을 가능하게 만들어줍니다.

정적 드로우 리스트와 프리미티브 집합

4.22의 메시 렌더링 파이프라인 에서는, 정적 드로우 리스트 (TStaticMeshDrawList)와 프리미티브 집합 (예를 들어, FTranslucentPrimSet, FCustomDepthPrimSet)이 FParallelMeshDrawCommandPassa로 대체되었습니다.
FParallelMeshDrawCommandPass는 패스당 단일 가시성 있는 메시 드로우 커맨드 리스트를 캡슐화합니다.

새로운 디자인은 중요한 두 가지 변화가 존재합니다:

  • 첫 번째로, 장면 당 리스트들이 가시성 있는 메시 리스트들로 대체되었습니다. 이전에는 정적 메시 패스를 드로잉 하는 것은 각 정적 메시에 대해 FViewInfo::StaticMeshVisibilityMap을 체크하여 보이는 메시를 선택하기 위해서 장면에 있는 패스 당 정적 메시 리스트들 전체를 순회해야 했었습니다. 새로운 디자인에서는, 드로잉은 단순한 보이는 메시 드로우 커맨드 배열 (FMeshDrawCommandPassSetupTaskContext::MeshDrawCommands)를 순회하는 일일 뿐입니다. 새로운 접근 방식이 장면 복잡성이 증가할 때 더 나은 스케일링을 보여줍니다.
  • 두 번째로 중요한 변화는 어떻게 정적 그리고 동적 메시 드로잉 리스트를 합병(merge)하는지 이고. 이 변화는 전체 메시 드로잉 파이프라인을 간결하게 만들 뿐 아니라 렌더러가 정적 그리고 동적 드로우를 같이 정렬할 수 있도록 합니다.

 또 이 파이프라인은 DrawDynamicMeshPass 함수를 통해 즉시 모드 메시 렌더링 에뮬리이션을 제공합니다. 이 방법은 아주 유연한 렌더링 패스이지만, 이 패스는 캐싱, 자동 인스턴싱을 지원하지 않고 많은 동적 메모리 할당을 수행하기 때문에 퍼포먼스가 중요한 메시 패스에서는 사용을 지양해야 합니다. 예를 들어, 이 방식은 에디터 전용 헬퍼 메시들을 렌더링 하기 위한 DrawViewElements를 대체합니다.

드로잉 정책

FDepthDrawingPolicy나 FBasePassDrawingPolicy와 같은 드로잉 정책들은 FDepthPassMeshProcessor와 FBasePassMeshProcessor에 의해 대체되었습니다. 특정한 패스 메시 프로세서들은 FMeshProcessor 베이스 클래스를 상속받으며 FMeshBatch를 패스를 위한 메시 드로우 커맨드들의 집합으로 변환하는 역할을 담당합니다. 바로 이 클래스가 최종 드로우 필터링이 일어나고, 셰이더 조합(permutation)이 선택되며 셰이더 바인딩들이 수집되는 지점입니다.

셰이더 바인딩

 이전까지는 모든 셰이더 파라미터가 적절한 드로잉 정책에 의해서 RHICmdList에 설정되었습니다. 이제는, 모든 파라미터는 FMeshDrawSingleShaderBindings 내부에 모이고, 이후에 드로잉 중에 SetOnCommandList가 호출되면 RHICmdList에 설정됩니다. 이런 동작은 전체 드로우 상태가 셰이더 바인딩과 함께 캐싱되도록 하기 위해 필요로 합니다.

 낡은 파이프라인은 공통 고수준 메시 패스 렌더 상태를 전달하기 위해 FDrawingPolicyRenderState를 사용했었습니다, 예를 들어, 유니폼 버퍼를 전달하는 것과 같은 경우입니다. 새로운 파이프라인은 기능적으로 중대한 변화는 없이 FDrawingPolicyRenderState를 FMeshPassProcessorRenderState로 개명하였습니다.

 셰이더의 SetParameters와 SetMesh 함수 내부를 채우고 있던 셰이더 바인딩의 다른 부분들은 GetShaderBindings와 GetElementShaderBinds로 대체되었으며, 드로우 당 파라미터는 커스텀 가능한 ShaderElementDataType 내부로 전달됩니다.

 리팩토링을 통해, 많은 개별 파라미터들이 패스별 또는 다른 유니폼 버퍼로 통합되었습니다. 이런 파라미터 설정 방식을 선호되어야 하며, 개별 파라미터를 사용하는 것은 자동 인스턴싱을 비활성화할 뿐 아니라, 개별 드로우 사이에서 상수 버퍼의 업데이트로 인한 성능 저하 문제를 야기할 수 있습니다.

 이전까지 ViewUniformBuffer나 DepthPassUniformBuffer와 같은 표준 유니폼 버퍼들은 매 프레임 새로운 데이터와 함께 재생성되었었습니다. 새로운 파이프라인에서 이들은 영속적(persistent)이며 전역적 (FScene::FPersistentUniformBuffers 내부에 유지됩니다)이기에 새로운 데이터를 전달하기 위해 재생성이 필요 없을 뿐 아니라 새로운 RHI 함수인 RHIUpdateUniformBuffer를 사용해서 내용이 업데이트됩니다. 이런 간접성은 셰이더의 메시 드로우 커맨드들이 캐시 되어있더라도 프레임 데이터를 전달받을 수 있도록 합니다.

FPrimitiveViewRelevance

FPrimitiveViewRelevance는 두 개의 추가 관련성 플래그와 함께 확장되었습니다:

  • bVelocityRelevance는 별도의 속도 패스를 위해 요구됩니다.
  • bTranslucentSelfShadow는 반투명한 셀프 셰도우를 위해 요구됩니다.

 추가적으로, 모든 동적 드로우들은 이제 뷰 관련성(relevance)과 연관되어 있으며, 뷰 관련성에서 특정 패스를 비활성화시킨다는 것은 패스의 렌더링을 비활성화시킨 게 됩니다.

셰이더

 새로운 파이프라인은 GPUScene을 새롭게 도입하였습니다, GPUScene은 장면에 존재하는 모든 프리미티브에 대한 프리미티브 유니폼 버퍼 데이터를 포함하고 있는 구조적 버퍼(structured buffer)입니다. 현재는 로컬 정점 팩토리 (정적 메시 컴포넌트)와 SM5 기술 레벨만이 이 렌더링 패스를 활용할 수 있습니다. GPUScene이 활성화된 상태에서 셰이더를 컴파일하기 위해선 프리미티브 유니폼 버퍼를 직접 접근하는 대신 GetPrimitiveData(PrimitiveId)를 사용해야 합니다.

 프리미티브 데이터 접근은 때론 커스텀 표현 머테리얼 노드 내부에서 일어납니다. 예를 들어, 프리미티브의 바운딩 박스에 접근하는 경우가 있습니다. 이들을 변환하기 위해선, Primitive.Member가 GetPrimitiveData(Parameters.PrimitiveId). Member로 대체되어야 합니다.

 

.
해당 이미지는 본 내용과 관련이 없습니다