[UE] SceneVisibility

윤정민·2026년 7월 26일

Unreal Engine

목록 보기
38/38

언리얼 렌더링 파이프라인 중 BeginInit에서 가시성을 판단하여 불필요한 Draw를 줄인다.
해당 문서에서는 가시성 판단 과정을 상세히 기술하겠다.

가시성 파이프라인

아래 함수를 통해 3단계를 통해 가시성을 판단한다.

  • FVisibilityViewPacket::BeginInitVisibility
    • FrustumCull
      • 프러스텀 + 거리
    • OcclusionCull
      • HZB / 쿼리
    • ComputeRelevence
      • 드로우/패스 분류

가시성 판단에는 아래 4가지 기법을 사용한다.

  • 비트맵 기반

    • 각 뷰가 씬의 프리미티브 수만큼 비트를 가진 Map을 만들고 단계별로 비트를 끔
    • View.PrimitiveVisibilityMap
  • 워드 단위 병렬 분할

    • 프리미티브를 32개(1DWORD) 단위로 묶어 태스크에 배분
    • WorkerThread x NumFrustumCullTaskPerThread기준으로 태스크 수 결정
  • CommandPipe 단계로 연결

    • 프러스텀 컬이 끝난 32개 플록을 곧바로 오클루전 큐로 흘려보냄
    • 따라서, 프러스텀 중 오클루전 이미 시작
  • AlwaysVisible 최적화

    • PrimitivesAlwaysVisibleOffset 이후의 프리미티브는 컬링 테스트 제외

FrustumCull

View별로 WORD 블록을 돌면서 비트별로 판정한다.
여러 테스트를 진행하며, 비용 낮은 -> 높은 테스트 순서로 진행한다.

1. Hide/Show 필터

  • SceneVisibility.cpp:625
  • View 내부 데이터, 플래그로 판단

2. 프러스텀 교차 판정

프리미티브가 View Frusutm 내부에 있는지 확인

  • SceneVisibility.cpp:599
  • 프러스텀 내부에 존재하는지 확인한다

Custum Culling

  • 커스텀 Visibility 훅

Sphere test (옵션)

Box vs 8-plane

  • IntersectBox8Plane
    • 평면이 정확히 8개일 때 실행
    • 루프와 경계 브랜치를 제거한 버전
    • 두 SIMD 그룹(4평면씩)으로 실행
    • 옥트리를 통해 내부 판정을 가속할 수 있음

3. 거리 컬링

  • 프러스텀 컬링 통과 시에만 테스트

OcclusionCull

프리미티브가 다른 물체에 가려지지 않았는지 확인
프러스텀+거리 통과시에만 테스트한다.

이전 프레인 쿼리 결과를 이번 프레임 테스트에 사용하는 것이 특징이다. (temporal)

  • 테스트 결과를 기다리지 않음으로 Wait 시간 제거

가림 판정

  • 판정 방법은 총 3개가 있음

    • OcclusionFeedback

      • GPU가 지난 프레임에 이 프리미티브의 픽셀을 실제로 그렸는지를 기록한 피드백 버퍼로 판정
    • HZBOcclusion

      • 이전 프레임 Mipmap Depth Depth로 만든 HZB에 BBox를 한번에 테스트

        • https://ebs12373.tistory.com/123

        • 바운드 박스를 스크린공간으로 투영 -> 박스의 가장 가까운 깊이 계산

        • 밉레벨 선택

          • 사각형이 약 2×2 텍셀만 덮는 밉 레벨을 고름
            • 텍셀 4개만 읽으면 됨
      • GPU: HZB에 가림 테스트 해서 결과 텍스처에 write

      • CPU: readback을 잠궈 ResultsBuffer 포인터에 연결

    • occlusion query

      • 픽셀 샘플을 통해 통과 픽셀이 0개라면 가려짐으로 판정
      • 매번 모든 Primitive를 쿼리할 순 없으니 화면점유율로 재쿼리 확률을 계산

이전 프레임 정보 저장

  • 이전 프레임 HZB 저장

  • 오클루전 쿼리 정보 저장

쿼리요청

  • 오클루전 쿼리는 GPU가 담당하기 때문에 Renderer에서 쿼리 요청을 담당
    • InstanceOcclusionQueryMask에 결과 저장 (다음 프레임 사용)
  • 모든 쿼리를 할 수 없으니 LastPixelsPercentage, LastProvenVisibleTime등을 통해 쿼리 여부를 결정

쿼리 결과사용

  • PrimitiveOcclusionHistory에 이전 테스트 요청 시 사용했던 Index를 저장해뒀다가 결과 조회시 사용

Relevance

컬링을 통과한 보여줄 프리미티브를 어떤 렌더 패스로 어떻게 그릴지 분류하는 단계이다.
PrimitiveSceneProxy가 머티리얼+설정값을 보고 FPrimitiveViewRelevance에 값을 채운다.

Draw Type

  • NotDrawRelevant
    • !bDrawRelevance가 설정되어 DrawCommand 제외
  • Static+Draw/Shadow
    • LOD 결정 후 StaticMeshVibilityMap에 마킹
      • 캐시된 DrawCommand 사용
  • Dynamic
    • AddDynamicPrimitive로 GDME 대상 등록

참고문헌

profile
그냥 하자

0개의 댓글