언리얼 렌더링 시스템 분석(14) - 확장: 현대 렌더링 엔진의 진화 역사 4부(결과 기간)
🌐 원문 링크: 剖析虚幻渲染体系(14)- 延展篇:现代渲染引擎演变史Part 4(结果期) (cnblogs.com/timlly)
📅 원문 발행일: 2022-05-14 | ✍️ 저자: Timlly (00 / )💡 시리즈 분류:
History of Rendering| 국내 업계 표준 용어 감수 및 수식/도해 복원 적용 완료
2016년 이후 시간이 흘렀고, 이 기간 동안의 게임 엔진은 영화와 TV 수준, 더 많은 물리학, 더 많은 효율성을 향해 발전했습니다. 나중에 분석을 살펴보겠습니다.
14.5.1 그래픽 API
14.5.1.1 다이렉트X
2016년 이후 DirectX는 주로 ID3D12Device, Shading Model 6.x, Ray Tracing, VRS, 루트 서명, 리소스, 동기화, 디버깅, PSO, 명령 목록, HLSL 등의 새로운 추가 또는 개선을 포함하여 DirectX 12 및 관련 하위 버전의 업데이트에 중점을 둡니다. 자세한 내용은 DirectX - Wikipedia 및 Direct3D 12의 새로운 기능을 참조하세요.
14.5.1.2 OpenGL
OpenGL은 2016년 이후 버전 4.6을 출시했습니다. 이 버전에는 SPIR-V, Multi-draw 간접, 버텍스 셰이더 획득 데이터, 통계 및 변환 피드백 오버플로 쿼리, 이방성 필터링, 클램핑 다각형 오프셋, 오류를 보고하지 않는 OpenGL 컨텍스트 생성, 원자 카운터에 대한 추가 작업, 불필요한 발산 셰이더 호출 방지와 같은 새롭거나 향상된 기능이 포함되어 있습니다.
OpenGL ES는 이 기간 동안 거의 움직이지 않았습니다.
14.5.1.3 불칸
2016년 이후 Vulkan이 출시한 버전, 시간, 기능은 다음과 같습니다.
버전 시간 특징
불칸 1.3 2022-01 특정 물리적 장치에 사용 가능한 확장, Vulkan 프로필 도구 솔루션, 멀티 스레드 애플리케이션을 위한 향상된 검증 계층 성능, 새로운 확장을 쿼리합니다.
불칸 1.2 2020-01 타임라인 세마포어, 공식 메모리 모델, 스레드 동기화 및 메모리 작업 의미 체계, 설명자 인덱싱, 여러 셰이더에 걸친 설명자 레이아웃 재사용, HLSL 셰이더에 대한 심층 지원.
불칸 1.1 2018-03 하위 그룹, 액세스할 수 없거나 복사된 리소스 렌더링 및 표시, 다중 뷰 렌더링, 다중 GPU, 16비트 메모리 액세스, HLSL 메모리 레이아웃, YCbCr 색상 형식, SPIR-V 1.3.
14.5.1.4 금속
Metal은 Apple의 자체 그래픽 API입니다. 2017년 6월 5일, Apple은 macOS High Sierra, iOS 11 및 tvOS 11에서 지원되는 Metal의 두 번째 버전을 WWDC에서 출시했습니다. Metal 2는 Metal용 별도 API가 아니며 동일한 하드웨어에서 지원됩니다. Metal 2는 Xcode에서 보다 효율적인 프로파일링 및 디버깅을 가능하게 하고, 기계 학습을 가속화하고, CPU 작업 부하를 줄이며, macOS에서 가상 현실, 특히 Apple A11 GPU의 기능을 지원합니다.
WWDC 2020에서 Apple은 Mac을 Apple Silicon으로 마이그레이션한다고 발표했습니다. Apple Silicon을 사용하는 Mac에는 이전에 macOS와 iOS에서 사용할 수 있었던 기능을 결합한 기능 세트가 포함된 Apple GPU가 탑재되며, Apple GPU의 TBDR(타일 기반 디퍼드 렌더링) 아키텍처에 맞게 맞춤화된 기능을 활용할 수 있습니다.
Metal은 사전 인코딩된 명령을 사용하여 GPU에 대한 낮은 오버헤드 액세스를 제공한 다음 비동기 실행을 위해 GPU에 제출되도록 설계되었습니다. 애플리케이션은 실행이 완료될 때까지 기다리는 시기를 제어하므로 애플리케이션 개발자는 GPU에서 실행되는 동안 추가 명령을 인코딩하여 처리량을 늘리거나 GPU 실행이 완료될 때까지 명시적으로 기다려 전력을 절약할 수 있습니다. 또한 명령 인코딩은 CPU 독립적이므로 애플리케이션은 각 CPU 스레드에 대한 명령을 독립적으로 인코딩할 수 있습니다. 렌더링 상태는 사전 계산되어 GPU 드라이버가 명령을 실행하기 전에 렌더링 파이프라인을 구성하고 최적화하는 방법을 미리 알 수 있습니다.
Metal은 애플리케이션 개발자에게 리소스(버퍼, 텍스처)를 생성할 수 있는 유연성을 제공합니다. 리소스는 CPU, GPU 또는 둘 다에 할당될 수 있으며 할당된 리소스를 업데이트하고 동기화하는 기능을 제공합니다. Metal은 명령 인코더의 수명 동안 리소스 상태를 적용할 수도 있습니다. macOS에서 Metal을 사용하면 앱 개발자는 CPU의 저전력 통합 GPU, 개별 GPU(일부 MacBook 및 Mac의 경우) 또는 Thunderbolt를 통해 연결된 외부 GPU를 선택하여 실행할 GPU를 결정할 수 있습니다. 또한 애플리케이션 개발자는 GPU 명령을 실행할 GPU의 우선순위를 정하고 특정 명령이 가장 효율적으로 실행될 GPU에 대한 권장 사항을 제공할 수 있습니다.
14.5.2 하드웨어 아키텍처
2016년 이후 Nvidia는 Pascal, Volta, Turing 및 기타 아키텍처 기반 GPU를 연속적으로 출시했습니다. Turing 아키텍처에는 RT Core라는 전용 레이 트레이싱 프로세서가 장착되어 있어 초당 최대 10기가 광선의 속도로 3D 환경에서 빛과 소리의 전파 계산을 가속화할 수 있습니다. Turing 아키텍처는 이전 세대 Pascal 아키텍처보다 실시간 레이 트레이싱 작업을 25배 가속화하고 CPU보다 30배 이상 빠르게 영화 효과의 최종 프레임을 렌더링할 수 있습니다.

튜링 아키텍처의 SM 구조 다이어그램. Ray Tracing을 위한 RT Core와 AI를 위한 Tensor Core가 포함되어 있습니다.
Intel에서 발표한 Multi Adapter Integrated + Discrete GPU는 통합 + 분리 기회, D3D12 다중 어댑터 배경, 실용적인 비대칭 다중 GPU 등을 포함하여 2020년 통합 및 분리 GPU에 적합한 다중 어댑터 기술을 설명합니다.
통합 그래픽의 기회: 많은 게임용 PC에는 통합 GPU와 개별 GPU가 모두 있습니다. 통합 회로는 종종 유휴 상태이고 통합 그래픽에는 많은 계산이 필요합니다! 그리고 인텔에는 성능 향상에 도움이 되는 확장 기능이 있습니다. 그러나 D3D12 다중 어댑터에는 많은 단점이 있으며, 특정 알고리즘 클래스의 경우 통합 GPU를 활용하여 적당한 엔지니어링 노력으로 더 높은 성능을 달성할 수 있는 방법이 있습니다.
D3D12 다중 어댑터 지원, D3D는 두 가지 방법으로 다중 GPU를 지원합니다.
링크드 디스플레이 어댑터(LDA, Linked Display Adapter). 여러 노드가 있는 어댑터(D3D 장치)로 표시되며, 일반적으로 동일한 GPU에서 대칭적으로 노드 간/노드 간 리소스를 투명하게 복사하거나 사용합니다.
명시적 멀티 어댑터. 어댑터 간 리소스 공유에는 많은 제한이 있으며 비대칭적일 수 있습니다. 이것이 바로 Intel이 수행하는 작업입니다.
다중 어댑터 방법:
공유 렌더링: 분할 프레임, 교체 프레임, 체커보드, 비대칭 GPU는 투자 수익이 매우 낮습니다.
포스트 프로세스: CMAA, SSAO, 카메라 효과... PCI 버스를 두 번 교차해야 합니다.
오클루전 컬링, 물리학, 인공 지능. 생산자-소비자는 렌더링에서 비동기적으로 실행할 때 더 잘 작동합니다.
통합 그래픽 메모리는 iGPU가 거의 해를 끼치지 않고 어댑터 전체에서 리소스를 공유하는 데 사용할 수 있는 시스템 메모리입니다.

어댑터 간 D3D12 리소스: 리소스는 어댑터에 바인딩된 D3D 장치에 의해 할당됩니다. 어댑터 간에 데이터를 전송하는 방법은 무엇입니까? 공유, 교차 어댑터 리소스는 교차 어댑터 공유 힙에 배치되어야 합니다. 힙 생성 단계: 데이터 크기 조정, 모든 장치에서 공유 힙 생성, 핸들 생성.

교차 어댑터 리소스 생성: 두 번째 장치에서 핸들을 열고 동일한 정렬 및 크기를 사용하여 두 어댑터 모두에 대한 교차 어댑터 힙에 배치된 리소스를 만듭니다.

입자 사례의 비동기 계산: 핑퐁 버퍼는 소스 및 대상 상태를 유지하고, 초기 상태를 읽고, 다음 상태를 계산하고, 결과를 렌더링하고, 다음 상태를 계산하는 동안 이전 상태를 렌더링하여 상태를 병렬화합니다(비동기 계산). 버퍼 수는 스왑 체인 길이와 일치합니다.

여러 어댑터에 대한 복사 단계 추가: 각 어댑터가 병렬 파이프라인을 형성하는 핑퐁 버퍼라는 개념입니다. 상태 n의 판독기 2개, 상태 n+1 계산, 상태 n-1 렌더링.

여러 어댑터가 있는 Pong: 프레임당 버퍼 교환.

리소스 할당: 렌더 버퍼는 로컬 어댑터 힙(기본값, 커밋됨), 어댑터 개별 메모리, 어댑터 기본 레이아웃을 사용합니다. 컴퓨팅 버퍼는 어댑터 힙, CPU 메모리, 선형 레이아웃 전반에 걸쳐 어댑터 간 배치를 사용합니다.

복사 대기열: 핵심 아이디어는 분리된 어댑터의 복사 대기열이 시스템 메모리에서 분리된 메모리로 복사하고 통합 메모리가 시스템 메모리이므로 명시적인 복사 단계 느슨한 타이밍을 갖춘 논리적 배열이라는 것입니다.

이러한 결합 + 분리 다중 GPU 아키텍처를 사용하면 리소스 생성, 어댑터 간 동기화, 명령 대기열과 같은 작업을 보다 효율적으로 처리할 수 있습니다. GpuView에서 얻은 결과는 병렬로 실행되는 단계, 두 가지 예, 전체 화면 응용 프로그램을 보여줍니다. 3D가 지배적일 때 계산 및 복사 시간이 있으며 경우에 따라 복사가 지배적일 수 있습니다(프레임 시간 > 렌더링 + 계산).

이 기술은 다음과 같은 경우에 가장 잘 작동합니다. 렌더링 GPU가 포화 상태이고 순수한 생산자-소비자(데이터는 버스를 한 번만 통과함), 작업이 완전히 오프로드될 수 있음(협업이 필요하지 않음), 렌더링이 기다리지 않고(파이프라인에 숨 쉴 공간이 있음) 바람직하게는 1프레임 이상 계산이 허용되고 많은 비동기 컴퓨팅 작업이 이 패턴에 적합합니다. PCIe 대역폭: Gen3 x16은 16GB/s, 4백만 개의 입자, 입자당 float4: 64MB, 16GB/64MB = 256Hz 최대 프레임 속도, 일부 GPU/구성은 x8입니다: 대역폭의 절반, 데이터 전송 크기를 가능한 한 낮게 유지하십시오! 사용량에 따라 데이터 버퍼를 분할하면 성능상의 이점이 있습니다. 이 체계는 입자뿐만 아니라 물리, 메시 변형, AI, 그림자, 많은 비동기 컴퓨팅 작업에도 이 패턴에 적합합니다. Intel 통합 그래픽을 확인하세요!
14.5.3 엔진 진화
14.5.3.1 포괄적인 진화
2016년 영화 품질을 향하여, Quantum Break의 앤티앨리어싱에서는 간접 조명, 참여 미디어, 기하학적 앨리어싱 및 반사 앨리어싱과 같은 영화 품질 및 앤티앨리어싱 기술에 대해 이야기했습니다.
Light pre-pass는 full deferred와 같습니다. 아이디어는 조명을 지오메트리에서 분리하는 것이지만, full deferred와는 달리 지오메트리는 두 번 그려집니다. 첫 번째 패스에서는 조명에 필요한 모든 데이터를 쓰고, 두 번째 패스에서는 광원을 읽고 다른 재료를 추가합니다.

라이트 프리패스의 장점은 조명에 사용되는 지오메트리 버퍼가 공간을 덜 차지하고 일반적으로 두 번째 지오메트리 패스에서 MSAA와 결합되는 두 번째 지오메트리 패스에 재질 변경 사항을 쉽게 추가할 수 있다는 것입니다. 두 번째 지오메트리 패스는 사용할 조명 샘플을 결정하며, 일반적인 방법은 현재 지오메트리를 이전 지오메트리와 비교하고 지오메트리 버퍼를 그린 다음 가장 가까운 일치 항목을 선택하는 것입니다. 이는 일치하는 항목이 있을 때 매우 잘 작동하지만 선택할 수 있는 좋은 샘플이 없으면 문제가 됩니다. 머리카락 및 잎사귀 셰이더에서는 알파 테스트 출력에 체커보드 패턴을 사용할 수 있지만 알파 테스트 출력의 체커보드 패턴은 제어하기 어렵고 절반 해상도 조명에서 실행되거나 샘플이 손실되기 시작합니다. 여러 계층의 알파 테스트로 인해 문제가 더욱 어려워집니다.
관련 샘플을 저장하는 것은 해결해야 할 핵심 문제입니다. 4xMSAA 지오메트리 버퍼를 사용할 수 있기를 바라지만 직접 조명은 너무 비쌉니다. 기사에 제공된 MSAA 솔루션은 기하 도형 클러스터링을 사용하고, 기하 버퍼를 4xMSAA 대상으로 렌더링하고, 샘플을 4xMSAA에서 비 MSAA로 줄이고(샘플 4개에서 샘플 1개로), 감소된 샘플에서 값비싼 셰이딩을 실행한 다음, 4x MSAA로 다시 빌드하고, 기하 구조 샘플을 늘리고(상대적으로 적은 비용), 조명 샘플을 적게(계산량이 많음) 하는 것입니다. 구체적인 과정은 다음과 같습니다.
- 하위 픽셀 오프셋을 구성합니다.
16개 샘플의 해시 값을 계산합니다. 16비트 일반 값, 8비트 심도 및 8비트 재질 ID를 포함한 32비트 값입니다.

- 초기 4개의 샘플을 선택합니다. 모서리에서 4개의 샘플을 선택하여 시작하고 모서리를 선택하여 고유한 샘플 수를 최대화합니다.

- 샘플을 재배포합니다. 선택한 각 샘플에 대해 중복이 있는지 테스트하고, 있는 경우 중복을 선택되지 않은 값으로 대체하여 불필요한 재결합을 피하고 화면과 일치하는지 확인하는 것이 좋습니다.

- 하위 픽셀 오프셋을 저장합니다. 2x2 픽셀 영역당 32비트와 MSAA 샘플당 2비트를 사용하여 최종 2x2 출력에 샘플 위치를 제공하는 픽셀 셰이더는 크기가 절반인 360p 이미지를 출력합니다.

- 다운샘플링.
하위 픽셀 오프셋을 읽습니다. 각 2x2 타일은 단일 32비트 하위 픽셀 오프셋을 공유하여 일반 픽셀 셰이더에서 전체 화면 패스를 실행합니다. 출력은 AO, SSR, GI 및 조명에 사용되는 최종 지오메트리 버퍼입니다.
- 먼저 쓰거나 평균을 쓰세요. 첫 번째 일치 항목을 출력하면 평균이 약간 더 나은 결과를 제공합니다.

기하학적 클러스터링과 비MSAA의 효과 비교:

두 번째 지오메트리 채널을 처리할 때 서브픽셀 오프셋은 각 MSAA 샘플에 사용할 조명 샘플을 제공하여 2비트 오프셋을 기반으로 조명 샘플을 읽습니다. 기하학 버퍼와 비교하기 위해 현재 샘플의 기하학적 특성을 계산할 필요가 없습니다. 픽셀 셰이더에서 샘플 커버리지(HLSL의 SV_Coverage)를 사용하고, 커버된 샘플의 평균을 사용하면 품질을 향상시킬 수 있지만 비용은 훨씬 더 높습니다. 이 기사에서는 firstbitlow와 샘플을 한 번 사용합니다.

기하학적 클러스터링, 비MSAA 및 TAA의 효과 비교:

이 기사에서는 일시적인 앤티앨리어싱과 업샘플링도 다룹니다. 회전된 그리드 오프셋을 사용하여 하위 픽셀 카메라 오프셋이 있는 4개 프레임. 각 프레임은 이전 세 프레임을 현재 투영으로 변환하여 프레임 간의 델타를 최소화하고 단일 계산 셰이더 패스에서 고정된 데이터를 공유합니다. TAA 클램핑의 경우 현재 프레임에서 인접 픽셀의 최소/최대 값을 계산하고, 하위 픽셀 오프셋 카메라로 인한 깜박임을 억제하기 위해 작은 속도 범위를 확장합니다. xyY를 고정하고 밝기만 확장하여 앨리어싱과 고스팅을 균등화합니다. 4개 프레임의 결과를 결합하는 TAA의 업샘플링을 위해 이전 프레임이 재투영되고 고정되었습니다. 프레임 간 샘플링이 인터리브되기 때문에 업샘플링에 좋은 위치입니다. 선형 샘플링의 효과는 놀라울 정도로 좋습니다.

또한 TAA는 연속된 4프레임의 평균이기 때문에 주기적 노이즈가 광범위하게 사용됩니다. 과도한 소음은 주변 클램핑에 문제를 일으킬 수 있습니다. 노이즈를 줄이기 위해 누적 버퍼를 사용하는 것은 시퀀스 노이즈에서 잘 작동합니다.
전체적으로 4x MSAA가 포함된 지오메트리 버퍼는 720p 이미지에 대해 잘 분산된 370만 개의 지오메트리 샘플을 제공합니다. 더 적은 수의 샘플을 사용하여 조명을 계산할 때 관련 데이터를 보존하려면 고품질 다운샘플링이 필요하며, 다운샘플링으로 생성된 하위 픽셀 오프셋은 다른 효과에 사용될 수 있습니다. MSAA는 여전히 지오메트리 앨리어싱과 관련되어 있으며 더 많고 더 나은 분산 샘플을 갖는 것이 많은 의미가 있습니다. N개의 과거 프레임을 저장하고 재투영하는 것은 TAA 및 고급을 위한 좋은 프레임워크를 제공합니다. TAA에 너무 많은 변경 사항을 입력하면 시스템이 파괴되므로 각 프레임이 충분히 안정적이어야 합니다. TAA는 앨리어싱을 고스팅으로 변환하며 클램핑 경계가 더 촘촘해지면 깜박임이 발생할 수 있습니다.
D3D12 및 Vulkan: Lessons Learned는 DX12 및 Vulkan 출시 1년 후 연설을 통해 차세대 그래픽 API를 기반으로 한 엔진 아키텍처의 발전과 그 영향을 설명했습니다. D3D11 드라이버는 매우 잘 최적화되어 있습니다. D3D11 드라이버를 넘어서기 위해 필요한 지식을 사용하십시오. D3D12는 그 위에 레거시 API 드라이버를 작성하기 위해 발명되지 않았습니다. 게임 엔진을 로켓에 비유한다면 DirectX 12와 Vulkan은 부스터로 간주될 수 있습니다.

DX12 및 Vulkan의 그래픽 API 이전의 게임 엔진은 가속기가 없는 단계 0~0.5로 간주될 수 있습니다.

DX12와 Vulkan을 통합한 후에는 특정 가속기가 있으며 1.0 단계로 업그레이드됩니다.

하지만 현재로서는 렌더러와 그래픽 API 사이에 너무 많은 결합이 있어 높은 수준이나 낮은 수준이 충분하지 않습니다. 가속이 제한된 2.0으로만 간주될 수 있습니다.

그래픽 API를 아래로 이동하고 낮은 수준의 그래픽 추상화 레이어를 추출한 후 3.0으로 업그레이드하고 더 큰 부스터를 얻을 수 있습니다.

당시 게임 엔진은 Vulkana 및 D3D12를 지원하도록 전환 중이었고 여전히 D3D11 지원이 필요했으며 대부분의 엔진은 1단계와 2단계 사이에 있었습니다. 모든 API를 최대한 활용하려면 많은 생각이 필요하고 다중 대기열 지원에는 추가 작업이 필요하며 D3D11과 호환되어야 합니다. D3D12/Vulkana를 대상으로 하고 D3D11에서 실행하는 것이 좋습니다.
미래를 위한 설계를 통해 이 기사에서는 일반적인 설계 문제를 지적하고, 엔진을 준비하고, 지식을 더 나은 성능으로 전환할 것입니다.
장벽 제어: 장벽은 D3D12/Vulkan의 새로운 개념이며, 슬픈 사실은 모두가 이를 잘못 이해하고 있다는 것입니다. 두 가지 실패 사례: 너무 많거나 너무 넓어서 성능이 저하되고 장벽이 없어 손상될 수 있습니다. D3D11 드라이버는 내부적으로 이러한 장벽 역할을 수행하며 이를 잘 수행합니다. 장벽이란 정확히 무엇입니까?
대상 렌더를 텍스처로 변환합니다. 압축 해제(및 캐시 플러시)가 필요할 수 있습니다. 공급업체와 GPU 차세대 간에 어떤 변화가 있을까요? 무작동일 수도 있고, 유휴 상태일 수도 있고, 전체 캐시 플러시일 수도 있습니다.
UAV를 리소스로 변환합니다. 제대로 수행되지 않으면 플러시를 생성하거나 유휴 상태를 기다려야 합니다. 올바르게 수행되면 이러한 전환이 무료일 수 있습니다.
누락된 장벽: 형식 문제 - GPU/드라이버 관련 손상, 동기화 문제 - 시간에 따른 손상.
하위 샘플링 및 섀도우 아틀라스와 같은 하위 리소스는 별도로 추적해야 합니다. 모든 하위 리소스를 변환하는 경우 하나씩 변환하는 대신 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES를 사용해야 합니다. 배치된 리소스 및 초기 상태의 경우 배치된 리소스 등으로 생성된 렌더 대상은 사용하기 전에 지워야 하며 지워진 상태로 직접 이동해야 하며 일부 임의의 상태 및 전환으로 시작하지 마십시오. 다음 다이어그램에는 "기본 상태" 또는 중복 전환이 있습니다. 즉, 대상 상태로 전환한 다음 다시 기본 상태로 전환합니다(실제로 사용되지 않고 다시 변환됨).

흥미로운 장벽:
ResourceBarrier(0, nullptr), 즉 아무것도 변경되지 않았으며 상태 추적이 잘못된 일을 하고 있음을 나타냅니다.
이전 상태는 다음 상태와 같습니다. 당신이 생각하는 것보다 더 많은 일이 일어나고 있습니다. 그냥 거절하세요.
-항상 기억하십시오 - 운전자는 운전자 자체의 경험적 방법이 아니라 귀하가 최선을 다하고 있다고 가정합니다!
모든 리소스 상태를 추적하는 대신 리소스의 99%는 변경할 수 없습니다. 읽기 전용, 전환 지점 찾기(채널 종료 시간, 여기에는 일괄 장벽, 필요한 장벽만 전환)가 있습니다.

장벽 디버깅 팁:
쓰기/읽기 비트가 있습니다.
모든 전환을 기록하세요. Grep과 스프레드시트는 친구입니다. 전환 수와 유형 등을 확인하세요.
전환 수는 쓰기 가능한 리소스 수에 따라 정렬되어야 합니다. 다시 말하지만, grep과 log는 여러분의 친구입니다. 장벽의 개수가 9000개를 넘으면 뭔가 수상해요!
앞에서 설명한 "최악의 경우" 모드와 동일한 모든 배리어 모드가 있지만 디버깅 목적으로만 사용됩니다.
리소스가 프레임당 적어도 한 번은 알려진 상태인지 확인하세요. 프레임의 끝/시작에서 모든 것을 알려진 상태로 전환하여 TAA 또는 섀도우 아틀라스 손상과 같은 문제를 해결합니다.
더 나은 방법은 D3D12의 "분할 장벽"인 Vulkan의 vkCmdSetEvent+vkCmdWaitEvents를 사용하여 드라이버에 전환을 처리할 시간을 주는 것입니다.

장벽 요약: 필요한 모든 리소스(그 이상은 아님)가 입력할 수 있는 가장 구체적인 상태로 변환되고 다양한 상태가 결합될 수 있는지 확인합니다.
제어 실행, GPU에 공급하는 방법(예: 작업 보내기), 먼저 명령 목록 제출, 프레임당 리소스 업데이트 및 시간 추적. 코어를 수동으로 할당하여 병렬성을 제한하지 마세요.
, 모든 코어를 자동으로 사용하는 작업/작업 시스템을 사용하려면 효율적인 작업 제출 및 리소스 동기화에 특별한 주의가 필요합니다.

위 사진에서는 무슨 일이 일어났나요? 미친 스레드 풀, CPU 작업은 마지막에 작업을 제출하고 작업 경계는 CPU/GPU 동기화 지점이 되며 작업이 완료된 후 명령 목록이 제어됩니다.

위: 각 펜스는 기본적으로 GPU에서 IDL을 기다리고 있습니다. 더 나은 접근 방식: 어쨌든 명령 목록의 "중간 프레임"에서 작업을 시작할 가능성이 없으므로 프레임당 리소스를 보호합니다. 울타리를 사용하여 여러 리소스를 보호합니다. 운영 체제가 이를 수행할 수 있는지 확인하고, 가능한 한 많이 일괄 커밋하고, 일찍 커밋하여 GPU가 항상 사용되도록 하십시오. 이상적인 제출은 다음과 같습니다.

워크로드 및 일정을 적절하게 이해하고 멀티스레드 설계를 사용합니다.

렌더링 패스: 프레임에 대한 높은 수준의 그래프를 생성하여 Vulkan의 렌더링 패스 및 하위 렌더링 패스를 통해 렌더러에 알리고 운전자가 최상의 일정을 선택할 수 있도록 합니다. "상관없어"라는 표현을 멋지게 표현할 수 있습니다.
디버깅 팁: 하나의 커밋으로 모든 명령 목록을 제출하도록 선택할 수 있습니다. 이는 가능하지 않은 경우 프레임 내 GPU/CPU 동기화가 필요한 타이밍 문제를 해결하는 데 도움이 됩니다. 명령 목록을 기다리는 옵션, 업로드/리소스 동기화에 도움이 되지만 일부 리소스가 손상되었습니까? 업데이트하기 전에 GPU를 새로 고치십시오.
제출 요약: 프레임 단위로 리소스를 추적하고, 프레임 구조를 이해하고, 스레딩을 수행하는 것은 우수한 CPU 활용률을 얻는 데 매우 중요합니다.
실용적인 DirectX 12 - 프로그래밍 모델 및 하드웨어 기능은 주로 DX12의 모범 사례, 하드웨어 기능 및 기타 콘텐츠를 설명합니다.
DX12는 엔지니어링 시간을 투자할 수 있는 기능과 함께 최대 GPU 및 CPU 성능을 제공하도록 설계되었습니다! 엔진 참고 사항, IHV 특정 경로가 필요합니다. 이것이 가능하지 않은 경우 DX11을 사용하십시오. 애플리케이션은 드라이버 및 런타임의 일부를 대체하며 동일한 코드가 시스템에서 제대로 실행될 것으로 기대할 수 없습니다. 이는 모든 콘솔, PC에서 동일합니다. 아키텍처별 경로를 고려하고 Nvidia 및 AMD 세부 사항에 주의하십시오.
작업 제출 방법에는 멀티스레딩, 명령 목록, 명령 번들, 명령 대기열 등이 포함됩니다.
DX11 드라이버의 멀티 스레드 처리: 렌더링 스레드(생산자), 드라이버 스레드(소비자), DX12 드라이버의 경우 작업자 스레드가 시작되지 않으며 명령 버퍼가 CommandList 인터페이스를 통해 직접 구축됩니다. 엔진이 모든 코어에서 확장되도록 하려면 명령 목록을 제출하는 하나의 렌더 스레드와 명령 목록을 병렬로 작성하는 여러 작업자 스레드가 있는 작업 그래프 아키텍처가 가장 잘 작동합니다.
명령 목록은 다른 명령 목록을 제출하면 작성될 수 있습니다. 제출하거나 렌더링할 때 유휴 상태를 유지하지 마십시오. 명령 목록은 재사용이 허용되지만 동시 사용 중지는 애플리케이션이 담당합니다. 작업을 너무 많은 명령 목록으로 나누지 마십시오. 15-30개의 명령 목록, 프레임당 5-10개의 ExecuteCommandLists 호출을 목표로 하십시오. 각 ExecuteCommandLists에는 고정된 CPU 오버헤드가 있으며 ExecuteCommandLists에 대한 각 호출은 새로 고침을 트리거하므로 명령 목록을 일괄 처리하고 각 ExecuteCommandList에 최소 200μs(바람직하게는 500μs)의 GPU 작업을 넣으려고 합니다. OS 예약 지연을 숨길 만큼 충분한 작업을 제출하고, ExecuteCommandLists에 대한 소규모 호출은 OS 스케줄러가 새 호출을 제출할 수 있는 것보다 빠르게 완료됩니다. 예를 들어 다음 그림은 다음과 같습니다.

강조 표시된 ECL 실행 시간은 약 20μs이며 운영 체제가 향후 작업을 예약하는 데 약 60μs가 필요합니다. 이는 40μs의 유휴 시간과 같습니다.
명령 번들은 프레임 초기에 작업을 커밋하는 좋은 방법입니다. GPU의 번들은 본질적으로 더 빠르지 않으므로 현명하게 사용하십시오! 호출 명령 목록에서 상태 상속 - 이를 활용하지만 상속된 상태를 조정하는 데 CPU 또는 GPU 비용이 발생할 수 있습니다. 좋은 CPU 부스트를 얻을 수 있는 것은 NVIDIA입니다. 번들로 동일한 5+그리기/디스패치를 반복하고, AMD: CPU에 어려움이 있을 때만 번들을 사용하십시오.
하드웨어 상태에는 PSO(파이프라인 상태 개체) 및 RST(루트 서명 테이블)가 포함됩니다. PSO는 사용되지 않는 필드에 대해 합리적이고 일관된 기본값을 사용하고, 드라이버가 PSO 컴파일을 수행하는 것을 허용하지 않으며, 작업자 스레드를 사용하여 PSO를 생성하며, 컴파일에는 수백 밀리초가 걸릴 수 있습니다. 서로 다른 블렌드 상태를 갖는 동일한 VS/PS와 같이 동일한 스레드에서 유사한 PSO를 컴파일하면 상태가 셰이더에 영향을 주지 않으면 셰이더 컴파일이 재사용되며, 동일한 셰이더를 동시에 컴파일하는 작업자 스레드는 첫 번째 컴파일의 결과를 기다립니다. RST는 가능한 한 작게 유지하고 주파수별로 정렬해야 합니다.
메모리 관리 측면에서는 명령 할당자, 리소스, 상주 및 기타 작업을 신중하고 합리적으로 사용해야 합니다. 또한 울타리와 장벽 내에서 동기화 작업을 신중하게 처리해야 합니다.
GDC2017: D3D12 및 Vulkan: 배운 내용은 GDC2017에서 공유된 DX12 및 Vulkan 학습 과정입니다. 이 기사에서는 엔진 작업 그래프 변환의 예를 언급합니다.

장벽 측면에서는 수동 작업이 더 이상 효과적이지 않으며 처음부터 Vulkan의 기본 지원을 통해 더 높은 수준의 추상화 다이어그램이 필요합니다. 셰이더 측면에서는 셰이더 순열이 점점 더 적어지고 Doom에는 단지 수백 개가 있으며 더 많은 게임에서 셰이더 변형을 더 일찍 잘라내기 위해 창의적인 파이프라인을 변경하고 있으며 (컴파일러 관련) 고급 작업이 진행되고 있습니다.

엔진은 더 높은 수준의 렌더링을 향해 발전하고, API 개선으로 사용이 더 쉬워졌으며, 게임 혜택도 향상되었습니다! 개방형 게임/확장성, 확장성은 아직 해결되지 않았습니다. 게임은 모든 설정에 대해 기존 및 새 API를 지원하며, 모바일 플랫폼은 점점 더 중요해지고 있으며 새로운 API가 앞으로 나아가는 길인 것 같습니다. 그래픽 API에 대한 새로운 접근 방식에는 ISV, IHV 및 표준 기관 간의 긴밀한 협력이 필요합니다. API는 게임 엔진과 함께 발전해 왔으며 출시 이후 개발자의 작업을 더 쉽게 만들기 위해 수많은 변경이 있었습니다!
DirectX 12 사례 연구는 NVidia에서 발표하며 DirectX12 관련 기술과 응용 사례를 설명합니다. DX12와 관련된 기술에는 비동기 대기열, 메모리 관리, 파이프라인 상태 개체, 셰이더 모델 5.1 리소스 바인딩, 멀티스레딩 등이 포함됩니다.
비동기식 대기열의 경우 컴퓨팅 대기열은 공급업체 전체에서 평균 5%의 향상으로 가속화됩니다. 비동기 워크로드는 기본적으로 해상도에 독립적이며(1080p에 맞게 조정됨) 해상도가 증가함에 따라 수익이 감소합니다.

엔진은 3개의 복제 대기열을 사용합니다. 다중 복제 대기열은 엔진 스레드 동기화를 단순화합니다.

SM 5.1 및 /all_resources_bound 셰이더 컴파일러 플래그는 셰이더 코드를 변경하지 않고도 성능을 약 1.0~1.5% 향상시켜 텍스처 액세스를 위한 덜 보수적인 코드 생성을 가능하게 합니다.

Ubisoft의 Anvil Next 엔진: DX12를 최대한 활용하고, 리소스 장벽을 최소화 및 일괄 처리하고, 병렬 CMD 목록 기록을 활용하고, 사전 컴파일된 렌더 상태를 사용하여 런타임 작업을 최소화하고, 메모리 공간을 최소화하고, 여러 GPU 대기열을 활용하도록 재설계되었습니다.

Anvil Next 엔진 그룹 배리어 전설.
Hitman 렌더러는 수평 로드 중에 생성된 반사 및 환경 프로브를 제외하고 완전히 동적인 장면을 처리합니다. 블록 디퍼드 라이팅, 전방 라이트용 별도 채널, 컬링 라이팅을 사용하는 도어/챔버(입구/유닛) 시스템. 섀도우는 4개의 VSM으로 계단식으로 배열되며, 4번째는 정적이고 4~8개의 추가 섀도우 맵이 있습니다.
CPU 성능을 위해 코드를 엔진 코드처럼 분석하고 수정할 수 있으며, 중복된 설명자를 너무 많이 설정하고 실제로 사용되는 설명자만 설정하도록 합니다. 차선책 일괄 처리: 결국 리소스 변환 및 명령 목록 제출을 일괄 처리하고 궁극적으로 멀티스레딩을 통해 가장 빠른 드라이버와 일치시킵니다.
당시 DX12 메모리 관리에도 문제가 있었는데, DX12 비디오 메모리 소모량이 DX11에 비해 너무 높았고 DX11 드라이버는 비디오 메모리 간 메모리 이동에 매우 능숙했습니다. 마지막으로 매우 간단한 LRU 모델을 사용하여 리소스를 페이징(제거)하는 시스템이 구현되었습니다. MakeResident에서 지연이 있었고 DX12, 특히 메모리가 부족한 GPU 카드에서 성능이 더 나빴기 때문에 많은 작업이 예상치 못한 일이었고 여전히 이상적이지 않았습니다. 렌더 타겟 메모리 재사용 시스템(배치된 리소스) 구현, 정적 리소스 하위 할당 도입, 모든 콘텐츠에 대해 제출된 리소스 생성은 많은 메모리를 차지하며, PC의 메모리 절약은 콘솔만큼 높지 않으며, 리소스 계층은 모든 메모리가 다양한 리소스에 사용되는 것을 방지합니다.

DX12 리소스 할당 및 펜싱: 설명자, 업로드 힙 등과 같은 프레임에서 많은 수의 동적 리소스 할당을 사용하여 프레임 리소스의 잠금 없는 할당을 달성하려면 초고속 할당자가 필요합니다. 펜스는 비용도 많이 들기 때문에 리소스를 세분화하여 재사용하는 데 사용하고 결국에는 신호 펜스를 사용하여 모든 리소스 재사용을 동기화합니다.
DX12 상태 관리: 픽셀 셰이더 개체를 사용하여 PSO 및 기타 상태를 저장합니다. 대다수의 픽셀 셰이더에는 해시를 통해 액세스할 수 있는 순열이 몇 개만 있습니다. 샘플러 상태 객체는 상태 관리에서 제거되었으며 16개의 고정 샘플러 상태를 사용하기로 결정되었습니다.

각 상태에 대해 고유한 상태 해시를 생성하고, 모든 상태 블록을 고유 ID가 있는 풀에 넣습니다. 상태 블록에는 래스터라이저 상태, 셰이더 등이 포함되며, 블록 ID를 비트로 사용하여 상태 해시를 구성합니다.

DX12 리소스 변환: 읽기/SRV를 기본 상태로 가정하고 RTV, UAV, DSV 및 그 반대로의 변환만 지원하고 UAV 장벽에만 추가 변환이 필요한 단순화된 리소스 변환 시스템을 구현했습니다. 기본 렌더링 스레드는 모든 변환을 제출합니다. 메인 렌더링 스레드는 명령 목록을 기록하고 모든 다중 스레드 동기화를 수행하여 코드를 크게 단순화할 수도 있습니다.

AAA 게임을 위한 DX12 메모리 관리: 명시적 메모리 관리는 우수하고 일관된 성능을 달성하는 열쇠입니다. LRU 리소스 관리 전략은 먼 길을 가고 있습니다. 리소스가 마지막으로 사용된 후 일정 기간 동안 메모리에 보관되었다가 제거될 때만 재활용 힙으로 이동됩니다. 리소스 바인딩 계층 지원 2. 테이블의 CB 설명자는 사용하지 않을 때 바인딩을 해제해야 합니다(0으로 설정). Nvidia 드라이버는 이제 해제되지 않은 설명자를 지원하고 CBV를 루트 서명으로 이동하여 바인딩 해제를 건너뜁니다. 루트 CBV로 사용되는 경우 CBV는 단지 GPU 주소이므로 CreateConstantBufferView()를 호출할 필요가 없습니다. 모든 RST 항목에 가장 적합한 셰이더 가시성 플래그를 사용하고 가능하면 회피를 피하십시오. SHADER_VISIBILITY_ALL 플래그는 CPU 메모리에 RST 상태를 캐시하여 중복 바인딩을 건너뛰어 CPU 성능을 향상시킵니다. 전체 프레임에 대해 두 레이아웃을 모두 사용하면 RST 변경이 최소화되어야 하는 것으로 나타났습니다. 원래 DX12 경로에는 중복성이 있습니다. 중복 장벽, 장벽은 추상화 계층에 숨겨져 있으며(자동으로 트리거됨) 대부분의 경우 효과적입니다. 특수한 경우 엔진은 명시적 장벽 관리로 전환하고, 지연 장벽은 추가 중복 및 일괄 장벽을 건너뛰고, 보류 목록에 장벽을 추가하고, 마지막 순간까지 기다려 목록을 새로 고치고, 중복성을 필터링하는 데 사용됩니다.
GPU 디버깅: API(CPU)의 오류 코드를 기반으로 충돌이 감지되었습니다. 명령의 마지막 N 프레임에서 충돌이 발생했습니다. CPU 호출 스택이 문제일 가능성이 높습니다.


NVIDIA AFTERMATH는 사용자 정의 마커를 인라인하는 명령 스트림을 사용하여 GPU 충돌 위치의 정확성을 향상시킬 수 있습니다. GPU는 각 마커에 도달하면 신호를 보내고 마지막으로 도달한 표시는 GPU 충돌 위치를 나타냅니다.

NVIDIA AFTERMATH GPU 충돌(헤더 + DLL) 진단을 돕는 새로운 도구, 매우 유연하고 간단한 API, 현재 DX11 및 DX12 UWP 및/또는 Windows와 호환됩니다. 제한 사항은 D3D 디버그 레이어와 호환되지 않는 NVIDIA GeForce 드라이버 버전 378.xx 이상이 필요하다는 것입니다.
고급 그래픽 기술: DirectX 12로 이동: 교훈은 또한 생산자-소비자 시스템, 디스패치 그래프 시스템, 장벽 변환 및 최적화, 리소스 관리, 리소스 종속성, 메모리 중복, 리소스 동기화, 셰이더, PSO 등과 같이 Ubisoft의 Anvil Next 엔진을 DirectX12로 포팅하는 구체적인 프로세스, 최적화, 기술, 전략, 교훈 등에 대해 자세히 설명합니다.
즉, 고급 렌더링 프로세스 지식을 사용하여 API 사용을 최적화함으로써 고급 생성 시스템은 렌더링 엔지니어의 디버깅 시간을 많이 절약합니다. 더 작은 단위의 Blob 기반 렌더링 인터페이스는 CPU 성능 향상을 극대화하고 작업 중복을 방지합니다. 아키텍처 작업은 다른 플랫폼/API에 도움이 됩니다. DX12를 사용하면 약 5%의 GPU 향상과 15%~30%의 CPU 향상을 얻을 수 있습니다.

DX11과 성능 동등성을 달성하는 것은 어려운 작업입니다. 성능을 최종 목표로 생각하지 말고, 노력을 비동기 컴퓨팅, mGPU, SM6 등과 같은 기능 잠금 해제, 콘솔과의 기능 동등성에 그 어느 때보다 가까워지고, 엔진 아키텍처를 개선할 수 있는 기회를 얻고, 다른 동등한 API로 포팅하는 것이 훨씬 쉬워지는 경로로 생각하십시오.
DX12 및 Vulkan에 대한 자세한 내용은 언리얼 렌더링 시스템 분석(13) - RHI 보충 자료: 최신 그래픽 API의 미스터리 및 지침을 참조하세요.
Northlight 엔진 개발: 교훈은 Northlight 엔진 개발의 DX12 포팅 과정과 교훈을 설명합니다. Northlight 엔진 렌더링 파이프라인:
G-버퍼, 속도, 섀도우 채널(멀티스레드).
전체 화면 그림자.
전체 화면 조명.
기본 투명 채널(멀티스레드).
포스트 프로세스.
DX12 기능 목록에는 설명자 테이블, 동적 리소스, 파이프라인 상태 개체, 명령 목록/할당자, 리소스 변환, 임시 리소스, 작은 리소스, 밉맵 생성, 빈 리소스, 버퍼 계산/추가, 쿼리 등이 포함됩니다. 이에 대한 설명은 아래에 있습니다.
설명자 테이블: 모든 셰이더 단계에서 사용할 수 있는 모든 리소스에 대한 설명자를 포함하는 테이블입니다. 각 그리기 호출에는 테이블이 필요하며 GPU에서 그리기가 완료되면 재사용할 수 있습니다.
동적 리소스: DX12에는 그런 것이 없습니다. 업로드 힙 링 버퍼를 사용하여 버전 제어/이름 바꾸기/회전, 한 번 쓰기(CPU), 한 번 읽기(GPU)를 직접 관리해야 합니다.
PSO: 생성은 문제의 부분입니다. 이상적으로는 송신 파이프라인에서 출력되고, 게임 시작 시 로드되며, 처음 터치할 때 생성됩니다. CS PSO는 CS가 로드된 상태에서 생성될 수 있으며, ~500개의 개별 그래픽 PSO를 생성하는 데 ~200ms가 걸립니다. 루트 서명(리소스 레이아웃), 셰이더 코드, 버텍스 셰이더 입력 레이아웃(버텍스/인덱스 버퍼 아님), 기본 유형, 블렌딩, 래스터 상태, MSAA 모드, 렌더링 대상 및 깊이 템플릿 형식 등을 포함합니다.
명령 목록/할당자: DX11의 즉시/지연 컨텍스트, 할당자는 메모리를 소유합니다.
리소스 변환: 드라이버는 더 이상 사용량을 추적하지 않으며 사용하기 전에 셰이더 리소스, 렌더링/깊이 대상, 소스/대상 복사, UAV, 렌더링 등 올바른 상태로 수동으로 변환해야 합니다.
리소스 스테이징/하위 리소스 업데이트: 동적 리소스 없음, 스테이징 리소스를 더 자주 사용, 링 버퍼 또는 영구 버퍼의 요청 시, 하위 리소스 업데이트 없음, d3dx12.h의 시뮬레이션 버전에 의존할 수 없음, 전환 텍스처 없음, 전환 버퍼를 통한 시뮬레이션.
작은 리소스: CreateCommittedResource는 64kB 페이지에 할당하고 작은 리소스에 대해 실행되지 않습니다. 이상적으로는 조각 모음된 힙의 모든 리소스를 하위 할당하거나 작은 리소스에 대한 특별한 경우입니다.
GenerateMips: DX12에는 그런 것이 없고, 이를 위한 컴퓨팅 셰이더를 작성했으며 수동 구현이 DX11보다 성능이 더 뛰어나지만 다양한 경우(2D/3D/배열/색 공간)를 처리해야 한다는 사실을 발견했습니다.
Null 리소스: nullptr은 더 이상 바인딩될 수 없습니다. 1D/2D/3D 텍스처, 버퍼, UAV 텍스처/버퍼, CBV, 샘플러에 대한 null 리소스가 필요합니다. 유형을 이해하려면 추상화에서 더 높은 수준으로 null 바인딩을 승격해야 할 수도 있습니다.
카운트/추가 버퍼: DX12에는 그런 것이 없으며 원자적으로 증가할 수 있는 별도의 카운트 버퍼가 있습니다.
쿼리: 쿼리 힙 관리/폴링, 구문 분석 병합(예: 여러 호출을 피하기 위해 일괄 처리), 전체 힙에서 다시 읽기 등 쉽게 잊혀지는 또 다른 주목해야 할 측면입니다.
DX11에서 DX12로 마이그레이션하면 이제 드라이버(진정한 베테랑)가 되어 메모리 사용량과 성능에 주의를 기울이고 병목 현상에 대한 최적화에 집중하며 별도의 CPU 및 GPU 타임라인을 고려합니다. 이식 과정에서 Northlight는 다음과 같이 다양한 개체에 대해 작동합니다.
자원 장벽. RT 바인딩, 디스크립터 테이블에 리소스 설정, 복사 시 메인 스레드에서 자동으로 리소스 변환을 수행합니다. 다른 비동기 렌더링 스레드는 변환을 허용하지 않습니다. 명령 목록을 실행하기 전에 리소스(주로 RT)가 올바른 상태인지 수동으로 확인하십시오. 불필요하게 남용하면 GPU 성능이 저하될 수 있지만 하드웨어에 따라 필요할 때만 UAV 장벽을 사용하고 일정 사이에 GPU를 유휴 상태로 만듭니다(DX11 스타일).
그리다. 그리기를 반복하고, DX11 스타일 세트에 대한 호출을 포착하고, 이전 값을 추적하고, PSO가 변경된 경우 더티로 표시하고, 더러우면 그리기 시 해시하고, 매핑 테이블에서 PSO를 가져옵니다. 변경 시에만 인덱스/꼭지점 버퍼, RT/DS 및 설명자 힙을 설정하면 컬렉션이 CPU에서 저렴하지만 하드웨어 컨텍스트 스크롤이 발생합니다. PSO는 읽기 전용이고 바인딩되어 있으며 각 그리기 호출마다 무료(GPU) 설명자 테이블로 회전되고 GPU에서 명령 목록을 실행한 후 재사용됩니다.
실. 한 스레드에서 제출된 모든 스레드의 명령 목록을 기록하는 짝수/지연 컨텍스트 간에는 차이가 없습니다.
Descriptor Table Manager(테이블 회전 처리), Descriptor Table Manager GPU Fence(테이블을 재사용할 수 있는 시기를 알려줌), Command List(GPU 실행이 완료된 후 재사용 가능), Command Distributor(여러 명령 목록에 사용 가능)를 풀에 저장합니다.

스레드를 초기화할 때 설명자 관리자, 설명자 관리자 펜스, 명령 할당자 및 명령 목록을 가져옵니다.
스레드를 종료할 때 CPU의 재사용 가능한 설명자 관리자와 명령 할당자를 해제합니다.
명령 목록을 실행한 후 GPU 재사용 가능 설명자 관리자 펜스와 명령 목록을 해제합니다.
요약하자면, GPU 성능: DX11과 일치하는 올바른 작업을 수행하는 것은 모든 아키텍처에서 중요하며, GPU 메모리 관리를 어지럽히는 것은 비용이 많이 들 수 있습니다. CPU 성능: DX11을 쉽게 능가하지만 실제로 API 오버헤드로 인해 제한됩니까? 인스턴싱, LOD 및 우수한 컬링 덕분에 드라이버가 드로우 콜에 압도당하는 것을 방지할 수 있습니다.
'레인보우식스' 렌더링 | Siege'는 현재 세대의 렌더링 엔진을 기반으로 한 게임 "Rainbow Six | Siege"의 첫 번째 반복입니다. 이 문서에서는 현재 세대의 하드웨어에서만 가능한 계산의 아키텍처 최적화와 품질 저하 없이 렌더링 속도를 50%까지 높일 수 있는 새로운 체스판 렌더링 기술에 중점을 둘 것입니다.
Siege GPU 프레임의 계층적 보기: 지오메트리 렌더링에는 평균 5ms가 걸렸고, 컬링, 캐시된 그림자의 과도한 사용, 조명(SSR 포함)에 평균 5ms, 체커보드 렌더링 지원, SSAO 및 SSR 레이 트레이싱이 비동기식으로 수행되었으며, 포스트 프로세스/기타 전체 화면 처리에 평균 4ms가 걸렸습니다.

CPU 중요 경로의 계층적 보기: 중요 경로 평균은 10ms, 모든 패스와 작업은 중요 경로를 최소화하기 위해 분기 및 결합이 가능하며, 캐시된 그림자, 불투명 패스의 최대 선형 길이는 4ms, 재질 기반 그리기 호출 시스템입니다!

불투명 객체에 대한 렌더링 파이프라인은 다음과 같습니다.

그림자 렌더링: 모든 그림자는 캐시 기반이며 컬링을 위해 캐시된 Hi Z를 사용합니다. 태양 그림자는 VGPR 압력을 완화하기 위해 분리된 채널과 픽셀당 작업을 줄이는 데 사용되는 캐시된 그림자 맵의 Hi Z 표현을 사용하여 전체 해상도에서 수행됩니다. 로컬 광원은 1/4 해상도로 구문 분석되고 구문 분석된 결과는 텍스처 배열에 저장됩니다. 광 축적 중에는 VGPR 사용량이 낮으며 양측 업샘플링이 사용됩니다. 해와 달의 그림자의 경우 로드 시 생성된 모든 정적 개체의 그림자 맵이 포함됩니다.

동적 객체 컬링에 항상 사용되는 정적 Hi-Z 섀도우 맵과 계단식 맵과 정적 맵을 혼합하여 섀도우 비용을 확장하는 기능입니다. Xbox One: 첫 번째 계단식은 완전히 동적이며(6K 해상도는 충분하지 않음), 두 번째와 세 번째 계단식은 동적 개체만 렌더링하고 정적 그림자 맵과 혼합되며, 네 번째 수준은 정적 그림자 맵으로 대체됩니다.

로컬 광원 투영의 경우 최대 8개의 가시 그림자 로컬 광원을 처리할 수 있습니다. 프로세스는 다음과 같습니다.

조명의 경우 프러스텀에 클러스터형 구조가 사용됩니다. 32x32 픽셀 타일, Z-인덱스 분포, 구조를 채우기 위한 조명 볼륨의 레이어 컬링, 광원으로 처리되는 로컬 큐브맵, 텍스처 배열의 그림자, 큐브맵 및 차단기(고보), 사전 구문 분석된 그림자 텍스처 배열을 사용하여 지연, 그림자 깊이 버퍼 배열을 사용하여 전달됩니다.

통합 버퍼: Rainbow Six의 많은 리소스는 통합 버텍스 버퍼, 통합 인덱스 버퍼, 통합 상수 버퍼 등과 같은 일종의 통합 버퍼에 위치합니다. 구조화된 버퍼는 자동으로 생성된 코드가 있는 원시 버퍼 위에 구축됩니다. GPU 통합 데이터는 C++ 데이터 설명자를 사용하여 처리되고 액세스 패턴을 지정하는 메타데이터로 전달됩니다. 균일 상수 버퍼 샘플 코드:

통합 버퍼의 이점: 데이터 레이아웃에 대한 완전한 제어, 다양한 데이터 유형 액세스(AOS, SOA, u32 배열 구조 등)를 쉽게 시도할 수 있음, 사용자 정의 패키징 및 새로운 데이터 유형 지원, 고급 API가 브로드캐스트 값을 지원하고, 자동 코드 생성을 통해 새로운 액세스 패턴으로 쉽게 마이그레이션할 수 있습니다.
머티리얼 기반 드로우 콜: 지오메트리와 상수가 통합된 후 셰이더, 비균일 리소스(텍스처 등), 렌더링 상태(샘플러 상태, 래스터 상태), 위를 공유하는 요소가 함께 일괄 처리되고 리소스 하위 집합을 사용하지 않는 패스와 상태가 추가로 함께 일괄 처리됩니다.
그리기 호출 수집: 초기화되면 각 하위 그리드 인스턴스가 3개의 배치(일반, 그림자 및 가시성)에 매핑됩니다. 배치 유형은 불필요한 데이터를 보호하는 데 사용됩니다. 각 배치는 MultiDrawIndexedIndirect 명령에 해당합니다.

각 하위 그리드 인스턴스에는 전역적으로 고유한 인덱스가 있습니다. 이 인덱스는 모든 데이터를 가져오는 데 사용되며 여러 간접 참조가 필요합니다.

각 채널에 대한 동적 버퍼로 하위 그리드 인스턴스 인덱스를 수집합니다. 채널당 하나의 배치 유형에만 매핑되고 다중 스레드 작업에서 버퍼가 채워집니다(선형 1.5ms). 컬링을 수행하기 위한 추가 데이터가 추가되었습니다: MultiDrawIndexedIndirect 항목, 새 인덱스 버퍼 오프셋, 추가 컬링 플래그.

성능 컬링이 사용되며 여러 유형의 컬링이 정의됩니다. 레벨 1 - 하위 메시 인스턴스 컬링, 레벨 2: 서브메시 청크(청크) 컬링, 레벨 3: 서브메시 삼각형 컬링.




결과:
승인되지 않은 DC 수(총계) 결합된 배치의 DC 수(VIS + GBUFFER + DECALS) 배치의 DC 수(음영 처리됨) 절단 효율
10537 412 64 73%
다음으로 체스판 렌더링에 대해 이야기해 보겠습니다.
체커보드 렌더링의 기본 아이디어는 앨리어싱 문제를 해결합니다. 먼저 품질을 테스트하기 위해 일련의 이미지에 대해 실험을 수행했습니다. 대부분의 이미지의 경우 체커보드 모드를 사용할 때 PSNR이 더 좋았으며 시각적 효과도 더 만족스러웠습니다. 처음부터 MSAA 2X를 사용한다는 아이디어가 유행하기 시작했습니다.

상단 행은 선형 근방 보간, 하단 행은 체커판 근방 보간입니다.
체커보드 렌더링 구현:
MSAA 2X를 사용하여 1/4 크기(1/2 너비 x 1/2 높이) 해상도로 렌더링하면 전체 해상도 이미지 샘플의 절반이 생성됩니다.
D3D MSAA 2x 표준 모드: 2가지 색상 및 Z 샘플.
모든 샘플을 강제로 렌더링하기 위한 샘플 수정자 또는 SV_SampleIndex 입력입니다.
각 샘플은 전체 화면 렌더링 대상의 정확한 픽셀 중심에 위치합니다.

체커보드 렌더링의 추가 이점: 파티클 효과를 샘플 단위가 아닌 픽셀 단위로 쉽게 평가할 수 있으므로 ESRAM에서 더 많은 것을 얻을 수 있습니다! 셰이더에서 그라디언트를 수정할 필요가 없습니다.

각 프레임에서 투영 행렬을 다시 오프셋하여 패턴을 변경할 수 있지만, PC에서 샘플 위치를 변경하는 것이 항상 가능한 것은 아닙니다.

공백 채우기: 아래 그림에서 알 수 없는 픽셀 P와 Q의 색상을 재구성하려면 현재 프레임의 바로 이웃 선형 Z, 현재 프레임의 바로 이웃 색상, 과거 색상 및 Z를 샘플링합니다.

기록 색상/Z: 이동 속도로 이웃을 선택합니다. 윤곽선을 유지하기 위해 카메라에 가장 가까운 이웃을 선택하고, 이동 속도를 사용하여 이전에 해결된 색상을 샘플링합니다. 이렇게 하면 필터링을 사용할 수 있지만 누적 오류가 발생합니다! 모션에서 이전에 계산된 깊이를 사용하여 Q에 대해 재투영된 색상을 B, E, F로 고정하여 고정 해제된 값에 혼합하기 위한 신뢰할 수 있는 값을 계산합니다. 분석 색상: 과거 색상, 직접 이웃의 보간 색상이 있으며 최종 색상은 A, B, E, F 및 Q 간의 최소 차이와 속도 크기라는 두 가지 추가 가중치를 사용하여 계산됩니다.
전체 흐름도는 다음과 같습니다. 내용을 많이 조정하여 다소 복잡한 문제를 해결했습니다! 1.4ms를 소비하는데 이는 8~10ms가 줄어든 것이다.

TAA는 체커보드 렌더링과 통합될 수 있으며 하위 샘플 수준에서 수행되는 동일한 해결 셰이더에서 실행될 수 있습니다. 체커보드 패턴 위에 MSAA 4X 스타일 디더링, 유사한 논리를 사용하여 색상 가중치 재투영, 추가 정보(Unteething)를 사용하여 잘못된 체커보드 패턴을 제거할 수 있습니다.
해상도는 이미지에 눈에 띄는 톱니 패턴을 도입하고 이를 제거하기 위해 필터를 적용합니다. 필터는 가로 또는 세로로 인접한 5개의 픽셀에서 작동하여 임계값 d 및 이진 픽셀을 각각 0 또는 1로 설정합니다. 범위가 [0, d] 또는 [1-d, 1]인 경우 01010 또는 10101 패턴을 감지합니다.

DICE의 Frostbite 엔진 팀 구성원이 발표한 컴퓨팅을 통한 그래픽 파이프라인 최적화에서는 컴퓨팅 셰이더를 사용하여 그래픽 파이프라인을 최적화하고, 보다 구체적으로 많은 삼각형을 렌더링하지 않고도 삼각형을 더 빠르게 렌더링하는 방법을 설명합니다. 이 기사에 포함된 다양한 개념은 다음과 같습니다.
개념 이름 번역하다
VGT 버텍스 그룹화\테셀레이터 버텍스 그루퍼, 테셀레이션
PA 기본 어셈블리 요소 조립
CP 명령 프로세서 명령 프로세서
IA 입력 어셈블리 어셈블리 가져오기
SE 셰이더 엔진 셰이더 엔진
CU 컴퓨팅 유닛 컴퓨팅 유닛
후기 성도 로컬 데이터 공유 로컬 데이터 공유
HTILE Hi-Z 깊이 압축 계층적 깊이 압축
GCN 그래픽 코어 다음 AMD 그래픽 코어 지정
SGPR 스칼라 범용 레지스터 스칼라 범용 레지스터
VGPR 벡터 범용 레지스터 벡터 일반 레지스터
ALU 산술 논리 장치 산술 논리 장치
SPI 셰이더 프로세서 보간기 셰이딩 보간기

당시 Frostbite 엔진은 너무 많은 드로우 콜(1000개 이상)과 높은 프리미티브 필 레이트 등의 문제에 직면했습니다. 솔루션 기회에는 다음이 포함됩니다.
CPU에서는 대략적인 컬링, GPU에서는 미세한 컬링이 수행됩니다.
CPU와 GPU 사이의 지연으로 인해 최적화가 방해됩니다.
GPU 제출!
깊이 인식 컬링. 그림자 경계\샘플 분포 그림자 맵을 줄이고, 기여하지 않는 그림자 캐스터를 제거하고, 색상 채널에서 숨겨진 개체를 제거합니다.
VR을 위한 늦은 래치 컬링. CPU는 보수적인 뷰 프러스텀를 적용하고 GPU는 개선됩니다.
삼각형 및 클러스터 제거.
그래픽 파이프라인에 직접 매핑됩니다. 셸 셰이더 작업을 오프로드하고 전체 테셀레이션 파이프라인을 오프로드하세요! 여러 패스와 프레임 간에 결과를 재사용하는 절차적 버텍스 애니메이션(바람, 천 등)
그래픽 파이프라인에 간접적으로 매핑됩니다. 경계 볼륨 생성, 전처리 스키닝, 버텍스 애니메이션(Blend Shape), GPU에서 GPU 작업 생성, 장면 및 가시성 결정.
플롯을 데이터로 취급하십시오! GPU에서 사전 구축, 캐시 및 재사용되고 생성됩니다.
자른 개요:

왼쪽 상단: 그리드, 특정 뷰, 카메라, 조명 등의 컬렉션을 포함하는 표시된 장면. 오른쪽 상단: 장면의 구성 가능한 메시 하위 집합, 셰이더 및 삼각형 스트립(버텍스/인덱스)을 공유하는 배치 내의 메시, DirectX 12 PSO(파이프라인 상태 개체)에 대해 거의 1:1 비율. 왼쪽 하단: 자체 버텍스 버퍼, 인덱스 버퍼, 프리미티브 수 등을 포함하는 인덱스 드로우 콜(삼각형 목록)을 나타냅니다. 오른쪽 하단: 웨이브프런트 처리를 위한 최적의 삼각형 수, 웨이브프런트당 64개의 스레드, 컬링 스레드당 1개의 삼각형, 작업 항목별로 처리되는 256개의 삼각형이 있는 AMD GCN.
컬링의 개요는 다음과 같습니다.

일반적인 프로세스 및 기술 포인트에는 비시차형 버텍스 버퍼, 클러스터링 컬링, 드로잉 압축, 삼각형 컬링, 방향 컬링, 작은 기본 컬링, 프러스텀 컬링, 깊이 컬링(깊이 차단, 깊이 피라미드, HTILE, 소프트 래스터 Z 등)을 사용하여 메시 ID를 다중 그리기 ID로 매핑하는 것이 포함됩니다.
최종 제거 성능 및 효과는 다음과 같습니다.


INSIDE 렌더링: 낮은 복잡도, 높은 충실도(The Rendering of INSIDE: Low Complexity, High Fidelity)는 로컬 그림자 볼륨 측정 및 강력한 물 렌더링 시스템과 같이 대기 외관을 구현하는 데 사용되는 다양한 효과를 포함하여 그해 인기 있는 암호 해독 탐색 게임인 Inside의 렌더링 기술을 공유합니다. 아티스트가 액세스할 수 있는 도구에 초점을 맞추면서 각 픽셀을 미세 조정하여 조명을 완전히 독립적인 확산, 반사 및 반사광 엔터티로 설계합니다. 이는 기본 기반 앰비언트 오클루전(AO) 및 스크린 스페이스 리플렉션(SSR) 분석을 활용하는 것을 의미합니다. 또한 디더링을 적절하게 사용하여 방해가 되는 아티팩트를 제거하여 아트워크의 미묘한 세부 사항이 색상 밴드에서 손실되는 것을 방지하는 방법도 자세히 설명합니다.
Inside는 Android 및 iOS와 같은 모바일 플랫폼에서 실행할 수 있는 어두운 퍼즐 게임입니다. 그때 나를 매료시켰던 게임이었다. 저자는 사진에서 알 수 있듯이 한때 높은 평가를 받았습니다.

이 문서에서는 안개 및 체적, HDR 블룸, 리본 및 디더링, 프로젝션 데칼(맞춤형 조명, 분석적 앰비언트 오클루전(AO), 스크린 스페이스 리플렉션(SSR)), 물 렌더링, 효과 분해(눈알 유인) 등을 포함한 많은 콘텐츠를 다룹니다. Inside에서는 Light Prepass 렌더링을 사용합니다. 프레임 개요는 다음과 같습니다.

안개는 Inside 아트 스타일의 중심인 것으로 밝혀졌으며 게임의 초기 장면 중 상당수는 실제로 안개 + 실루엣이었습니다. 다음은 안개의 결합 효과입니다.

위에서 아래로: 안개 없음, 선형 안개, 선형 안개 + 광선.
대기 산란으로서의 글로우는 매우 넓은 후광으로, 화면의 절반이고 다운샘플링된 다음 광범위한 블러만 필요하기 때문에 여러 번 블러됩니다. HDR 글로우는 두 번째 글로우 채널로, 밝게 빛나는 객체에만 적용되며 마스크 객체의 좁은 글로우는 재질(알파 채널에 기록됨)만 방출합니다. 마스크 값은 RGB를 비선형 강도로 다시 매핑하고 중간 HDR 값은

샘플링 모드에서는 다운샘플링 시 13개 샘플, 업샘플링 시 9개 샘플을 흐리게 하는 발광 필터 [JIMENEZI4]를 사용합니다. 포스트 프로세스 설정 단계 및 절차는 다음과 같습니다.

다음으로 볼류메트릭 조명에 대해 이야기해 보겠습니다.
볼륨 조명은 raymarch의 카메라 조명, 섀도우 맵 투영 공간의 배경 깊이의 단계 크기를 사용하고 각 단계에서 조명 기여도(샘플링 섀도우 맵, 쿠키, 감쇠 등)를 계산합니다.

픽셀당 3개의 디더링된 샘플을 사용하면 블루 노이즈가 좋은 샘플링을 제공하는 반면, 과소샘플링된 영역에서는 더 적은 수의 샘플로 왜곡 결과를 찾기 위해 노이즈 속으로 되돌아갑니다.

반해상도는 저주파 효과에 사용되며, 이는 업샘플링 시 깊이 인식 흐림입니다. 단계는 다음과 같습니다:
청소 전 깊이 버퍼는 0입니다.
채널 1, 절반 해상도. 정면 깊이.
채널 2, 절반 해상도. 광선 단계별 볼륨 안개, 출력 광원 강도(8비트) + 최대 깊이(24비트).
채널 3, 전체 해상도. 반투명 개체 정렬, 깊이 인식 구문 분석, 업샘플링 및 흐림.

채널 3의 구체적인 프로세스는 다음과 같습니다.

또한 분산 크기 흐림, 4개 샘플, 깊이 감지 샘플 등을 사용하여 TAA에 영향을 미치고 다운샘플링하고 시간이 지남에 따라 TAA를 통합하도록 합니다. 다음은 여러 가지 디더링 방법을 비교한 것입니다.


기본 색상 채널에는 매우 명백한 색상 밴딩(색상 스케일) 결함이 있습니다.

위의 문제를 해결하기 위해 조명을 개별적으로 디더링하고 최종 패스에서 완전히 균일한 노이즈를 도입하고 반투명도 노이즈를 발생시키지 않지만 특수 블렌딩 모드를 사용하여 솔루션은 각 패스 후에 디더링하고 모든 중간 렌더 대상을 수동으로 srgb(pow2, 특별한 것은 아님)로 변환하고 낮은 해상도(흐림을 위해)에서 디더링하면 1픽셀보다 큰 노이즈가 발생하지만 다행히 결과는 표시되지 않습니다.

지터링 및 노이즈 을(를) 활용하여 color,을(를) 활용하여 노멀(Normal)! !
바운스 라이트는 전역 조명에 사용되며 바닐라 도트 제품을 사용하는 대신 슬라이더를 사용하여 페이드하는 점을 제외하면 일반 램버트 포인트 라이트와 거의 같습니다. 이를 램버트 랩 또는 하프 램버트라고 부르며 덜 지향적이고 부드러운 결과를 제공합니다.

de14.png)
다양한 강도의 바운스 라이트.
고정되어 있지 않기 때문에 창문을 열고 손전등을 옮기는 데 자주 사용됩니다. 전통적인 접근 방식(복도를 덮기 위해 일련의 점을 만들거나 방을 채우기 위해 배열을 만드는 것)을 사용하는 대신 Inside에서는 전체 변환 행렬을 사용하여 알약이 늘어나고 버튼이 눌려진 상자에 더 적합한 비균일 모양을 얻고 오버드로 및 겹침이 적기 때문에 오버헤드가 더 낮습니다.

이 기사에서는 AO 데칼과 섀도우 맵도 다룹니다.



위에서 아래로: 포인트 AO, 구체 AO, 박스 AO 효과 및 구현 방법.

위에서 아래로: 섀도우 데칼이 없는 상태, 섀도우 데칼이 있는 상태, 섀도우 데칼이 시각화된 상태입니다.
SSR의 경우 특별한 화면 공간 추적 방법이 사용됩니다.

왼쪽에서 오른쪽으로: 화면 공간에서 위쪽으로 광선을 방출하고 경계 상자의 가장 가까운 수평 출구로 광선을 이동한 다음 위쪽으로 계속 추적합니다.
// SSR계산/산출(Calculate)()
// GPU의 셰이딩
sDirProj = mul(projection, vec4(vDir + vPos, 1.0));
SDir = normalize(sDirProj.xyz / sDirProj.w - sPos);
// SSR계산/산출(Calculate)(개선 )
// CPU계산/산출(Calculate)투영/프로젝션 의 ,설정(Set)uniform변수
_DirProject = vec(viewportSize, nearClip / (nearClip - fraClip));
// GPU의 셰이딩
sDir = vec3(vDir.xy - vRay.xy * vDir.z, vDir.z * rcpDepth) * _DirProject;계단식 아티팩트를 방지하기 위해 무작위 샘플링(블루 노이즈 + TRAA)이 사용되었습니다.

수역(표면 및 수중)은 체적 안개, 반투명도, 굴절, 반사 및 기타 효과를 포함한 레이어 렌더링을 사용합니다.

수면의 층상 조합 효과.
수중에도 변위된 가장자리, 외부 또는 전면, 내부 또는 후면과 같은 레이어가 추가되어 수면과 동일한 레이어 렌더링이 있습니다.

인사이드의 특수효과 역시 많은 기술과 최적화 기법을 활용해 매우 특별하다.

각 입자에 무작위 오프셋을 적용하고 한 방향으로 롤링하면서 입자 텍스처를 월드 공간의 입자에 투영합니다. 그림의 예는 상자에서 나오는 방향이므로 아래쪽을 가리키고 있습니다.

렌즈 플레어 샘플링 방법.

다양한 수면 효과 시뮬레이션.
INSIDE의 시간적 재투영 앤티앨리어싱도 Inside와 관련되어 있지만 TAA의 적용 및 최적화에 중점을 둡니다.

먼저 몇 가지 기본적인 직관을 살펴보세요. 표면 조각의 국소 영역은 여러 프레임에 걸쳐 계속 표시될 수 있습니다. 관찰자와 피사체 사이의 관계가 매 프레임마다 변경되면 래스터라이제이션도 변경됩니다. 시간을 거슬러 올라가면 이 변경 사항을 사용하여 현재 프레임을 최적화할 수 있습니다.

현재 프레임의 조각을 이전 프레임의 조각과 연결하려면 깊이 버퍼 정보를 사용하여 공간적으로 수행하고 재투영할 수 있으며 가장 가까운 표면 조각으로 제한되지만 이것이 항상 가능한 것은 아니며 때로는 데이터가 단순히 존재하지 않는 경우도 있습니다. 요소는 언제든지 가려질 수도 있고 안 가려질 수도 있어서 정확하게 뒤로 물러나는 것이 어렵고, 보는 사람과 피사체의 관계가 절대 변하지 않는다면 뒤로 물러서도 추가 정보가 나오지 않는데...

1단계: 프러스텀를 흔듭니다. 카메라가 정적이면 정보가 손실되므로 렌더링 전 각 프레임이 샘플 분포에서 텍셀 오프셋을 가져오고 "오프셋"을 사용하여 투영 오프셋을 계산하고 "투영 오프셋"을 사용하여 프러스텀를 자르는 것으로 설정되었습니다.
2단계: 각 조각에 대해 다음 단계를 수행합니다.

정적 장면 재투영:
현재 조각 p_uv에서 시작합니다.
선형 깊이에 따라 크기가 조정된 현재 프레임의 깊이와 프러스텀 매개변수를 사용하여 월드 공간 p,lerp 각도 광선을 재구성합니다.
p를 이전 프레임으로 재투영: q_cs = mul(VP_prev', p), q_uv = 0.5 * ( q_cs.xy / q_cs.w ) + 0.5.
샘플링 내역: c_hist = Sample(buf_history, q_uv.

역동적인 장면의 재투영:
- 역동적인 장면의 경우 속도 버퍼가 필요합니다.
TAA를 처리하기 전에 특별 패스가 필요합니다.
정적 재투영을 사용하여 카메라 모션 초기화: v = p_uv - q_uv.
상단에 동적 개체 렌더링: v = comput_ssvel(p, q, VP, VP_prev').
재투영 단계는 읽기와 빼기가 됩니다: v = 샘플(buf_velocity, p_uv), q_uv = p_uv - v.

TAA 과정에서는 재투영 및 에지 모션, 제한된 히스토리 샘플, 이웃 클램핑 등의 세부 사항을 처리하고 최종적으로 제한된 히스토리 가중치를 융합하여 사용하는 것도 필요합니다.
Inside의 TAA 2.0은 믹스에 모션 블러를 추가합니다.

모션 블러 폴백을 사용한 최종 블렌딩 단계:
이전과 같이 히스토리 버퍼를 업데이트합니다: rt _history = c _feedback.
출력 대상의 경우 모션 블러 입력과 혼합합니다.
c _motion = Sample_motion ( buf _color , unjitter( p _uv ), v)
rt _output = lerp( c _motion , c _feedback , k_trust)
k_trust = invlerp( 15, 2, |v| )
모션 블러로 강제 전환(이력 없음!) 빠르게 움직이는 조각을 찾습니다.

좋은 샘플 분포를 선택하는 것과 관련하여 많은 시행착오, 실용적인 접근 방식, 화면에 가까이 다가가기, 고대비 영역 확대, 품질과 수렴 속도 간의 적절한 균형 찾기, 휴리스틱: 횡스크롤 게임.

일부 테스트 순서:

구현 요약: Halton(2, 3)의 처음 16개 샘플을 사용한 지터 프러스텀, 속도 버퍼 생성, 카메라 모션 + 역학(수동 표시), 가장 가까운(깊이) 조각을 기반으로 한 속도 재투영, RGB 최소-최대 원형 3x3 영역의 이웃 클램핑에 중심 클리핑 사용, 모션 블러 폴백, ||v||일 때 효과적 2보다 크고 15에서 완전히 효과적이지만 기록에는 작동하지 않습니다.
Uncharted 4의 시간적 안티앨리어싱은 Uncharted 4의 시간적 안티앨리어싱도 공유합니다. 이 문서의 초점은 보다 자세한 구현 세부 정보를 제공하는 것입니다.
정적 이미지의 경우 입력 및 출력을 설정하고, 전체 화면 셰이더를 실행하고, 과거와 현재 렌더링된 텍스처 사이를 보간합니다.
float3 currColor = currBuffer.Load(pos);
float3 historyColor = historyBuffer.Load(pos);
return lerp(historyColor, currColor, 0.05f);동영상의 경우 동일한 위치에서 히스토리 버퍼를 샘플링할 수 없으며 이전 프레임(있는 경우)에서 현재 프레임 픽셀의 위치를 찾을 수 없으므로 화면 밖의 픽셀과 가려진 픽셀을 처리해야 합니다. 먼저 GBuffer 채널에서 전체 화면 모션 벡터 버퍼(fp rg16)를 생성해야 합니다.
// GBuffer VS
posProj = posObj * matWvp;
posLastProj = posLastObj * matLastWvp;
// GBuffer PS
posNdc -= g_projOffset;
posLastNdc -= g_projOffsetLast;
float2 motionVector = (posLastNdc - posNdc) * float2(0.5f, -0.5f);프로그래밍된 애니메이션 개체(식물, 머리카락, 물 버텍스 이동 등)의 경우 현재 프레임과 마지막 프레임에 대해 두 번 실행해야 합니다. 결정론이 필요합니다. 마지막 프레임의 시간을 입력하면 버텍스 위치가 정확히 동일해집니다. 텍스처에서 uv를 롤링합니다. 즉, 표면 UV 공간(deltaU, deltaV)에서 롤링할 때 화면 공간(deltaX, deltaY)이 얼마나 변경되는지를 나타냅니다.
deltaU = ddx(U) * deltaX + ddy(U) * deltaY;
deltaV = ddx(V) * deltaX + ddy(V) * deltaY;구문 분석된 deltaX 및 deltaY는 화면 픽셀에 있으며 모션 벡터 단위로 변환됩니다. 반사의 경우 미러링된 모션 벡터를 사용할 수 없습니다. 미러링된 픽셀은 일반적으로 이전 프레임에서 동일한 것을 반영하지 않았기 때문입니다. 이 문제는 어렵지 않지만 많은 단계를 포함하며 평면 반사에만 적용할 수 있습니다. 모든 것에는 모션 벡터가 있어야 하지만 일부는 지원되지 않습니다. 입자 연기, 물 흐름, 구름 모션 등과 같은 복잡한 텍스처 애니메이션; 아티스트가 제어하는 모션 벡터 불투명도와 같은 투명한 개체. TAA 이후에 그려보면 어떨까요? 그리기 순서가 항상 허용되는 것은 아닙니다. TAA를 건너뛰는 것은 모두 지터링됩니다. 지터링된 깊이 버퍼가 테스트에 사용되기 때문에 지터를 제거하는 것만으로는 충분하지 않습니다. TAA가 문제를 제거한 후: 빗방울, 총알 자국, 불꽃... 그 외에는 다른 어떤 것도 제거할 수 없었습니다. 일단 TAA를 사용하면 끝까지 가야 합니다. 모션 벡터 샘플링 기록 버퍼를 사용하여 모션 벡터 버퍼를 TAA에 입력으로 추가합니다.
float2 uvLast = uv + motionVectorBuffer.Sample(point, uv);
float3 historyColor = historyBuffer.Sample(linear, uvLast);선형 샘플러 사용 시 중요한 사항: 포인트 샘플이 관련 없는 픽셀에 포함될 수 있으며, 선형 샘플이 완전히 손실되지는 않지만 흐려지는 결과를 낳습니다(나중에 설명).
과거 색상과 현재 색상은 폐색/화면 밖 비존재, 조명 변화, 가장자리의 다른 측면(프로젝션 지터) 등으로 인해 일치하지 않을 수 있습니다. 과거 색상을 고정해야 합니다. Dust 514의 클램핑 방법을 사용하여 현재 프레임 픽셀을 중심으로 하는 3x3 이웃을 샘플링하고 각 RGB 채널에 대한 최소/최대 이웃을 계산합니다.
float3 neighborMin, neighborMax;
// calculate neighborMin, neighborMax by
// iterating through 9 pixels in neighborhood
historyColor = clamp(historyColor, neighborMin, neighborMax);부재 및 조명 변경의 경우, 너무 다른 히스토리 색상을 클램핑하여 3x3 이웃을 사용하면 클램핑이 가장자리 AA에 영향을 주지 않으며 가장자리 픽셀의 경우 가장자리 반대편의 히스토리가 클램핑되지 않습니다. 과거의 색상과 현재의 색상을 다시 혼합할 시간입니다. 이번에는 동영상 이미지를 지원합니다.
return lerp(historyColor, currColor, blendFactor /*0.05f*/);흐림과 지터의 균형을 맞추려면 동적 blendFactor가 필요합니다. UE4 방법 기반: 로컬 대비가 낮을 때 증가하고, 픽셀 모션이 하위 픽셀에 도달할 때 감소하고, 기록이 클램핑에 가까울 때 감소하며, 결과는 여전히 약간 흐릿합니다. 흐림 현상을 해결하려면 다음 이웃 가중치를 사용하여 전체 화면 전달이 필요합니다.
return saturate(center + 4*center - up - down - left - right);TAA에는 여전히 한 가지 문제가 있습니다. 고스팅, 클램핑이 이를 방지해야 하지만 일부 영역에서는 작동하지 않는 것 같습니다. 고스팅은 강한 빛이 비춰지는 어둠 속에서 빽빽한 풀과 울퉁불퉁한 표면과 같은 고주파수 및 고강도 색상 변화로 인해 발생합니다. 인접 최소/최대 값이 커져 클램핑이 효과적이지 않게 됩니다.
historyColor = clamp(historyColor, neighborMin, neighborMax);
// 의 코드 로써 코드
uint currStencil = stencilBuffer.Sample(point, uv);
uint lastStencil = lastStencilBuffer.Sample(point, uvLast);
blendFactor = (lastStencil & 0x18) == (currStencil & 0x18) ? blendFactor : 1.f;잔상은 사라졌지만 새로 표시된 픽셀은 매우 선명하고 들쭉날쭉해 보입니다.

blendFactor가 1일 때 가우스 흐림 색상을 반환합니다.
blendFactor = (lastStencil & 0x18) == (currStencil & 0x18) ? blendFactor : 1.0f;
float3 blurredCurrColor;
// Gaussian blur currColor with 3x3 neighborhood
if (blendFactor == 1.0f)
return blurredCurrColor;가우스 가중치는 다음과 같습니다.
템플릿이 수정된 후에도 여전히 1픽셀 두께의 고스트가 남아 있습니다.

색상 기록은 선형적으로 샘플링되는 반면 스텐실 기록은 포인트 샘플링되고 가장자리가 일치하지 않습니다. 해결 방법은 스텐실 버퍼의 개체 윤곽선을 1픽셀씩 확대하는 것입니다. 현재 프레임 깊이와 스텐실 버퍼를 입력으로 사용하여 전체 화면 셰이더를 만듭니다. 각 픽셀(p)은 자신의 깊이를 4개의 이웃 픽셀(왼쪽 위, 오른쪽 위, 왼쪽 아래, 오른쪽 아래)과 비교하고 다른 이웃 픽셀은 무시합니다. 깊이에 가장 가까운 픽셀 템플릿을 출력하고, 확장된 스텐실 버퍼를 TAA 입력에 추가하고, 이전 프레임의 템플릿은 확장된 버전에서 가져와야 하며, 템플릿 테스트에는 확장된 버전을 사용하고, 가장자리 감지는 확장되지 않은 버전을 사용합니다. 모션 블러가 고스팅을 숨길 수도 있으므로 수동으로 표시하는 이유인 잔디와 같은 표시를 방지하기 위해 스텐실 표시 개체 가장자리 주변의 약간의 지터를 수정했습니다.
화면 외부 픽셀의 경우 픽셀 기록이 이전 프레임의 화면을 떠났을 수 있으며, 이는 셰이더에서 감지되고 blendFactor가 1로 설정됩니다. 이는 새로 발견된 사례와 일치합니다. 기록 없음, 가우시안 블러의 현재 색상을 사용합니다.
1080p의 PS4 GPU에서 메인 셰이더는 0.8ms 미만이며 모션 벡터 계산, 선명 셰이더(0.15ms), 확대된 스텐실 셰이더(0.4ms) 등 기타 많은 관련 비용이 발생합니다. TAA의 다른 이점: 픽셀당 여러 샘플을 획득하고, 계산을 여러 프레임으로 확장하고, 병합에 TAA를 사용하는 그래픽 기능, 하나의 샘플이 표시되지만 여러 샘플에 걸쳐 사용됩니다.
이 기사에서는 RSM(Reflective Shadow Map)에 TAA를 사용하는 아이디어에 대해서도 설명합니다. 손전등 관점에서 256x256 버퍼로 장면을 렌더링합니다. 각 픽셀은 VPL(Virtual Point Light)로 처리됩니다. 각 픽셀이 모든(65536) VPL로 조명되는 전체 화면 셰이더를 실행하지만 알고리즘 복잡성은 O(n*m)이므로 비용이 너무 높습니다! Uncharted 4는 VPL 버퍼를 16x16, 1/4 너비 x 1/4 높이 전체 화면 셰이더로 다운샘플링했지만 그 결과 결과가 너무 흐릿하고 흐릿했으며 VPL(256)이 부족하여 아티팩트가 발생했습니다. 덜 폭력적인 솔루션이 필요하지만 렌더링 해상도로는 이를 감당할 수 없습니다. 각 픽셀은 16개의 VPL을 무작위로 샘플링하고, 인접한 픽셀은 16개의 서로 다른 VPL을 샘플링합니다. 각 64x64 화면 공간 타일은 64k VPL을 모두 포함할 수 있습니다. PBR 매뉴얼에 설명된 낮은 시차 시퀀스를 사용하여 64x64 타일의 두 픽셀이 동일한 VPL을 사용하지 않도록 64k에서 16번 샘플링하면 큰 차이가 발생하여 심각한 노이즈가 발생합니다. 따라서 시간적 샘플링을 도입할 수 있으며, 각 픽셀은 프레임당 서로 다른 16개의 VPL을 샘플링합니다. 실제로는 16개 이상의 VPL이 있으며, TAA는 프레임을 안정적인 이미지로 수렴합니다. 가장 좋은 점은 TAA 셰이더를 변경할 필요가 없다는 것입니다.
TAA는 스크린 스페이스 리플렉션(SSR), 그림자 흐림, 스크린 스페이스 앰비언트 오클루전(SSAO), 카메라 투명도 근처, LOD 변환 및 일부 머리카락 투명도에도 사용할 수 있습니다. 해결되지 않은 문제: 지원되지 않는 모션 벡터, 일부 곡물/물은 TAA 없이 더 좋아 보입니다. SSR이 절반 해상도로 작동하도록 하기 위한 비우호적인 다운샘플링 및 흐림; TAA는 더 높은 프레임 속도에서 더 잘 작동하고 더 빠르게 수렴하며 아티팩트가 덜 눈에 띕니다.
'Skylanders: SuperChargers'의 혼합 해상도 렌더링은 Skylanders: SuperChargers 게임에 사용된 혼합 해상도 렌더링 기술을 설명합니다. 첫 번째 시도는 장면 깊이가 다운샘플링된 다음 저해상도 버퍼에 대해 래스터라이제이션되고 양측 업샘플링을 사용하여 저해상도 렌더가 업샘플링된 다음 마지막으로 장면 버퍼에 합성되는 혼합 해상도의 단일 패스를 사용하는 것이었습니다.

양방향 업샘플링을 위한 코드:
float4 vBilinearWeights = GetBilinearweights(vTexcoord);
float4 vSampleDepths = GetLowResolutionDepths(vrexcoord);
float vPixelDepth = GetHighResolutionDepth(vTexcoord);
float4 vDepthWeights = GetDepthsimilarity( vPixelDepth, vSampleDepths);
return vDepthWeights * vBilinearWeights;처리하는 픽셀이 거의 상호 배타적이기 때문에 깊이 다운샘플링 시 최소값과 최대값이 결합됩니다. 때로는 간단한 것이 작동하는 것으로 나타났습니다. 체커보드 패턴에서 최소값과 최대값을 번갈아 사용하면 전체 4x4 픽셀 블록에 대해 좋은 깊이 표현을 제공할 수 있습니다.

Texture2D SourceDepthTexture;
SamplerState PointSampler;
float main(float2 vTexcoord : TEXCOORD0, float2 vWindowPos : SV_Position) : SV_Target
{
// Gather the 4 depth taps from the high resolution texture that cover this texel SourceDepthTexture.
float4 fDepthTaps = GatherRed(PointSampler, vTexcoord, 0);
// Identify the min and max depth out of the 4 taps
// NOTE: It doesn't matter if your depth is negative or positive here
float fMaxDepth = max4( fDepthTaps.x, fDepthTaps.y, fDepthTaps.z, fDepthTaps.w);
float fMinDepth = min4( fDepthTaps.x, fDepthTaps.y, fDepthTaps.z, fDepthTaps.w);
// Classify the low resolution texel as either a max texel or min texel based on the window pos
return checkerboard( vWindowPos) > 0.5f ? fMaxDepth : fMinDepth;
}결과적인 깊이 버퍼는 아래 아치 아래의 풀잎에서 볼 수 있듯이 고주파 깊이 불연속성을 체커보드 패턴으로 변환합니다. 그러므로 이를 평가하는 방법이 필요하다.

여러 가지 깊이 다운샘플링 방법의 픽셀 오류 값은 다음과 같습니다. min/max 방법의 오류가 가장 작은 것을 볼 수 있습니다.

원본 참조와 최소/최대 간의 렌더링 비교:

양방향 업샘플링 모드는 다음과 같습니다.

그런데 두 번째 시도에서는 해상도보다 결과가 나빠 보이는 경우가 있는데, 샘플에 문제가 있는 걸까요? 포인트 샘플링을 사용하는 것이 더 낫습니까? 어떤 경우에는 결과를 깊이 가중치가 없는 단순한 선형 필터링과 비교할 때 결과에 이상한 아티팩트가 있어 무슨 일이 일어나고 있는지 알 수 있습니다. 그러면 왜 아래 그림의 상황(양방향 필터링에서 명백한 앨리어싱)이 발생합니까? 이는 양측 업샘플링 및 얼마나 깊은 유사성을 계산하는지와 관련이 있습니다.

깊이 유사성은 일반적으로 다음 코드로 계산됩니다.
float4 GetDepthSimilarity( float fCenterDepth, float4 vSampleDepths)
{
// fThreshold뎁스 의
loat fScale = 1.0f / fThreshold;
float4 vDepthDifferences = abs(vSampleDepths - fCenterDepth);
return min(1.0f / (fScale * vDepthDifferences + fEpsilon) , 1.0f);
}일반적으로 깊이 유사성은 고해상도 픽셀과 저해상도 픽셀 간의 깊이 차이를 확인하여 계산됩니다. 이 숫자는 임계값(fThreshold)과 함께 사용되어 깊이가 유사한지 확인합니다. 따라서 작은 임계값을 선택하면 잘못된 가장자리를 감지하게 됩니다(아래 왼쪽 이미지). 마찬가지로 임계값이 너무 크면 가까운 가장자리가 손실됩니다(아래 오른쪽 이미지).

이는 고정된 깊이 바이어스 값이 양측 가중치에 사용되기 때문입니다. 문제는 표면이 화면 속으로 물러날수록 단일 픽셀 단계로 표시되는 단위 수가 증가한다는 것입니다. 따라서 임계값은 깊이에 따라 설정되어야 합니다.

대신 이 논문에서는 임계값을 결정하기 위한 기초로 장면으로 다시 밀려나는 비행기의 모델을 사용합니다. 선형 블렌딩이 전면에 유지되도록 단일 픽셀의 각도 차이와 평면의 경사가 입력으로 제공됩니다. 따라서 결과를 얻는 것은 간단한 삼각법 문제가 되며, 다운샘플링할 때 깊이 값이 2픽셀 떨어져 있을 수 있다는 사실을 보상하기 위해 값의 크기를 조정합니다.

개선된 임계값의 효과와 샘플링 결과는 다음과 같습니다.


그러나 목표 경사 임계값을 사용하기 전과 후의 또 다른 문제의 예는 다음과 같습니다. 왼쪽에 표시된 것은 수직 필터링이 아닌 수평 필터링입니다.

따라서 세 번째 시도에서는 일부 효과가 여전히 좋지 않고 앨리어싱이 많이 발생했으며 투명 모델은 훨씬 더 나빴습니다. 가장자리 앨리어싱을 줄이기 위해 이중 통과 방법이 사용됩니다.

깊이와 색상의 가장자리 감지는 다음 방법으로 샘플링되었습니다.

부분 업샘플링 단계:
- 패스 1:
가장자리를 다듬습니다.
채널에 템플릿 비트를 설정합니다.
패스 2:
고해상도 스텐실(hi-stencil)을 구성합니다.
- 고해상도 템플릿을 다시 로드하려면 전체 화면 직사각형을 그립니다.
4번째 시도에서 얻은 효과는 릴리즈 레벨에 이르렀으며, 360에서 실행되는 성능은 다음과 같습니다.

게임에서 사용되는 지터 감쇠로 인해 아래 이미지에서 최소/최대 버퍼가 페이딩 트리의 지터 특성을 명확하게 유지하는 것을 볼 수 있습니다.

장점은 게임에 도움이 되는 콘텐츠이고, 오프스크린 렌더 타겟이 매우 유용하며, 성능 확장이 가능하다는 것입니다. 단점은 미리 곱해진 렌더 타겟, 제한된 블렌딩 모드, 고해상도 템플릿에 대한 의존성, 최악의 경우 더 비싸고 높은 오버헤드입니다.
드라이버 추상화는 그래픽 API를 더 잘 추상화하고 캡슐화하는 방법에 대해 이야기했습니다. 이 기사의 추상화는 원래 DX9 기반의 경량 레이어였으며 DX10과 일치하도록 업데이트되었으며 렌더링 프로세스 자체가 아닌 메서드/호출을 추상화했습니다. 기존 렌더링 파이프라인은 다음과 같습니다.

작업 항목은 입력, 출력, 프로그램 등과 같은 단일 렌더링 작업을 설명하는 데 필요한 최소 데이터입니다. GPU 작업일 필요는 없으며 최대한 일반적이며 완전히 독립적입니다.
자원은 무엇이든 될 수 있습니다. 클라이언트 코드의 블랙박스입니다. 서로 다른 플랫폼과 심지어는 서로 다른 실행에서 서로 다른 구현을 가질 수 있습니다. 인스턴스가 있을 수 있으며 수명 주기가 길 수도 있습니다. 수명주기 전체에 걸쳐 메모리에 반드시 존재하지 않을 수도 있습니다. 리소스의 일반적인 대표자는 텍스처, 셰이더, 모델 등입니다. 인스턴스는 리소스이고 임시적이며 클라이언트 코드의 블랙박스이며 현재 프레임에서 렌더링되는 모델 인스턴스와 같은 리소스와 동일한 코드로 처리됩니다. 핸들에는 설정(color_handle, color::red) 및 가져오기(colour_handle)와 같은 인터페이스가 있습니다. 내부 핸들은 인스턴스 메모리의 오프셋입니다. 이는 클라이언트가 리소스와 인스턴스에 액세스할 수 있는 유일한 방법입니다. 특정 인스턴스나 리소스에 요청된 매개변수가 없으면 NOP입니다. 디버깅에는 유형 감지가 있습니다.
새로운 파이프라인은 다음과 같습니다. 더 나은 디커플링과 최적화 기회를 달성하기 위해 상위 수준 및 하위 수준 렌더링 레이어를 분리하는 리소스 관리자를 추가합니다.

요약하자면, 기본 코드에 가능한 한 많은 컨텍스트를 제공하고, 높은 수준에서 어떤 가정도 하지 않고, 모든 옵션을 열어두고, 성능에 영향을 주지 않고 일반화하고 추상화하는 것을 두려워하지 말고, API의 경량 캡슐화는 더 이상 최선의 선택이 아닙니다.
픽셀에서 현실로 - 차세대 게임 엔진에 대한 생각'에서는 2016년 게임 엔진 현황과 향후 트렌드에 대해 이야기합니다. 2016년 주류 게임 엔진은 멀티스레딩, 멀티플랫폼, 최신 그래픽 API, 디퍼드 렌더링, PBR, 전역 조명, 동적 환경 및 60FPS@1080P를 특징으로 했습니다. 당시 부족한 부분은 앨리어싱, 섀도우, 투명도, 애니메이션, 로딩시간, 성능, 콘텐츠 제작 등이었다. 최근 떠오르는 기술로는 커뮤니티 기반 게임, 사용자 제작 콘텐츠, 모바일 단말, VR/AR, e-스포츠, 방송 등이 있다. 영화와 게임의 차이점은 아래 표와 같다.
영화 게임
레예스/레이 트레이싱 다이렉트 3D/OpenGL
객체 공간 음영 화면 공간 음영
다수의 가시성 샘플 작은 가시성 샘플
사진 품질 처리량
당시 GPU 기반 REYES는 작은 삼각형, 장면 복잡성, 속도 부족 등의 문제에 직면한 반면, 실시간 Ray Tracing은 해상도, 다중 모니터, 속도 부족 등의 문제에 직면했기 때문에 REYES/Ray Tracing을 게임에 사용할 시기가 충분히 성숙되지 않았습니다. 더 나은 접근 방식은 아이디어를 빌려 결합하는 것입니다. 객체 공간의 그림자 = 본질적으로 안정적이며 음영에서 가시성 샘플링을 분리합니다 = 다중 속도, 가시성 버퍼 = 메모리 및 대역폭 감소. 가능한 렌더링 파이프라인은 다음과 같습니다:

Multirate는 가시성 샘플, 음영 샘플, 조명 샘플, 물리학, 인공 지능, 입력, 조명 전송 업데이트 등으로 더욱 확장될 수 있습니다. 톱니의 경우 거울 톱니에는 Lean Mapping [OlanoBaker 2010]을 사용할 수 있고 그림자 톱니에는 Frustum Traced Raster Shadows [WymanHoeltzleinLefohn15]를 사용할 수 있으며 반투명에는 OIT를 사용할 수 있습니다. zlib보다 2배 향상된 압축 기술, 절차적으로 합성된 Substance, Wang Tiles [Wang61] [Stam97] [Liyi04]를 통해 로딩 시간을 향상시킬 수 있습니다.
클라우드는 하나의 상자에서 거대한 세계, 수천 명의 플레이어, 마이크로 클라이언트, 콘텐츠 제작, 스튜디오를 지원할 수 있습니다. Amazon의 클라우드 렌더링 GameLift 아키텍처 다이어그램은 다음과 같습니다.

2018년 게임 엔진은 앨리어싱, 올바른 공간, 올바른 빈도, 올바른 배치, 지각 안내, 프로그래밍 콘텐츠, 클라우드 연결 등의 "중요성"과 거의 관련이 없습니다. 연구 핫스팟에는 절차적 합성, 압축, 3D 스캐닝, 인식 과학, 다중 속도 렌더링, 애니메이션, 분산 물리학/인공 지능/렌더링 등이 포함됩니다.
64비트 게임용 저조각화 메모리 시스템 구축은 게임 내 저조각화 메모리 관리 시스템을 공유합니다. PS3에서 이식된 기존 메모리 시스템에는 VRAM을 시뮬레이션하는 고정 크기 메모리 풀이 있었습니다. 문제는 낭비되는 메모리가 많고, 메모리 풀당 최악의 시나리오, 작은 할당의 오버헤드, 조각화, 텍스처 스트리밍 지원 불가능 등입니다. 메모리 조각화는 연속되지 않은 작은 청크로 조각화된 힙이며, 혼합된 할당 수명으로 인해 메모리가 충분하더라도 할당이 실패할 수 있습니다.

설계 목표는 낮은 조각화, 높은 활용도, 간단한 구성, PlayStation®4 운영 체제 및 PC 지원, 효율적인 텍스처 스트리밍 지원, 포괄적인 디버깅 지원입니다.
가상 메모리는 프로세스 내에서 가상 주소를 사용하며, 물리적 주소에 매핑된 가상 주소이다. CPU가 물리적 주소를 찾으려면 운영 체제와 하드웨어 지원이 필요합니다.

가상 메모리는 메모리 조각화를 줄일 수 있습니다. 조각화는 주소 조각화입니다. 가상 주소를 사용하면 가상 주소 공간이 물리적 주소 공간보다 큽니다. 연속 가상 메모리는 물리적 메모리에서 연속적이지 않습니다. 메모리 페이지는 페이지 단위로 매핑되며 x64는 4kB 및 2MB 페이지를 지원하고 PlayStation 4 운영 체제는 16kB(4x4kB) 및 2MB를 사용하며 GPU는 더 많은 크기를 갖습니다. 2MB 페이지가 가장 빠르며, 16kB 페이지가 메모리를 덜 차지합니다. 이 글에서는 64kB(4x16kB 페이지)를 사용합니다. 64kB는 PlayStation 4 GPU의 최소 및 최적 크기입니다. 16kB는 특별한 경우에도 사용됩니다.
Onion Bus와 Garlic Bus는 모두 CPU 및 GPU 액세스를 두 배로 늘릴 수 있지만 대역폭은 다릅니다. Onion = 빠른 CPU 액세스, Garlic = 빠른 GPU 액세스.
이 기사의 메모리 시스템은 전체 가상 주소 공간을 나누고 필요에 따라 실제 메모리를 매핑합니다. 할당자 모듈은 자체 공간을 관리합니다. 각 모듈은 전문화되어 있습니다. 할당자 개체는 시스템의 인터페이스입니다.
class Allocator
{
public:
virtual void* Allocate(size_t size, size_t align) = 0;
virtual void Deallocate(void* pMemory) = 0;
virtual size_t GetSize(void* pMemory) { return 0; }
const char* GetName(void) const;
};
//
void* GeneralAllocator::Allocate(size_t size, size_t align)
{
if (SmallAllocator::Belongs(size, align))
return SmallAllocator::Allocate(size, align);
else if (m_mediumAllocator.Belongs(size, align))
return m_mediumAllocator.Allocate(size, align);
else if (LargeAllocator::Belongs(size, align))
return LargeAllocator::Allocate(size, m_mappingFlags);
else if (GiantAllocator::Belongs(size, align))
return GiantAllocator::Allocate(size, m_mappingFlags);
return nullptr;
}가상 주소 공간:

소형 할당 모듈: 대부분의 할당은 64바이트 이하, 약 250,000개 할당, 약 25M입니다. 헤더 정보 없이 동일한 크기의 16kB 페이지로 조각화를 방지하기 위해 패킹됩니다.

작은 할당 모듈의 장점과 단점, +경량 구현, +매우 낮은 낭비, +유연한 메모리 활용, +빠름, -메모리 병목 현상을 감지하기 어려움.
대규모 할당 모듈은 거대한 가상 주소 공간(160GB)을 예약하고 각 테이블을 동일한 크기의 슬롯으로 나누고 64kB 페이지를 필요에 따라 매핑 및 매핑 해제하여 연속 메모리를 보장합니다.

텍스처 스트리밍은 큰 할당 슬롯을 예약하고, 가장 가까운 2의 거듭제곱으로 반올림하고, 최소 밉과 최대 64kB를 로드하고, 복사나 조각 모음 없이 필요에 따라 페이지를 매핑 및 매핑 해제합니다. 대용량 할당 모듈의 장점과 단점, + 헤더 정보 없음, + 간단한 구현(약 200줄의 코드), + 조각화 없음, - 페이지 크기로 반올림된 크기, - 매핑 및 매핑 해제 커널 호출이 상대적으로 느립니다.
중간 할당 모듈은 중간 크기 할당을 처리하고 헤더 정보가 없으며 크고 작은 크기를 제외한 모든 크기가 여기에 할당됩니다. 연속되지 않은 가상 페이지, 증가 및 축소, 헤더 정보가 있는 기존 이중 연결 목록, 마늘에 적합하지 않은 메모리(GPU)(데이터와 함께 저장된 헤더), Pow2 여유 목록.

Headerless Allocation Module은 GPU 할당, 중소형 할당, 해시 테이블 조회 등에 사용됩니다.
할당자 유형에는 GeneralAllocator, VramAllocator, MappedAllocator, GpuScratchAllocator, FrameAllocator 등이 포함됩니다. GPU 스크래치 할당자(GpuScratchAllocator)는 프레임당 할당, 이중 버퍼링을 위해 렌더러에서 사용되며 릴리스 할당이 필요하지 않으며 원자적으로 보호됩니다. GpuScratchAllocator의 장점과 단점: + 헤더 또는 청구서 없음, + 조각화 없음, + 빠름, - 고정 크기, - 최악의 경우 정렬은 공간을 낭비합니다. 프레임 할당자(FrameAllocator), 프레임이 푸시되고 팝되며 메모리를 해제할 필요가 없으며 각 스레드는 고유하며 임시 작업 버퍼에 적합합니다.
#include <ls_common/memory/ScratchMem.h>
struct Elem
{
…
};
void ProcessElements(size_t numElements)
{
ls::ScratchMem frame;
Elem* pElements = (Elem*)MM_ALLOC_P(&frame, sizeof(Elem) * numElements);
}FrameAllocator의 장점과 단점: + 헤더 또는 청구서 없음, + 조각화 없음, + 동기화 없음, + 빠름, - 포인터 전달에 주의하세요!
스레드 안전성: 가장 낮은 수준의 뮤텍스, 할당자 인스턴스는 보호되지 않으며 프레임 할당자에는 잠금이 없으며 훌륭하고 간단합니다.
성능이 초점은 아니지만 여전히 중요하고, 매핑/매핑 해제가 느리고 눈에 띄는 차이가 없으며, 게임 중에 너무 많은 할당을 하지 않으며, 파일 로딩이 병목 현상이 발생합니다. 메모리 정리 값은 다음과 같습니다(memset의 바이트 값은 읽기 가능하고 기억 가능한 상태로 유지됩니다).
0xFA: Flexible memory allocated
0xFF: Flexible memory free
0xDA: Direct memory allocated
0xDF: Direction memoryfree
0xA1: Memory allocated
0xDE: Memory deallocated통계, 가능한 모든 것이 추적되고 실시간 그래프가 제공되며 자동화된 테스트를 통해 기록됩니다. 중간 할당 헤더의 여유 바이트인 메모리 헤더 보호는 메모리 병목 현상을 감지하지만 너무 늦을 때까지 감지하는 경우가 많습니다. 메모리 블록 보초는 일반 할당자를 우회하며 각 할당은 자체 페이지에 있고 앞뒤에 매핑되지 않은 페이지가 있으며 너무 많거나 너무 적으면 충돌이 발생합니다.
요약: 최신 콘솔은 풍부한 가상 메모리를 지원하고, 가상 메모리는 많은 옵션을 제공하고, 할당 패턴을 중심으로 메모리 시스템을 설계하고, 분석이 중요하며, 작은 할당이 좋은 시작이며, 모듈식 할당자를 사용하면 사용자 정의가 쉬워집니다! 디버깅 기능은 매우 중요합니다!
악마는 세부 사항에 있습니다. idTech 666은 idTech 엔진 렌더링 파이프라인의 렌더링 기술과 성능 최적화에 대해 설명합니다. 당시 idTech의 렌더링 파이프라인 프로세스와 성능 데이터는 다음과 같습니다.

클러스터링된 조명 시스템은 "Clustered Deferred and Forward Shading"[Olson12] 및 "Practical Clustered Shading"[Person13]에서 파생되었으며 투명한 표면에서 작업할 수 있고 추가 패스나 작업이 필요하지 않으며 깊이 버퍼와 독립적이며 깊이 불연속점에서 거짓 긍정이 없습니다. 클러스터 조명 단계는 다음과 같습니다.
복셀화/래스터라이제이션 처리. CPU에서 완료되며 깊이 슬라이스당 작업 1개입니다.
로그 깊이 분포. 근거리 및 원거리 평면을 확장합니다:
. 각 항목은 복셀화되고 항목은 조명, 환경 프로브 또는 데칼이 될 수 있고 항목 모양은 OBB 또는 프러스텀(프로젝터)이며 화면 공간
, 의 래스터라이제이션 및 깊이 경계로 제한됩니다. 클립 공간을 개선합니다. 클립 공간의 셀은 AABB, N 평면 및 셀 AABB, OBB는 6개 평면, 프러스텀는 5개 평면, 코드는 SIMD를 사용하여 모든 볼륨에 대해 동일합니다.
//Pseudo-code - 1 job per depth slice ( if any item )
for (y=MinY; y<MaxY; ++y)
{
for (x =MinX; x<MaxX; ++x)
{
intersects = N planes vs cell AABB
if (intersects)
{
Register item
}
}
}세계를 자세히 묘사하는 기술: 가상 텍스처 업데이트; 알베도, 반사성, 부드러움, 노멀, HDR 라이트맵, 하드웨어 sRGB 지원, 반사성 앤티앨리어싱을 위해 Toksvig를 부드러움으로 베이킹합니다. UAV 출력을 최종 해상도로 직접 읽어들이기; 비동기 전산 트랜스코딩, 비용은 거의 관련이 없습니다. 디자인 결함이 여전히 존재합니다. 반응형 텍스처 스트리밍 = 텍스처 팝핑; 내장형 기하학 래스터라이제이션가 포함된 데칼; 메가 텍스처 스탬핑으로 실시간 교체, 더 빠른 작업 흐름/더 적은 디스크 저장 공간; 노멀 맵 블렌딩, 모든 채널의 선형 올바른 블렌딩, 밉맵/비등방성, 투명도, 정렬, 0 그리기 호출, BC7 x 8k 데칼 아틀라스를 사용한 8k; 또한 혼합 설정, "혼합된 레이어"의 일반화를 포함하여 아티스트가 손으로 배치한 데칼 아틀라스에 색인된 상자 투영; 프러스텀 뷰당 4k로 제한되며 일반적으로 1k 이하로 표시됩니다. LODization, 아트는 최대 시청 거리를 설정하고 플레이어 품질 설정도 시청 거리에 영향을 미칩니다. 동적 변형 불가능한 형상에 대한 연구, 데칼에 개체 변형 적용.
조명 측면에서는 단일/통합 조명 코드 경로를 사용하고 불투명 패스에 대한 셰이더 순열 없음, 지연되고 투명하며 분리된 입자 조명, 정적/일관성 분기가 이제 훌륭합니다. 이를 활용해 보세요! 컨텍스트 전환을 줄이려면 모든 정적 형상에 동일한 셰이더를 사용하세요. 조명 구성 요소에는 다음이 포함됩니다. 확산 간접 조명 - 정적 형상의 라이트맵용, 동적 복사 조도 볼륨용, 반사형 간접 조명 - 반사(환경 프로브, SSR, 스페큘러 반사 폐색), 동적 조명 및 그림자용.
// Pseudocode
ComputeLighting( inputs, outputs )
{
Read & Pack base textures
for each decal in cell
{
early out fragment check
Read textures
Blend results
}
for each light in cell
{
early out fragment check
Compute BRDF / Apply Shadows
Accumulate lighting
}
}그림자는 아틀라스, PC(고사양)용 32비트 8k x 8k 아틀라스, 콘솔용 16비트 8k x 4k, 거리에 따른 가변 해상도, 거리에 따른 시간 분할, 정적 지오메트리 최적화 메시에 캐시/패킹됩니다. 광원이 움직이지 않으면 정적 지오메트리 섀도우 맵을 캐시하고, 프러스텀 내부에 업데이트가 없으면 건너뛰고, 업데이트가 없으면 동적 지오메트리를 캐시된 결과와 결합하고, 애니메이션(예: 깜박임)을 계속 사용할 수 있으며, 아트 설정/품질 설정이 위의 모든 항목에 영향을 줍니다. 그림자 프러스텀 투영 행렬에 대한 인덱스, 모든 조명 유형에 대한 동일한 PCF 조회 코드, VGPR 압력 감소, 병렬 조명 캐스케이드 포함, 캐스케이드 간 디더링 사용, 단일 단계 캐스케이드 조회, VSM 및 그 파생물 시도, 몇 가지 결함이 있고 개념적으로 래스터라이제이션에서 필터링 빈도를 분리하는 등 순방향 렌더링에 대한 좋은 잠재력이 있습니다.
조명 시 VGPR 압력에 주의하고, HDR 색상용 float4와 같은 수명이 긴 데이터 <--> RGBE 인코딩된 단위로 압축하고, 레지스터 수명을 최소화하고, 중첩된 루프/최악의 경우 경로를 최소화하고, 분기를 최소화하고, 콘솔(PS4)에서 56 VGRS, 컴파일러 비효율로 인해 PC에서 더 높습니다(@AMD 컴파일러 팀, 좋은 plz 수정 - 성능 저하). 반정밀도 지원은 미래에 도움이 될 것입니다. Nvidia: UBO/const 버퍼 사용(필요한 파티션 버퍼 = 더 많은/못생긴 코드), AMD: SSBO/UAV 우선 순위를 지정합니다.
대략적인 유리 근사치: 최대 절반 해상도 밉, 총 4 밉, 가우스 커널(대략 GGX 로브), 표면 매끄러움을 기반으로 한 혼합 밉, 성능 향상을 위해 프레임당 2로 제한되는 굴절 전송, 데칼을 통한 표면 매개변수화/변형.

후처리의 경우 데이터 읽기는 다음과 같이 최적화됩니다. 비발산 작업을 위한 GCN 스칼라 단위, 데이터 가져오기 속도 향상, VGRP 저장, 일관된 분기, 더 적은 명령어(SMEM: 64바이트, VMEM: 16바이트)에 이상적입니다. 각 픽셀이 자신이 속한 단위로부터 조명/데칼을 가져오는 클러스터형 셰이딩 사용 사례는 본질적으로 다르지만 분석할 가치가 있습니다.

대부분의 파면은 하나의 셀에만 들어갈 수 있으며 근처 셀은 대부분의 콘텐츠를 공유하며 스레드는 주로 동일한 데이터를 가져옵니다. 스레드 단위 데이터 수집은 최적이 아니며 이러한 데이터 융합을 활용하지 않습니다. 셀 내용에 대해 가능한 스칼라 반복을 결합하고 모든 스레드가 정확히 동일한 데이터를 독립적으로 가져오지 않도록 합니다.
액세스 패턴을 활용하세요. 데이터의 경우 각 셀에 대해 정렬된 항목 배열(라이트/데칼) ID, 동일한 구조가 라이트 및 데칼 처리에 적용됩니다. 각 스레드는 서로 다른 노드에 액세스할 수 있으며, 각 스레드는 이러한 배열에 대해 독립적으로 반복됩니다. 스칼라 로딩은 직렬화를 반복하고, 모든 스레드 중 최소 항목 ID 값을 계산하고, ds_swizzle_b32/작은 위치 불일치, 선택한 인덱스와 일치하는 스레드에 대한 항목을 처리하고, 균일 인덱스->스칼라 지시어, 일치하는 스레드가 다음 인덱스로 이동합니다.

특수 경로: 하나의 셀만 터치하는 경우 빠른 경로, GCN1 및 2에서는 저렴하지 않은 최소 항목 ID 계산 방지, 일부 추가(사소한) 스칼라 가져오기 및 작업, 직렬화는 스레드 간 지역성을 가정하고, 너무 많은 셀을 터치하면 상당한 속도 저하가 발생하고, 파티클 조명 아틀라스 생성이 비활성화됩니다.
동적 해상도 스케일링: GPU 로드에 따른 적응형 해상도(PS4에서는 대부분 100%, Xbox에서는 더 높음, 동일한 대상에서 렌더링, 뷰포트 크기 조정)
Intrusive: 추가 셰이더 코드가 필요하며 OpenGL에서만 옵션입니다. 미래: 콘솔과 Vulkan에서 여러 렌더 타겟을 겹쳐서 TAA는 비동기 계산에서 업샘플링하여 다양한 해상도에서 샘플을 수집할 수 있습니다.
비동기식 포스트 프로세스: 섀도우 및 깊이 프로세스는 계산 단위를 거의 사용하지 않으며 고정 그래픽 파이프라인이 무겁습니다. 불투명도 패스는 100% 사용되지 않으며 사후 처리와 겹칠 수 있습니다. 효과 대기열에서 미리 곱해진 알파가 있는 버퍼에서 GUI를 렌더링하고, 계산 대기열에서 사후 처리/AA/업샘플/구성 UI를 처리하고, 프레임 N+1의 그림자/깊이/불투명도와 겹치고, 계산 대기열(사용 가능한 경우)에서 표시하여 잠재적으로 대기 시간을 낮출 수 있습니다.
또한 이 기사에서는 GCN 아키텍처에 대한 특정 최적화도 다루고 있습니다. 향후 작업은 주파수 소비를 분해하여 이점을 얻고 텍스처 품질, 전역 조명, 전반적인 세부 사항, 작업 흐름 등을 개선하는 것입니다.

[주목해야 할 상위 5대 기술: 2017~2021](https://www.bizcommunity.com/Article/196/706/154305.html#:~:text= VR이 틈새 시장으로 남을 동안 주목해야 할 상위 5대 기술%3A 2017 to,commonplace%2C. More)에서는 2017년부터 2021년까지의 기술 동향과 신흥 기술에 대해 설명합니다. 통찰력을 얻는 데 도움이 될 5가지 기술:

가장 중요한 것은 인공지능과 인지기술이다. 다음 5가지 주요 기술은 빠른 상호 연결을 지원합니다.

모바일 엣지 컴퓨팅, 클라우드렛, 포그 컴퓨팅, 산업용 인터넷, SDN 및 OpenNFV가 포함됩니다. 엣지 컴퓨팅은 모든 사람에게 도움이 되지만 더 높은 수준의 기술이 필요합니다.
Remedy Northlight 엔진의 최신 그래픽 기술에서는 Remedy Northlight 엔진의 렌더링 기술의 엔진 내 구현과 DirectX 레이 트레이싱, 영역 그림자, 앰비언트 오클루전(AO), 반사, 간접 디퓨즈 등을 포함한 일부 최근 개발 결과에 대해 설명합니다.
실시간 Ray Tracing의 가시성 기반 알고리즘의 예는 다음과 같습니다.

AO에서 SSAO와 광 추적 AO의 비교는 다음과 같습니다.

다양한 rpps에 대한 조명 추적 AO의 효과도 다릅니다.

반사 측면에서 SSR과 광 추적 반사 사이에는 분명한 차이점이 있습니다.

AO와 유사한 간접 디퓨즈의 경우, 많은 불일치 광선, GI가 희박한 그리드 볼륨에 저장됩니다. 정적 기하학 및 정적 조명 세트를 기반으로 계산된 방사조도, 동적 기하학은 빛을 받을 수 있지만 계산된 방사조도에 영향을 주지 않습니다. 동적 기하학은 기여하지 않습니다. 삼선형 샘플링은 계단식 패턴을 생성하고 얇은 기하학은 빛 누출을 일으킬 수 있으며 조명은 코사인 분포에서 방사선을 샘플링하여 누락된 기하학을 고려하여 수집됩니다.

또한 기하학의 교차점에서 조명을 샘플링할 수도 있습니다. 최종 광추적 구성요소와 조합 효과는 다음과 같습니다.


요약하면, 최첨단 GPU 레이 트레이싱은 DXR을 통해 쉽게 접근할 수 있고, 성능은 목표에 도달하고, 래스터라이제이션에 적합하지 않은 알고리즘의 프로토타입을 쉽게 만들 수 있으며, 기존 저주파 아키텍처와 결합할 수 있습니다.

고급 그래픽 기술 튜토리얼: 'Claybook'의 GPU 기반 클레이 시뮬레이션 및 레이 트레이싱 기술은 Second Order의 첫 번째 게임인 Claybook에 대해 설명합니다. 이 게임에는 GPU 기반 클레이 및 유체 시뮬레이터, 완전히 변형 가능한 세계와 캐릭터, 지향성 거리 필드 모델링 및 레이 트레이싱 시각 효과를 비롯한 다양한 혁신적인 기술이 포함되어 있습니다. 현세대 콘솔에서 게임의 레이 트레이싱된 비주얼과 시뮬레이션을 통해 60fps를 달성하는 데 필요한 기술의 생성, 최적화 및 요령과 비표준 렌더러 및 시뮬레이션 기술이 Unreal Engine 4 위에 통합되는 방법에 대해 논의합니다.
지향 거리 필드(SDF): SDF(P) = P에서 가장 가까운 표면까지의 부호 있는 거리로, 분석 거리 함수와 볼륨 텍스처의 두 가지 형태로 사용 가능합니다. 분석적 거리 기능은 장면 데모, 거대한 셰이더, 많은 수학, 데이터가 없는 경우에 널리 사용됩니다. 볼륨 텍스처는 거리 함수, 삼선형 필터를 저장하고 Claybook은 밉 맵과 함께 볼륨 텍스처를 사용합니다. Claybook의 월드 SDF는 해상도 = 1024x1024x512, 형식 = 부호 있는 8비트, 크기 = 586MB(5 밉 레벨), [-4, +4] 복셀 거리, 256 값/8 복셀, 1/32 복셀 정밀도, 밉 레벨당 이중 최대 단계(월드 공간)를 갖습니다.
GPU에서 월드 SDF를 생성하는 단계:
- SDF 브러시 메쉬를 생성합니다. 64x64x32 디스패치, 4x4x4 스레드 그룹.
타일 중심 T에서 브러시 볼륨을 샘플링합니다. SDF > 래스터 타일 경계 + 4복셀인 경우 컬링합니다. 승인되면 GSM에 원자적으로 추가 + 저장합니다.
- GSM에서 브러시를 순환합니다. 허용되는 경우 셀 중심 C의 샘플[i]는 그리드(선형), 로컬 + 전역 원자 압축에 저장됩니다.

- 일정 좌표를 생성합니다. 64x64x32 스케줄링, 4x4x4 스레드 그룹.
브러시 그리드 셀을 읽습니다.
- 비어 있지 않은 경우: 쓰기 인덱스를 얻기 위한 원자 추가(L+G), 셀 좌표를 버퍼에 씁니다.

- 밉 마스크를 생성합니다. 4x 스케줄링(mips), 4x4x4 스레드 그룹.
그룹화: 1개의 더 넓은 복셀 그리드 L-1 이웃을 로드하고 1=0 마스크를 다운샘플링하여 GSM에 저장합니다.
마스크를 1복셀(3x3x3)씩 확대합니다.
Mask=0은 그리드 셀 좌표를 씁니다.
8x8x8 타일에서 레벨 0(희소)을 생성합니다. 간접 스케줄링, 8x8 스레드 그룹.
그룹화: 그리드 셀 좌표(SV_GroupId)를 읽습니다.
그리드에서 브러시를 읽고 GSM에 저장합니다.
GSM, 샘플[i]의 브러시 루프를 통해 exp 평활화 최소/최대 작업을 수행합니다.
WorldSDF의 레벨 0에 복셀을 씁니다.
밉(희소)을 생성합니다. 4x 간접 스케줄링(mips), 8x8 스레드 그룹.
그룹화: 더 넓은 L-1 이웃의 복셀 4개를 로드합니다. 2x2x2 다운샘플링(평균)이며 GSM에
그룹화: GSM(아래)에서 3단계 에이코날 방정식을 실행합니다. 확장 순서: 2복셀이 4복셀이 됩니다.
8x8x8 동네의 중심을 저장하세요.

구형 추적 알고리즘:
D = SDF(P).
P += 광선 * D.
(D < 엡실론)인 경우 중단됩니다.

다층 볼륨 텍스처 추적:
Loop
D = volume.SampleLevel(origin + ray*t, mip)
t += worldDistance(D, mip)
IF D == 1.0 -> mip += 2
IF D <= 0.25 -> mip -= 2; D -= halfVoxel
IF D < pixelConeWidth * t -> BREAK
// 만약 픽셀(Pixel),이면 인터럽트 ,의 LOD!마지막 단계: 구 추적은 수렴하기 위해 무한한 단계가 필요합니다. 평면, 삼선형 필터링 = 조각별 선형 표면, 기하 계열, 마지막 두 샘플

콘 추적의 분석 솔루션:

대략적인 원뿔 추적 프리패스:

레이 트레이싱 결과: 원뿔 추적은 빈 공간의 넓은 영역을 건너뛰고 단계 크기를 크게 줄이며 볼륨 샘플링에서 더 많은 캐시 지역성을 제공합니다. 밉 매핑은 캐시 지역성, Log8 데이터 스케일링을 향상시킵니다: 100%, 12.5%, 1.6%, 0.2%,... 측정됨(1080p 렌더링), 8MB 데이터 액세스(512MB), 99.85% 캐시 적중률. 기존 문제에는 과도한 스테핑, 로드 밸런싱 등이 있으며 자체 완화 계획이 있습니다.
AO의 경우 표면 노멀 방향으로 원뿔을 구성하고 무작위 변형 + 시간 누적을 추가합니다. AO 광선은 낮은 SDF 밉, 더 나은 GPU 캐시 위치 및 더 적은 대역폭, 소프트 원격 AO를 사용합니다. Claybook은 UE4 SSAO, 소규모(거의) 앰비언트 오클루전(AO)도 사용합니다.

상위: SSAO; 하단: SSAO + RTAO.
부드러운 그림자 구 추적: 부드러운 반그림자 확장 그림자, 광선에 따른 단계 SDF 근사 최대 원뿔 범위, 데모씬 원뿔 범위 근사:
c = min(c, light_size * SDF(P) / time);
부드러운 그림자에 대한 클레이북 개선: 가장 가까운 거리의 삼각 측량, Demoscene=단일 샘플(최소), 현재 및 이전 샘플의 삼각 측량, 밴딩 감소. 디더링된 그림자 조명, UE4 시간 누적, 남은 밴딩 아티팩트 숨기기, 더 넓은 내부 반그림자.

개선 전후 비교:

가벼운 추적에 소요되는 시간:

SDF에서 메시로의 변환: 2채널 근사화, 여러 삼각형이 동일한 입자를 가리키고, 입자를 먼저 생성해야 합니다. PBD 시뮬레이터를 위한 선형 입자 배열(표면) 및 삼각형 렌더링을 위한 인덱스 버퍼를 출력합니다. 단일 간접 그리기 호출을 사용하여 그려진 모든 메시입니다. 입자로 변환하려면 64x64x64 디스패치 및 4x4x4 스레드 그룹을 사용하십시오. 프로세스는 다음과 같습니다.
그룹화:
SDF 이웃을 GSM에 로드합니다. 가장자리 내부/외부에서 발견된 경우
GSM의 이웃을 읽습니다.
P를 표면으로 이동합니다(경사하강법).
입자 ID를 할당합니다(L+G 원자).
배열[id]에 P를 씁니다.
입자 ID를
그리드에 씁니다.
64x64x64 디스패치 및 4x4x4 스레드 그룹을 사용하여 삼각형으로 변환합니다. 프로세스는 다음과 같습니다.
그룹화:
SDF 이웃을 GSM에 로드합니다. XYZ 에지가 발견되면
GSM 근처를 읽습니다.
각 XYZ 변에는 삼각형(L+G 원자)의 2배가 할당됩니다.
의 id 그리드에서 입자 ID를 3번 읽습니다. 인덱스 버퍼에 삼각형을 씁니다(3x 입자 ID).
비동기식 계산:
- 프레임을 3개의 비동기 세그먼트로 분할합니다.
UE4의 GBuffer와 섀도우 캐스케이드가 겹칩니다.
UE4의 속도 렌더링 및 깊이 압축 해제를 오버레이합니다.
UE4용 오버레이 조명 및 포스트 프로세스.
작품은 즉시 제출됩니다.
펜스 시작(x3)을 기다리는 컴퓨팅 큐.
- 펜스 연속을 기다리는 메인 큐(x3).

비동기식 계산은 fps를 19% 이상 증가시킬 수 있습니다.
UE4 렌더러에 통합됨:
- GBuffer 조합.
전체 화면 PS 결합 레이 트레이싱 데이터.
샘플링 재료 맵(사용자 정의 Gather4 필터링).
UE4의 GBuffer+깊이 버퍼(SV_Depth)에 씁니다.
섀도우 마스크 조합.
전체 화면 PS에서 구체 추적 그림자까지.
- UE4 섀도우 마스크 버퍼에 쓰기(알파 블렌딩 사용)
UE4 RHI 커스터마이징:
- 암시적 동기화 없이 렌더 대상을 설정합니다.
겹치는 깊이/색상을 압축 해제할 수 있습니다.
드로잉은 여러 RT에 겹쳐질 수 있습니다(아래 이미지).
암시적 동기화 없이 RT/버퍼를 지웁니다.
비동기 계산 기능이 누락되었습니다.
버퍼/텍스처 복사 및 삭제.
- 셰이더 인덱스 버퍼 쓰기를 계산합니다.

UE4 RHI 사용자 정의(추가): GPU->CPU 버퍼 리드백, UE4는 지연 없이 2D 텍스처 리드백만 지원하고, 다른 리드백 API는 전체 GPU를 지연시키며, 버퍼는 원본 뷰와 유형화된 뷰를 가질 수 있습니다. 넓은 원시 쓰기 = 좁은 유형 버퍼를 효율적으로 채웁니다.
UE4 최적화: 간접 디스패치/가져오기의 겹침 허용, 지우기 및 복사 작업의 겹침 허용, 서로 다른 RT 그리기의 겹침 허용, GPU 캐시 플러시 및 지연 감소(아래), 최적화된 스테이징 버퍼, 빠르고 명확한 개선. 최적화된 장벽 및 울타리, 최적화된 텍스처 배열 하위 리소스 장벽, 3D 텍스처를 위한 향상된 GPU 타일링 모드, 향상된 부분 2D/3D 텍스처 업데이트, 5배 더 빠른 히스토그램 + 눈 적응형 셰이더, 4배 더 빠른 오프라인 CPU SDF 생성기(베이킹).

구현 참고 사항: 대규모 원시 버퍼에 저장된 물리 데이터, 넓은 로드 4/Store4 명령(16바이트), 비트 압축: 입자 위치: 16비트 표준, 입자 속도: fp16, 입자 플래그(활동, 충돌 등)에 대한 비트 필드, 벤치마크 도구: https://github.com/sebbbi/perftest. 그룹 공유 메모리는 SDF 생성, 메쉬 생성, 물리학 및 동일한 데이터를 반복적으로 로드할 때 사용되는 거대한 성능 도구입니다. 스칼라 로딩은 AMD의 성능상 큰 승리입니다. 사용 사례: 일정한 인덱스 원시 버퍼 로드, 사용 사례: SV_GroupID를 기반으로 하는 원시 버퍼 로드, SGPR에 저장된 로드가 더 나은 점유율을 얻습니다.
Unity의 엔터티 컴포넌트 시스템 및 데이터 지향 디자인은 객체 지향 디자인, 데이터 지향 디자인, 엔터티 컴포넌트 시스템, 실제 사례 등을 포함하여 Unity의 ECS 및 데이터 지향 디자인 기술을 공유합니다. OO의 일반적인 구현: 클래스 계층 구조, 가상 기능, 캡슐화는 "한 번에 한 가지 작업을 수행"하는 접근 방식, 늦은 결정을 알아야 하기 때문에 위반되는 경우가 많습니다. 간단한 OO 컴포넌트 시스템:
// Component base class. Knows about the parent game object, and has some virtual methods.
class Component
{
public:
Component() : m_GameObject(nullptr) {}
virtual ~Component() {}
virtual void Start() {}
virtual void Update(double time, float deltaTime) {}
const GameObject& GetGameObject() const { return *m_GameObject; }
GameObject& GetGameObject() { return *m_GameObject; }
void SetGameObject(GameObject& go) { m_GameObject = &go; }
private:
GameObject* m_GameObject;
};
class GameObject
{
public:
GameObject(const std::string&& name) : m_Name(name) { }
~GameObject()
{
for (auto c : m_Components)
delete c;
}
// get a component of type T, or null if it does not exist on this game object
template<typename T> T* GetComponent()
{
for (auto i : m_Components)
{
T* c = dynamic_cast<T*>(i);
if (c != nullptr)
return c;
}
return nullptr;
}
// add a new component to this game object
void AddComponent(Component* c)
{
c->SetGameObject(*this);
m_Components.emplace_back(c);
}
void Start()
{
for (auto c : m_Components)
c->Start();
}
void Update(double time, float deltaTime)
{
for (auto c : m_Components)
c->Update(time, deltaTime);
}
private:
std::string m_Name;
ComponentVector m_Components;
};
// Utilities
// Finds all components of given type in the whole scene
template<typename T>
static ComponentVector FindAllComponentsOfType()
{
ComponentVector res;
for (auto go : s_Objects)
{
T* c = go->GetComponent<T>();
if (c != nullptr) res.emplace_back(c);
}
return res;
}
// Find one component of given type in the scene (returns first found one)
template<typename T>
static T* FindOfType()
{
for (auto go : s_Objects)
{
T* c = go->GetComponent<T>();
if (c != nullptr) return c;
}
return nullptr;
}
// various components
// 2D position: just x,y coordinates
struct PositionComponent : public Component
{
float x, y;
};
// Sprite: color, sprite index (in the sprite atlas), and scale for rendering it
struct SpriteComponent : public Component
{
float colorR, colorG, colorB;
int spriteIndex;
float scale;
};
// Move around with constant velocity. When reached world bounds, reflect back from them.
struct MoveComponent : public Component
{
float velx, vely;
WorldBoundsComponent* bounds;
MoveComponent(float minSpeed, float maxSpeed)
{
/* … */
}
virtual void Start() override
{
bounds = FindOfType<WorldBoundsComponent>();
}
virtual void Update(double time, float deltaTime) override
{
/* … */
}
};
// components logic
virtual void Update(double time, float deltaTime) override
{
// get Position component on our game object
PositionComponent* pos = GetGameObject().GetComponent<PositionComponent>();
// update position based on movement velocity & delta time
pos->x += velx * deltaTime;
pos->y += vely * deltaTime;
// check against world bounds; put back onto bounds and mirror
// the velocity component to "bounce" back
if (pos->x < bounds->xMin) { velx = -velx; pos->x = bounds->xMin; }
if (pos->x > bounds->xMax) { velx = -velx; pos->x = bounds->xMax; }
if (pos->y < bounds->yMin) { vely = -vely; pos->y = bounds->yMin; }
if (pos->y > bounds->yMax) { vely = -vely; pos->y = bounds->yMax; }
}
// game update loop
void GameUpdate(sprite_data_t* data, double time, float deltaTime)
{
// go through all objects
for (auto go : s_Objects)
{
// Update all their components
go->Update(time, deltaTime);
// For objects that have a Position & Sprite on them: write out
// their data into destination buffer that will be rendered later on.
PositionComponent* pos = go->GetComponent<PositionComponent>();
SpriteComponent* sprite = go->GetComponent<SpriteComponent>();
if (pos != nullptr && sprite != nullptr)
{
/* … emit data for sprite rendering … */
}
}
}OO 디자인의 문제: 코드를 어디에 넣을 것인가? 게임의 많은 시스템은 충돌, 손상, AI와 같은 "하나의 개체"에 속하지 않습니다. 2개 이상의 개체에서 작업합니다. 게임 내 "엘프 회피 거품": 무언가를 피하는 데 회피 논리를 적용한다고요? 피해야 할 일에 회피논리를 얹는다? 다른 곳? 많은 언어가 "단일 디스패치"이고 이에 작동하는 개체와 메서드가 있지만 우리에게 필요한 것은 회피 시스템이 두 개체 세트에서 작동하는 "다중 디스패치"입니다.
OO 디자인의 문제점: 무엇이 무엇인지 알기가 어렵습니다. Unity 프로젝트를 시작하고 그것이 어떻게 작동하는지 알아내려고 노력한 적이 있습니까? "게임 로직"은 수백만 개의 구성 요소에 분산되어 있으며 개요가 없습니다.
OO 디자인 문제: "지저분한 기본 클래스" 문제:
EntityType entityType() const override;
void init(World* world, EntityId entityId, EntityMode mode) override;
void uninit() override;
Vec2F position() const override;
Vec2F velocity() const override;
Vec2F mouthPosition() const override;
Vec2F mouthOffset() const;
Vec2F feetOffset() const;
Vec2F headArmorOffset() const;
Vec2F chestArmorOffset() const;
Vec2F legsArmorOffset() const;
Vec2F backArmorOffset() const;
// relative to current position
RectF metaBoundBox() const override;
// relative to current position
RectF collisionArea() const override;
void hitOther(EntityId targetEntityId, DamageRequest const& damageRequest) override;
void damagedOther(DamageNotification const& damage) override;
List<DamageSource> damageSources() const override;
bool shouldDestroy() const override;
void destroy(RenderCallback* renderCallback) override;
Maybe<EntityAnchorState> loungingIn() const override;
bool lounge(EntityId loungeableEntityId, size_t anchorIndex);
void stopLounging();
float health() const override;
float maxHealth() const override;
DamageBarType damageBar() const override;
float healthPercentage() const;
float energy() const override;
float maxEnergy() const;
float energyPercentage() const;
float energyRegenBlockPercent() const;
bool energyLocked() const override;
bool fullEnergy() const override;
bool consumeEnergy(float energy) override;
float foodPercentage() const;
float breath() const;
float maxBreath() const;
void playEmote(HumanoidEmote emote) override;
bool canUseTool() const;
void beginPrimaryFire();
void beginAltFire();
void endPrimaryFire();
void endAltFire();
void beginTrigger();
void endTrigger();
ItemPtr primaryHandItem() const;
ItemPtr altHandItem() const;
// … etc.OO 디자인의 문제점: 성능. 1백만 개의 스프라이트, 20개의 버블: 330ms 게임 업데이트, 470ms 시작 시간, 메모리에 분산된 데이터, 가상 함수 호출.
OO 디자인 문제: 메모리 사용. 1백만 개의 스프라이트, 20개의 버블: 310MB 메모리 사용량, 각 구성 요소에는 게임 개체에 대한 포인터가 있지만 이를 필요로 하는 사람은 거의 없습니다. 각 구성 요소에는 가상 함수 테이블에 대한 포인터가 있으며, 각 게임 개체/구성 요소는 개별적으로 할당됩니다. 일반적인 메모리 보기:

OO 디자인의 문제점: 최적화가 가능합니다. 멀티스레드하는 방법? GPU에서 실행하는 방법은 무엇입니까? 많은 OO 디자인에서는 매우 어렵습니다. 누가 어떤 데이터를 읽고 어떤 데이터를 쓰는지 명확하지 않습니다.
OO 설계 관련 문제: 테스트 가능성. 이에 대한 테스트를 어떻게 작성하시겠습니까? OO 설계에는 테스트, 개체 계층 구조, 관리자, 어댑터, 싱글톤 생성 등을 위해 많은 설정/모의/위조가 필요한 경우가 많습니다.
CPU 성능 추세:

CPU-메모리 성능 격차:

컴퓨터의 지연 시간 데이터:
CPU L1 캐시에서 읽기: 0.5ns.
분기 예측 실패: 5ns.
CPU L2 캐시에서 읽기: 7ns.
RAM에서 읽기: 100ns.
SSD에서 읽기: 150000ns.
RAM에서 1MB 읽기: 250000ns.
네트워크 패킷 CA->NL->CA: 150000000ns를 보냅니다.
코드와 데이터를 결합해야 합니까? 일반적인 OO는 코드와 데이터를 클래스에 넣는 이유는 무엇입니까? "코드를 어디에 넣을 것인가"라는 질문을 떠올려 보세요:
// this?
class ThingThatAvoids
{
void AvoidOtherThing(ThingToAvoid* thing);
};
// or this?
class ThingToAvoid
{
void MakeAvoidMe(ThingThatAvoids* who);
};
// why not this instead? does not even need to be in a class
void DoAvoidStuff(ThingThatAvoids* who, ThingToAvoid* whom);데이터 우선: "모든 프로그램과 그 모든 부분의 목적은 데이터를 한 형식에서 다른 형식으로 변환하는 것입니다.", "데이터를 이해하지 못하면 문제를 이해하지 못하는 것입니다" – Mike Acton. 이 책은 Nicklaus Wirth의 1976년 고전 책입니다. "데이터 구조"가 먼저 와야 한다고 말할 수도 있지만, "객체"에 대해서는 전혀 언급하지 않는다는 점에 유의하세요!
하나가 있으면 여러 개가 있습니다. 얼마나 자주 뭔가를 먹나요? 게임에서 가장 일반적인 상황은 다음과 같습니다. 몇 가지 사항이 있고 여기에는 어떤 코드라도 사용할 수 있으며 너무 많아서 성능에 주의해야 합니다.
virtual void Update(double time, float deltaTime) override
{
/* move one thing */
}
// 의
void UpdateAllMoves(size_t n, GameObject* objects, double time, float deltaTime)
{
/* move all of them */
}데이터 지향 설계(DOD): 이 문제를 해결하기 위해 데이터를 이해하는 데 필요한 이상적인 데이터는 무엇입니까? 어떻게 정리되어 있나요? 누가 무엇을 읽고, 누가 무엇을 쓰는가? 데이터의 패턴은 무엇입니까? 일반적인 경우 디자인에서는 "하나"가 거의 없습니다. 그런데 코드가 한 번에 하나만 처리하는 이유는 무엇입니까? 국방부 관련 리소스:
데이터 지향 디자인(또는 OOP를 사용하여 자신을 곤경에 빠뜨릴 수 있는 이유) 블로그 게시물, Noel Llopis
데이터 지향 디자인 슬라이드의 실제 사례, Niklas Gray
데이터 지향 설계 및 C++ 동영상, Mike Acton
일반적인 C++ 헛소리 슬라이드 갤러리, Mike Acton
데이터 지향 디자인 블로그 게시물 및 링크, Adam Sawicki
기존 Unity GO/컴포넌트 설정은 ECS입니까? 기존 Unity 설정에서는 구성 요소를 사용하지만 ECS는 사용하지 않습니다. 구성 요소는 "지옥의 기본 클래스" 문제 중 일부를 해결하지만 다른 문제는 해결하지 않습니다. 논리, 데이터 및 코드 흐름은 추론하기 어렵고 논리는 한 유형/클래스 내에서 한 번에 한 가지(업데이트 등)에 대해서만 수행되며("코드를 넣을 위치" 문제) 메모리/데이터 지역성은 그다지 좋지 않으며 여러 가상 호출 및 포인터가 필요합니다.
ECS(엔티티 구성 요소 시스템): 엔터티는 데이터베이스의 "기본 키"와 같은 일종의 식별자일 뿐입니다. 예. 구성 요소는 데이터입니다. 시스템은 특정 구성 요소 집합이 있는 엔터티에서 작동하는 코드입니다.
ECS/DOD 예: 간단한 "게임"을 떠올려 보세요. 코드 400줄, 스프라이트 1백만 개, 버블 20개: 업데이트 시간 330ms, 시작 시간 470ms, 메모리 사용량 310MB.

1단계: 어리석음을 바로잡습니다. GetComponent는 GO에서 구성 요소를 검색하여 매번 한 번 찾아서 저장할 수 있습니다! 330ms → 309ms.

GetComponent는 이를 캐시하는 회피 구성 요소의 내부 루프에 있습니다. 309ms → 78ms.

지금은 어디에 시간을 보내고 있나요? 프로파일러 사용(Mac의 Xcode Instruments):

몇 가지 시스템을 만들어 보겠습니다. 회피 시스템, 회피 및 회피 이제 이러한 구성 요소는 거의 데이터일 뿐이며 시스템은 작동할 모든 것을 알고 있습니다.
struct AvoidThisComponent : public Component
{
float distance;
};
// Objects with this component "avoid" objects with AvoidThis component.
struct AvoidComponent : public Component
{
virtual void Start() override;
};
// "Avoidance system" works out interactions between objects that have AvoidThis and Avoid
// components. Objects with Avoid component:
// - when they get closer to AvoidThis than AvoidThis::distance, they bounce back,
// - also they take sprite color from the object they just bumped into
struct AvoidanceSystem
{
// things to be avoided: distances to them, and their position components
std::vector<float> avoidDistanceList;
std::vector<PositionComponent*> avoidPositionList;
// objects that avoid: their position components
std::vector<PositionComponent*> objectList;
void UpdateSystem(double time, float deltaTime)
{
// go through all the objects
for (size_t io = 0, no = objectList.size(); io != no; ++io)
{
PositionComponent* myposition = objectList[io];
// check each thing in avoid list
for (size_t ia = 0, na = avoidPositionList.size(); ia != na; ++ia)
{
float avDistance = avoidDistanceList[ia];
PositionComponent* avoidposition = avoidPositionList[ia];
// is our position closer to "thing to avoid" position than the avoid distance?
if (DistanceSq(myposition, avoidposition) < avDistance * avDistance)
{
/* … */
}
}
}
}
};위는 시스템의 로직 코드이다. 78ms → 69ms. 마찬가지로 MoveSystem이라는 이동 시스템을 만들어 보겠습니다.
// Move around with constant velocity. When reached world bounds, reflect back from them.
struct MoveComponent : public Component
{
float velx, vely;
};
struct MoveSystem
{
WorldBoundsComponent* bounds;
std::vector<PositionComponent*> positionList;
std::vector<MoveComponent*> moveList;
void UpdateSystem(double time, float deltaTime)
{
// go through all the objects
for (size_t io = 0, no = positionList.size(); io != no; ++io)
{
PositionComponent* pos = positionList[io];
MoveComponent* move = moveList[io];
// update position based on movement velocity & delta time
pos->x += move->velx * deltaTime;
pos->y += move->vely * deltaTime;
// check against world bounds; put back onto bounds and mirror the velocity component to "bounce" back
if (pos->x < bounds->xMin) { move->velx = -move->velx; pos->x = bounds->xMin; }
if (pos->x > bounds->xMax) { move->velx = -move->velx; pos->x = bounds->xMax; }
if (pos->y < bounds->yMin) { move->vely = -move->vely; pos->y = bounds->yMin; }
if (pos->y > bounds->yMax) { move->vely = -move->vely; pos->y = bounds->yMax; }
}
};위는 모바일 시스템의 로직인데, 69ms → 83ms, 뭐! ! ! ? ? ? 다시 분석해 보세요.

지금까지 배운 교훈: 한 곳을 최적화하면 예상치 못한 이유로 인해 CPU, 캐시, 프리페칭 등의 순서가 잘못되어 작업 속도가 느려질 수 있습니다. C++ RTTI(dynamic_cast)는 매우 느릴 수 있으므로 GameObject::GetComponent에서 사용합니다.
// get a component of type T, or null if it does not exist on this game object
template<typename T> T* GetComponent()
{
for (auto i : m_Components)
{
T* c = dynamic_cast<T*>(i);
if (c != nullptr)
return c;
}
return nullptr;
}그런 다음 C++ RTTI 사용을 중지하세요. "유형" 열거형이 있고 각 구성 요소가 유형을 저장하는 경우... 83ms → 54ms! !
enum ComponentType
{
kCompPosition,
kCompSprite,
kCompWorldBounds,
kCompMove,
kCompAvoid,
kCompAvoidThis,
};
// ...
ComponentType m_Type;
// was: T* c = dynamic_cast<T*>(i); if (c != nullptr) return c;
if (c->GetType() == T::kTypeId) return (T*)c;지금까지의 성능 업데이트: 6배 향상(330ms → 54ms)! 메모리 사용량: 310MB → 363MB 증가, 구성 요소 포인터 캐시, 각 구성 요소의 유형 ID... 코드 줄: 400+ 줄 → 500, 뭔가를 제거해 보겠습니다!
피하고 피하십시오. 이 구성 요소는 누구에게 필요합니까? 맞습니다. 아무도 없습니다. 회피 시스템을 사용하여 개체를 등록하면 됩니다. 54ms → 46ms, 363MB → 325MB, 500 → 455라인.

현실적으로 구성 요소 계층 구조가 필요한 사람은 누구입니까? GameObject에 구성 요소 필드를 포함시키면 됩니다. 46ms → 43ms 업데이트, 398 → 112ms 시작 시간, 325MB → 218MB, 455 → 350줄.
// each object has data for all possible components,
// as well as flags indicating which ones are actually present.
struct GameObject
{
GameObject(const std::string&& name)
: m_Name(name), m_HasPosition(0), m_HasSprite(0), m_HasWorldBounds(0), m_HasMove(0) { }
~GameObject() {}
std::string m_Name;
// data for all components
PositionComponent m_Position;
SpriteComponent m_Sprite;
WorldBoundsComponent m_WorldBounds;
MoveComponent m_Move;
// flags for every component, indicating whether this object "has it"
int m_HasPosition : 1;
int m_HasSprite : 1;
int m_HasWorldBounds : 1;
int m_HasMove : 1;
};단일 게임 객체 할당을 중지합니다. 벡터<GameObject*> → 벡터<GameObject>, 43ms에 업데이트되고 112→99ms, 218MB→203MB에 시작됩니다.

일반적인 레이아웃은 AoS(Array of Structures)입니다. 즉, 일부 개체와 그 배열입니다. 이해하고 관리하기 쉽습니다. 각 개체에 대한 모든 데이터가 필요한 경우 좋습니다.
// structure
struct Object
{
string name;
Vector3 position;
Quaternion rotation;
float speed;
float health;
};
// array of structures
vector<Object> allObjects;메모리에 있는 데이터는 어떤 모습인가요?
struct Object // 60 bytes:
{
string name; // 24 bytes
Vector3 position; // 12 bytes
Quaternion rotation; // 16 bytes
float speed; // 4 bytes
float health; // 4 bytes
};
모든 데이터가 필요하지 않으면 어떻게 되나요? 우리 시스템이 물체의 위치와 속도만 필요하다면... CPU여, 첫 번째 물체의 위치를 읽어보세요(아래 그림, 위)! 물론, 바로 여기... 메모리에서 전체 캐시 라인을 읽을 수 있도록 도와드리겠습니다(아래 하단 이미지)!

시스템에 객체의 위치와 속도만 필요하지만 결국 메모리에서 모든 것을 읽게 되지만 각 객체에는 60바이트 중 16바이트만 필요하다면 이는 낭비되는 메모리 트래픽의 **74%**에 해당합니다!
뒤집기: 배열 구조(SoA). 각 데이터 멤버마다 별도의 배열이 있고 배열을 동기화 상태로 유지해야 하며 "객체"는 더 이상 존재하지 않습니다. 데이터는 인덱스를 통해 액세스됩니다.
// structure of arrays
struct Objects
{
vector<string> names; // 24 bytes each
vector<Vector3> positions; // 12 bytes each
vector<Quaternion> rotations; // 16 bytes each
vector<float> speeds; // 4 bytes each
vector<float> healths; // 4 bytes each
};메모리에 있는 데이터는 어떤 모습인가요?
struct Objects
{
vector<string> names; // 24 bytes each
vector<Vector3> positions; // 12 bytes each
vector<Quaternion> rotations; // 16 bytes each
vector<float> speeds; // 4 bytes each
vector<float> healths; // 4 bytes each
};
SoA에서 부분 데이터 읽기: 시스템에 객체의 위치와 속도만 필요한 경우... CPU, 첫 번째 객체의 위치를 읽어보세요! (아래 그림). 물론이죠. 바로 여기... 메모리에서 전체 캐시 라인을 읽을 수 있도록 도와드리겠습니다! (해설) 그래서 다음 4개 객체의 위치도 CPU 캐시로 읽어옵니다(아래 그림 하단).

SoA 데이터 레이아웃 변환: 매우 일반적이지만 과용하지 않도록 주의하세요! 경우에 따라 개별 배열의 수가 구조 배열(SoAo 등)의 구조에 역효과를 가져올 수 있습니다.
구성 요소 데이터의 SoA 레이아웃으로 돌아갑니다. 더 이상 게임 개체 클래스가 아니라 EntityID일 뿐입니다. 43ms→31ms 업데이트, 99→94ms 시작, 350→375줄.
// "ID" of a game object is just an index into the scene array.
typedef size_t EntityID;
// /* … */
// names of each object
vector<string> m_Names;
// data for all components
vector<PositionComponent> m_Positions;
vector<SpriteComponent> m_Sprites;
vector<WorldBoundsComponent> m_WorldBounds;
vector<MoveComponent> m_Moves;
// bit flags for every component, indicating whether this object "has it"
vector<int> m_Flags;결과: 100만 개의 스프라이트, 20개의 버블: 330ms → 31ms 업데이트 시간, 10배 더 빨라졌습니다! 470ms → 94ms 기동시간, 5배 빨라졌습니다! 310MB → 203MB 메모리 사용량, 100MB 절약! 400 → 375줄의 코드, 코드는 더욱 작아집니다! 우리는 아직 스레딩, SIMD를 시작하지도 않았습니다…
'에이전트 오브 메이헴'의 렌더링 기술은 주제 OIT, 조명 계산, 글로벌 일루미네이션 등을 포함하여 에이전트 오브 메이헴 게임에서 사용된 렌더링 기술을 공유합니다.
OIT에서 이전 트랜스루센트 렌더링은 CPU에서 알파를 뒤에서 앞으로 정렬했으며, 정렬된 알파 수가 많으면 CPU 렌더링이 비효율적이며, 픽셀 대신 "객체"로 정렬되고, 점프를 정렬하고, 저해상도 알파가 고해상도 알파로 정렬되지 않음을 의미했습니다. 해결책: OIT? 그러나 많은 OIT 기술은 GPU에서는 비효율적입니다. **가중 혼합 OIT(WBOIT)**를 시도해 볼 수 있습니다.

가중치 블렌딩 OIT의 이점은 CPU 비용이 역전된다는 것입니다. 이제 알파는 깊이 대신 렌더 상태(예: 재질/셰이더)별로 정렬할 수 있고, GPU에서 효율적이며, 알파 셰이더에 일부 수학이 추가되고, 간단한 전체 화면 합성 단계, 저해상도 및 고해상도 알파가 원활하게 정렬되고 점프하지 않으며, 정렬 문제가 너무 복잡하지 않고 원활하게 전환됩니다. 단점은 어디에나 마법의 숫자가 있고 매우 불투명한 알파는 제대로 수행되지 않으며 항상 "잘못"된다는 것입니다. 가중 혼합 OIT는 순서 혼합 대신 가중 평균을 사용합니다.

가중치 함수(McGuire)의 가중치는 가중치가 높고 적용 범위가 높으며 가중치가 개체 자체에 더 가까운 "마법의" 데이터입니다.

자체 조명 알파가 주요 문제입니다. 동일한 자체 조명 알파 값 E를 갖는 n개의 레이어를 고려할 수 있습니다.

주요 아이디어: 더 많은 정보를 축적합니다. "가산성" ≒ 추가된 레이어 수, 가산성을 통해 가중 평균을 증폭합니다. 새로운 WBOIT의 시각적 요약:

WBOIT의 공식과 가산성은 다음과 같이 설명됩니다.

새로운 조합 방법:

가중치 기능 및 자체 조명: 순수 자체 조명 Alpha는 불투명도가 0이므로 가중치 계산 시 자체 조명이 포함되어야 하며 가중치 0이 허용되어야 합니다.

구현: 2개의 RT로 구성된 간단한 MRT 설정. 두 번째 MRT는 알파 채널에 대한 별도의 블렌딩 컨트롤을 사용하여 R 채널에 평균을 저장하고 알파 채널에 가산도를 저장합니다.
조명 측면에서 다중 조명 모델(모두 PBR), PCF 그림자, 가변 반그림자 그림자(PCSS), 투사된 텍스처, 질감 있는 이미터 영역 조명, 투광 조명, "현실적인" 튜브 조명, 정사각형 또는 원형 스포트라이트, 검정색(네거티브 라이트), 라이트 클리핑 평면, 라이트 오클루전 및 포털과 같은 많은 (비싼) 조명 기능이 구현되었습니다. 빛 누출은 표준 솔루션에서 흔히 발생하는 문제입니다.

조명 폐색 몸체를 사용하고 유한한 조명 클리핑 평면을 사용합니다.


작동 원리는 폐색기 "그림자" 프러스텀(아래 그림 왼쪽)에서 타일을 제거하고 각 조명에 대해 픽셀별로 확인해야 하는 마스크를 나열하는 것입니다(아래 그림 오른쪽).


구현된 순서도 개요:

GI 측면에서는 LPV를 사용하여 빛 폐색 효과를 개선하고, 실내에서는 고정된 로컬 볼륨을 사용하므로 품질이 향상되고 매 프레임마다 주입 및 전파가 필요하지 않습니다. 이전 LPV 광 폐색에는 광 오버플로의 거친 이산화 및 형상 누락과 같은 문제가 있었습니다.

그럼에도 불구하고 차단기를 배치하는 아티스트는 GI에도 사용될 수 있습니다!

전파 중 폐색체: 광 폐색체가 볼륨에 주입되면 "축" 폐색(각 축을 따른 폐색량)으로 저장됩니다. 전파 과정에서 빛을 차단하고 GI "그림자"(아래 그림 왼쪽)를 생성합니다. 4x4x4 매크로 셀의 경우 광 차단체를 제거하여 각 LPV 셀에서 고려되는 차단체 세트를 줄입니다. 적용 과정에서 삼선형 샘플링의 조명이 차단되고 러프 그리드에서 빛 누출이 제거됩니다(아래 오른쪽 그림).

개발 중 엔진 재구축: 'Mafia III'의 교훈은 게임 Mafia III에 사용된 엔진을 재구축하면서 배운 과정, 기술, 교훈을 공유합니다. 이 엔진 리팩토링의 목표는 대용량 데이터를 처리할 수 있는 사용하기 쉬운 도구, 데이터 기반, 주요 변경 사항은 새로운 세계 편집, 새로운 개체 시스템, 빌드 시스템, 로컬 반복, 시각적 스크립팅, 미들웨어 통합, 물리, 애니메이션, 탐색, 사용자 인터페이스, 오디오 등입니다.
새로운 세계 편집기는 C#/WPF 및 DevExpress의 새로운 도구를 사용하고, 이전 편집기 플러그인을 새 편집기에 통합하며, 엔진 통신에 C++/CLI를 사용하여 사용자가 최대한 빨리 참여할 수 있도록 합니다.
새로운 개체 시스템에는 자산 및 파일 관리, 상속 및 그룹화, 콘텐츠 작성자 권한 부여 등이 포함됩니다. 자산 및 파일 관리의 목표는 쉽게 종속성을 추적하고, 바이너리 및 텍스트 형식을 지원하고, 노력을 절약하고, ID로 개체를 식별하고, 이전 버전과 앞으로 호환되는 것입니다. 직렬화를 위해 C++ 리플렉션을 사용하면 엔지니어가 데이터, 매크로 기반 내부 프레임워크, 합리적인 전방 및 후방 호환성, 버전 제어 시스템이 필요하지 않으며 강력한 코드 데이터 종속성을 노출하는 것이 매우 간단합니다. 각 객체에는 고유한 식별자가 있고, 자산의 자유로운 이동이 가능하며, 서비스에서 TOC 및 추적 ID를 읽고, 종속성을 쉽게 쿼리할 수 있습니다. 상속 시스템은 자산 재사용성을 향상시키고, 엔지니어와 콘텐츠 제작자가 사용하기 쉽고, 모든 기능을 뛰어넘고, 직렬화된 코드로 처리되고, 리플렉션 및 고유 ID를 기반으로 하며, 수정 가능한 항목에 제한이 없습니다. 결과는 훌륭하지만... 상위 노드에 비해 저장 측면에서 하위 노드가 조각화되어 있습니다.

종속성을 다시 저장했지만 프로덕션에서 수정하는 방법을 모르기 때문에 종속성을 다시 저장하는 "기능"이 도입되었으며 언제 사용해야 하는지 이해하기 어렵습니다. 콘텐츠 제작자의 역량을 강화하세요. 개체를 합성하고, 개체를 그룹화하고, 시각적 언어를 사용하여 개체 수준 스크립트를 작성하는 기능입니다. 각 개체에 대해 고유한 ID를 갖는 것은 훌륭하지만, 비교 기반 일반 상속 시스템은 자식이 있는 부모 노드를 갖는 것이 까다로우며 사용자에게 예상보다 더 많은 권한을 제공하고 기술이 허용하는 모든 것이 사용됩니다.
요약하자면, 신규 사용자에게 더 빠른 학습 곡선, 일관된 편집기 제어 및 프로덕션 배포를 제공하는 최신 엔진으로 업그레이드하는 것은 그다지 즐겁지 않습니다.
지난 20년 동안 GPU 제조업체와 게임 개발자들은 "더 나은 프레임 속도"라는 성배를 위해 노력해 왔습니다. 그러나 부드러움의 문제는 잘 이해되지 않습니다. 파악하기 어려운 프레임 타이밍: 속도보다 부드러움에 대한 사례 연구는 단일 GPU에서도 종종 발생하는 무서운 "마이크로 끊김 현상"의 매우 독특하고 알려지지 않았지만 오히려 중요한 원인을 탐구합니다. 근본적인 문제, 문제의 역사, 문제 해결을 위한 프로토타입 접근 방식에 대해 논의합니다. 애플리케이션에서 말더듬 사례가 완벽한 사례보다 "빠르나요"? 예, 자세한 내용은 아래 그림을 참조하세요.

끊김 현상은 게임이 얼마나 빨리 표시되는지 모르기 때문에 발생합니다! 게임이 느리게 실행되고 있다고 "생각"하는 이유는 무엇입니까? 1980~90년대 8비트/16비트 시대에는 고정된 하드웨어였고 항상 같은 시간이었고 문제가 없었습니다. 다양한 NTSC/PAL 버전을 기억하시나요? 90년대/2000년대에는 소프트웨어 렌더링/그래픽 가속기, 타이밍 및 보간이 시작되었지만 파이프라인에는 문제가 없었습니다. 오늘은 무슨 일이에요?
이론: "APl/운전자의 잘못". 실제 GPU 로드는 게임에서 "숨겨집니다". 이 "기능"은 당시 Flush() 및 Finish() 동작의 변경으로 인해 2000년대 초반 "드라이버 벤치마크 전쟁" 중에 도입되었을 수 있으며 결합자는 도움이 되지 않았습니다. 이를 보상하기 위한 내부 메커니즘은 무엇입니까? 그렇기 때문에 찾기가 너무 어렵습니다! 어쨌든 파이프라인 하드웨어를 잠재력을 최대한 활용하는 것은 불가피하며 "버퍼 유휴 시간"이 허용되지만 알아야 합니다!
나쁜 타이밍의 두 가지 측면은 첫째, 심장 말더듬의 주요 원인인 나쁜 타이밍 피드백입니다(그러나 때로는 다른 원인도 있습니다). 두 번째는 잘못된 프레임 스케줄링입니다. 이는 "느림"에서 "완벽함"으로 복구할 때 끊김 현상이 발생하는 주요 원인입니다. 권장사항, 과거 프레임이 얼마나 오래 지속되었는지 알아야 하고, 비동기 통계가 있어야 하며, 경험적 방법을 사용해야 하고, 그것이 완벽하지 않다는 것을 인정해야 하며, 이상적으로는 다음 프레임이 얼마나 오래 지속되는지 알 수 있지만 그것은 불가능합니다. 다음 프레임 표시를 예약할 수 있어야 합니다. 빠른 것이 항상 더 좋은 것은 아닙니다! 시간이 얼마나 남았는지 아는 것이 사실 가장 문제가 되는 부분이다. 오래된 논리 알고리즘은 일반적으로 다음과 같습니다.
frame_step = 16.67 ms // (assuming 60fps as initial baseline)
current_time = 0
while(running)
Simulate(frame_step) // calculate inputs/physics/animation... using this delta
RenderFrame()
current_time += frame_step
PresentFrame() // scheduled by the driver/OS
frame_step = LengthOfThisFrame() // calculated by the game새로운 논리 알고리즘은 다음 코드로 변경됩니다.
frame_step = 16.67 ms // (assuming 60fps as initial baseline)
current_time = 0
pending_frames_queue = {} // (empty)
frame_timing_history = {}
while(running)
Simulate(frame_step) // calculate inputs/physics/animation... using this delta
RenderFrame()
current_time += frame_step
// current_time는 의
current_frame_id = PresentFrame(current_time)
AddToList(pending_frames_queue, current_frame_id)
// 정보
QueryFrameInfos(pending_frames_queue,frame_timing_history)
//
frame_step = FrameTimingHeuristics(pending_frames_queue, frame_timing_history)위의 FrameTimingHeuristics() 내부 구조는 다음과 같습니다.
Pending_frames_queue 대기열에서 이미 사용 가능한 모든 프레임을 폴링하고 해당 타이밍을 Frame_timing_history에 기록합니다.
일정이 완료되지 않은 프레임이 있는 경우, 해당 길이를 frame_step에 반환합니다(이것이 프레임 속도를 줄이는 방법입니다).
Recovery_count_threshold 연속 프레임이 초기이고 해당 마진이 <recovery_margin_threshold인 경우, 프레임 단계에 사용된 길이를 반환합니다(이것이 프레임 속도를 높이는 방법입니다).
OpenGL+VDPAU 프로토타입: 개념 증명으로 2015년 8월 Talos 원리에서 구현되었습니다. NV_present_video를 사용하는 OpenGL 확장은 원래 비디오 재생용이므로 타이밍 기능이 있습니다. 거의 완료됨: 미래 프레임을 합리적으로 배열하고 과거 프레임의 타이밍 정보를 얻습니다. 그러나 에지 정보가 없으면 복구하기 어렵습니다. Linux의 OpenGL 플랫폼용 특정 NVIDIA 보드에서만 사용할 수 있으며 널리 사용 가능하지는 않지만 요점을 입증합니다.
Vulkan 및 VK_GOOGLE_display_timing: Talos 원리 및 Serious Sam Fusion에 구현되어 예정된 향후 프레임, 과거 프레임의 타이밍 정보, 가장자리 정보(모호한가요?) 등 모든 것이 가능합니다. Android에서만 사용할 수 있으며 Metal 및 DX12는 아직 사용할 수 없습니다.
고려 사항: 언제 느린 것에서 완벽하게 되기로 결정합니까? 느린 속도로 하강할 때 타이밍을 어떻게 수정할 수 있습니까? 속도를 예측하고 완벽한 하강을 할 수 있을까요? 가능하다면 이것은 "매우 매끄럽게" 될 것입니다. 아마도 더 좋을 것입니다! VRR 모니터는 어떻습니까? Vsync가 꺼져 있으면 어떻게 되나요? 둘 다 가능하지만 아직 구현되지 않았습니다!
주관성: 궁극적으로 이는 인식의 문제입니다. 일부 사람들은 서로 다른 의견을 가지고 있고 개발자마다 사용자에게 다양한 옵션을 노출하는 접근 방식이 다를 수 있습니까?
중간계를 위한 성능 및 메모리 사후 분석: Shadow는 주로 성능 최적화와 메모리 최적화로 나누어지는 "Middle-earth: Shadow of War"에서 30fps와 메모리를 달성하기 위한 Monolith의 엔지니어링 전략을 공유했습니다.
스레드에 대한 동기화 기본 요소: 커널 기본 요소를 사용하는 대신 경량 원자 스핀 잠금을 사용하여 원자 데이터 액세스를 보호합니다. 컨텍스트 전환이 필요한 경우 커널 프리미티브가 계속 사용됩니다. 컨텍스트 전환의 실제 비용은 캐시 제거입니다. 가벼운 다중 읽기-단일 쓰기 기본 요소가 도입되었습니다. 여러 스레드에서 물리 시뮬레이션 상태를 읽는 것이 그 예입니다. Microsoft 플랫폼에는 SRW(Super Light Read and Write) 잠금 기본 요소가 있고 Sony에는 유사한 기본 요소가 있습니다. 읽기 수는 두 개의 원자 스핀록 인스턴스와 원자 카운터를 사용하여 추적할 수 있습니다. 첫 번째 원자 스핀록은 읽기 잠금 역할을 하고 두 번째 원자 스핀록은 쓰기 잠금 역할을 합니다.
스레드 CPU 클러스터: 콘솔의 두 CPU 클러스터 간에 워크로드를 분할하여 공유 L2를 활용합니다. 첫 번째 CPU 클러스터는 게임 로직을 실행하고, 두 번째 CPU 클러스터는 렌더링 로직을 실행합니다. 클러스터가 동일한 캐시 라인을 동시에 건드리지 않도록 요구하는 흑마술인 Shadow of War의 복잡성 증가로 인해 성능이 10% 향상되었습니다.
스레딩에 대한 전체적인 접근 방식: 많은 작업을 유지하고, 단일 스레드 코드를 최대한 많이 유지하고, 주니어 엔지니어의 진입 장벽을 낮추고, 동시성으로 인해 발생하는 버그 수를 줄이고, 전체 동기화가 덜 필요하며 일반적으로 CPU 캐시를 더 잘 활용합니다. 전체 시스템을 백그라운드 스레드로 이동하고 대규모 시스템에 대한 하드 선호도를 설정합니다. 우선순위가 낮은 스레드로 CPU 유휴 시간을 채우는 것은 비동기 컴퓨팅의 개념과 유사하지만 파일 I/O, 스트리밍, 비동기 레이캐스팅과 같은 CPU 코어에 적용됩니다.
스레드 파이프라인: 작업은 한 방향으로 작업을 푸시하는 순환 명령 버퍼를 사용하여 파이프라인화되며, 이러한 각 명령 버퍼는 전용 코어에서 실행되는 전용 스레드에서 실행되므로 각 파이프라인 단계에서 프레임당 33.3ms의 전체 데이터를 얻을 수 있습니다.

스레드의 동적 프레임 조정: 스레드를 파이프라인할 때 파이프라인의 다음 단계가 1프레임(33.3ms)을 초과하지 않도록 보장됩니다. 이상적으로는 모든 파이프라인 단계가 병렬로 실행되며 각 단계 사이에 몇 밀리초의 오프셋이 있습니다. 전체 파이프라인이 파이프라인의 첫 번째 단계에 의해 제한되는 경우에도 마찬가지입니다. 전체 시스템이 마지막 단계에 묶여 있으면 파이프라인의 확장성으로 인해 몇 프레임 전에 시뮬레이션된 프레임을 표시하게 되며 우리는 항상 v-sync의 마지막 단계에 묶여 있습니다.

화면에 프레임이 표시되기 200밀리초 전에 입력이 시뮬레이션 스레드에서 평가되기 때문에 입력 대기 시간이 문제가 됩니다. 솔루션은 GPU의 디스플레이 큐를 모니터링하는 동적 프레임 조정 시스템입니다. 큐가 가득 차면 GPU에 바인딩되고, GPU에 바인딩되면 첫 번째 단계(예: SimulationThread)를 인위적으로 일시 중지하여 할당된 것보다 약간 더 많은 시간이 걸립니다. 망원경을 축소시키는 Sleep(33.3 TimeOfSimulationThread + 1).

알려진 최악의 경우 시뮬레이션된 스레드는 이제 50ms로 단축됩니다.

렌더러의 상수 버퍼: 게임과 엔진 추상화 계층 사이에 복사가 너무 많습니다. 각 상수는 개별적으로 설정된 다음 매 드로우콜마다 재생성되는 상수 버퍼로 조합됩니다. 상수 버퍼는 업데이트 빈도에 따라 중단되며, 렌더러의 상수에 액세스하면 실제 상수 버퍼에 대한 포인터가 반환되어 상수 버퍼가 접근자를 통해 게임에 직접 노출됩니다. 더티 상태와 프레임 코드가 추적되어 GPU로 전송되면 새 복사본이 생성되고 더티 상태가 지워지며, GPU가 프레임 코드를 지울 때까지 메모리는 재사용되지 않습니다. 명명된 상수 버퍼를 바인딩하면 포인터만 설정되고 머티리얼 상수 버퍼는 빌드 단계에서 자산에 구워집니다.

뼈 변형을 예로 들어 보겠습니다.

각 상수 버퍼 상수는 해당 상수가 얼마나 자주 사용되는지에 대한 경험적 방법을 통해 수동으로 정렬되며, 거의 사용되지 않는 상수와 일반적으로 0으로 설정되는 상수는 상수 버퍼의 맨 아래에 정렬됩니다. 할당된 상수 버퍼는 사용된 상수와 0이 아닌 상수를 보유할 만큼만 크기 때문에 액세스되는 메모리 양이 크게 줄어듭니다. GPU에서 버퍼 끝을 지나 읽으면 0이 반환되어 그래픽 API 오류 메시지가 발생하지만 이를 억제할 수 있습니다. 렌더 노드가 포함된 캐시된 상수 버퍼는 G 버퍼 단계 및 CSM 단계의 뼈대와 같이 변경되지 않는 경우 다른 단계에서 재사용할 수 있습니다.
렌더러를 위한 일반 최적화: 빠른 의미론/LCUE를 갖춘 D3D11.X와 같은 더 빠른 자사 그래픽 API로 전환합니다. 모든 프레임 간 참조 카운터가 제거되었으며 프레임 코드만 수명 주기를 관리하는 데 사용됩니다. 전체 그래픽 API 상태를 캐시하여 자사 그래픽 API에 대한 중복 상태 변경을 제거합니다. 캐시 라인 경계에 동적 GPU 메모리를 할당하고 캐시 라인 끝에 패딩한 다음, 프레임 코드를 사용하여 CPU 액세스를 위해 해당 메모리를 추적함으로써 CPU 및 GPU 캐시 플러시가 줄어듭니다. 동적 CPU 로드 스케일링, CPU 로드를 기반으로 LOD를 롤아웃하여 메시 수를 줄이고, 높은 밉 흐름을 일시 중지하여 CPU 사용량, 메모리 압력 및 물리적 페이지 매핑 비용을 줄입니다. 이제 알려진 최악의 시나리오에서 렌더링 스레드가 45ms로 단축되었습니다.

메모리 측면에서 Shadow of War의 큰 성능 향상은 모든 할당을 대형 2MB 페이지로 전환하여 64KB 페이지에 비해 성능이 20% 향상된다는 점입니다. Hugepages는 프로세스가 생성될 때 모든 hugepage를 사전 할당하여 비용이 많이 드는 TLB(번역 조회 버퍼) 손실을 줄입니다. 거의 항상 GPU 제한이 있지만 이는 PC에서도 달성됩니다.

알려진 최악의 시나리오에서 시뮬레이션 스레드는 이제 40ms로, 렌더링 스레드는 36ms로 줄어듭니다.

개발 빌드: DLL은 엔지니어링 반복을 개선하는 데 사용되며 모든 프로젝트에는 증분 링크가 활성화되어 있습니다. 디버그: 일부 엔지니어는 FastLink에 액세스할 수 있으며 실행 파일은 이러한 DLL을 로드하고 실행하는 작은 스텁입니다. 단편적 빌드: 이제 DLL이 LIB로 컴파일되고 증분 연결이 비활성화됩니다. 실행 파일은 여전히 작은 스텁이며 이제 LIB에 연결되어 런타임 성능이 약 10% 향상됩니다. LTCG는 모든 미들웨어를 포함한 모든 플랫폼과 모든 프로젝트에서 활성화되었으며, Microsoft 플랫폼의 LTCG는 10% 더 향상된 반면 PS4의 LTCG는 약 5%의 개선을 제공했습니다. PGO는 모든 플랫폼에서 활성화되고 PGO 성능은 모든 플랫폼에서 약 5% 향상되므로 Microsoft 플랫폼에서 COMDAT 폴딩을 비활성화하면 PGO의 이점이 무효화됩니다. 알려진 최악의 시나리오에서 시뮬레이션 스레드는 이제 33ms로, 렌더링 스레드는 30ms로 줄어듭니다.

GPU 가상 메모리: 최신 GPU는 CPU와 같은 가상 메모리를 사용합니다. 물리적 메모리는 연속적일 필요는 없습니다. 물리적 메모리는 페이지 단위로 매핑되거나 매핑 해제될 수 있습니다. 하나의 물리적 메모리 페이지는 여러 가상 메모리 주소에 매핑될 수 있습니다.

64K 페이지: 64KB 페이지를 사용하면 큰 페이지보다 크기가 작고 공유 및 재사용이 더 쉽다는 장점이 있습니다. 64KB 페이지 사용의 단점은 TLB 미스율 증가로 인해 액세스 속도가 느려진다는 것입니다.
밉맵 스트리밍: Shadow of Mordor는 밉맵을 지속적으로 스트리밍하지만 로드 시간을 줄이기 위해 언로드하지 않습니다. 텍스처가 사용되면 높은 밉이 스트리밍됩니다. 메모리를 절약하기 위해 Shadow of War는 높은 수준의 밉맵을 드나들고 고정된 밉맵 메모리 풀을 사용해야 합니다. 하이밉은 텍스처 2D 메모리의 66%입니다. 빌드 시 각 메쉬가 분석되고 텍스처 밀도가 가장 높은 가장 큰 삼각형이 결정되어 저장됩니다. 런타임 시 메시가 렌더링되면 CPU는 해당 삼각형을 화면 공간에 투영하고 대략적인 밉맵 값을 계산하는 데 사용됩니다.

CPU 시스템은 프레임(64)당 분석할 수 있는 여러 메시/재료로 제어되며, 각 메시는 프레임 코드로 제어되고 스래싱을 방지하기 위해 댐퍼로 제어됩니다. 초당 1920메시를 테스트하면 밉맵 분석의 CPU 비용은 프레임당 0.1ms로 고정됩니다. 높은 밉은 64KB 페이지 풀을 사용합니다. 이 페이지 풀은 프로세스 생성 시 사전 할당되며, 풀이 소진될 때까지 높은 밉이 로드되며, 높은 밉 스트리밍을 지원하는 모든 텍스처는 물리적 메모리 지원 없이 생성됩니다.

위의 접근 방식은 높은 밉을 위한 메모리 풀을 사용하여 약 1.0GiB의 메모리를 절약할 수 있습니다.
Shadow of War는 지형, 캐릭터 모델, 대부분의 구조, FX 시퀀스 프레임 등과 같은 다양한 텍스처 배열을 사용합니다. 장점은 Texture2Darray의 슬라이스가 모두 동일한 레벨에서 샘플링된다는 점이며 이는 블렌딩에 매우 유용합니다. 일반적으로 여러 2D 텍스처를 샘플링할 때보다 Texture2Darray를 샘플링하기 위해 셰이더의 분기를 피하는 것이 더 쉽습니다. 그러나 문제는 패딩과 복사입니다. 패딩을 방지하기 위해 GPU가 실제로 읽는 텍스처 부분에 64KB 페이지를 수동으로 바인딩하면 레이아웃 패딩에 물리적 메모리를 사용할 수 없습니다. 압축된 MIP는 64KB 페이지보다 작고 64KB 페이지를 공유하는 MIP이며 항상 실제 메모리 페이지에 의해 지원됩니다.

복사 문제는 슬라이스 간에 64KB의 물리적 메모리 페이지를 공유함으로써 해결됩니다. Texture2DArray에는 Texture2D 슬라이스에 대한 참조만 포함됩니다. 런타임 시 슬라이스의 물리적 페이지는 Texture2Darray에 매핑됩니다. 각 슬라이스는 참조 카운트됩니다. 슬라이스의 물리적 메모리는 모든 참조가 사라질 때까지 해제되지 않습니다. 압축된 MIP는 단일 64KB 페이지보다 작으며 중복된 상태로 유지됩니다. 또한 이 솔루션을 사용하면 슬라이스를 일반 텍스처 2D로 사용하고 이를 메모리 내 Texture2DArray와 공유할 수 있으며, 한 번에 하나의 슬라이스만 수행하면 되므로 빌드 시간도 단축됩니다.

결론: 중복을 피하면 시나리오에 따라 평균 약 3억이 절약되고 패딩을 피하면 아티스트가 2^n이 아닌 배열을 만들 수 있습니다.
Far Cry 5의 오픈 월드 렌더링 과제에서는 Far Cry 5의 세계를 개발하는 데 사용된 렌더링 기술에 대해 설명합니다.
물 렌더링의 경우 깊이 다중 해상도 처리에서는 물의 깊이를 사용합니다. 장점은 아티스트들이 물 위에서 SSAO와 SSS(스크린 스페이스 쉐이딩)를 선호한다는 점인데, 이는 물 표면에서 그림자, 대기 산란, 안개 등이 지연되기 때문에 최적화된 것입니다. 단점은 물 위에 지연된 그림자가 나타나고 타일드 라이트 컬링이 수중 라이트를 올바르게 컬링하지 못한다는 점이지만 QC에서는 오류를 보고하지 않았으므로 좋은 절충안입니다. 수중에서 투명한 물체를 보고 싶다면 어떻게 해야 할까요? 마지막으로 FC5는 투명 채널을 두 개로 분할합니다.

for each transparent object
find water plane at XY location
if above water plane
render after water
else if below water plane
render before water
else // if intersecting water plane
render before and after water
end
end컬링의 경우 워터가 깊이 테스트를 사용하여 물을 클리핑한 후, 워터 컬링 전은 버텍스 셰이더에서 워터 클리핑 평면을 생성합니다.
시간대별로 마음에 드는 날을 골라보세요! 해나 달은 일정한 주기로 항상 거기에 있습니다. 오늘과 어제의 해와 달의 위치를 계산하고, 시간이 지남에 따라 오늘의 위치에서 어제의 위치로 전환되므로 내일 12시는 오늘 12시와 같습니다.
CalculateSunPosition( timeToday, latitude, longitude, &azimuthToday, &zenithToday );
CalculateSunPosition( timeYesterday, latitude, longitude, &azimuthYesterday, &zenithYesterday );
float dayBlendFactor = secondsFromMidnight / (24.0f * 60.0f * 60.0f); // seconds in a day
float azimuth = LerpAnglesOnCircle(azimuthToday, azimuthYesterday, dayBlendFactor);
float zenith = LerpAnglesOnCircle(zenithToday, zenithYesterday, dayBlendFactor);눈에 보이는 달의 위상이 여전히 발생하는 보름달인 것처럼 달빛을 계산하고 달빛의 방향을 달의 빛나는 부분에서 나오도록 변경하여 다음과 같은 버그를 방지합니다.

그러나 여전히 많은 문제가 있습니다. 밤에는 물리적 조명 값의 대비 범위를 지원할 수 없으며, 조명 반경을 클램핑하면 대비 범위만 증가하고, 조명 아티스트는 밤을 지원하기 위해 조명을 어둡게 하여 하루 중 다른 시간대에 잘못된 동작을 초래합니다. 달의 조명을 시뮬레이션하기 위해 조명 장비를 사용하는 영화의 방법을 바탕으로 해결책은 달의 밝기를 높이고 달의 광원을 연한 파란색으로 변경하여 빛을 채우고 대비를 줄이는 최소한의 환경 조건을 시뮬레이션하는 것입니다. 밝은 달은 지는 태양과 경쟁하면서 새벽/황혼을 희석시킬 것입니다.

FC5는 또한 톤이 이미지의 여러 영역을 다르게 매핑하는 로컬 톤매핑을 사용하여 밝은 영역을 더 작은 동적 범위로 줄입니다. 포스트 프로세스 로컬 톤매핑을 시도했지만 블루밍과 같은 아티팩트가 존재했습니다. 새로운 아이디어: 주요 문제는 어두운 내부와 밝은 외부입니다. 창, 문 등과 같이 노출을 조정해야 하는 화면 영역을 수동으로 표시하고 이를 노출 포털이라고 부릅니다. 곱셈 블렌딩을 통해 뒤의 색상이 어두워지거나 밝아지고 카메라에 가까울수록 페이드 아웃되는 양면 지오메트리입니다.

노출 포털의 로컬 톤매핑.
GI를 기반으로 한 로컬 톤매핑도 있습니다. 로컬 노출에는 양측 흐림 효과가 사용되어 화면에서 2D 공간의 닫힌 영역, 3D 공간의 먼 영역을 구분하고 조명 값의 로컬 평균을 제공합니다. 3D 공간에 이미 조명 값의 로컬 평균이 있다면 어떻게 될까요? 사실 이런 정보도 있어요! 이것은 로컬 라이트와 태양, 하늘 폐색으로부터의 간접 조명을 저장하는 전역 조명 시스템입니다. 알고리즘: 현재 장면 노출에서 중간 회색 참조를 생성하고, 현재 픽셀에서 평균 조명 밝기를 계산합니다. 하늘 조명과 간접 조명을 모두 포함하고 모든 직접 조명(태양광 포함)을 무시하고, 값을 비교하고 이에 따라 픽셀 조명을 조정합니다(모든 조명 셰이더에서 발생).

Unity의 HD 렌더 파이프라인을 통한 통합 렌더링을 향한 길은 Unity의 HDRP 파이프라인과 관련된 구현 프로세스와 기술을 공유합니다.
HDRP(고화질 렌더 파이프라인)의 설계 목표는 PC(DX11, DX12, Vulkan) XBox One, PS4, Mac과 같은 크로스 플랫폼, 항상 물리적 기반 렌더링입니다. 통일된 조명, 동일한 조명 기능을 불투명도, 투명도 및 볼륨에 사용할 수 있습니다. 일관된 조명, 모든 조명 유형은 모든 재질과 전역 조명에 적용되어 이중 조명/이중 폐색을 최대한 피합니다. 조명 아키텍처 측면에서 지연, 순방향 및 혼합의 비교는 다음과 같습니다.

모든 것에 대해 포워드 렌더링으로 전환할 수도 있습니다.

재료 구조는 다음과 같습니다.

데칼의 렌더링 아키텍처는 다음과 같습니다.

HDRP의 BRDF는 다음과 같습니다.
조명 셰이더. HDRP의 재질 ID: 표준+반투명, 표준+광택+비등방성, 표준+무지개+하위 산란과 같은 재질 특성의 비트마스크입니다.
GBuffer 제약. 저장 공간은 무지개빛, 이방성, 표면 아래 산란/반투명성과 같은 고유한 재료 특성을 제공합니다.
표준 셰이더의 GBuffer 레이아웃은 다음과 같습니다:

또한 HDRP는 이방성, 바니시, GGX 다중 산란, 무지개(무지개빛), 표면 아래 산란 및 기타 효과를 지원합니다.

조명 측면에서 LPV의 전역 조명이 지원됩니다.

실시간 레이 트레이싱을 지원하는 하드웨어 및 API의 최근 발전으로 최종 프레임의 품질을 대폭 향상할 수 있는 새로운 그래픽 기능이 등장했습니다. 실시간 Ray Tracing을 활용하여 하이브리드 게임 엔진을 구축하면 실시간 Ray Tracing 기능(기존 그래픽 API 포함)을 프로덕션 게임 엔진에 통합할 때 고려해야 할 문제에 중점을 두고, 실시간 Ray Tracing 기능의 구현 세부 사항을 조사하고, 개발 중에 얻은 교훈을 제공합니다. 그런 다음 반사 및 무작위 영역 조명 음영과 같은 최신 렌더링 파이프라인에서 실시간 레이 트레이싱을 활용하는 여러 알고리즘에 대한 개요를 제공하여 생산 엔진의 상용 소비자 하드웨어에서 빠른 성능을 달성하는 데 필요한 중요한 최적화에 대한 통찰력을 제공합니다.
전통적인 렌더링 파이프라인은 아래 그림과 같습니다. 파란색 부분은 간접광과 관련이 없으므로 무시해도 됩니다. 아래 사진의 붉은색은 간접광과 관련된 무대입니다.

아래 이미지의 노란색 단계의 경우 솔루션은 다중 바운스 또는 근사치입니다. 다음으로 살펴볼 것은 투명성입니다. 이는 레이 트레이싱에 적합한 후보인 것 같습니다. 그렇죠?

화면 공간 조명 문제는 투명한 재질(다차원성, 성능, 필터링)에도 적용되는 것으로 나타났습니다. SSS에 대한 체적 솔루션은 현재 탐색 중이지만 올바른 SSS 체적 솔루션은 없습니다. 하이브리드 렌더링 파이프라인의 프로세스는 다음과 같습니다.

간접 조명의 경우 분할 및 근사화 Karis 2013은 분산을 줄이는 데 도움이 되며 파란색은 래스터라이제이션 또는 레이 트레이싱을 사용하여 미리 계산되고 평가됩니다.

RTX의 렌더링 프로세스는 다음과 같습니다.

무작위 영역 조명 렌더링 프로세스는 다음과 같습니다.

데이터 기반 아키텍처는 팀의 비프로그래밍 부분이 새로운 기능을 쉽게 추가해야 하기 때문에 비디오 게임에서 매우 일반적인 개념입니다. 이 모델은 모든 인기 있는 게임 엔진에서 구현되며 콘텐츠 제작자에게 힘을 실어주고 창의력을 발휘하는 핵심 기술입니다. 'Frostpunk'의 콘텐츠 기반 게임플레이 프로그래밍은 11비트 스튜디오 내부 기술의 데이터 기반 게임플레이 아키텍처와 이것이 Frostpunk의 게임플레이 코드와 게임의 전반적인 제작 프로세스에 어떤 영향을 미치는지 소개합니다.
데이터 기반 아키텍처: ECS(엔티티 구성 요소 시스템), 유연하고 쉽게 확장 가능한 구성, 디자인 및 아트 팀에서 만든 콘텐츠를 기반으로 프로그래머는 도구만 제공하며 아키텍처는 여러 반복과 실험을 허용합니다. 데이터 기반 아키텍처 없이는 고유한 커뮤니티 빌더를 만드는 것이 불가능합니다.
RTTI 클래스는 XML 노드 또는 이진 C++ 클래스로 직렬화될 수 있는 런타임 유형 식별자입니다. XML은 편집기에서 사용되며 바이너리 형식은 게임에서 사용됩니다. 템플릿은 RTTI 클래스가 게임의 개체를 정의하고 GUID로 식별되며 편집기에서 지원되는 파일입니다.

템플릿 예: 엔터티 템플릿 - 게임 내 개체 유형 정의, 구성 요소 템플릿 - 구성 요소 정의, 그리드 템플릿 - 그리드 정의 및 데이터 가져오기, UI 스타일 - UI 요소/UI 화면 정의. ECS 구현 예는 다음과 같습니다.

컴포넌트에 저장된 상태/데이터, 시스템에 구현된 로직, 시스템이 전역 상태를 유지할 수 있음, ECS 외부의 일부 기능(UI, 입력...). 구성 요소와 구성 요소 템플릿은 RTTI 클래스입니다. 엔터티 템플릿에는 구성 요소 템플릿 목록이 있습니다. 구성 요소는 템플릿 개체, 템플릿 개체에 저장된 상수 데이터 및 구성 요소 개체에 저장된 가변 데이터에 대한 참조를 유지합니다. 엔터티당 하나의 구성 요소 유형, 명확한 구성, 구성 오류 감소. 구성 요소 유형당 하나의 시스템, 단일 책임 원칙, 단순화된 아키텍처. 시스템/구성 요소 클래스 상속은 없으며, 각 구성 요소 유형은 시스템 결과, 가능한 비트마스크 ID(아래 그림)를 규정하고 새 구성 요소 유형을 추가하여 기능을 확장합니다.

구성 요소 종속성 및 초기화 순서 지원: RequireComponent<Type>, AddAfterComponent<Type>. 구성요소 세트: 건물, 시민, 자원 더미 등 가장 일반적으로 사용되는 엔터티 유형을 정의하고 중첩될 수 있는 구성요소를 포함하는 디자이너가 정의한 구성요소 배치입니다. 반복되면 최상위 구성요소 정의가 사용됩니다.
class GeneratorComponent : public ComponentImpl<GeneratorComponent, GeneratorComponentTemplate>
{
DECLARE_PROPERTIES(GeneratorComponent, ComponentBase)
{
DECLARE_ATTRIBUTES(Attr::RequireComponent<BuildingComponent>());
DECLARE_ATTRIBUTES(Attr::AddAfterComponent<HeaterComponent>());
DECLARE_PROPERTY(SteamGenerationUpkeep, 0);
DECLARE_PROPERTY(SteamPower, 0);
...
}
...
Map<EntryLink<ResourceEntry>, int> SteamGenerationUpkeep;
float SteamPower = 0.0f;
friend class GeneratorSystem;
};아키텍처 미리보기:

"Capcom RE ENGINE의 DirectX 12 최적화 기술"은 DX12 기술을 사용하고 최적화하는 Capcom의 RE 엔진에 대한 이야기를 들려줍니다. 사용되는 도구에는 RGP, RGA 등이 포함됩니다.
RE 엔진은 플랫폼 독립적인 명령인 "중간 그리기 명령"을 사용하여 프로그래머가 플랫폼 지식 없이도 그리기 명령을 작성할 수 있도록 하며 다중 플랫폼 개발에 유용하며 다중 스레드에서 그리기 명령을 생성할 수 있습니다. 이러한 "중간 그리기 명령"은 생성 후 정렬된 다음 우선순위 변수(단위 64비트 값)를 사용하여 그리기 순서를 제어하고 사용자가 자체 일괄 처리를 결정할 수 있도록 하며 UAVOverlap의 동기화 타이밍 및 비동기 스케줄링을 제어하는 데 사용됩니다.
PC에 적응하기 위해 콘솔을 최적화하기 위한 조치에는 오클루전 컬링을 위한 MultiDraw 사용, UAVOverlap, Wave 지침 및 깊이 제한 테스트가 포함됩니다. DirectX 12의 최적화에는 리소스 장벽 감소, 버퍼 업데이트, 루트 서명, 메모리 관리 등이 포함됩니다. 전반적으로 ExecuteIndirect는 생각만큼 개선되지는 않지만 GPU 기반 오클루전 컬링 구현에는 매우 유용합니다. GPU 기반 폐색 제거는 ExecuteIndirect 및 Predication 명령의 두 가지 방법으로 구현할 수 있습니다. ExecuteIndirect는 4바이트로 정렬되며 CountBuffer를 사용하여 간접 매개변수 실행 횟수를 제어합니다. 예측 명령은 8바이트로 정렬되어 있으며 콘솔과 호환되지 않습니다. 가시성은 "VisibleBuffer"를 사용하여 관리됩니다. 실제로 이는 RE 엔진의 버퍼, 바이트 주소 버퍼입니다. 요소 수는 장면의 최대 메시 수와 동일하며 각 요소에는 각 메시의 가시성이 포함됩니다. 0xffff는 표시됨을 의미하고 0x0000은 표시되지 않음을 의미합니다. 가시성을 테스트할 때 EarlyZ를 사용하여 ([earlylengthstencil] 속성)을 그리고 VisibleBuffer에 0xffff를 저장하고 웨이브 [dorobot16]에서 동일한 주소 쓰기를 최소화하십시오.
[earlydepthstencil]
void PS_Culltest(OccludeeOutput I)
{
// 로써 로 의 의 기록/쓰기(Write).
uint hash = WaveCompactValue(I.outputAddress);
[branch]
if (hash == 0)
{
RWCountBuffer.Store(I.outputAddress, 0xffff);
}
}그런 다음 가시성 테스트 결과를 적용합니다. 그리드별로 그리기를 적용하고, MaxCommandCount를 사용하여 그리기 수를 지정하고, VisibleBuffer를 CountBuffer로 지정하고, CountBuffer 0xffff: 그리기 활성화(MaxCommandCount로 계산), CountBuffer 0: 그리기 비활성화합니다.
void ExecuteIndirect(
ID3D12CommandSignature *pCommandSignature,
UINT MaxCommandCount,
ID3D12Resource *pArgumentBuffer,
UINT64 ArgumentBufferOffset,
ID3D12Resource *pCountBuffer,
UINT64 CountBufferOffset);
개선의 여지도 있습니다. 소품 및 캐릭터 메시에 효과적인 컬링 방법은 작은 AABB 단위에 효과적이지만 항상 표시되고 더 나은 결과를 위해 메시를 미세하게 분할해야 하는 대형 메시에는 효과적이지 않습니다. 대형 메시를 자동으로 세분화하여 256개의 삼각형을 일괄 처리로 클리핑하고, 각 일괄 처리는 연속적인 간접 매개변수로 구성되며, 각 일괄 처리에서 AABB를 생성할 수 있습니다. 그러나 이 접근 방식에는 몇 가지 문제가 있습니다. 거의 모든 그리기가 768 인덱스 미만이고, 배치 크기가 크면 성능이 저하되며(하드웨어에 따라), 인접한 간접 매개변수가 연속되면 명령이 병합됩니다.

부분 Z-프리패스(Partial Z-prepass): 가능한 한 적은 수의 프래그먼트 셰이더를 실행하고, 메시당 Z-프리패스가 비싸고, 비용이 이점을 초과할 수 있으며, Z-프리패스를 카메라 근처의 메시로 제한하고, 자동 파티셔닝 모델을 재사용합니다. 다양한 자르기 방법의 성능 비교:

그러나 GPU 기반 오클루전 컬링은 상당한 성능 향상을 달성할 수 없는 것으로 나타났습니다.

UAVOverlap: DirectX12 종속성 없는 셰이더를 병렬로 실행할 수 있습니다. UAV 장벽의 종속성은 명확하지 않습니다. 읽고 있는 것인지, 쓰는 것인지는 분명하지 않습니다. 각 일괄 처리가 별도의 위치에 기록되면 병렬로 실행될 수 있습니다. WAW(write-after-write) 위험을 피할 수 있는 경우. 각 컴퓨팅 셰이더 디스패치에 대한 UAV 동기화를 제어하여 UAV 동기화를 비활성화하여 병렬 실행을 가능하게 합니다. DirectX 11에서는 AGS 및 NVAPI를 사용하여 동등한 기능을 도입할 수 있습니다.
// uavResourceSyncDisable는 비활성화(Disable)UAV의 동기화 。
void dispatch(u32 threadGroupX, u32 threadGroupY, u32 threadGroupZ, bool uavResourceSyncDisable = false);
void dispatchIndirect(Buffer& buffer, u32 alignedOffsetForArgs, bool uavResourceSyncDisable = false);UAVOverlap을 활성화하면 약간의 개선이 이루어졌습니다.

Wave 명령: 셰이더 스칼라화는 조명, GPU 기반 오클루전 컬링, SSR에 사용되는 스레드의 병렬 작업 속도를 높일 수 있습니다. Wave Intrinsic은 불필요한 동기화를 제거하여 스칼라화 효율성을 향상시킵니다. AGS 내장 Shader Model 5.1을 사용하여 DirectX 11 및 DirectX 12에서 지원되며 Shader Model 6.0에서도 작동합니다.

깊이 경계 테스트: 외부 픽셀 셰이더를 제거하는 데 주로 사용되는 특정 깊이 범위까지 깊이를 고정하고 DirectX 12(Creators Update) 및 DirectX 11.3, DirectX 11(AGS 및 NVAPI 포함)에서 작동하며 RE ENGINE에서는 데칼 및 빔에 사용됩니다. 데칼을 처리할 때 깊이 테스트에 실패한 픽셀에서 실행하세요. 완전히 가려지면 처리를 건너뛰고 깊이 경계 테스트를 사용하여 해결하는 것이 가장 좋습니다.

리소스 장벽에 대한 최적화가 없는 원래 빌드에서는 리소스 장벽이 배치로 삽입되어 그리기 명령을 실행하기 전에 현재 배치에 필요한 리소스 장벽을 즉시 변환했습니다.

이는 많은 리소스 장벽으로 이어지며, 이는 GPU 기반 폐색 선별이 성능을 크게 향상시키지 못하는 이유 중 하나입니다.

리소스 장벽이 많은 단계는 운영 효율성이 낮습니다.

리소스 장벽 감소: 각 리소스의 하위 리소스를 고려하여 최적화함으로써 모든 중간 그리기 명령으로 최적의 리소스 장벽을 수동으로 생성하기가 어렵습니다. 어려움은 최대 GPU 성능을 얻고 버그가 없는 상태를 유지하는 데 있습니다. 명령 분석을 위한 사전 통과를 추가하고, 리소스 장벽 위치를 자동으로 계산하고, 중간 그리기 명령을 분석하고, 중간 그리기 명령을 우선순위에 따라 정렬합니다. 각 리소스의 그리기 명령 사용량을 시간순으로 추적할 수 있습니다. 우선순위 순서를 변경하면 종속성이 있는 배치를 분석하여 GPU의 효율성을 쉽게 향상시킬 수 있습니다. 자원 장벽을 압축하고 패키징하는 과정은 다음과 같습니다.

상단: 이전 리소스의 장벽에서 다양한 시점의 장벽을 검색합니다. 중간: 이러한 장벽의 공통 시점을 찾습니다. 하단: 후속 장벽을 동일한 시점으로 마이그레이션하고 일괄 통합을 수행합니다.
장점은 내부 구현 및 캐싱에 너무 민감할 필요가 없어 불필요한 리소스 장벽을 줄일 수 있다는 것입니다. 단점은 명령어 파싱 시간이 필요한데 PC가 엄청 빠르네요!

아래와 같이 버퍼를 업데이트할 때 여전히 일부 비효율성이 있습니다.

DMA 전송 시 드라이버로 인해 발생하는 수많은 리소스 장벽:

무슨 일이에요? 그래픽 대기열의 버퍼 업데이트, GPU 파티클 버퍼 업데이트 및 스킨 매트릭스 업데이트와 같은 복사 버퍼, CopyBufferRegion은 DMA 전송으로 수행됩니다. DMA 전송을 수행할 때 강력한 캐시 플러시가 실행되고 L1 캐시, L2 캐시, K 레벨 캐시, 배치 리소스 장벽이 영향을 미치지 않습니다! 가능한 해결책은 프레임당 업데이트가 하나만 있는 경우 업데이트에 CopyQueue를 사용하고, 컴퓨팅 셰이더가 사용되는 경우 업데이트에 컴퓨팅 셰이더를 사용하는 것입니다.
StructuredBuffer<uint> fastCopySource;
RWStructuredBuffer<uint> fastCopyTarget;
[numthreads(256,1,1)]
void CS_FastCopy( uint groupID : SV_GroupID, uint threadID : SV_GroupThreadID )
{
fastCopyTarget[(groupID.x * 2 + 0)*256 + threadID.x] = fastCopySource[(groupID.x * 2 + 0)*256 + threadID.x];
fastCopyTarget[(groupID.x * 2 + 1)*256 + threadID.x] = fastCopySource[(groupID.x * 2 + 1)*256 + threadID.x];
}고정 버퍼 업데이트 최적화: 업로드 힙을 통해 모든 상수 버퍼를 업데이트합니다. 동일한 고정 버퍼를 업데이트하려면 리소스 장벽과 CopyBufferRegion(DMA 전송)이 필요하며 업로드 힙에 새 값을 저장하고 업로드 힙 오프셋 주소를 가져옵니다. ConstantBuffer를 사용하는 셰이더는 오프셋 주소만 참조하면 되며 더 이상 리소스 장벽과 복사 버퍼가 필요하지 않습니다. 복사 버퍼 감소 비교를 통해 비효율성을 성공적으로 제거:


루트 서명: DirectX12는 셰이더 빌드 시간이 아닌 런타임에 결정되는 DX11 및 콘솔과 유사한 RootSignature를 사용하여 각 IHV에 대한 사용자 지정 최적화를 제공하고, AMD의 경우 RootParameter를 테이블로 사용하고, NVIDIA의 경우 RootParameter를 사용하여 ConstantBuffer 액세스를 최적화합니다.

메모리 관리: 첫 번째 구현에서 메모리 회수는 약 50%의 메모리 사용량에서 시작되었습니다. 이는 게임 플레이 중에 많은 스파이크가 발생하는 매우 보수적인 수치였습니다. Resident Evil 2에서는 각 방의 로드 및 처리를 제어하면 일시 중지 메뉴의 UI를 로드하는 동안에도 캐릭터가 움직일 때마다 스파이크가 발생했습니다. 메모리 사용량이 90%를 초과하면 참조되지 않은 메모리가 제거되는 마이크로 제거를 방지하기 위해 메모리가 소진될 때까지 제거하지 마십시오.
위의 모든 최적화 후에 성능이 24% 향상되었습니다(최적화는 쉽지 않습니다!!).

'Trials Rising'의 GPU 기반 렌더링 및 가상 텍스처링은 세계의 복잡성이 크게 증가하면서 모든 대상 플랫폼(PS4, Xbox One, Switch, PC)에서 일정한 60FPS 성능을 달성하기 위한 Trials Rising 팀의 여정을 설명합니다. GPU 기반 렌더링 구현 및 가상 텍스처와의 통합, 주요 혁신, 최적화 및 성능 결과에 대한 세부 정보가 포함되어 있습니다. Nintendo Switch 플랫폼에 GPU 기반 렌더링 확장성과 기술 효율성을 개선하는 데 전념하고 있습니다.
GPU 기반 렌더링은 GPU에서 직접 테스트 결과를 사용하고, GPU의 배치 인스턴스를 사용하고, 서로 다른 메시의 인스턴스를 병합하여 가시성 테스트를 GPU로 이동합니다. GPU는 프러스텀에서 테스트한 부분뿐만 아니라 장면 상태를 감지할 수 있으며, GPU는 자체적으로 렌더링 기능을 제공합니다.

GPU 데이터 구조: 지오메트리(예: 버텍스 및 인덱스 풀)를 저장하는 2개의 GPU 버퍼, 인스턴스 매개변수(예: 인스턴스 데이터 풀)를 저장하는 1개의 대형 GPU 버퍼, 인스턴스 설명자로 표시되는 인스턴스, 장면의 모든 설명자의 배열을 저장하는 1개의 GPU 버퍼. CPU와 GPU는 주로 이 목록의 인덱스를 사용하여 작동합니다. 인스턴스 설명자는 내부 및 외부 데이터를 포함하며 설명 세트에 매우 가까운 장면의 모든 인스턴스를 나타낼 수 있는 거의 포인터 테이블입니다.

CPU 및 GPU 인스턴스 상태 동기화: CPU는 인스턴스 상태 시뮬레이션 및 GPU에 업로드를 담당하고, GPU는 인스턴스 데이터를 읽기 위한 신호를 기다립니다. 직접 상태 재생성은 매 프레임마다 작동하지 않습니다. 첫 번째 구현 결과에 따르면 데이터 트래픽이 상당히 높으며 앞으로 증가 추세가 있을 것입니다. 데이터 전송 개선: 인스턴스 업데이트 속도가 일정하지 않고, 상태 매개변수 평균 업데이트 속도가 다양하며, 일반적으로 안정적입니다. "고정" 매개변수는 특정 인스턴스 클래스에 적용되고, 다수의 "유휴" 구성 요소는 동기화된 상태의 최소값입니다.
미니 배치: 버퍼 오프셋과 기록할 데이터가 포함된 간단한 목록을 작성합니다. 일괄 처리 프로세스의 순서가 중요합니다.

GPU 인스턴스 테이블 일괄 처리:

풀 배치:

마이크로 일괄 처리 결과: 지연된 동기화, 모든 GPU 구조에 대해 단 하나의 명시적 동기화 지점, 버퍼 액세스/수정을 위한 GPU 경합 없음, 일괄 데이터 수집으로 CPU 성능이 크게 향상되고 일괄 풀 데이터 분산이 GPU 성능에 영향을 미치며 "더티" 상태의 인스턴스가 훨씬 적습니다.
가변 동기화 속도: 가변 애니메이션 속도를 사용하여 "중요도" 요소를 기준으로 인스턴스 상태를 동기화하고, 결정성을 유지하고(재생, 디버깅 등을 위해) 가능할 때마다 자동으로 "중요도"를 계산한다는 아이디어, 전반적인 동기화 문제는 네트워크 동기화와 매우 유사해 보입니다.

또한 이 기사에서는 비동기 컴퓨팅을 사용하여 물리 시뮬레이션을 병렬로 처리합니다.

가상 텍스처: 일반적으로 일반 텍스처 스트리밍 기술보다 낮은 메모리 사용량과 데이터 전송 압력으로 모든 텍스처 데이터에 한 번에 액세스하여 GPU 기반 렌더링의 "배치" 효율성을 크게 향상시키고 일부 플랫폼/API에서 사용할 수 있는 바인딩되지 않은 텍스처를 대체합니다.

VT는 전용 채널을 사용합니다. 전용 카메라를 사용하여 VT 페이지 요청 채널, 스트림 예측, 텍스처 사전 로드 등을 보려면 추가 뷰포트 컬링이 필요합니다. 형상을 두 번 래스터라이제이션하여 페이지 요청 RT, 더 작은 렌더 대상(1/4 해상도 + 지터), 페이지 요청 저장(x 좌표, y 좌표, mip), CPU 분석 및 로드 요청 생성을 생성합니다. In place PR: 렌더 대상을 두 개의 UAV 버퍼(Bloom 필터 버퍼, 페이지 요청 버퍼)로 교체하고, PR 필터링, 정렬 등을 GPU로 이동하고 이를 GBuffer의 각 픽셀에 위임하여 CPU, 투명 채널에 대한 페이지 요청, 알파 블렌딩 채널 등의 시간을 절약할 수 있습니다. Trials Rising"결국 "In place PR"을 사용하게 되면서 모든 홀수 프레임(Xbox One 타이밍)을 변경하여 CPU 시간을 약 35밀리초만큼 줄일 수 있습니다. 고려해야 할 추가 텍스처 로딩 지연 반투명도는 셰이더 코드 단순화에 적합합니다. 가상 텍스처 확장성: 프레임당 페이지 요청은 시스템의 "성능"을 결정하고 렌더링 해상도 및 VT 페이지 캐시 크기에 따라 크게 달라집니다. 두 매개변수는 "온라인" 및 "오프라인" 설정에서 제어할 수 있습니다.
GPU 기반 렌더링 확장성: GPU 파이프라인의 컴퓨팅 부분은 매우 빠르며, 컬링 및 지오메트리 구성 규모는 GPU 클록 및 메모리 대역폭/지연 시간을 기반으로 하며, 래스터라이제이션는 해상도 및 규모를 기반으로 하며, GPU 파이프라인에는 CPU/GPU의 특정 데이터 경로가 필요하며, 인스턴스 동기화는 메모리 대역폭에 영향을 미치고, 작은 인스턴스 오버헤드가 있는 일괄 처리는 실제 작업 부하보다 높습니다. CPU/GPU 로드에 따라 런타임 상세 수준을 조정하여 저사양 플랫폼에서 멀리 있는 개체에 대해 보다 공격적인 컬링 설정을 사용합니다.
Snowdrop은 Ubisoft에서 개발한 AAA 게임 엔진으로 The Division과 후속작을 지원합니다. 'The Division 2'의 효율적인 렌더링에서는 프레임 구성, 비동기 계산, 멀티스레딩, 내장 함수, 명령 목록 제출 등과 같이 PC 및 콘솔에서 최적의 성능을 달성하기 위해 The Division 2에서 사용되는 일부 기술을 설명합니다.
Snowdrop은 비동기 컴퓨팅과 그래픽 파이프라인의 조합을 사용합니다. 파이프라인 개요는 다음과 같습니다(상반부는 그래픽 파이프라인, 하단은 비동기 컴퓨팅).

전체 파이프라인은 CPU/렌더링/GPU 작업 인터리빙, 조기 제출, 빈번한 제출, 렌더링 또는 프레임 레이아웃에 대한 필수 정보 없음, 자동 리소스 전환 추적을 사용하지만 자동으로 추적하지 않도록 선택할 수 있습니다. 프레임당 50~60개의 커밋, 200개의 전환/100개의 장벽, 3~6,000개의 그리기 호출, 3~6백만 개의 프리미티브, (일부 공급업체) 즉석 명령 목록을 작성하는 것보다 더 많은 시간을 커밋합니다. 렌더 코어는 렌더 상태/PSO 및 리소스 생성(버퍼, 픽셀 저장소, 텍스처, RT)을 포함한 비명령 목록 작업을 처리합니다. . . 렌더링 컨텍스트, 그래픽/컴퓨팅/지연/DMA를 관리합니다.
버퍼를 업데이트할 때 모든 임시 데이터는 업로드 버퍼에 복사된 다음 GPU 로컬 버퍼에 복사되고 셰이더는 GPU 로컬 버퍼에서만 읽습니다! 더 빠르지는 않지만 더 안정적인 프레임 속도입니다. 명령 목록 연결은 일부 콘솔에서 사용할 수 있어 기록되는 동안 명령 목록을 실행할 수 있어 CPU 및 GPU 정지 위험을 최소화하지만 DirectX® 12에서는 사용할 수 없습니다. 솔루션: Mimic! ! ! ExecuteCommandLists, 종료, 재설정과 같은 명령 목록 작업을 처리하고 이러한 작업의 CPU 비용을 숨기고 자체 작업자 스레드와 작업 대기열을 가지며 실제로 사용자 정의 드라이버 스레드인 큐 관리자를 입력합니다.

큐 관리자는 레코드, 열기, 컨텍스트당 하나의 큐, 실행 컴퓨터, 그래픽, DMA 등과 같은 명령 목록 상태를 원자적으로 추적하여 우선순위가 지정된 라운드 로빈 방식으로 가능한 것을 제출합니다. 대기열 관리자 세부정보:

네이티브와 큐 관리자 간의 비교:

큐 관리자는 대부분의 CPU 정지를 제거하고, 명령 목록을 예측적으로 준비하고, 명령 목록 생성/재설정 시 정지를 방지하고, 중복 신호/대기를 제거할 수 있습니다.
비동기식 계산에 대한 제출도 대기열 관리자에 의해 처리됩니다. 두 가지 유형의 계산 작업 부하(gfx 상태에 따라 다름, 독립적, 빠르게 완료할 필요가 없는 작업 부하)입니다. 비동기식 계산의 예: 깊이 다운샘플링 및 조명 컬링, 안개 및 볼륨 계산, 비와 눈에 대한 GPU 입자, 하늘/덮개 샘플링, 잔디/식물 업데이트, 그림자(가변 반그림자 사전 계산), GI 재조명 등. 비동기식 계산은 gfx 파이프라인을 지연시키고 GPU 사용량이 부족할 수 있습니다. 콘솔에서: 비동기 계산 사용을 제한합니다. D3D12_COMMAND_QUEUE_PRIORITY는 PC에서 지원되지 않습니다.
최신 그래픽의 높은 좀비 처리량은 Saber 엔진의 렌더링 파이프라인(고급 GPU 워크플로우, 셰이딩 개요, Vulkan 최적화) 및 좀비 렌더링(클로즈업 및 중거리 캐릭터, 원거리 항공기 그룹, 데칼) 등을 다룹니다. Saber Engine 렌더링 파이프라인은 GPU 기반 가시성 시스템, 전체 깊이 프리패스, 순방향+PBR 셰이딩, 베이크된 GI:RNM+우세 방향, 2프레임 대기 시간, 멀티스레드 명령 버퍼 로깅을 특징으로 합니다. GPU 워크플로는 다음과 같습니다.

GPU 가시성 시스템: "게임을 위한 실용적이고 동적 가시성"[Hill11]을 기반으로 하며 간단하고 효율적이며 PVS/포털 등이 필요하지 않습니다. 메인 카메라: 손으로 제작한 폐색기를 사용한 HZB 오클루전 컬링, PSSM 분할: 추적 컬링만, 100,000개 이상의 개체 장면에 대한 0.7ms(XBox One) GPU 예산, CPU 리드백에 1프레임 지연이 필요합니다.

D3D11과 Vulkan 간의 렌더링 파이프라인 비교:

Vulkan 대 D3D11: GPU 시간 최대 10% 감소, 웨이브 지시어(GL_KHR_shader_subgroup), 음영 처리 중 스칼라화된 순방향 조명/반사 루프, 비동기 계산, 반정밀도 수학. 보조 드라이버 스레드 없음: 총 렌더링 CPU 로드가 40% 감소하고 MT 명령 버퍼로 인해 CPU 중요 경로가 20% 감소합니다. 렌더 타겟 메모리 오버랩은 메모리를 30%까지 줄이고 동적 해상도를 지원합니다.
좀비 렌더링: 프레임당 5,000개 이상의 눈에 보이는 좀비, 대부분 비대화형 배경, 300개 이상의 전경 "실제" 게임 내 엔터티/캐릭터, 완전히 발달된 두뇌를 가진 50마리의 좀비, 드로우 콜 압력을 줄이는 데 사용되는 인스턴스, 유연한 인스턴스별 시각적 사용자 정의 시스템. 사용자 정의 메시: 3가지 기본 원형/스켈레톤(남성/여성/"큰" 남성), 스켈레톤당 최대 50개의 뼈, 모델당 4개의 메시 영역(다리/몸통/머리/머리카락), 영역당 2~5,000개의 삼각형, 영역당 4~8개의 메시 변형, 총 70개 이상의 고유한 메시 조합, 10개의 고유한 좀비 모델(화학물질, 비명 등).

사용자 정의 색상 및 얼룩 마스크: 메쉬 영역당(셔츠/청바지/신발/머리카락): 색상 마스킹 텍스처(ARGB8 텍스처, 저해상도), 얼룩 마스킹 텍스처(ARGB8 텍스처, 저해상도); 공유 얼룩 텍스처 세트(혈흔/눈/먼지): 알베도/보통/러프니스 텍스처, 모든 텍스처는 타일링되어 텍스처 배열로 저장됩니다. 색상: 채널 마스크 + 단색, 색조: 채널 마스크 + 텍스처 배열 인덱스와 같은 인스턴스별 상수.

좀비 렌더링 인스턴스화: 가시성 시스템에서 단일 좀비를 가져오고 동일한 메시를 인스턴스화 버킷으로 수집하고 영역에서 버킷으로 변경되는 동일한 메시를 수집하며 다른 LOD 모델이 버킷을 분리합니다. 누적된 버킷을 렌더링 대기열로 처리하고, 가시성 마스크별로 버킷을 정렬하고(각 활성 카메라에는 자체 비트가 있음), 동일한 가시성 마스크가 있는 메시를 배치로 수집하고(최대 30개의 메시), 각 배치에 대해 인스턴스별 데이터로 연속 상수 버퍼를 채우고, 각 프로세스/카메라(Z, SM, 음영)에 대해 배치당 1개의 그리기 호출을 생성합니다.
좀비 렌더링된 배경 인구: 5000개 이상의 좀비, 비대화형: 본질적으로 총 8개의 사전 구운 변형이 포함된 GPU 기반 애니메이션입니다: 2개의 메시 유형 x 4개의 고유한 모양, The Technical Art of Uncharted 4"[Maximov16]에서 영감을 얻은 메시당 최대 400개의 삼각형. 기존 잔디 렌더링 솔루션을 활용하고, 텍스처로 구운 버텍스 애니메이션을 추가하고, 사전 모델링된 트랙을 따라 이동합니다.
Halcyon Architecture - "Director's Cut"은 미니 게임 PICA PICA의 렌더링 아키텍처 및 관련 기술을 공유합니다. Halcyon의 렌더링 개요는 다음과 같습니다.

렌더 핸들: 핸들과 연관된 리소스, 경량(64비트), 상수 시간 조회, 유형 안전(예: 버퍼 및 텍스처), 직렬화 또는 전송 가능, 이중 삭제 등 세대 간 안전, 삭제 후 사용. 백엔드는 동일한 프로세스에서 혼합 및 일치될 수 있으므로 화면 왼쪽에 DX12가 있고 화면 오른쪽에 VK가 있어 VK 구현을 더 쉽게 디버그할 수 있습니다.

렌더링 명령: 지정된 대기열 유형, 사양 확인, 실행이 허용됩니까? 예를 들어 계산과 자동 일정을 사용하면 어디로 갈 수 있나요? 비동기 계산.

렌더링 다이어그램: 프레임 다이어그램 -> 렌더링 다이어그램: "프레임" 개념 없음, 완전 자동 변환 및 분할 장벽, 백엔드에 관계없이 단일 구현, 상위 수준 렌더링 명령 흐름에서 변환, 렌더링 다이어그램에 숨겨진 API 차이점. 다중 GPU에 대한 지원은 대부분 암시적이고 자동이며 계획 전략을 지정할 수 있습니다. 서로 다른 주파수, 동일한 GPU의 여러 그래프 조합: 비동기 컴퓨팅, mGPU: GPU당 그래프, 코어 외부: 서버 클러스터, 원격 스트리밍.

그래프 렌더링에는 그래프 구성(입력 및 출력 지정, 직렬 작업 지정) 및 그래프 평가(고도 병렬화, 고급 렌더링 명령 기록, 자동 장벽 및 전환)의 두 단계가 있습니다. 또한 다중 GPU 렌더링 스케줄링도 지원합니다.

또한 Halcyon은 가상 다중 GPU 기술을 사용합니다. 대부분의 개발자는 GPU가 하나만 있고 2개의 GPU 시스템에는 적합하지 않으며 3+GPU에는 드물고 쇼룸에 적합하며 최대 11개까지 일반 개발에는 적합하지 않습니다.

Halcyon의 셰이더 크로스 플랫폼 솔루션은 다음과 같습니다:

별로 작지 않은 빛: HDR 디스플레이에 'Destiny 2' 도입 Destiny 2에서 HDR 디스플레이를 지원하기 위해 취한 접근 방식을 설명하고 SDR 생성 콘텐츠를 HDR 세계로 가져오는 과제를 포함하여 이 새로운 기술을 지원하기 위해 Destiny 렌더링 파이프라인이 어떻게 변경되었는지 살펴봅니다. 또한 데스티니 가디언즈의 독특한 모습을 유지하기 위해 데스티니 가디언즈에서 고품질 HDR 출력을 달성하는 데 사용된 기술을 살펴보고 작업에서 배운 교훈을 반영해 보겠습니다.

Destiny 2의 렌더링 파이프라인은 다음과 같습니다.

톤매핑 효과 비교:

컬러 그레이딩에 사용되는 LUT는 수학적 매핑을 사용하는 SDR입니다. 우리는 항상 선형 입력, 톤매핑을 먼저 한 다음 변환을 원합니다. 변환을 무시하면 되돌릴 수 있습니다.

SDR Color = TonemapForSDR (Input Color);
LUT Color = LutLookup (SDR Color);
...
Transform = Input Color / max (SDR Color , 0.001);
...
LUT Color *= Transform;InputColor가 0이면 LutColor도 0입니다. UI 렌더링 프로세스는 다음과 같습니다.

새로운 렌더링 파이프라인은 다음과 같습니다:

EOTF는 전압에서 빛의 강도까지의 전기광학 전달 함수입니다. OETF는 광도에서 전압까지의 광-전기 전달 함수입니다. sRGB의 EOTF는 다음과 같습니다.

BT.709 OETF:

기술적인 문제: 향상된 HDMI, 셰이더에서 채도의 신중한 사용, 음수에 대한 fp16 버퍼, SDR 공간의 AA, 화면 소음을 강조하는 더 깊은 검정색. 이 기사에서는 HDR LUT를 사용하고, 사용자 인터페이스에서 채도/휘도를 사용하고, ICtCp 등을 사용하고, 마지막 단계는 톤매핑입니다. 오프라인 HDR 파이프라인은 다음과 같습니다.

배운 교훈: 콘텐츠 검증, SDR 파이프라인 변경 준비, HDR 버퍼를 최대한 오랫동안 유지, RGB 대안 탐색, 측광 장치 사용, 비교 도구 만들기.
6년간의 월드 오브 탱크 최적화: 노트북부터 고급 PC까지 모든 시스템에서 게임을 훌륭한 경험으로 만들기는 병렬 렌더링, 동시 렌더링, 탱크 트랙, Havok/AVX2, 레이 트레이싱 섀도우 등을 포함하여 월드 오브 탱크에서 수년간의 최적화 경험을 공유합니다.
울트라북 최적화 - 섀도우: 공유 비디오 메모리, 정적 개체용 ASM(Adaptive Shadow Map), 동적 개체용 CSM(Cascade Shadow Map)을 사용하여 Intel 하드웨어를 올바르게 감지합니다.

최적화된 울트라북 - 성능 최적화: 동적 해상도 성능에 따라 장면은 동적 해상도로 렌더링되고 크기가 조정되지 않으며 UI는 항상 PC 게임의 첫 번째 구현 중 하나인 전체 해상도로 렌더링되어 게임에서 안정적인 30fps 프레임 속도를 허용합니다. 최적의 템플릿+클립() 성능을 위해 Intel GPU에서 식물 렌더링을 위한 2개의 스텐실 쓰기에 대한 하드웨어 특정 최적화(2015).

2018년에는 최신 멀티 코어 CPU용 엔진을 준비하기 위해 TBB가 도입되었습니다. 첫 번째 문제는 좋은 운영 체제를 선택하는 것이었습니다. 좋은 운영체제를 선택하는 방법은 무엇입니까? WoT 엔지니어링 팀 표준: 사용하기 쉽고 두 가지 유형의 병렬성: 기능/작업 및 데이터, 풍부하고 강력한 기능, 매우 우수한 지원. TBB(스레딩 빌딩 블록)는 병렬 알고리즘 및 데이터 구조, 스레드 및 동기화, 확장 가능한 메모리 할당 및 작업 예약입니다. 특별한 컴파일러 지원에 의존하지 않고 C++, Windows, Linux, OS X, Android 및 기타 운영 체제를 지원하는 라이브러리 전용 솔루션입니다.

WoT 1.0의 멀티스레드 렌더링 아키텍처는 다음과 같습니다.



2018년까지 WoT는 SIMD(AVX2, ISPC)와 같은 기술을 사용하여 병렬성을 더욱 가속화했으며 TBB를 사용하여 Havok의 파괴 시스템을 가속화했습니다.

2019년에 WoT는 레이 트레이싱을 사용하여 그림자 품질을 향상시킵니다.

RT 섀도우 구현 세부 사항:
- CPU 측: 2단계 가속 구조.
BLAS BVH. 모든 탱크 메시에 적용되며 메시 로드 중에 한 번 구축되어 GPU에 업로드되고 메시의 하드 스킨 부분은 여러 정적 BVH로 분할되며 소프트 스킨 부분은 건너뜁니다.
TLAS BVH. Intel Embree 및 Intel TBB를 사용하는 멀티스레드 방식으로 모든 프레임이 재구성되어 GPU에 업로드됩니다.
GPU 측: 픽셀 셰이더 또는 컴퓨팅 셰이더.
균일한 원뿔 분포를 기반으로 하는 시간적 광선 지터입니다.
BVH 횡단 및 광선 삼각형 교차점.
시간 축적.
디노이저(SVGF 기반).
시간적 안티앨리어싱.

CPU BVH 성능: 2.5% CPU 프레임 시간, TBB 스레드, SSE 4.2(원래 WoT 내부 BVH 빌더보다 5.5배 빠름), 프레임당 최대 5MB의 GPU 데이터 업데이트, 최대 72MB의 정적 GPU 데이터. 관련 최적화: RT 그림자는 탱크에 의해서만 투사될 수 있으며 알파 테스트 형상을 지원하지 않습니다. BLAS LOD, 픽셀당 1개의 광선, 다음 조건이 발생하는 경우 광선 픽셀 추적을 중지합니다. NdotL<=0, 픽셀이 그림자 맵에 의해 차단되고 카메라에서 300미터 이상 떨어진 경우.
Call of Duty: Modern Warfare의 소프트웨어 기반 가변 속도 셰이딩은 Call of Duty: Modern Warfare(2020)에 사용된 새로운 렌더링 파이프라인을 다룹니다. 이는 고도로 사용자 정의 가능한 소프트웨어 기반 가변 속도 쉐이딩을 가능하게 합니다. 이미지의 주파수와 일치하는 해상도로 렌더 대상의 일부를 렌더링하는 방법입니다. 사용 가능한 장치의 하위 집합으로 제한되는 하드웨어 기반 솔루션과 달리 소프트웨어 기반 구현을 통해 광범위한 소비자 하드웨어에서 더 높은 품질과 성능을 달성할 수 있습니다. 사전 통과 렌더링, 가변 속도 추정기, 셰이더 커널 계산을 위한 새롭고 고유한 픽셀 패킹 방식, 순방향+ 렌더러의 최종 프레임 렌더링을 포함하여 파이프라인의 각 단계에 대한 설계 프로세스, 최종 구현 및 심층 검사가 설명됩니다. 품질 및 성능 스펙트럼 전반에 걸쳐 다양한 사용 사례를 더 잘 충족하기 위해 다른 렌더러 유형 및 작업 유형의 잠재적 구현 및 미래 지향적인 확장에 대해 논의합니다.

2020년의 많은 하드웨어는 이미 하드웨어 가변 속도 셰이딩(VRS)을 지원하고 AMD-RDNA2 GPU, Intel-11세대 APU, NVIDIA-Turing GPU 등을 포함한 DX12 Ultimate [DX19] [DX20]와 같은 하드웨어에서 가변 속도 셰이딩을 지원합니다.

다양한 기능은 다양한 계층에서 지원됩니다.
Tier 1: 각 추첨에 대한 음영 비율을 설정합니다.
계층 2: 최소 타일 크기가 8x8픽셀인 각 화면 타일의 음영 비율(및 기타 주파수)을 설정합니다.
이미지 주파수에 맞게 음영 비율을 선택할 수 있습니다[LEI19].

이로 인해 다중 해상도 렌더링 파이프라인 [DRO17]이 탄생했습니다.

저해상도로 표시된 재질의 성능은 3x~3.8x로 확장되며, 렌더링 대상 마이크로블록 적중 수와 화면의 전체 해상도와 저해상도 입자 간의 중첩에 따라 차이가 결정됩니다. 0.3ms~0.4ms의 조합: 업샘플링/파싱/재구성 프로세스, 모든 서브샘플이 필요한 차동 블록 수에서 차이가 발생합니다. 일부 고삼각형 투명 그래픽의 쿼드 점유에 대한 우려는 GPU MSAA 효율성으로 인해 달라질 수 있습니다.
COD 팀은 프리패스를 4xMSAA(기본 해상도 목표와 일치하는 ½ 해상도)로 렌더링하고, 4xMSAA에서 불투명도를 렌더링하고, 그리기당 1s, 2s, 4s 모드를 허용하고, DX12 VRS Tier 1.0과 일치하는 유연성을 통해 프리패스 렌더링 속도가 크게 향상되는 것을 확인했습니다. 그러나 이 실험의 결과는 실패였습니다. IQ 목표는 달성되지 않았고(성능 모드에서), 성능 목표에 도달하지 못했습니다(최악의 경우 변화 없음).

그 이유는 살아남은 삼각형이 132,000개이고, 살아남은 픽셀이 886,000개이며, 삼각형당 평균 6.7픽셀이 있기 때문입니다.

새로운 개념: 래스터라이제이션 및 쿼드 점유, MSAA와 쿼드 점유의 상호 작용, MSAA와 메모리의 상호 작용(인터리브 렌더링), MSAA 및 쿼드 점유와의 템플릿 상호 작용.

래스터라이제이션와 쿼드 점유 간의 관계.

4인실 점유율과 해상도 사이의 관계.

4인실과 MSAA의 관계.

쿼드 점유와 MSAA 및 템플릿 간의 관계.

MSAA 재구성과 인터리브 렌더링 간의 관계.
COD 팀의 계획은 모든 것을 흰색으로 만들고 VRS 마스킹을 위해 스텐실을 사용하는 것이었습니다. 초기 연구에서는 집계된 샘플 속도, 인터리브 렌더링, VRS 폐색에 최적화된 CS/PostFX 작업과 같은 최악의 시나리오에서 부정적인 성능 저하를 최소화할 수 있음을 보여줍니다. 하드웨어 VRS에 비해 소프트웨어 VRS의 주요 장점은 모든 플랫폼에서 사용할 수 있고, 타일이 작아서 성능이 더 높을 수 있고, 타일이 작아지고 암시적 재구성 방법으로 인해 이미지 품질이 더 높아질 수 있다는 것입니다. 소프트웨어 VRS 파이프라인은 다음과 같습니다.

일반 설정: 프레임 렌더링은 그리기 및 CS 작업에 대한 4xMSA 재구성/디인터레이스를 고려하며, VRS는 MSAA의 타일 크기(16x16)에서 작동하는 하드웨어 구현과 달리 픽셀 쿼드 세분성(2x2)에서 실행됩니다. Swizzle 패턴은 VRS 음영 비율 맵에서 수동으로 생성된 스텐실 마스크인 회전 기능이 있는 사각형입니다.

VRS 이미지 마스크: 이미지가 아닌 데이터만을 기반으로 하는 쿼드별 세분화된 2비트 마스크로, 이미지 음영 처리 속도 추정 및 VRS 렌더 마스크 생성에 사용됩니다. 4가지 모드: 단일 샘플, Delta H, Delta V, 모든 샘플, 모든 샘플 모드에서 보존되는 여기 픽셀.

기울기 감지:
// Image Base Gradient Codes
#define VRS_IB_0 ( 0x0 ) // No grad
#define VRS_IB_DH ( 0x1 ) // Dir Hor
#define VRS_IB_DV ( 0x2 ) // Dir Ver
#define VRS_IB_ALL ( 0x3 ) // All dirs
#define VRS_IB_MASK( VRS_IB_ALL )
// Local Weber-Fechner JND k calculation
float tileLuma = min3( colorM, colorNW,
min3(colorSW, colorSE,
min3(colorNE, colorW,
min3( colorE, colorN, colorS ) ) ) );
float visiblityThreshold = vrsQualityThreshold * max(tileLuma, deviceBlack);
// Horizontal
float dh = max( abs( colorW - colorM ), abs( colorE - colorM ) );
float ddh= max( abs( colorNW - colorNE ), abs( colorSW - colorSE ) );
dh = max( dh, ddh );
// Repeat for Vertical
// VH direction and delta
result.vrsRate = VRS_IB_0;
result.vrsRate |= dh < visiblityThreshold ? 0 : VRS_IB_DH;
result.vrsRate |= dv < visiblityThreshold ? 0 : VRS_IB_DV;
// Merge quads – promoting through individual directions to all directions
result.vrsRate |= ddx( result.vrsRate );
result.vrsRate |= ddy( result.vrsRate );그라데이션 내역 스크롤(FIFO 대기열): 재투영된 프레임 4개를 유지합니다.
// VRS history roll during gradient detection at quad resolution
// Reprojection happens in main VRS tile shader.
if(((dispatchThreadID.x | dispatchThreadID.y) & 0x1) == 0)
{
uint vrsHistoryRate = vrsRateRWTex[dispatchThreadID >> 1];
vrsRateRWTex[dispatchThreadID >> 1] = (freshResults.vrsRate & 0x3) | ((vrsHistoryRate<<2) & 0xFC);
}VRS 렌더 마스크 생성:
CS 작업 소비자: 속도 버퍼, 재투영 및 일관되지 않은 거부가 포함된 4프레임 VRS 이미지 마스크 기록[JIM17], 프리패스의 FMask – VRS 형상 마스크를 생성합니다.
CS 작업 생산자:
4프레임 VRS 이미지 마스크 기록 재투영, 8비트 – 4 x 2비트 이미지 마스크가 한 번에 재투영되고 나중에 그라데이션 감지 중에 회전됩니다.
VRS 렌더 마스크(쿼드별), 마지막 4개 프레임에서 8비트 재정렬된 FMask 또는 2비트 이미지 마스크(VRS 이미지 마스크 3 샘플 및 FMask3인 경우 FMask가 선호되는 경우 알파 테스트용 잔디와 같은 무거운 형상의 불연속 렌더링에 최적화됨) FMask는 샘플 시간에 간접 순서 지정을 피하기 위해 샘플 순서로 재정렬되며 디블로킹 및 재구성에만 사용됩니다.
4XMSA 템플릿이 점묘법 렌더링 모드로 업데이트되었습니다. VRS 렌더링 템플릿에서 파생되며, 겹치는 Texture2D 템플릿 대상에 직접 작성됩니다.
VRS 파면 버퍼(픽셀당).
또한 소프트웨어 VRS의 렌더링 프로세스에는 프리패스 및 Forward+와 같은 프로세스가 포함되며 후속 이미지 재구성에는 디블로킹 및 구문 분석과 같은 프로세스가 포함됩니다. 또한 이 기사에서는 평면 반복, 파도 압축 및 태양 가시성 작업을 포함한 CS 작업을 최적화합니다. 이러한 복잡한 작업 후에 숲이 너무 복잡하면 1ms 이상의 개선을 얻을 수 있습니다.

복사 조도가 약간 낮은 실내 장면에서는 다음과 같은 이점이 더욱 분명해집니다.

소프트웨어 VRS 파이프라인의 일부를 선택합니다.

얼라이언스를 위하여! 월드 오브 워크래프트와 인텔이 최적화된 아제로스에 대해 논의하며 2020년 월드 오브 워크래프트의 렌더링 최적화에 대해 공유합니다.
WOW가 Direct X 12(및 Metal)에 대해 수행한 작업에는 멀티 스레드 명령 목록 생성, 비동기 파이프라인 생성, 비동기 텍스처 업로드가 포함되며 프레임 속도가 50에서 80으로 증가했습니다. 또한 하드웨어 VRS는 픽셀 셰이더 작업의 하드웨어 기능을 줄이는 데 사용됩니다. 작동 원리는 픽셀 셰이더가 픽셀 단위 대신 픽셀 그룹을 호출하도록 하는 것입니다. 이는 셰이딩 레이트 하의 LOD와 유사하게 MSAA의 확장으로 간주될 수 있습니다. VRS를 제어하는 방법은 그리기 호출별, 화면 공간 마스킹 및 버텍스/기하학 셰이더를 통해입니다.


VRS의 가장 큰 수혜자는 화면 공간의 큰 삼각형입니다.

VRS 전환은 눈에 띄지 않을 수 있습니다. 2x1은 가정된 16:9 화면 비율을 활용하여 더 부드러운 전환을 허용합니다.

VRS를 사용하기 가장 좋은 장소: 지형, 모션 블러, DOF, 먼 물체 등과 같이 지각적으로 눈에 띄지 않을 수 있는 무거운 픽셀 셰이더 및 낮은 시각적 품질을 찾으십시오. VRS의 장점은 가장자리/윤곽 보존이며 가장자리 기반 AA(예: CMAA)와 잘 작동하고 VRS가 적용된 시스템을 제어하며 특히 확대 채널 없이 깊이 기반 텍스트 효과에 유용합니다. 렌더링 규모의 장점은 버텍스 및 대역폭 비용 감소, 1920과 3840 사이의 모든 값과 같은 부드러운 강도 범위입니다. VRS의 한계는 화면 공간에 비해 삼각형의 밀도가 높으면 이점이 최소화되고 파티클 시스템에서 VRS를 사용하는 것이 약간 투박해 보일 수 있다는 것입니다.
Elwynn Forrest 장면의 성능은 1x1에서 61FPS, 2x2에서 68FPS, 4x4에서 76FPS입니다. 시각적 품질의 균형을 맞추면 일반적으로 5~10% 정도 개선됩니다. 요약하자면, 드로우 콜 VRS는 통합이 매우 쉽고(DX12 엔진에서) 동적으로 원활하게 활성화될 수 있으며 품질을 최소화하면서 픽셀 셰이더 비용을 줄일 수 있습니다.
새롭고 강력한 GPU IP가 출시됨에 따라 Imagination Technologies는 플레이어에게 최고의 게임 경험을 제공하기 위해 낮은 수준의 성능 개선을 위해 Roblox와 긴밀히 협력해 왔습니다. PowerVR에서 Roblox Vulkan 최적화 렌더링에서는 Roblox 게임 내 복셀 조명 시스템, EVSM 섀도우 맵 구현, 셰이더 최적화 및 PowerVR에 최적화된 Roblox 렌더러의 기타 최신 기능을 살펴봅니다. 또한 모바일 장치의 분석 및 최적화 프로세스를 설명하고 비동기 컴퓨팅을 사용하여 PowerVR 성능을 향상시키는 방법을 검토합니다.
Roblox 조명 시스템의 목표는 굽지 않고, 모든 개체가 언제든지 움직일 수 있고, 조명을 완전히 비활성화할 수 없는 것입니다. 시각적 및 게임플레이에 큰 영향을 미치고, 콘텐츠의 "성능" 영향을 최소화하고, 저가형 노트북/휴대폰(D3D9/GL2/GLES2 종류)에서 실행하고, 고급형 노트북/휴대폰에서 멋진 조명 효과를 얻고자 합니다.
조명 시스템에 대한 높은 수준의 개요, 기존 기능에는 광원(태양/달, 하늘, 로컬 조명)이 포함되고, 기하학과 광원은 동적이며, 모든 광원은 그림자를 투사할 수 있으며, 거친 복셀 조명은 어디에나 있어 효율적이고 부드러운 조명을 생성하며, 그림자 맵은 중간 범위에서 고급 및 고품질 태양 그림자를 지원합니다. Forward+는 향후 도입될 예정입니다. 고급형, 고품질 로컬 조명, 더 나은 복셀 조명, 더 나은 스카이라이트가 제공됩니다.
조명 시스템의 0단계는 복셀입니다. 대부분의 작업은 CPU에서 수행됩니다. 동적 형상을 복셀화하고 햇빛, 채광창, 누적된 로컬 조명 RGB와 같은 각 복셀에 대한 조명 효과를 계산하고 정보를 GPU에 업로드합니다(RGB: 빛 + 채광창 x 하늘색, A: 햇빛). 프래그먼트 셰이더의 최종 조명입니다. CPU 성능 관리: 복셀 그리드는 블록으로 나누어지고 매 프레임마다 몇 개의 블록만 업데이트되며 품질은 고정되지만 업데이트는 "오래된" 것일 수 있습니다. 업데이트 커널은 수동으로 최적화된 SSE2/NEON을 사용합니다. GPU 성능 관리: GLES2는 이중선형 필터링이 포함된 단일 3D 텍스처 조회를 사용하여 2개의 2D 텍스처 맵 조회를 사용하여 3D 텍스처 조회를 시뮬레이션하고 형상과 빛의 복잡성을 완전히 분리합니다.
조명 시스템의 1단계는 더 나은 복셀입니다. 시스템의 전체 디자인을 유지하고, 공간을 절약하기 위해 HDR 조명 색상을 RGBM을 사용하여 인코딩하고, 스카이라이트를 별도로 저장하고, 하늘을 BRDF, 이방성 점유에 더 잘 통합하고, 복셀라이저는 복셀당 3개의 축 값을 유지하며, 콘텐츠 호환성에 중요하며, 결과는 섀도우 맵/포워드+에 더 가깝습니다. GLSL의 최적화는 다음과 같습니다.
// 스칼라 알고리즘
vec_1 = (float_1 * vec_2) * float_2; --> vec_1 = (float_1 * float_2) * vec_2;
// inversesqrtsqrt오버헤드/비용
vec_1 = sqrt(vec_2); --> vec_1 = vec_2 * inversesqrt(vec_2);
// abs() neg() and clamp(…, 0.0, 1.0)로써
float_0 = max(float_1, 0.0); --> float_0 = clamp(float_1, 0.0, 1.0);
vec_0 = vec_1 *vec_2 +vec_3; --> vec_0 = clamp(vec_1 *vec_2 +vec_3, 0.0, 1.0);너무 많은 레지스터가 사용되어 단일 클러스터에서 처리되는 스레드 수가 줄어들고 결과적으로 활용도가 낮아집니다. PowerVR이 16비트 부동 소수점을 사용하여 레지스터 압력을 줄이고 점유율을 늘릴 수 있습니다(최대 100%). PBR 셰이더의 경우 A 시리즈의 경우 사이클 수가 9%, Rogue(Oppo Reno)의 경우 12% 감소하여 활용도가 33% 향상되었습니다. PBR+IBL 셰이더의 경우 A 시리즈의 사이클 수는 9% 감소하고 Rogue(Oppo Reno)의 사이클 수는 20% 감소하며 활용도는 36% 증가합니다. PVRShaderEditor를 사용하여 사이클 번호와 어셈블리를 분석합니다.

PowerVR에서의 Roblox 분석.
조명 시스템의 2단계는 그림자 맵입니다. 복셀 그림자가 너무 러프니스 때문에 그림자 맵이 도움이 됩니다! 뛰어난 품질, 과제는 "부드러운" 그림자, 높은 재렌더링 비용, 많은 그림자 투사 광원, 단순화를 위해 태양 그림자만 방출하는 것입니다. 그림자 맵 렌더링: 계단식 블록 그림자 맵, 1-4 계단식, 품질 수준에 따라 멀리 계단식은 그림자 업데이트를 방지할 수 있도록 블록으로 나뉩니다. 캐스케이드 섀도우맵 렌더링을 위한 가속 기술인 CSM 롤링이 사용됩니다. 캐스케이드를 업데이트해야 하는 경우 한 번만 수행하면 됩니다. 여러 타일이 더티로 표시된 경우 해당 타일에서 형상이 다시 렌더링되고 CPU는 블록별로 프러스텀 컬링을 수행합니다. 빛의 방향이 바뀌면 캐시가 무효화되며 이 문제에 대한 좋은 해결책을 찾지 못했습니다. 그림자 부드러움: 넓은 범위에 걸쳐 그림자 맵 "부드러움"을 원하고, 넓은 PCF 코어는 고해상도에서 비용이 많이 들고, 화면 공간 필터링은 투명한 기하학과 타일링 성능으로 인해 비실용적입니다. Roblox는 그림자 렌더링을 샘플링에서 완전히 분리하는 EVSM을 사용하지만 빛 누출이 있습니다... Z 범위를 좁히세요! 그림자 프러스텀를 수신 형상에 단단히 맞추고, 캐스터 형상을 렌더링할 때 "팬케이킹"(VkPipelineRasterizationStateCreateInfo::lengthClampEnable)하고, EVSM을 샘플링할 때 과도하게 어둡게 한 다음, 표준 2패스 흐림(수평 및 수직)을 사용하여 그림자 맵을 흐리게 합니다. 계산을 위해 가우시안 블러를 이동하시겠습니까?

분리 가능한 커널 가우시안 블러는 두 개의 1D 프로세스를 사용하여

가우시안 흐림 수집 알고리즘 계산: PowerVR의 최적 작업 그룹 크기는 32, 8x8 영역을 처리하기 위한 8x4 작업 그룹 크기, 셰이더 루프를 여러 번 시도합니다(여기서는 스레드당 2텍셀).

주변 영역을 포함한 깊이 값을 공유 메모리로 읽어 텍스처 획득 횟수를 줄입니다.

Morton 순서: VK_IMAGE_TILING_OPTIMAL로 생성된 이미지는 최적화 처리를 위해 Morton 순서를 사용합니다. 이는 정렬된 텍셀 영역(512비트 캐시 라인)을 로드하여 캐시 효율성을 향상시킵니다.

작업 패킹: 프레임당 두 개의 대기열 간에 대체 명령 제출을 통해 프레임 독립적인 스케줄링과 작업 패킹 증가가 가능합니다! 두 리소스 세트를 번갈아 사용해야 할 수도 있습니다. 더 많은 개발자들이 Imagination Tech Doc을 추천합니다.

계산을 통한 개선: 5x5 흐림으로 프레임 속도가 40% 더 빨라졌습니다! (메이주프로 7 플러스 PowerVR 7XTP)

idTech 7: Rendering the Hellscape of Doom Eternal은 idTech 7의 렌더링 기술을 공유합니다. idTech 7은 포워드 렌더링을 완전히 사용하고, 여전히 소수의 Uber 셰이더, 더 큰 레벨 및 더 복잡한 환경, 더 많은 스트림 로딩, 모든 플랫폼에서 낮은 레벨 API를 사용하며 동일한 해상도의 콘솔에서 여전히 60fps를 유지합니다.
Doom에서는 하이브리드 비닝이 사용되었습니다[Olson12]. 도전 과제는 Doom의 더 큰 장면이었고, 멀리 있는 작은 조명과 데칼이 하나의 큰 클러스터로 끝나고, 적들은 조명 장비를 가지고 있었고, 전투에서 발사체와 충격 스티커의 동적 볼륨이 더 크고, 아티스트는 더 많은 조명과 데칼을 배치하고 싶었고, CPU 부하를 줄이기 위해 GPU 컬링으로 이동하고 싶었고, 클러스터링과 타일링의 새로운 혼합이었습니다.
하이브리드 비닝은 "향상된 타일링 및 클러스터 렌더링 선택"[Drobot2017]에서 영감을 받았습니다. 문제는 일부 장면에 수천 개의 조명이나 데칼이 있고, 상태 변경으로 인해 하드웨어 래스터 타일 비닝이 비효율적이며, 예산이 매우 부족하다는 것입니다(500us 미만).
컴퓨팅 셰이더 래스터라이제이션: 단순성을 위해 육면체만 비닝하고, 낮은 해상도, 보수적인 래스터라이제이션가 필요하며, 많은 경우에 아티스트가 찾을 수 있으며, 정밀도를 위해 부동 소수점 깊이를 반전시킵니다. 비닝된 래스터라이제이션 [Abrash2009]: 설정 및 컬링, 대략적인 래스터라이제이션, 정밀한 래스터라이제이션, 비트 필드를 목록으로 구문 분석하는 이러한 프로세스에는 많은 세부 사항이 포함되며 많은 장에서 이미 이 기술을 설명했기 때문에 여기서는 건너뜁니다.
기하학적 세부 사항: 아티스트는 창작 그리드의 일부로 기하학적으로 정의된 작은 데칼을 원합니다. 문제는 추가 프레임 예산이 거의 없다는 것입니다. 포워드 렌더러: G-버퍼에서 블렌딩할 수 없으며, 지연으로 전환하더라도 G-버퍼 블렌딩이 너무 느립니다.

메시 UV의 투영 행렬, 월드 공간 -> 텍스처 공간, 투영당 2x4 행렬 사용(8 부동 소수점 = 32바이트), 객체를 저장할 공간 -> 디스크의 텍스처, 모델 행렬과 곱하여 월드 -> 텍스처 공간 행렬, 인스턴스당 지오메트리 데칼에 필요한 메모리. R8 버퍼로 인덱스 렌더링: 백 깊이 패스, 크거나 같은 깊이 비교, z-파이팅을 피하기 위한 깊이 오프셋, 데칼은 동일 평면에 있어야 하며 이 패스에는 50us가 걸립니다. 프래그먼트 셰이더의 각 하위 메시 투영 목록 순회: 인스턴스 설명자 세트에 바인딩된 목록, G 버퍼가 전달되지 않기 때문에 임의로 혼합됩니다.

제한 사항: 하위 메시당 최대 254개 투영, 하나의 데칼에 여러 투영이 필요할 수 있음, 곡선 형상을 잘 수행하지 못함, 인스턴스당 투영 저장소가 필요함, 현재 레벨당 최대 1000개의 데칼이 있음, 박스형 데칼은 항상 맨 위에 있고 애니메이션 형상 투영은 프레임마다 계산됩니다.
지오메트리 캐시: Alembic 캐시에서 컴파일된 [Gneiting2014]를 기반으로 개선된 압축, 예측 프레임, 계층적 B 프레임, 순방향 및 역방향 모션 예측, 비트스트림 압축을 위한 Oodle Kraken, 캐시가 동일한 경우 애니메이션 가능한 색상 및 UV인 경우 인스턴스가 스트림 데이터 청크를 공유할 수 있습니다.
자동 스키닝: 위치 스트림에 대한 대규모 데이터 속도 감소[Kavan2010], 뼈대 행렬은 다른 스트림처럼 양자화 및 압축되며 특정 메쉬에서만 작동하고 버텍스 애니메이션은 계속 지원됩니다.
3바이트 탄젠트 좌표계: 탄젠트 좌표계는 각 프레임에 대해 계산되고 스트리밍되므로 법선과 접선에 대해 두 개의 벡터를 저장하는 것은 매우 비쌉니다. 아이디어: 접선의 노멀 + 회전만 저장하고, 교차곱으로 파라탄젠트를 재구성합니다. 팔면체 표준 인코딩의 경우 2바이트(버텍스 노멀에 충분함), 회전의 경우 1바이트입니다. 디코딩: 탄젠트를 회전하려면 결정된 직교 벡터가 필요합니다. 법선과 벡터(예:
벡터가 직교하기 때문에 이전 항은 취소됩니다.

또한 idTech 7은 재료 혼합, GPU 삼각형 컬링 및 GPU 지오메트리 병합도 지원합니다. 기하학적 병합의 구현 세부 사항은 다음과 같습니다.
모든 리소스는 전역적으로 인덱싱이 가능합니다. 모든 버텍스 버퍼는 단일 전역 풀에 할당되며, 기하학 스트리밍, 모든 텍스처 및 버퍼 설명자의 전역 배열과 일치합니다.
형상 세트에서 동일한 PSO를 사용하여 최대 256개의 가시 메시를 그룹화합니다.
컬 셰이더는 각 지오메트리 세트에 대해 사용자 정의 간접 인덱스 버퍼를 생성합니다. 각 32비트 인덱스에 버텍스 ID와 인스턴스 ID를 패킹하고, 지오메트리 세트당 하나의 그리기 호출을 수행하고, 하나의 컴팩트 그리기 호출에서 256개의 메시를 렌더링합니다.
VS: 인스턴스 ID + 지오메트리 세트 ID를 사용하여 인스턴스 데이터를 검색합니다. 지오메트리 세트 ID는 인라인 상수로 전송되고, 인스턴스 ID는 인덱스 값, 버텍스 버퍼 페치의 오프셋, 인스턴스 설명자 세트 등에서 추출됩니다.
셰이더 컴파일러는 "결합 가능한" 셰이더 변형을 생성합니다. 다양한 텍스처/버퍼 가져오기 직렬화, 인스턴스 데이터의 추가 간접 참조, SSBO는 버텍스 어트리뷰트 대신 버텍스 데이터를 가져옵니다.
그림자 렌더링과 병렬로 비동기 계산에 대한 선별/병합을 계산합니다.

왼쪽에서 오른쪽으로: 장면 샘플, 메시, 형상 세트.
결과: 삼각형 컬링 + 병합을 사용하여 밀집된 장면에서 최대 5ms의 GPU를 절약하고 VS에서 거의 낭비가 없어 본질적으로 고정 기능 병목 현상을 제거합니다. 유사한 CPU 절약: CPU 가시성 패스 중에 수행된 설정인 깊이 및 불투명도 패스에 동일한 간접 인덱스 버퍼를 재사용하는 것은 이미 당혹스러울 정도로 병렬입니다. 이미 스칼라 최적화를 수행 중인 코드에 유용하며, 낮은 순열 수에서 가장 잘 작동하여 어쨌든 셰이더 수를 가능한 한 낮게 유지합니다. 이론적 절충: 인스턴스 데이터 검색은 이제 달라졌으며 일반적으로 VS 내부에서 발생하며 궁극적으로 눈에 띄지 않습니다.
이 기사에서는 물 렌더링, 반투명 표면 및 기타 기술에 대해서도 다룹니다.

최근 하드웨어의 발전으로 GPU에서 광선을 추적하는 기능이 그 어느 때보다 쉬워졌으며 게임 엔진은 레이 트레이싱 효과(예: 반사, 부드러운 그림자, 앰비언트 오클루전(AO) 또는 전역 조명)를 실시간 파이프라인에 통합하여 가능한 경우 화면 공간에서 보다 근사한 레이 트레이싱 효과를 대체함으로써 이를 활용했습니다. 전부는 아니지만 대부분의 효과는 2차원 몬테카를로 통합에 의존합니다. 이 경로를 따라 더 높은 차원으로 모험을 떠나 더 많은 간접 바운스나 더 많은 분산 효과(DOF, 모션 블러)를 추가하여 전체 경로 추적에 더 가깝게 하는 것을 상상할 수 있습니다. 제한된 실시간/대화형 예산을 최적으로 활용할 수 있도록 샘플링 방식을 조정해야 합니다. 광선에서 경로 추적까지: 차원 탐색에서는 위 효과를 근사화하는 방법을 설명합니다.
오프라인에서 실시간으로의 레이 트레이싱의 몇 가지 중요한 측면:
조명을 현명하게 선택하세요. 몬테카를로 통합법, 분산, 중요도 샘플링, 다중 중요도 샘플링 등이 사용됩니다.
(비)난수를 신중하게 선택하세요. 도메인 왜곡, 준랜덤 시퀀스, 낮은 비유사성, 계층화.
레이 예산을 가장 유용한 곳에 사용하세요. 적응형 샘플링.
오류를 이해하고 방지합니다. 강도 클램핑, 경로 정규화.
몬테카를로 간략한 검토:

Quasi Monte Carlo(QMC): 결정론적, 낮은 불일치 시퀀스/앙상블(Halton, Hammersley, Larcher-Pillichshammer)은 무작위보다 빠르게 수렴합니다. Sobol 또는 (0-2) 시퀀스는 샘플 수, 환상적인 계층적 속성을 알 필요가 없습니다.

아래 그림을 보면 경사지고 분산된 지면에 빛의 넓은 영역이 있습니다. 카메라 바로 앞에는 굴절률이 1인 얇은 유리판이 있습니다(따라서 완벽한 투과율). 이는 장면의 대부분(전부는 아니지만)이 창 뒤에 있는 상당히 일반적인 시나리오의 디버그 버전입니다.

광선에 대한 고정된 분할 요소가 있기 때문에 인덱스도 쉽게 추적할 수 있습니다. 각 조명 샘플 계산에 대해 샘플 i부터 i+3까지 사용합니다. 물론, Cornell 상자의 경우처럼 각 조명 위치가 해당 위치와 매우 다르다면 큰 차이가 없을 것입니다(그러나 속성이나 순서를 고려하면 적어도 그 정도는 좋을 것입니다). 그러나 위치가 더 유사하다면(또는 현재 시나리오와 정확히 동일하다면) 어떨까요? . .

카메라에 직접 표시되는 지상의 64개 광원 샘플을 사용합니다.

아래 이미지는 샘플링 예산을 더 쉽게 테스트할 수 있도록 하는 약간 다른 시나리오입니다. 장면의 얇은 유리 조각은 더 거칠며, 이 거친 효과를 더 잘 이해하기 위해 바닥에 텍스처를 적용했습니다.

이전과 동일한 샘플링 방법을 사용하면 거친 유리에 의해 생성된 BSDF 광선의 일관성은 물론 이전만큼 좋지 않아 아래와 같이 더 거친 이미지가 생성됩니다.

픽셀 간 상관 관계가 좋지 않고 4D 시퀀스의 일부 차원이 픽셀 내에서 상관 관계가 좋지 않은 상황이 발생했습니다. 이를 위해 Jarosz et al.이 사용한 시각화 규칙에 따라 4D 점의 다양한 2D 투영을 보고 싶습니다. (직교 배열 논문에서): 축의 각 차원에 해당하는 인덱스를 볼 수 있으며 배열의 각 셀에 해당 2D 슬라이스가 표시됩니다. 이는 샘플링 루틴에 사용되는 슬라이스인 차원 (0,1) 및 (2,3)의 2D 슬라이스이며 실제로 동일합니다.

이제 아래의 "진단" 슬라이스를 살펴보겠습니다. (0,3)과 (1,2)도 동일합니다. 나머지 (0,2)와 (1,3)은 (0,0)과 (1,1)과 동일합니다. . .

실제로는 고위도 Sobol 시퀀스가 필요합니다. 가능한 Sobol 시퀀스는 많이 있으며 [Grünschloß] 및 [Joe 2008]의 Sobol 시퀀스는 낮은 샘플 수에 대해 저차원 2D 투영의 계층적 속성을 최적화합니다.

표본 크기는 작지만 모든 차원 쌍을 사용하면 매우 좋은 결과를 얻을 수 있습니다! 이전의 다양한 패딩 시도에서 발견한 문제가 사라졌습니다.

차원을 올리면 실제로 품질이 가장 낮은 2D 슬라이스를 찾을 수 있습니다(==> 피적분 함수의 가장 중요한 부분에 대해 가장 낮은 차원을 사용해야 합니다).

추가 개선 사항에는 모든 차원에 Owen 지시문을 적용하는 것이 포함됩니다. 이는 앞서 언급한 대로 시퀀스 기능의 정렬 패턴을 깨고 수렴 속도를 향상시키는 데 도움이 됩니다. 이는 빠른 프로세스가 아니기 때문에(특히 실시간의 경우) 사전 계산되어 많은 수의 샘플을 저장할 수 있습니다. ==> 이는 256D에서 256포인트를 사용하는 HDRP에서의 작업입니다.

금상첨화: 화면 공간의 블루 노이즈:

백색소음과 청색소음의 비교:

최종 차원: 더 높은 차원으로 들어갈 때 모든 차원을 동시에 고려하고 재귀적인 저차원 적분을 고려하지 마십시오(더 자연스럽게 시작되더라도). 실시간(사전 계산된) 선택 시퀀스: Monte Carlo 분산을 화면 공간의 블루 노이즈로 배포하는 낮은 시차 샘플러[Heitz 2019], 점진적 다중 지터 샘플 시퀀스[Christensen 2018]. 고차원 컬렉션에 대한 주목할만한 최근 작업: Monte Carlo 렌더링을 위한 직교 배열 샘플링 [Jarosz 2019]. 실시간 라우팅 및 추적의 미래는 무엇일까요? 조명 운송의 실시간 재구성 [Wyman 2020].
실시간 사무라이 시네마: Ghost of Tsushima의 조명, 분위기 및 톤매핑에서는 Ghost of Tsushima 게임에 사용된 조명, 하늘 분위기, 톤매핑 및 기타 렌더링 기술에 대해 설명합니다.

조명: 아트 디렉션에서는 "스타일화된 사실성"을 요구하고, 조명 모델은 물리적 기반이며, 물리적으로 합리적인 값으로 작성된 재료, 일부 사진 측량, 동적 하늘 및 로컬 조명에서 데이터를 전송하여 런타임 시 간접 조명 계산, 하늘, 구름, 안개 및 안개 입자에 대한 물리적 기반 하늘 모델, 사용자 지정 기술을 사용하여 HDR 및 톤 맵으로 렌더링, 조명은 물리적 정확성에서 벗어날 수 있으며, 아티스트는 원하는 모양을 얻기 위해 전역적으로 조정할 수 있습니다. 간접 조명에는 디퓨즈와 스페큘러 반사, 대기 볼륨 조명에는 하늘과 구름, 안개, 입자 등이 포함됩니다. 톤매핑에는 로컬 톤매핑 연산자, 사용자 정의 톤매핑 색상 공간 및 화이트 밸런스, Purkinje Shift(저조도 시각적 시뮬레이션)가 포함됩니다.
간접광의 디퓨즈: 쓰시마의 크기, 동적 시간 및 날씨에는 새로운 접근 방식이 필요했습니다. 즉, 총 20x80 타일에 대해 200m 정사각형 타일당 16x16x3을 사용하는 보조 SH 프로브의 정규 그리드입니다. 사면체 메쉬는 도시, 마을, 농장, 성 등과 같은 보다 복잡한 상황에 사용됩니다. 위치를 통해 흐르고, 일반 메쉬를 오버레이하고, 교차점에서 혼합됩니다.

런타임 재조명: 조도 프로브는 런타임 시 업데이트되어야 하며 하늘 가시성은 오프라인 단계에서 캡처되고 2도 SH(단일 채널)로 인코딩되며 조도는 캡처되지 않습니다. 램버트 코사인 로브와 연결된 하늘 가시성에 하늘 SH를 곱하여 런타임 시 하늘을 SH에 투영합니다.
반사된 채광창: 가능하지만 직접적인 하늘 조명만 제공하고 반사광은 제공하지 않습니다. 완벽한 전송 매트릭스? 메모리(9x)가 너무 많고 캡처에 시간이 너무 오래 걸립니다. 채광창이 반구 전체에 걸쳐 거의 일정하다고 가정하면 균일한 흰색 하늘로 세계를 비추면 "바운스 하늘 가시성"이 포착됩니다. 평균 하늘색을 곱합니다(SH부터 0차까지).

태양/달 바운스 추가: 가상의 땅과 벽에 빛을 반사하고

방향성 강화: 레벨 2 SH의 주파수는 상대적으로 낮으며 간접 조명은 여러 곳에서 밋밋해 보입니다. 삼각형을 향한 선형 SH 최대 방향을 따라 Lerp를 계산하는 것은 저렴합니다. 다이렉트 부분과 리바운드 부분은 별도로 계산되며 모든 기상 조건에서 25% 향상이 있습니다.
Deringing: 최종 방사조도가 모든 곳에서 긍정적일 것이라는 보장은 없습니다. 하늘 가시성에 고정 디링을 적용하면 방향성과 충실도가 감소합니다. 대신 하늘 밝기와 최종 방사조도는 CPU에서 계산된 깊이 3의 이진 검색 트리를 사용하여 최소값을 찾기 위한 뉴턴 반복을 통해 런타임에 계산됩니다.

벨소리 꺼짐(왼쪽)과 켜짐(오른쪽) 비교:

빛 누출 솔루션: 사면체 메쉬 프로브를 내부 프로브와 외부 프로브로 나누고 표면, 형상 속성 또는 셰이더 매개변수, 버텍스 그리기, 지연 데칼에 0-1 내부 마스크

간접광의 스페큘러 반사: Infamous의 시애틀은 230개의 정적 반사 프로브를 사용하는데, 이는 이미 메모리 한계를 뛰어넘고 있습니다. 쓰시마는 235개를 사용했지만 재조명에 필요한 추가 데이터는 주문형, 생물군계당 기본 프로브, 인스턴스화된 내부 프로브, 중첩된 프로브에 대한 지원 추가(한 번에 최대 128개의 재조명 프로브)였습니다.
오프라인으로 캡처된 데이터: 알베도 큐브맵(BC1 형식), 노멀 + 깊이 큐브맵(BC6H 형식), RG: 팔면체 노멀 인코딩, 깊이(쌍곡선), 모든 큐브맵 256x256x6.
반사 프로브를 위한 새로운 조명: 비동기 계산(프레임당 하나)에서 루프를 실행하고, 먼 그림자 아틀라스로 그림자를 음영처리하고, 타일당 128x128 텍셀을 사용하는 타일당 그림자 맵을 실행합니다. 반사 프로브 밝기 정규화에도 사용되는 간접 조명용 단일 SH 샘플은 필터링된 중요도 샘플링을 사용하여 사전 필터링되었으며 GPURealTimeBC6H를 사용하여 BC6H로 압축되어 메모리 사용량을 줄이고 샘플링 성능을 향상시켰습니다.
큐브맵 그림자 추적: 먼 그림자 맵은 내부 음영 처리, 낮은 그림자 해상도 및 LOD 조합에는 충분하지 않습니다. 관찰: 깊이 큐브맵에는 각 큐브맵 텍스처를 다시 조명할 때 많은 폐색 정보가 있습니다. 평행 광선의 교차점 찾기, 큐브맵 볼륨 사용, 교차점에서 샘플 깊이, 하늘 깊이 ⇒ 폐색되지 않음, 4x4 PCF 사용. 꽤 투박하지만 저렴하고 효과적입니다.

수평 폐색: 버텍스 노멀

하늘 대기 조명은 미리 계산된 3D LUT를 사용하여 Mie 방사조도에 그림자를 적용하고 Rayleigh 방사조도에 앰비언트 오클루전(AO)을 적용합니다. Haze는 AO의 평균 하늘 가시성을 사용합니다. 구름은 포물면 텍스처로 렌더링됩니다. 현재 태양과 달 각도의 3D LUT는 각 프레임마다 2D로 리샘플링됩니다. 업샘플링은 일출 및 일몰 시 앨리어싱을 방지하기 위해 큐빅 필터링을 사용하여 수행되므로 향후 조회 비용이 더 저렴해집니다. 또한 Rayleigh 색상 공간도 사용자 정의됩니다.

구름은 768x768 포물선 텍스처로 렌더링되며, 앤티앨리어싱에는 구름 밀도를 사용하고 Mie 산란에는 Henyey-Greenstein 위상 함수를 사용하여 체적 안개(국소 조명, 앤티앨리어싱)를 달성합니다. 추가적으로 파티클 라이팅에 대해서도 설명합니다.
톤매핑 측면에서 Infamous의 게임에서는 물리적으로 합리적인 디퓨즈 알베도 값을 유지하고 디퓨즈 색상 참조 맵을 생성하기 위해 노력합니다.

하이라이트 밝기가 임계값을 초과하는 경우에만 밝기를 사용하여 주로 조도를 기반으로 하는 노출 시스템으로 전환합니다. 다이내믹 레인지를 다룰 때 실내 조명은 상대적으로 어둡고 하늘이 대부분의 조명을 주도합니다. 인간의 시각 시스템은 매우 넓은 동적 범위를 인식할 수 있으며, 양측 필터를 사용하여 전체 대비를 줄이면서 이미지 세부 사항을 보존할 수 있습니다.
톤매핑은 색상 공간도 처리합니다. 채도가 높은 색상을 청록색, 자홍색 및 노란색으로 공간적으로 잘라내고 채널별 "Reinhard" 연산자만 적용하여 채널별 톤 맵을 색상으로 렌더링합니다.

몇 가지 색상 공간을 시도했습니다: ACES2065-1(AP0), ACEScg(AP1), Rec.2020, DCI-P3, ACEScg가 그중 최고이지만 여전히 빨간색이 노란색에 너무 편향되어 조정된 빨간색 기본 x 좌표(0.713⇒0.75)입니다.


효과 비교:

또한 톤매핑은 화이트 밸런스, Purkinje Shift 등과 같은 효과도 처리합니다.

대규모 지형 렌더링을 위한 동시 이진 트리 실험에서는 대규모 지형 렌더링을 위해 동시 이진 트리를 사용하는 Unity의 새로운 기술 결과를 공유합니다. 대규모 지형 기하학의 적응형 세분화를 계산할 때 동시 이진 트리의 기본 사항과 이점을 다루고, 원래 기술을 Unity 게임 엔진에 통합하려는 최신 노력을 자세히 살펴봅니다. 아래 이미지의 녹색 노드는 세분화 체계에 표시하려는 삼각형에 해당하는 이진 트리 표현의 리프 노드입니다.

이는 동시 이진 트리의 다른 모든 수준에 저장된 합계 감소 트리입니다. 비트 필드에서 1(또는 리프 노드)로 설정된 비트 수를 루트 노드까지 점진적으로 추가하여 비트 필드에 의해 인코딩된 이진 트리의 총 리프 노드 수를 제공합니다. 그런 다음 이 합계 감소 트리를 순회함으로써 0을 무시하면서 1로 설정된 비트를 반복하는 방법, 즉 리프 노드를 반복하는 방법이 제공됩니다. 실제 예로 돌아가서, 인코딩된 이진 트리는 가장 긴 가장자리 이등분을 나타냅니다. 이를 사용하여 세분화의 각 활성 삼각형에 스레드를 할당합니다.

테셀레이션 초기화: 최대 테셀레이션 깊이를 선택하고 CBT는 설정된 깊이까지 가능한 모든 이진 트리를 인코딩합니다. 변경되면 CBT가 다시 코딩되고 CBT 버퍼가 초기화되며 부호 없는 정수 배열 및 축소 트리는 비트 필드를 단위로 압축합니다.

테셀레이션 업데이트:

렌더링 테셀레이션:

렌더링을 동기식으로 업데이트합니다.

결론: CBT는 고도로 사용자 정의 가능한 LOD 표준에 맞춰 낮은 저장 비용과 우수한 성능을 갖춘 대규모 지형 지오메트리 렌더링 방법입니다.
14.5.3.2 빛과 그림자 기술
Uncharted 4의 Deferred Lighting은 Uncharted 4의 Deferred Lighting을 공유합니다.
목표와 동기는 머티리얼 데이터 읽기/수정이 필요한 많은 화면 공간 효과(파티클, 데칼), 더 중요한 SSR, 큐브맵, 간접 그림자 등이 머티리얼 데이터 저장을 피할 수 없다는 것입니다. Compact GBuffer는 고밀도 지오메트리에서 비용이 많이 들고, 포워드 셰이더의 조명 복잡성으로 인해 레지스터에 엄청난 압력이 추가되어 지오메트리 패스 속도가 더욱 저하됩니다.
Uncharted 4는 마침내 완전히 연기된 기능을 사용합니다. GBuffer는 게임의 모든 자료를 지원해야 했지만 당시 하드웨어에는 메모리와 대역폭이 너무 많았습니다. GBuffer는 픽셀당 16비트의 부호 없는 버퍼입니다. 비트는 제작 중에 기능 간에 지속적으로 이동하며, 다양한 기능에 필요한 비트 수를 결정하기 위한 수많은 시각적 테스트, 내부 기능을 캡슐화하기 위해 GCN 매개변수를 많이 사용합니다.

세 번째 옵션인 GBuffer는 좀 더 복잡한 머티리얼에 사용되며, 머티리얼의 종류에 따라 다르게 표현됩니다. 옵션인 GBuffer를 사용하는 재료에는 천, 머리카락, 피부 및 실크가 포함됩니다. GBuffer 표현식은 상호 배타적입니다(예: 옷감과 스킨을 동일한 픽셀에 배치할 수 없음). 이 제약 조건은 머티리얼 제작 파이프라인에 적용됩니다. 머티리얼에 필요하지 않은 경우 선택적 GBuffer는 쓰거나 읽혀지지 않습니다.
문제는 모든 조명 유형은 말할 것도 없고 피부, 천, 식물, 금속, 머리카락 등이 지원되어야 하기 때문에 지연된 셰이더가 빠르게 매우 비대해질 수 있다는 것입니다. 재료 분류를 통해 개선될 수 있습니다. 실제 재료 ID가 아닌 재료 "ID" 텍스처를 저장하고, 사용된 셰이더 기능의 비트마스크만 저장하며, 12비트를 8비트로 압축합니다(기능 상호 배타성을 고려하여). 각 16x16 타일에 대해 전체 타일의 재질 마스크를 사용하여 조회 테이블에 인덱싱합니다. 조회 테이블은 미리 계산되어 있으며 타일의 모든 기능을 지원하는 가장 간단한 셰이더를 가지고 있습니다.
uint materialMask = DecompressMaterialMask(materialMaskBuffer.Load(int3(screenCoord, 0)));
uint orReducedMaskBits;
ReduceMaterialMask(materialMask, groupIndex, orReducedMaskBits);
short shaderIndex = shaderTable[orReducedMaskBits];이 셰이더가 조명을 계산할 타일 목록에 타일 좌표를 원자적으로 추가합니다. 원자 정수는 dispatchIndirect 매개변수 버퍼의 디스패치 번호이기도 합니다.
if (groupIndex == 0)
{
uint tileIndex = AtomicIncrement(shaderGdsOffsets[permutationIndex]);
tileBuffers[shaderIndex][tileIndex] = groupId.x | (groupId.y << 16);
}분류는 성능을 크게 향상시켰으며 이전에도 유사한 기술이 문헌에서 사용되었습니다.

더욱 최적화할 수 있습니다. 천 셰이더를 예로 들면, 모든 픽셀이 천인 타일의 경우(즉 천 재질 마스크 비트가 1로 설정됨) 이 분기가 하는 일은 항상 true로 평가되어야 하기 때문에 오버헤드를 추가하는 것뿐입니다. 타일의 모든 픽셀이 동일한 재질 마스크를 가질 때 사용되는 또 다른 미리 계산된 테이블, 즉 "분기 없는" 배열 테이블을 만듭니다. 분류 중에 이 상황을 확인하고 적절한 테이블을 사용하면 분기가 제거될 뿐만 아니라 전역 컴파일러 최적화 기회도 제공됩니다.
//
short shaderIndex = shaderTable[orReducedMaskBits];
//
bool constantTileValue = IsTileConstantValue( … );
short shaderIndex = constantTileValue ? branchlessShaderTable[orReducedMaskBits] : shaderTable[orReducedMaskBits];
개선 전(왼쪽)과 개선 후(오른쪽) 비교.
최악의 경우 비용이 많이 드는 시나리오의 성능 향상: 4.0ms - 최적화 없음("uber 셰이더"), 3.4ms(-15%) - 최상의 셰이더 선택 시, 2.7ms(-20%, 전체 -30%) - 분기 없는 셰이더 사용. 평균적으로 브랜치 없는 셰이더는 매우 저렴한 비용으로 10~20%의 추가 개선을 제공할 수 있으며, 최고의 셰이더를 선택하면 평균 20~30%의 개선을 제공할 수 있습니다. 이를 통해 기본 성능에 영향을 주지 않고 재료의 복잡성과 다양성을 달성할 수 있으며 게임의 나머지 부분에 영향을 주지 않고 하나의 셰이더(예: 실크 셰이더)에 복잡성을 추가할 수 있습니다. 인터페이스 구현은 여러 번의 반복 후에도 깨끗하고 투명한 상태로 유지되며 범주형 컴퓨팅 셰이더가 런타임에 거의 영향을 주지 않고 비동기 계산에서 실행된다는 추가 이점이 있습니다.
조명 유형에 따라 다양한 컴퓨팅 셰이더를 할당하여 더욱 개선할 수 있으며, 몇 가지 조명 유형으로 인해 대부분의 복잡성과 비용이 추가됩니다. 반복하고, 비트의 가치를 실제로 이해하고, 궁극적으로 좋은 시스템에 도달하는 것은 어렵습니다. 단순한 것이 더 좋으며 약간의 성능 향상을 위해 일부 기능이 희생될 수 있습니다.
거울 폐색에 대해 이야기해 봅시다. 큐브맵은 로컬 폐색을 설명하지 않습니다. 해결책은 때때로 폐색 내부/주변에 더 많은 큐브맵을 추가하는 것입니다. 이는 성능/메모리 비용은 말할 것도 없고 형상 배열 방식으로 인해 항상 실현 가능한 것은 아닙니다. Frostbite의 specular occlusion과 같은 샘플링 위치에서는 AO 값만 사용할 수 있는데 매우 잘 작동하지만 방향성은 어떻습니까?
보다 정확한 폐색을 얻기 위해 Uncharted 4는 샘플 포인트가 폐색되는 방법과 방향을 인코딩하는 일부 인코딩을 사용하여 반사 로브를 어떻게든 폐색합니다.

왼쪽: 반사 로브; 오른쪽: 최소 폐색 원뿔 - 곡선 원뿔.
오프라인 처리 중에 곡선 원뿔은 화면 공간의 구부러진 노멀 및 원뿔에 설명된 방법을 사용하여 생성되며 최소 폐색 방향은 다음과 같이 정의됩니다.

그 중 빛의 길이가 일정 거리보다 작으면

반사 원뿔의 경우 Phong/GGX 로브를 일치시키는 Drobot과 같은 아이디어를 사용하여 로브 에너지의 90%에 맞는 원뿔을 찾습니다. GGX의 경우 간단한 일치 항목이 발견되었습니다.

두 원뿔이 교차하는 경우 교차점에서 입체각을 찾습니다.

교차하는 두 원뿔의 입체각은 다음 공식을 사용하여 계산할 수 있습니다. 두 개의 원뿔 각도

float IntersectionSolidAngle(float cosTheta1, float cosTheta2, float cosAlpha)
{
float sinAlpha = sqrt(clamp(1.f - cosAlpha*cosAlpha, 0.0001f, 1.f));
float tanGamma1 = (cosTheta2 - cosAlpha*cosTheta1) / (sinAlpha*cosTheta1);
float tanGamma2 = (cosTheta1 - cosAlpha*cosTheta2) / (sinAlpha*cosTheta2);
float sinGamma1 = tanGamma1 / sqrt(1 + tanGamma1*tanGamma1);
float sinGamma2 = tanGamma2 / sqrt(1 + tanGamma2*tanGamma2);
// Now we compute the solid angle of the first cone (This is divided by 2*kPi. That factor is taken into account in the texture)
float solidAngle1 = 1 - cosTheta1;
return (SegmentSolidAngleLookup(cosTheta1, sinGamma1) + SegmentSolidAngleLookup(cosTheta2, sinGamma2)) / solidAngle1;
}
샘플이 심하게 가려져 방향성 라이트맵의 설명으로 돌아가면 에너지는 유지되지만 반사 디테일은 손실되어 대부분 좋아 보입니다! 이 접근 방식은 상대적으로 비용이 많이 들고 하나의 매개변수가 고정되면 함수가 단순화됩니다. 러프니스 파라미터를 결정한 다음 거칠기에 따라 최종 결과를 조정할 수도 있습니다. 성능상의 이유로 일부 수준에서는 비활성화되어 있습니다. 동적 개체(예: 캐릭터)에는 적합하지 않으며 앞서 언급한 더 간단한 폐색 방법을 사용할 수 있습니다. 물리적 기반은 아니지만 많은 폐색 문제를 해결합니다. 앞으로 나아갈 수 있고, 더 정확한 폐색을 위해 다른 표현을 사용하고, 완전히 다른 방향으로 갈 수 있습니다.
순간 그림자 매핑을 사용하여 앤티앨리어싱된 그림자 렌더링에서는 그림자 앤티앨리어싱을 달성하기 위해 MSM(모멘트 섀도우 맵)을 사용하는 기술을 설명합니다.
섀도우 맵은 실시간 렌더링의 기본 기술이지만 제한된 해상도로 인해 심각한 앨리어싱이 발생할 수 있습니다. 기존 솔루션으로는 PCF(% Progressive Filtering), VSM(Variance Shadow Map) 등이 있다. PCF는 샘플 필터링 영역, 임계값, 각 픽셀에 대한 필터링을 수행하므로 많은 비용이 소모된다.

깊이 분포의 경우 셰이딩은 깊이, 즉 한 텍셀 단계의 함수이며 일반적으로 단조 함수입니다.

VSM은

그 밖에도 푸리에 계수를 저장하는 CSM(Convolution Shadow Map, Convolution Shadow Map),

순간부터 그림자까지, 많은 분포는 표면의 그림자 여드름을 피하기 위해 동일한 4개의 순간을 공유합니다.

경계를 계산하는 효율적인 방법이 필요합니다. 기본 아이디어는 경계가 항상 매우 구체적인 깊이 분포로 달성된다는 유용한 수학적 정리를 활용하는 것입니다. 즉, 주어진 4개의 모멘트와 일치하는 세 가지 다른 깊이 값만 사용하며 그 중 하나는 깊이가 최소화되는 것입니다. 따라서 두 개의 깊이 값과 세 단계의 높이만 더 계산하면 되는데, 이것이 바로 모멘트 섀도우 매핑 알고리즘이 하는 일입니다.

이전 예의 경계는 충분히 선명하지 않은 반면, 아래 이미지에 표시된 경계는 매우 좁기 때문에 재구성이 매우 정확합니다. 대부분의 경우를 포함하는 필터 영역의 두 표면이 완벽하게 재구성되었습니다.

그러나 문제가 있습니다. 하드 섀도우를 필터링하기 위해 텍셀당 64비트 이상을 감당할 수 없지만 깊이 지수만 저장하면 반올림 오류가 너무 커집니다. 기본적으로 섀도우 맵의 4개 채널에는 하단에 표시된 4가지 기본 기능이 저장됩니다.

사용 가능한 값 범위가 제대로 활용되지 않습니다.

해결책: 최적화된 다항식 기반을 사용하십시오. 이제 64비트이면 충분합니다.

범위의 볼륨 최대화 활용:

MSM의 사용과정은 다음과 같습니다.
- 순간 그림자 플롯을 생성합니다.
다중 샘플링된 깊이 버퍼로 렌더링합니다.

- 분석할 때 순간을 계산합니다.

- 2채널 가우스 + 밉맵과 같은 필터링.

- 복원의 순간.
조각을 색칠하고,
필터링된 순간 그림자 맵 샘플링(밉매핑, 이방성 등 사용)
역양자화 변환:

- 바이어스 순간. 예: 두 순간은 비트 2⋅3에 저장됩니다.
반올림 오류는 모멘트를 무효화합니다.
보간법으로 복구합니다:
, . 4⋅16비트이면
. 빛샘이 조금 더 많아졌습니다.
MSM, EVSM 및 PCF 비교:

MSM은 또한 반투명 폐색기의 그림자, 순간 부드러운 그림자 및 사전 필터링된 단일 산란을 지원합니다.


결론: 순간 그림자 맵은 다른 필터링 가능한 그림자 맵보다 성능이 뛰어나고 컨볼루션 그림자 맵보다 메모리 요구 사항이 훨씬 낮으며 분산 그림자 맵, 지수 그림자 맵 및 지수 분산 그림자 맵보다 빛 누출이 적습니다. 순간 섀도우맵은 다음과 같은 경우 일반 섀도우맵보다 빠릅니다: 작은 섀도우맵 해상도(앤티앨리어싱으로 인해 가능), 큰 출력 해상도(예: 4k 및 VR), 큰 필터 영역(부드러운 그림자에 적합), 표면 여드름은 거의 문제가 되지 않습니다.
실시간 영역 조명: 연구에서 생산까지의 여정에서는 영역 광원 연구부터 제품 적용까지 전체 링크 기술을 설명합니다. 이 기사에서는 모든 주파수(예: 서로 다른 러프니스)의 영역 광원에 대해 올바른 응답을 원한다고 언급합니다.

이방성을 원할 경우 선형 변환 코사인을 진입점으로 사용할 수 있습니다.

LTC를 사용하여 코사인, 러프니스, 이방성, 경사, 무작위 및 기타 조명 효과를 얻을 수 있습니다.

행렬을 미리 적용한 후 선형변환의 코사인을 구할 수 있다. 러프니스, 시야각 등의 요소를 미리 계산하면 약 80kb의 조회 테이블 데이터를 얻을 수 있습니다.

LTC의 역변환을 통해 원래 코사인 항을 복원할 수 있습니다.

면적 적분은 실제로 주변 적분으로 변환될 수 있습니다.

관련 코드:
float EdgeIntegral( float v1, float v2, float n)
{
float theta = acos(dot(v1, v2));
float3 u = normalize(cross(v1, v2));
return theta * dot(u, n);
}
float PolyIntegral(float3 v[4], float3 n)
{
float sum;
sum += EdgeIntegraL(v[0], v[1]);
sum += EdgeIntegral(v[1], v[2]);
sum += EdgeIntegral(v[2], v[3]);
sum += EdgeIntegral(v[3], v[0]);
return sum/(2.0 * pi);
}구현 프로세스:
- 거칠기와 보는 각도를 기준으로
을 찾습니다. 거칠기가 크면 두꺼운 조명 영역이 생성됩니다.

정규화된 행렬의 4개 항목이 필요합니다.


렌더링이 안정적이고 정확해집니다.

LUT를 찾을 때 더 쉬운 방법이 있습니다.

을 사용하여 다각형을 변환합니다. 다각형을 위쪽 반구에 맞게 자릅니다. 법선에 의한 곱셈을 제거하고 대신 벡터 모양 요소를 사용할 수 있습니다.

다각형은 프록시 구로 근사화될 수 있습니다.

효과 비교:

- 모서리 적분을 계산합니다. 다음 코드를 사용하여 계산하면 밝은 영역에 밴드 결함이 있습니다.
float EdgeIntegral( float v1, float v2, float n)
{
float theta = acos(dot(v1, v2));
float3 u = normalize(cross(v1, v2));
return theta * dot(u, n);
}
다음 코드를 수정합니다.
float EdgeIntegral( float v1, float v2, float n)
{
float theta = acos(dot(v1, v2));
//
float3 u = cross(v1, v2) / sin(theta); // :float3 u = normalize(cross(v1, v2));
return theta * dot(u, n);
}
보기엔 좋아보이지만, 에이코스 안에는 악이 숨어있습니다! acos 구현을 수정하고 합리적인 피팅을 사용해야 합니다.
float EdgeIntegral( float v1, float v2, float n)
{
float x = dot(v1, v2);
float y = abs(x);
float a = 5.42031 + (3.12829 + 0.0902326*y)*y;
float b = 3.45068 + (4.18814 + y)*y;
float theta_sintheta = a / b;
if(x < 0.0)
theta_sintheta = pi*rsgrt(1.0 - x*x) - theta_sintheta;
float3 u = cross(v1, v2);
return theta_sintheta*dot(u, n);
}이전 곡선과 새 곡선의 비교:

최종 효과는 마침내 좋습니다.

그러나 더 낮은 비용으로 적합합니다.
float EdgeIntegral( float v1, float v2, float n)
{
(...)
// float a = 5.42031 + (3.12829 + 0.0902326*y)*y;
// float b = 3.45068 + (4.18814 + y)*y;
// float theta_sintheta = a / b;
float theta_sintheta = 1.5708 + (-0.879406 + 0.368609*y)*y;
(...)
}또한 이 LTC 방법은 텍스처 영역 광원도 지원합니다.

요약: PS4@1080p의 확산 + 반사 성능: 0.9ms로 수치 문제가 해결되었습니다.
Treyarch의 Volumetric Global Illumination은 볼륨 텍스처의 GI, Lean 텍스처 데이터, 프로브에 의해 구워진 IBL 및 볼록한 블렌드 모양을 포함하여 Blizzard가 체적 전역 조명과 관련하여 제시한 기술입니다. 기존의 반사 프로브와 방사량 볼륨에는 모두 가시성 문제가 있습니다. 즉, 각 프로브의 가시성 항목이 고려되지 않습니다.

반사 프로브를 복셀 방식으로 렌더링하는 경우 필요한 시간이 엄청납니다.

색상은 반사 프로브에서 수집되어 큐브맵에 다시 투영되고 결합되어 구멍을 채웁니다.

효과적으로 복셀당 4096개의 광선은 15개의 이웃 샘플을 고려하여 누락된 광선에 색상이 지정됩니다.

또는 기존 프로브에서 재투영합니다.

재투영 시 큐브맵에서 입체각을 정의하는 표면까지의 거리, 각도, 거리를 기준으로 이웃 후보를 정렬하고, 깊이 피라미드에 대해 샘플 영역을 검증하고, 보이는 경우 적절한 밉 샘플링을 수행합니다.

distFromUnitCube = sqrt( 1 + u^2 + v^2 ); // Compensation for cube-map shape.
angleOfVoxel = 4 * PI / numSamples; // Solid angle from voxel.
inSqrt = 1 + distFromVoxel^2 * angleOfVoxel * ( angleOfVoxel – 4*PI ) / ( 4 * PI^2 * distFromProbe^2 );
angleOfProbe = 2*PI * ( 1 – sqrt(inSqrt) ); // Solid angle from reflection probe.
cubeRes = 1.0f / sqrt( angleOfProbe * distFromUnitCube^3 ); // Resolution needed for sample.
mipLevel = clamp( mipCount – log2( cubeRes ), 0, mipCount ); // Mip level to use.
return mipLevel;가장 큰 이점은 하드웨어 렌더링, 바운스를 얻기 위한 재렌더링, 레이트레이싱 및 재투영을 한 번만 수행한다는 것입니다. 텍스처 인코딩은 BC6H 압축 환경 큐브를 사용하며, 장점은 3개의 샘플, 하드웨어 삼선형 필터링만 있다는 것입니다.
color = xVolume.SampleLevel( coord ) * normal.x * normal.x +
yVolume.SampleLevel( coord ) * normal.y * normal.y +
zVolume.SampleLevel( coord ) * normal.z * normal.z;
//
color[n] = normal^2 * float3(Xsample[n], Ysample[n], Zsample[n]);또한, 빛샘 현상이 큰 문제인데, 기존의 해결 방법은 일반 값을 기준으로 삼선형을 조정하는 것입니다[Silvennoine15]. 기사에서는 평면, SDF 등 더 많은 복셀 데이터 솔루션을 시도했지만 벽에 검은 점과 같은 바람직하지 않은 결함이 있었습니다. 그래서 저는 폴오프 볼륨을 사용하고 아티스트가 GI 볼륨의 클리핑 모양을 정의하는 직육면체를 배치하도록 했습니다. 직육면체의 각 측면에는 폴오프 GI에 대한 페더 거리가 있습니다. 복잡한 공간의 경우 볼록한 감쇠 모양을 사용하세요. 런타임 구현:
AABB 볼륨을 선별하여 볼륨 목록을 생성합니다.
확장, 병합 또는 뺄 수 있는 6개 평면 세트인 가시 볼륨인 Convex Hull CSG에 대한 픽셀당 감쇠를 계산합니다.
법선을 기준으로 세 가지 환경 큐브 값을 샘플링합니다.
모든 볼륨 간의 결과를 혼합합니다.
해결해야 할 문제에는 복셀 내의 형상, 조명 균열 등이 포함됩니다. 또한 반사에는 반사 평면을 사용합니다.
타일 셰이딩: 라이트 컬링 – 빛의 속도에 도달하면 무료 러프 컬링을 위해 래스터라이저를 활용하고 빠른 컬링 노력을 위해 초기 깊이 테스트를 활용하는 타일 조명을 타일링하고 컬링하는 새로운 기술이 도입되었습니다. 또한 명시적인 다중 GPU 프로그래밍 기능을 활용하는 기술도 제시됩니다.
타일 셰이딩의 장점은 조명 단계에서 모든 가시광선을 한 번에 사용한다는 것입니다. 단점은 타일 세분성을 사용하면 덜 정확한 컬링이 발생하고 프러스텀 원시 테스트가 너무 거칠거나 너무 느리다는 것입니다. 왜 컬링에 관심을 가져야 할까요? 컬링 자체는 비용이 많이 드는 작업일 수 있으므로 정확한 컬링은 조명 속도를 높일 수 있으며 "오탐지"를 도입하면 조명 성능이 크게 저하될 수 있습니다! 컬링 과제는 컬링 단계에서 얻은 "거짓 긍정" 조명의 수를 최소화하고 타일 셰이딩 렌더링에서 라이트 셰이딩 성능을 향상시키는 것입니다.
구면과 프러스텀 평면: 절대 사용하지 마세요! 실제로 가장 일반적으로 사용되는 테스트는 프러스텀 및 경계 상자 테스트로, 큰 구에 대해서는 매우 부정확합니다.

제거 정확도를 높이는 방법은 무엇입니까? 타일의 최소-최대 z와 모든 교차점의 최소-최대 z를 비교하면 4개의 광선이 더 잘 작동합니다.


그러나 컴퓨팅 셰이더에 대한 컬링은 형편없습니다. 이는 간단한 열거입니다. 총 작업 = X Y N, 여기서 X – 타일 그리드 너비, Y – 타일 그리드 높이, N – 조명 수입니다. 컬링 성능을 향상시키는 방법은 무엇입니까? 열거 순서를 줄이고, 화면을 4~8개의 하위 화면으로 세분화하고, 하위 화면 프러스텀를 기준으로 조명을 대략적으로 선별하고, 선별 단계에서 해당 하위 화면을 선택합니다. 이는 적은 수의 광원으로 최대 2배까지 개선할 수 있지만 더 많은 것이 필요합니다! 우리는 컴퓨팅 능력에 의해 제한되어 있으며 셰이더에서 특수 하드웨어 장치로 일부 작업을 오프로드하려고 합니다! 계산에서 그래픽 파이프라인으로 전환해 보겠습니다! 좋았던 시절처럼!
라이트 컬링을 위해 그래픽 사용: 래스터라이저를 사용하여 라이트 조각 생성, 빈 타일은 기본적으로 건너뛰기, 폐색에 대한 깊이 테스트 사용, 폐색 타일의 불필요한 작업 건너뛰기, 미세 컬링 및 라이트 목록 업데이트를 위해 PS의 기본 광선 교차 사용. 아이디어 개요: 컬링 단계 청킹 → 1픽셀, 조명 볼륨 → 프록시 기하학, 거친 XY 컬링 → 래스터라이제이션, 거친 Z 컬링 → 깊이 테스트, 미세 컬링 → 픽셀 셰이더.
통합하는 방법? 우버 셰이더를 사용하지 말고 항상 타일 셰이딩을 축소, 컬링(새로운 방법 사용), 조명의 3단계로 분할하세요. 새로운 컬링 방법 개요: 카메라 프러스텀 컬링, 깊이 버퍼 생성, 래스터라이제이션 및 분류에 대한 설명은 다음과 같습니다.
- 1단계: 카메라 프러스텀 컬링. 가시광원을 "외부"와 "내부"로 분리하는 카메라 프러스텀를 기반으로 조명을 컬링합니다.

2단계: 깊이 버퍼를 만듭니다. 각 타일에 대해: "외부" 빛의 최대 깊이를 찾아 복사하고, "내부" 빛의 최소 깊이를 찾아 복사합니다. 깊이 테스트는 고성능의 핵심입니다! 셰이더에서 [earlylengthstencil]을 사용하세요.
3단계: 래스터라이제이션 및 분류. 깊이 테스트를 사용하여 빛 형상을 렌더링합니다. "외부" - 최대 깊이 버퍼, 전면 직접 깊이 테스트, "내부" - 최소 깊이 버퍼, 뒷면에 대한 역방향 깊이 테스트, 정확한 컬링 및 타일별 조명 목록 생성을 위해 PS를 사용합니다.
일반적인 조명 유형: 점 조명(전방향), 방향 조명(스포트라이트), 조명 기하학은 프록시 기하학으로 대체될 수 있습니다.

포인트 라이트의 프록시 지오메트리는 구에 충분히 가까운 기하학적 구(2개 분할, 8진수 기반, 아래 왼쪽 이미지)를 사용하며, 낮은 다각형은 낮은 해상도에서 잘 작동하고, 정삼각형은 래스터라이저 시간을 줄일 수 있습니다. 스포트라이트의 프록시 형상(아래, 오른쪽)은 탐조등에서 반구까지 쉽게 매개변수화할 수 있으며 평면 부품을 사용하여 영역 조명을 처리할 수 있습니다.

래스터라이제이션된 라이트 컬링의 장점: 조명이 없는 타일과 가려진 라이트에는 적용할 수 없으며 대략적인 컬링은 거의 무료입니다! 작은 크기의 광원에 대한 성능 향상은 놀랍습니다. 복잡한 프록시 모델도 사용할 수 있습니다! 수학적으로 말하면 이는 분기 및 바인딩 프로세스입니다! 성능 비교는 다음과 같습니다. 일반적으로 몇 배의 개선이 있습니다.

래스터라이제이션된 컬링에 대한 결론: 동일한 CS 버전보다 3~20배 빠르고, 더 적은 비용으로 더 적은 "오탐지"를 생성하고, 해상도 스케일링이 향상되고, 래스터라이제이션를 통해 복잡한 조명 볼륨으로 작업할 수 있습니다.
Decima Engine: Advances in Lighting 및 AA는 Decima Engine의 조명 및 앤티앨리어싱 기술을 공유합니다. Decima 엔진은 원래 Killzone 시리즈용으로 개발되었으며 현재 Horizon: Zero Dawn 및 Death Stranding에 사용됩니다. 이 기사에서 다루는 렌더링 기술에는 단일 점 광원의 광 벡터를 구부려 구형 영역 광원을 근사화하는 향상된 방법, 높은 안개에 대한 사실적인 대기 산란, 1080p를 위한 2프레임 시간 앤티앨리어싱 솔루션, 최적화된 2160p 체커보드 렌더링 및 PS4 Pro에서 사용되는 "직소 퍼즐" 솔루션 전략이 포함됩니다.
영역 조명의 경우 모양에 대해 GGX를 통합하는 것이 어렵습니다. 다양한 근사 방법, 성능 대 품질 균형, 특정 모양(예: 다각형 조명의 경우 [Hill16]), 구형 조명의 경우 저렴한 "뒤틀린" 포인트 조명 트릭 [Karis13]은 왜곡을 일으킬 수 있지만 개선될 수 있습니다.

픽셀당 1개의 포인트 조명을 사용하여 영역 조명을 근사화하는 방법은 무엇입니까? 점광을 픽셀의 반사 벡터 [Karis13](아래, 왼쪽)쪽으로 이동하면 Phong 모델[Picott92]에서는 잘 작동하지만 마이크로패싯 모델에서는 잘 작동하지 않습니다. 즉, 피크 응답이 여전히 "무시"될 수 있습니다. 아이디어: 점광원을 주변으로 이동하여 반응을 최대화합니다. 주요 요소: N·H(아래 그림, 오른쪽).

[Karis13]의 방법은 L을 반사 벡터 방향으로 구부리고, 반대로 L을 구부려 N∙H를 최대화하는 것입니다.

N을 최대화하는 ψ∙H를 해결하는 것은 어렵습니다. 등가 문제는 다음과 같이 해결될 수 있습니다.

그런 다음 뉴턴의 반복 방법을 사용하여 다음을 해결합니다.

효과 비교는 다음과 같습니다.

이 문서에서는 높은 안개 구현에 대해 설명합니다. 주요 단계와 알고리즘은 다음과 같습니다.



높은 안개 효과:

복잡한 자연 장면이 있는 Decima 엔진의 경우 곡률이나 하위 픽셀 너비와 같은 형태학만으로는 충분하지 않으며 모든 식물은 알파 테스트를 거쳤으며 반투명도입니다. 오버헤드는 비쌀 수 있습니다. SMAA [Jimenez12]는 초목에서 속도가 느려질 수 있으므로 FXAA에 TAA를 보충하세요. 다음 표는 다양한 시나리오에서 다양한 AA의 소비를 보여줍니다.


TAA에는 이전 프레임 데이터가 필요하지만 Horizon은 그렇지 않습니다. AA가 다른 모든 것에 적용된 후 매우 얇은 형상과 낮은 품질의 모션 벡터가 많이 필요합니다. 피드백 루프의 누적 기록은 없으며 현재 및 이전 원시 렌더링만 입력으로 사용됩니다. TAA의 적응형 1D 선명화 기능을 사용하여 두 프레임 내에서 픽셀당 4x 가장자리 샘플링:

샘플링 모드는 FLIPQUAD [Akenine02]와 유사하지만 더 선명하고 추가 밉맵 로직이 없으며 MSAA/EQAA 하드웨어가 필요하지 않으며 선과 그리드의 앨리어싱 제거가 좋지 않습니다(FXAA로 해결).

체스판 렌더링과 다른 AA 간의 효과 및 성능 비교는 다음과 같습니다.

PS4 Pro의 2160p 체커보드 렌더링:
- 전형적인 체스판 렌더링.
프레임당 픽셀의 50%를 렌더링합니다.
매 프레임마다 대체 샘플링 위치.
깊이 버퍼, 삼각형 인덱스 버퍼, 알파 테스트 범위 등 간격을 "지능적으로" 채우기 위해 기본 해상도 힌트를 렌더링합니다.
2160p@30Hz에서 기본 해상도는 Horizon에 대한 오버헤드가 너무 크며 UI와 최종 백버퍼만 기본 해상도이고 모든 것이 2160p 보드에서 실행되며 기본 해상도 힌트가 없어 표준 해상도를 깨뜨립니다...
각 프레임(아래, 왼쪽)의 모든 픽셀 모서리의 50%와 사용 가능한 평균 모서리를 렌더링하면 모든 픽셀이 동일하게 처리됩니다. 기본 해상도 힌트가 필요하지 않으며, 형태학적 트릭도 없고, 디더링 모드도 없습니다(아래 중간 이미지). 두 프레임 모두 기본 픽셀당 4개의 샘플을 사용하여 AA 안정성은 1080p의 TAA와 유사합니다(아래 오른쪽 이미지).

가장 가까운 두 픽셀 모서리의 평균화는 본질적으로 앨리어싱되지 않습니다.

단일 프레임 대각선에는 여전히 문제가 있습니다. FXAA는 대각선으로 적용됩니다.

체커보드 렌더링 요약: 체커보드 해상도(1920x2160)에서 렌더링 및 사후 처리되어 (YCoCg)의 탱그램(2160x2160)으로 변환됩니다. 여기서 YCoCg는 다음 패스에 사용됩니다. 단일 GatherRed()의 루마 샘플 4개. 일반 FXAA를 적용하면 직소 퍼즐로 인한 대각선의 앨리어싱이 제거됩니다. 현재의 직소 퍼즐과 재투영된 역사적 직소 퍼즐을 혼합하여 2160p로 출력합니다.

GGX+Smith 마이크로패싯을 위한 PBR 확산 조명에서는 마이크로패싯을 기반으로 한 BRDF, GGX+Smith 마이크로패싯 모델의 디퓨즈 시뮬레이션 및 다른 디퓨즈 BRDF와의 비교를 설명합니다.
확산 마이크로패싯: Oren Nayar의 논문과 동일한 방법으로 좋은 근사치를 찾기 위해 수치적으로 적분을 풀면 조명의 최대 절반이 누락됩니다! 여러 집회를 무시할 수 없습니다. . . (전체 Oren Nayar에는 두 번째 집회도 포함되어 있습니다).

기사에서 G항이 수정되었습니다(아래 사진의 왼쪽은 수정되지 않은 부분이고 오른쪽은 수정된 부분입니다):

향상된 Smith 근사 방법은 비용과 효과를 모두 향상시켰습니다.

효과 비교(램버트, 디즈니, 신형):

타일링 및 클러스터링 렌더링을 위한 향상된 컬링은 Blizzard COD에서 사용하는 타일링 및 클러스터링 조명 알고리즘의 개선 사항을 공유합니다.

데이터 구조 분기에서 이전 조명 알고리즘의 성능 문제:
타일: 정방향에서 삼각형은 여러 타일을 통과할 수 있습니다. 지연 시에는 파면이 타일 크기와 일치할 수 있습니다.
클러스터링: 순방향에서는 삼각형이 여러 클러스터에 걸쳐 있을 수 있으며, 지연 시 파면은 여러 Z-슬라이스를 통과할 수 있습니다.
복셀 트리: 파면은 여러 복셀에 걸쳐 있을 수 있습니다.
삼각형/텍셀: 파면은 여러 삼각형/텍스처에 걸쳐 있을 수 있습니다.

분기의 성능 문제: VMEM 및 VALU는 비용이 많이 듭니다. 분기를 넘어서는(즉, 타일 내에서) 모든 계산은 벡터로 수행됩니다. 모든 메모리 로드는 일관성이 있더라도 각 벡터에서 발생하므로 많은 수의 TCC 장치를 차지합니다. 메모리 작업은 벡터로 수행되므로 ALU 소비가 늘어납니다. 높은 VGPR 소비. 모든 작업이 벡터 기반이므로 모든 상수 데이터(예: 엔터티 설명자)를 VGRS에 로드해야 합니다.
스칼라화: 한 번에 하나의 가지 항목에서만 웨이브프런트를 실행하고, 샘플링된 모든 항목에 대해 웨이브프런트를 반복하고, 모든 웨이브프런트 스레드를 마스크하여 선택한 항목에만 작용하고, 다음 항목으로 이동합니다. 전달 및 지연이 가능합니다.

데이터 컨테이너: 계층 구조. 각 항목의 표시되는 엔터티에 대한 모든 포인터를 저장하고 엔터티 번호, 간접 주소 지정으로 인한 값비싼 순회 및 가변 메모리 저장 비용에 의해 제한되지 않는 리프 클러스터에 대한 포인터입니다.

스칼라화된 계층적 컨테이너: 셰이더는 완전히 스칼라화되어 있으며 VMEM/SMEM 및 VALU/SALU 균형이 더 좋고 VGPR 사용량이 낮습니다(정방향 로딩과 유사). 성능은 매우 가변적입니다. 동일한 엔터티가 다른 컨테이너에 있는 경우 Wavefront는 엔터티를 여러 번 처리할 수 있으며, 이로 인해 데이터 일관성/중복성에 따라 속도가 저하될 수 있습니다. 이상적으로 스칼라화는 엔터티 수준에서 수행되며, 이를 위해서는 정렬된 컨테이너(플랫 비트 배열)가 필요합니다.
데이터 컨테이너: 플랫. 플랫 비트 배열은 비트 모음입니다. 전역 목록에서 n번째 엔터티의 가시성의 n번째 비트를 나타냅니다. 단순 순회 – 비트 순회, 메모리/엔티티 바인딩 – 뷰 프러스텀 컨텍스트별로 주로 사용됩니다.

비트마스크 스칼라화: 셰이더는 완전히 스칼라화되고 엔터티당 한 번씩 실행됩니다. VGPR 사용량은 베이스라인에 비해 낮고 상당히 높아 더욱 우아한 코드라고 할 수 있습니다. 합성 테스트 셰이더의 스칼라화 결과(조명이 조밀한 환경에서 조명 조회에 적용되는 스칼라화):

계층적 데이터 컨테이너는 타일, 클러스터, 복셀 주소와 같은 컨테이너 수준에서 스칼라화될 수 있으며, 플랫 데이터 컨테이너는 라이트/프로브/데칼 인덱스와 같은 저장 엔터티 수준에서 스칼라화될 수 있습니다.
또한 Z-Binning 프로세스가 개선되었습니다.

포워드 + 렌더러에 대한 Z-비닝 알고리즘 단계:
- CPU:
조명을 Z별로 정렬합니다.
가능한 전체 깊이 범위에 걸쳐 균일한 간격으로 빈을 설정합니다.
각 빈 경계 내에서 최소/최대 조명 ID를 사용하여 2 x 16비트 LUT를 생성합니다.
GPU(PS/CS):
벡터 로딩 Z-BIN.
파동 균일 광원의 최소/최대 ID입니다.
최소/최대 범위 내의 광원 비트에서 웨이브가 균등하게 로드됩니다.
가벼운 최소/최대 ID에서 벡터 비트마스크를 만듭니다.
벡터 Z-Bin 마스킹을 사용하여 균일한 광원을 마스킹합니다.
// Flat Bit Array iterator scalarized on entity with Z-Bin masked words
wordMin = 0;
wordMax = max(MAX_WORDS - 1, 0);
address = containerAddressFromScreenPosition(screenCoords.xy);
zbinAddr = ContainerZBinScreenPosition(screenCoords.z);
zbinData = maskZBin.TypedLoad(zbinAddr, TYPEMASK_NUM_DATA(FORMAT_NUMERICAL_UINT, FORMAT_DATA_16_16));
minIdx = zbinData.x;
maxIdx = zbinData.y;
mergedMin = WaveReadFirstLane(WaveAllMin(minIdx)); // mergedMin scalar from this point
mergedMax = WaveReadFirstLane(WaveAllMax(maxIdx)); // mergedMax scalar from this point
wordMin = max(mergedLightMin / 32, wordMin);
wordMax = min(mergedLightMax / 32, wordMax);
// Read range of words of visibility bits
for (uint wordIndex=wordMin; wordIndex<=wordMax; wordIndex++)
{
// … //
}
// Read range of words of visibility bits
for (uint wordIndex=wordMin; wordIndex<=wordMax; wordIndex++)
{
// Load bit mask data per lane
mask = entityMasksTile[address + wordIndex];
// Mask by ZBin mask
uint localMin = clamp((int)minIdx - (int)(wordIndex*32), 0, 31);
uint maskWidth = clamp((int)maxIdx - (int)minIdx+1, 0, 32);
// BitFieldMask op needs manual 32 size wrap support
uint zbinMask = maskWidth == 32 ? (uint)(0xFFFFFFFF) : BitFieldMask(maskWidth, localMin);
mask &= zbinMask;
// Compact word bitmask over all lanes in wavefront
mergedMask = WaveReadFirstLane(WaveAllBitOr(mask));
while (mergedMask != 0) // processed scalar over merged bitmask
{
bitIndex = firstbitlow(mergedMask);
entityIndex = 32*wordIndex + bitIndex;
mergedMask ^= (1 << bitIndex);
ProcessEntity(entityIndex);
}
}포워드+렌더러의 메모리 성능:

포워드+렌더러의 Z-Bin 성능:


또한 이 기사에서는 조명 효과와 성능을 최적화하기 위해 보수적인 래스터라이제이션 컬링, 원자 경합 해결, 광원 프록싱과 같은 방법을 사용합니다. 그 중 광원 에이전트는 에이전트를 더 많은 렌더링 엔터티로 확장하고 래스터라이제이션 일괄 처리를 향상시킵니다.

다양한 타일 래스터라이제이션 방법의 성능.

다양한 클러스터 래스터라이제이션 방법의 성능.

광원제의 효과 비교.

라이트 에이전트의 성능 비교.
Call Of Duty: Infinite Warfare의 사전 계산된 조명은 COD의 사전 계산된 조명과 관련된 다양한 기술을 설명합니다. 사전 계산된 조명 프로세스에 관련된 기술에는 라이트 맵, 감지 조명, 라이트 맵 - 대규모 구조적 기하학(표현, 투영), 라이트 프로브 - 기타 모든 것(조명에서 가시성 분리, 가시성 표현, 보간된 조명, 저장 및 액세스를 위한 경량 메시 구조: 생성, 베이킹, 가시성 표현) 등이 포함됩니다.
구조적 기하학: 최대 성능 향상을 위해 ADH(주변 하이라이트 방향)로 인코딩된 라이트맵, 탄젠트 공간, 반팔면체 인코딩, BC6H 색상, 맵당 압축을 비활성화하는 옵션.

왼쪽: 전통적인 라이트맵 효과; 오른쪽: COD가 예상하는 라이트맵 효과.
폐색만 있는 원거리 조명 아래의 확산 표면에 대한 렌더링 방정식:

특성이 매우 다른 두 가지 용어, 즉 입사광(부드럽고 잘 동작함)과 가시성(빠르게 변화하는 고주파 방향 구성 요소)을 분리해야 합니다! COD는 정점에 가시성을 저장하고 조명은 객체의 일부 지점에 저장됩니다. 가시성을 위해 가시성은 원뿔(축, 원뿔 각도 및 축척(0~1))로 저장됩니다. 가시성은 인스턴스 간에 공유되며 한 번만 베이킹하면 됩니다(변환 중).

가시성을 베이킹할 때 4차 SH 생성, 표면 균일 샘플링, 검증 샘플, 비선형 반복 평활화, 선형 SH의 표준을 추가 채널에 보간, 크기 조정. 원뿔의 최소 제곱 맞춤: 최상의 선형 축, 비선형 맞춤 각도, 그러나 1d에 불과합니다. 비율은 단순히 원뿔 자체의 적분에 대한 원뿔의 적분 가시성의 비율입니다.


조명: 단일 조명 환경으로는 충분하지 않습니다. 대형 물체의 조명은 크게 변할 수 있으며 그라데이션으로 변환할 수 있지만 [Annen2004] 품질/비용이 만족스럽지 않습니다. 여러 샘플링 지점을 생성하고 물체 주위에 흩어져 있으며 개수는 물체 크기에 따라 다르며 이 지점에 입사광을 저장하고 전체 물체를 보간합니다. 샘플링 위치 결정: 객체 크기를 기반으로 N(프로브 대상 수)을 계산하고, 객체 형상을 균등하고 조밀하게 샘플링하고, k-평균 클러스터링을 수행하고, 샘플을 N 클러스터에 할당하고, 느슨해진 후 최종 클러스터 중심이 샘플링 위치가 됩니다.

보간 조명: 샘플링 위치 세트의 공분산 행렬을 계산하고, 고유값의 상대적 크기에 따라 보간 모드가 결정되며, 고유벡터는 보간의 로컬 공간을 정의합니다. 다양한 차원에 대한 보간 방법은 다음과 같습니다.

효과 비교:

라이트 프로브 그리드의 경우 비균일 그리드가 사용됩니다. 먼저 레벨 볼륨의 매우 대략적인 복셀화를 수행하고, 사면체화 복셀화하고, 직육면체 = 멋지고 규칙적인 TET를 입력하면 됩니다. 사면체를 세분화하여([Schaeffer04]의 구성표) 인접한 영역이 최대 1개의 하위 분할 수준으로 분리되도록 하고, 지오메트리 근처에서 세분화하고, 내비메시 및 수동으로 배치한 관심 영역을 세분화합니다.

계층 구조의 맨 아래 지점에 대한 대략적인 조명을 계산하고, 계층 구조의 각 하위 구분에 대해 오류, 즉 주어진 수준과 하위 수준의 보간된 조명 사이의 제곱 차이를 계산하고 셀 볼륨에 대한 적분을 분석합니다. 오류, 관심 영역에 대한 근접성 등을 기준으로 최적화의 우선순위를 지정하여 계층의 최상위부터 다시 최적화합니다. 마지막 점 세트는 규칙적이고 형상 및 신호와 정렬되지만 TET 셀은 재구성된 메시의 셀이 아닙니다.


왼쪽: 사면체 메시; 오른쪽: 조명 메시.
라이트 그리드 가시성: 빛이 벽을 관통하며 검색 위치에서 보이지 않는 경우에도 프로브가 사용됩니다. 프로브는 영향을 제한하기 위해 일부 가시성 정보로 보강됩니다. 각 프로브에 대해 첫 번째 교차점의 무게 중심(0-1 범위)과 함께 접촉하는 각 테트에 대해 삼각형 깊이 맵이 저장됩니다.

다양한 사전 계산 방법의 효과 비교:

ADH 투영 프로세스:

요약하자면, 조명이 더 상세해지고 표현이 더 복잡해짐에 따라 렌더링 방정식의 다양한 구성 요소를 별도로 고려하십시오. 비용을 줄이기 위해 더 간단한 구조로 다시 샘플링하고 최소 제곱이 도움이 되지만 정규화하는 것을 잊지 마십시오.
'디트로이트: 비컴 휴먼'의 조명 기술에서는 PBR, 직접조명(분석광, 그림자, 체적조명), 간접조명 등 디트로이트-비컴 휴먼의 조명 기술을 설명한다.
포토메트릭 유닛은 조명 일관성이 주요 목표이므로 실제 참조와 더 쉽게 비교할 수 있으며 아티스트는 실제 입력 값을 사용하여 조명 정보를 알베도에 굽는 것을 방지하여 더 나은 장면 대비/범위를 허용합니다.

광도 단위에는 다음이 포함됩니다.
광도(lm): 방출되는 빛의 총량. 평행광 이외의 광원은 lm 단위로 측정됩니다.
광도(cd): 입체각 방향당 lm.
조도(lux): 표면에 떨어지는 빛의 양. 평행광은 럭스 단위로 측정됩니다.
휘도(cd/m²): 특정 방향의 단위 면적당 cd.

강제 2차 감쇠, 조명은 매우 높고 정시광에 가깝습니다.

발광 표면: 노출 값(EV)으로 표현되는 모든 재료의 방출 강도 매개변수(+색상), cd/m²는 선형 척도이지만 사람의 눈으로 인지할 수 없으며, cd/m²는 지각적으로 선형이며, +1 EV는 인지되는 광도의 두 배입니다.
장면 노출: 레벨 편집기에서 장면이 올바르게 노출되어야 합니다. 자동 노출은 권장되지 않습니다. 일반적인 조명 조건에서 측정된 노출을 사용합니다. 레벨은 장면 영역(SZ)으로 구분됩니다. 촬영 감독은 각 "SZ"에 대한 노출을 제공합니다. 전환 없이 고정된 값입니다. 카메라가 SZ에 들어갈 때 노출이 적용됩니다. 노출은 카메라 셔터 속도와 조리개 수치의 조합을 나타내는 EV100으로 표시됩니다. EV100은 ISO100 센서 감도의 노출 값으로, 일관된 조명 범위를 보장하기 위한 프레임워크를 제공합니다. 장면 노출은 사전 노출(pre-expose) 축적 버퍼에 적합합니다. 게임에서의 노출에는 더 많은 제어가 필요합니다.
카메라 노출: 장면 노출에 대한 노출 보정을 통해 노출을 동적으로 변경하는 제어 기능을 제공합니다. 아티스트는 자동 노출 = 게임 스테이지(메인), 수동 노출 = 컷 장면(메인)의 4가지 카메라 노출 유형 중에서 선택할 수 있습니다. 카메라 노출 유형: 수동(EV100의 노출 값은 애니메이션 곡선으로 제어할 수 있음), 카메라(f-스톱, ISO, 셔터 시간과 같은 실제 카메라의 설정에 따라 계산됨), 자동 평균(장면의 대수 평균 밝기에 따라 계산됨), 자동 영역(장면에 수동으로 배치된 "장면 영역" + EV "데칼"에 제공된 노출 값에 따라 계산됨)
광도 단위(디버그):
- Virtual Spot Meter는 cd/m² 및 EV100, RGB 및 sRGB 값 단위로 절대 픽셀 밝기를 제공합니다. 이는 방출 표면을 조정하고 표면 반사의 높은 값을 디버깅하는 데 매우 유용합니다.

- Error Color Debug 메뉴는 장면이 잘 노출되었는지 확인하는 데 사용됩니다. 녹색은 중간 회색(18%), 분홍색은 피부색, 보라색은 검은색, 빨간색은 흰색입니다.

재료 보정: 이제 좋은 조명 프레임워크, 실제 참조 및 일관성 값이 있으므로 재료에 동일한 처리가 필요하며 모든 재료를 스캔하는 것은 불가능합니다. 일부 물체와 재료 샘플을 캡처하고, 환경적으로 제어되는 방을 설정하고, 엔진에서 쉽게 복제할 수 있는 3개의 백열 전구가 있는 암실을 구축하세요. 캡처된 자료는 조명 환경을 확인하는 데 도움이 됩니다. 이를 중심으로 다양한 조명 환경에서 캡처된 암실 및 기타 전체 범위 IBL [LAG16], 재료 특성 시각화, 개체/재료 참조 비교 및 모든 소품을 도구를 통해 확인할 수 있는 등 다양한 보정된 조명 환경을 제공하는 "동결 도구"가 구축되었습니다.

재료 특성이 범위를 벗어난 값을 강조 표시합니다. 빨간색: 기본 색상이 잘못되었습니다. 유전체 재료는 sRGB [30 240] 내에 있어야 하며, 금속 재료는 sRGB [186 255] 내에 있어야 합니다. 파란색: 유리 셰이더 반사율이 잘못되었습니다. 프레넬 반사율은 sRGB 범위 [52 114] 내에 있어야 합니다. 노란색: 금속 매개변수가 잘못되었습니다. 금속 값은 0 또는 1에 가까워야 하며, 그 사이의 값은 일반적으로 잘못되었습니다.

직접 조명의 경우 방향 조명, 포인트 조명, 스포트라이트, 프로젝터 조명(감쇠가 있는 상자에 제한된 "방향" 조명) 등 모든 광원이 정시에 작동합니다.
그림자 측면에서 그림자 맵은 디더링에 블루 노이즈를 사용하고 기본 흐림 반경의 3배, 최대 15배를 사용하는 8샘플 PCF+ 임시 슈퍼샘플링을 특징으로 합니다. 형상 법선에서 계산된 자동 그림자 오프셋(사용자 정의된 [HOL11]) 과도한 레지스터 압력으로 인해 실용적이지 않은 PCSS를 시도했지만 치아 셰이더에만 해당됩니다.
Shadow Atlas의 그림자는 8192x8192x 아틀라스에 16비트 정밀도로 저장되며 256x256 청크로 분할됩니다. 아티스트는 256, 512, 1024의 3가지 크기 중에서 해상도를 선택할 수 있으며, 카메라 거리에 따라 그림자 크기를 조정할 수 있습니다. 해상도는 최대 4단계로 절반으로 줄일 수 있습니다. 픽셀 밴딩을 방지하기 위해 4단계로 해상도를 줄이고, 256픽셀의 배수에 도달하면 아틀라스에 다시 압축할 수 있습니다. 라이트의 뷰 프러스텀에서 무언가가 움직일 때만 업데이트되고, 포인트 라이트 그림자 표면을 개별적으로 제외할 수 있으며, 클리핑 평면 근처에 조정 가능한 그림자가 있고, 수치적 정확성과 라이트 위치 지정에 도움이 되며, 클리핑 평면 근처의 라이트와 장식될 수 있습니다(회전 없음).
디더링 및 TAA, 각각 최대 1440px의 4개 분할 및 16비트 정밀도를 사용하여 일시적으로 슈퍼샘플링된 PCF(8개 샘플)를 사용한 방향 계단식 그림자 매핑, 대부분의 장면은 2개 또는 3개 분할, 자동 분할 할당을 사용합니다.
정적 그림자는 카메라 거리에 따라 정적 그림자로 전환되며 단 1개의 샘플에만 이중선형 비교, 정적 그림자 아틀라스, 아틀라스 크기: 2048x2048, 그림자당 64x64, 최대 1024개의 그림자가 있습니다. 방향성 정적 그림자는 레벨의 모든 정적 기하학을 포함하는 대형 텍스처입니다(크기: 8192x8192).
클로즈업 섀도우는 1536² 픽셀에서 최대 두 개의 섀도우를 추가하여 접촉 및 셀프 섀도우의 정확도를 높입니다. 아티스트는 장면에서 캐릭터와 같은 관련 개체를 선택하고 이러한 개체에만 클로즈업 그림자가 적용됩니다. 객체 선택: 반경 10미터 내에 표시된 모든 표시된 객체, 스킨된 객체 경계 볼륨은 스킨된 포인트 클라우드에서 계산됩니다. 근거리/원거리 평면은 근거리 수신기에 의해 선택된 경계 볼륨에 맞고 프러스텀 외부의 객체는 근거리 그림자 평면에 투영됩니다.

클로즈업 그림자는 UE의 객체별 그림자와 유사합니다. 클로즈업 그림자 켜짐(아래 그림 왼쪽)과 꺼짐(아래 그림 오른쪽) 비교:

통합 체적 조명([WRO14] [HIL15])을 사용하는 체적 조명, 조명 그룹 깊이 일치, 체커보드 렌더링 사용, 블루 노이즈 디더링 TAA, 직사광 및 확산 프로브 격자로 조명, GI 베이킹에 대한 안개 효과, 의사 다중 산란. 체적 조명이 표면을 통해 누출될 수 있습니다(아래 상단 이미지), 누출 수정 단계(아래 하단 이미지): 타일별로 저장된 최소/최대 깊이, 조명 평가 중 복셀 두께를 고정하기 위해 "최대 깊이"를 사용하고 볼륨 텍스처 샘플링에 Z 오프셋을 적용합니다(TileDepthVariance > 임계값).

간접 조명 측면에서는 HL2 환경 큐브가 사용되었고 정적 기하학을 위한 버텍스 베이킹, 동적 기하학을 위한 광원 프로브, 의사 간접 반사광 조명, 정적 및 동적을 위한 통합 솔루션이 필요했습니다. IBL(반사 이미지 기반 조명), 장면 큐브맵 캡처, GGX NDF 굽기 [WAL07] [KARIS14], 반딧불 방지를 위한 중요한 샘플 필터링, 아티스트 제어 영향 상자 및 시차 상자에 이상적인 프로브 기반 솔루션입니다. 또한, irradiance sparse octree도 사용됩니다. 옥트리 셀에는 각 모서리에 하나씩 8개의 프로브가 있습니다. 공간 지점은 실제로 오프셋 프로브인 프로브를 버리지 않고 항상 8개의 프로브로 둘러싸여 있습니다. 옥트리 수준은 불연속적입니다. 아래 그림의 주황색 점은 계산된 프로브이고 연한 파란색 점은 보간된 프로브입니다.

아래 그림에서는 각 리프 노드에 2x2x2 데이터가 저장되어 있어 중복성이 많습니다. 아래 그림에서 데이터는 중복된 데이터가 적은 3x3x3 상위 노드에 저장됩니다.

2차 SH를 사용한 구면 고조파, 4개 계수, Geomerics [Geomer15]를 사용하여 재구성, 3개의 RGBA16F 볼륨 텍스처(R, G, B), 24055개의 프로브 → (105x105x3) x 3개의 텍스처 약 3MB.
GI가 표시될 때 프로브를 폐기하지 않음을 사용하면 단순히 하드웨어(3D) 이중선형 필터링을 사용하여 3D 텍스트에서 옥트리 셀 해시 키(Morton 키, O(1), 32비트로 제한됨)를 찾고 텍스처 좌표 버퍼에 미리 계산된 해시를 사용하여 체적 텍스처를 샘플링할 수 있습니다. X 좌표는 처음 15비트에 인코딩되고 Y 좌표는 다음 15비트에 인코딩되며 Z 좌표는 마지막 2비트에 인코딩됩니다. 이것의 이점은 GI 스위치(내부 조명 스위치, 번개 등) 및 GI 전환(시간, 제한/해제 등)을 지원하므로 컴퓨팅 셰이더를 사용하여 여러 GI 세트를 혼합하는 것이 매우 간단하다는 것입니다.
GI 전환: 입구까지의 거리와 노멀 방향을 기준으로 GI의 동적 개체를 통해 입구 주변의 거리를 설정하여 내부 ← 외부 등 장면 영역 간의 하드 GI 전환을 방지합니다.

GI 전환 끄기 및 켜기 비교 차트:

대부분의 정적 객체는 내부 및 외부 벽과 같은 고유한 장면 영역에 위치하지만 문, 창문 및 창틀은 어떻습니까? 장면 영역에 지정되었지만 다른 영역에서 볼 수 있으며 장면 영역에 지정되지 않았습니다.
'디트로이트: 비컴 휴먼'의 클러스터 포워드 렌더링 및 앤티앨리어싱은 Playstation 3에서 Playstation 4로의 Quantic 엔진의 진화, 디퍼드 라이팅에서 클러스터 포워드 라이팅으로의 변환, 이점 및 직면한 문제를 해결하는 방법을 소개합니다. 또한 SSR, SSAO, PCF 그림자, 피부 표면 산란 및 체적 조명과 같은 TAA 및 해당 응용 프로그램을 소개합니다.


클러스터링된 포워드 렌더링은 GPU를 사용하여 더욱 유연하고 효율적입니다. 새로운 조명 알고리즘: 블록 렌더링, 포워드 + 렌더링, 클러스터링된 포워드 렌더링. 그들의 비교는 다음과 같습니다:

클러스터링된 포워드 렌더링에는 세 가지 패스가 있으며 해당 프로세스는 다음과 같습니다.

클러스터링된 포워드 렌더링을 위한 최적화: 조명 루프가 벡터 레지스터 대신 스칼라 레지스터를 사용하도록 강제하고 모든 것이 동일한 공간(뷰 공간)을 최대한 많이 사용하도록 조명을 정렬합니다. TAA에는 더 적은 수의 그림자 텍스처 샘플(8개만)을 사용하여 컴파일러가 2x4 텍스처 그림자 샘플이 포함된 루프와 특정 거리에서 하나의 텍스처 그림자 샘플만 사용하는 구운 그림자 텍스처를 사용하도록 합니다. 깊이 패스가 필요합니다. 클러스터링은 픽셀별 조명 및 정점별 조명에 사용할 수 있습니다! 가능하다면 이미지 기반 조명을 지연된 채널로 이동하세요.
조명 주기 최적화: 4가지 유형의 조명(점 조명, 스포트라이트, 방향 조명 및 프로젝터), 그림자 및 투영 텍스처가 있습니다. 첫 번째 버전은 4사이클(각 조명 유형에 대해 하나씩)을 사용하고 나중에는 모든 유형의 조명을 처리하기 위해 1사이클로 변경됩니다.
For each light:
ComputeLightAttenuation(...);
ComputeShadow(...); // → Higher register usage for sun shadow
ComputeProjectedTexture(...);
ComputeFinalLightingColorWithMaterialBRDF(...);
// 최적화 그림자(Shadow),추가(Add)
ComputeSunShadow(...); // → Lower register usage
For each light:
VisibilityTestBitField(...); // → Early exit
ComputeLightAttenuation(...); // → Early exit
TestNDotL(...); // → Early exit
ComputeShadow(...); // → Early exit
ComputeProjectedTexture(...);
ComputeFinalLightingColorWithMaterialBRDF(...);위 단계를 최적화한 후에는 광원 수가 줄어듭니다.

반투명도 최적화: 투명도는 성능을 저하시킬 수 있습니다. 유리 전용 이미지 기반 조명, 입자: 중심당, 구형 고조파, 절반 해상도입니다.
Detroit Games는 다중 셰이딩을 위해 GPU 파생물을 사용할 수 있는 TAA의 셰이딩 앤티앨리어싱을 구현하는데, 이는 잘 작동하지만 비용이 많이 듭니다. 정규 분포 함수(NDF) 필터링(Shading Antialiasing을 위한 노멀 분포 필터링 및 최적화 버전 [Shading Anti-Aliasing을 위한 오류 감소 및 단순화](https://yusuketokuyoshi.com/papers/2017/Error Reduction and Simplification for Shading Anti-Aliasing.pdf))을 사용할 수 있으며, 이는 TAA와 잘 작동하고 비의 세부 사항을 더욱 분명하게 만듭니다.

위에서 아래로: TAA 꺼짐, TAA 켜짐, TAA+NDF 필터링.
TAA는 그림자, HBAO, SSR, 피부의 화면 공간 하위 표면 산란 및 체적 조명에도 사용할 수 있습니다. TAA의 공통 파트너는 저주파 성분이 최소화되고 에너지 집중 피크가 없는 소음인 블루 노이즈(Blue Noise)입니다.

왼쪽이 백색소음, 오른쪽이 청색소음, 맨 아래줄이 타일링 모드입니다.
시간 샘플링이 포함된 SSR의 경우 TAA 채널이 있고 체커보드를 사용하여 이웃을 고정합니다.

Frostbite의 사전 계산된 전역 조명은 경로 추적, 구형 조화 라이트 맵 및 효율적인 라이트 맵 패키징 알고리즘을 포함하여 "FIFA", "Madden", "Frontline" 및 향후 게임을 위해 Frostbite에서 개발한 정적 GI 기술을 설명합니다.
Flux는 Frostbite용 경로 추적기, 다음 이벤트 추정(무차별 대입)을 통한 단방향 경로 추적, CPU 구현(Intel Embree, IncrediBuild XGE), 실시간 아티스트 워크플로우의 GPU 구현으로 구워졌습니다.

Frostbite의 경로 추적을 위한 SH 라이트 맵에는 확산 조명, 효율적인 코딩, 근사 반사 조명과 같은 기술이 포함되어 있습니다. 베이크된 GI는 렌더링 방정식에 대한 부분 솔루션을 저장하는 위치 에 의해 생성된 키가 있는 데이터베이스/캐시입니다.

그 중 눈 벡터 𝜔𝑜를 알 수 없으며(베이킹 중에는 카메라가 없음), 베이킹 시 셰이딩 노멀 𝑛을 알 수 없을 수도 있습니다. 런타임 시 기본 디퓨즈 BRDF(예:
구면 고조파를 사용하는 이유: RNM 또는 ℋ-Basis와 달리 탄젠트 좌표계가 필요하지 않음, 색도계로 분리된 RGB 방향 조명, 주변 + 하이라이트 방향(AHD)과 다름, 고대비 확산 조명, 대략적인 간접 반사 조명, RGB L1의 SH에 대한 우수한 압축 옵션. 베이킹 구형 고조파 프로세스:


복사조도의 SH를 단순화하려면 복사조도와 같은 공식을 도출해야 합니다.

Irradiance SH 라이트맵 인코딩: 4개의 RGB 텍스처를 사용하여 12개의 SH 계수, L0 HDR(BC6H 텍스처)의 계수, L1 LDR(3x BC7 또는 BC1 텍스처)의 계수, RGB SH 라이트맵의 전체 점유: BC6+BC7의 경우 고품질 모드 32비트(4바이트)/텍셀; BC6+BC1의 경우 저품질 모드 20비트(2.5바이트)/텍셀. 예: 4096 x 4096 라이트 맵, 32비트/텍셀에서 64MB, 20비트/텍셀에서 40MB.
스페큘러 반사 조명에서 스페큘러 반사를 근사화하는 일반적인 아이디어는 라이트맵에서 L1 구면 고조파 데이터를 사용하고 SH에서 주 광원 방향을 도출하고(L1 데이터만 정규화) L1 밴드의 길이를 기준으로 "확산" 또는 "초점"을 추정하는 것입니다.
float focus = lightmap.L1 ); // [0..1]추정된 매개변수를 사용하여 가상의 광원을 생성하고 이 숫자를 표준 GGX 반사 공식에 연결합니다. 대략적인 반사 라이트맵 셰이더: L1 진폭을 사용하여 비선형 확산 SH 조명과 유사하게 빛의 초점을 추정합니다. 0.0에 가까우면 빛이 여러 방향에서 나온다는 의미이고, 1.0에 가까우면 빛이 주로 한 방향에서 나온다는 뜻입니다. 표면 러프니스를 빠른 영역 조명 근사로 조정하고, 휴리스틱이 전방향 조명을 제안할 때 하이라이트를 더 부드럽게 만듭니다. 순전히 시각적으로 즐겁고 믿을 수 있는 결과를 기반으로 한 임의의 경험적 근사입니다.
// Approximate an area light by adjusting smoothness/roughness
float lightmapDirectionLength = length(lightmapDirection); // value in range [0..1]
float3 L = lightmapDirection / lightmapDirectionLength;
float adjustedSmoothness = linearSmoothness * sqrt(lightmapDirectionLength);
// Proceed with standard GGX specular maths
또한 이 기사에서는 반구 및 텍셀 샘플링, 수렴 감지 렌더링, 겹치는 형상 처리, 올바른 이중선형 보간 보장, 효율적인 조명 아틀라스 패키징 등과 같은 다양한 기술을 다룹니다. 관심 있는 어린이는 원본 텍스트를 읽을 수 있습니다.
HDR 이미지 기반 조명: 획득부터 렌더링까지 HDR 하의 IBL 요구 사항부터 구현까지의 프로세스와 관련 기술 및 최적화를 설명합니다. 이미지 기반 조명(IBL)은 실제 사진, 물리적 정확성, 측광 단위, 조명과 일치하는 환경 등의 특성을 가지고 있습니다. 다음은 HDR 및 LDR의 IBL 효과에 대한 비교 사진입니다.


HDR과 LDR 사이에 왜 그렇게 큰 차이가 있습니까? 포인트 라이트로서의 IBL의 합:

합계의 함수는 함수의 합계와 같지 않습니다.

IBL로 올바른 조명을 얻는 핵심은 자산이 아닌 밝기, 톤매핑된 출력입니다. 톤매핑은 진정한 HDR 렌더링의 기본 부분입니다. 광채로서의 환경 맵: 전체 밝기 범위, 포스트 프로세스 없음, 화이트 밸런스 없음, 선형. 실제 밝기 값, 가능한 개체의 99%가 10000nit 앞에 있지만 나머지 개체는 조명에 큰 영향을 미칩니다.

디지털 카메라로 촬영한 환경 이미지는 여전히 태양보다 약 350배 더 어둡습니다. 디지털 이미지의 품질은 해상도, 렌즈 플레어, 노이즈 등의 요인에 따라 달라집니다. 방사성 맵 조립: 원시 전처리, PTGui/HDR 저장, 반전된 응답 곡선, 광도 보정.

그 중 PTGui는 실제 HDR 옵션을 사용하고 사전 정의된 역반응 곡선을 사용하는 파노라마 스티칭 및 HDR 조립 소프트웨어입니다.


부동 소수점 형식이 불가능한 경우 보다 정확한 패킹을 허용하는 절대값으로 저장하면 조명 설정은 기본적으로 각 환경에 대해 동일합니다. 태양 밝기의 경우 조도계로 조도를 측정하고, 하드웨어가 없으면 색상 검사기로 흰색 대상을 촬영하여 색상이나 밝기를 복구하고 계산을 수행합니다. 태양광 밝기 측정기는 "플랫" 센서를 사용하여 센서가 정상적으로 태양을 향할 때를 측정합니다.

태양의 밝기 계산 과정: 대상을 태양에 노출시키고 촬영하고, 태양이 작은 물체에 의해 차단될 때 촬영하여 채광창을 얻고, 첫 번째에서 두 번째를 빼고, 알베도로 나누어 조명을 얻습니다.

HDR, 사진 보정, IBL 조명 렌더링을 사용한 후 렌더러(Maxwell Render)와 디지털 사진을 비교하면 다음과 같습니다.

Call of Duty: WWII의 Material Advances에서는 일반 및 광택 매핑(세부 광택과 결합된 합리적인 함수 피팅), 재질 표면 폐색, 다중 산란 디퓨즈 BRDF(에너지 보존 확산) 등과 같은 COD: WWII의 고급 재질 기능을 설명합니다.
일반 및 광택(NDF)은 다양한 규모의 기하학적 정보를 나타냅니다. 노멀이 특정 거리로 후퇴하면 픽셀 풋프린트 아래의 노멀 변화가 광택(NDF)으로 표시되어야 합니다.


MIPMAPPING 처리(짧은 일반 길이를 광택으로 변환):

일반 변형은 MIP로 인코딩되며, 낮은 MIP는 더 높은 일반 변형을 인코딩하며 색상이 더 어둡습니다.

노멀 맵은 높이 맵을 생성한 다음 높이 맵에서 오클루전 맵을 생성합니다.

AO를 처리할 때 차단된 방향은 동일한 확산 알베도를 가지며 비슷한 방식으로 차단됩니다.

원본 AO와 개선된 AO 비교:

또한 폐색을 동등한 원뿔 각도로 변환합니다.

다양한 차단 방법의 효과 비교:

간접 반사 폐색은 원뿔 기반 방법을 사용하며 환경 BRDF는 원뿔 각도 θ, 32x32x8 텍스처 조회 테이블의 3차원으로 확장됩니다. 가장 왼쪽 슬라이스는 2차원 조회 테이블과 동일합니다. 완전히 포함되지 않은 원뿔이고 가장 오른쪽 슬라이스는 스케일=0, 바이어스=0: 완전히 가려진 원뿔입니다.

디퓨즈에서 에너지 보존을 달성하기 위해 ENVBRDF 조회 테이블이 사용됩니다. EnvBRDF 조회 테이블은 수집되어 눈에 반사되는 스페큘러 반사된 빛 에너지의 비율을 나타냅니다. 동일한 조회 테이블은 준광원의 표면에 의해 산란되는 빛 에너지의 비율도 나타냅니다.

일반 Lambert와 에너지 절약 Lambert의 비교:

또한 지표각에서의 반사 효과가 향상되었습니다.

Lambert와 완전 다중 분산 BRDF의 비교:

BRDF 슬라이스를 사용한 2D 유리 함수 피팅:

완전한 다중 산란 디퓨즈와 장착된 다중 산란 디퓨즈의 비교:

최근 실시간 셰이딩 기술의 발전으로 정교한 영역 조명을 사용하여 물리적 기반 엔터티를 조명하는 것이 가능해졌습니다. 여전히 중요한 과제는 정확한 Area Light Shading입니다. DXR의 출현으로 레이 트레이싱을 통해 이 문제를 해결할 수 있는 문이 열렸지만 올바른 공식이 명확하지 않으며 몇 가지 잠재적인 함정이 있습니다. 예를 들어, 가장 널리 사용되는 전략은 광원의 무작위로 분산된 지점까지 광선을 추적하고 가시성을 평균화하는 것입니다. 그러나 이는 올바르지 않으며 시각적 왜곡을 생성합니다. 대신, 올바른* 부드러운 그림자의 실시간 레이 트레이싱은 올바른 결과를 계산하는 부드러운 그림자의 정의와 기존 분석 영역 조명 솔루션과 함께 작동하는 효율적인 구현을 제안합니다.
이전 LTC는 차단된 조명을 처리할 수 없었지만 보다 사실적인 빛과 그림자는 다음과 같아야 합니다.

이전 문헌에서는 빛 추적만 사용하는 부드러운 그림자를 제안했습니다. 이 방법은 평균 가시성입니다.

그러나 BRDF를 사용하여 직접 조명을 얻은 다음 부드러운 그림자에 빛 추적의 평균 가시성을 곱하면 잘못된 결과를 얻게 됩니다.

올바른 접근 방식은 아래 그림의 오른쪽과 같습니다.

무작위화도 사용할 수 있지만 BRDF의 모든 용어는 강제로 무작위화되어야 합니다.

무작위화의 결과는 너무 많은 노이즈와 너무 많은 흐림입니다.

따라서 레이 트레이싱된 부드러운 그림자와 완전한 무작위화라는 두 가지 솔루션 모두 잘못된 결과를 얻게 됩니다. 올바른 부드러운 그림자 알고리즘은 다음과 같아야 합니다.

수학적으로, 우리는 모든 것이 확실히 정확하다는 것을 알 수 있습니다:

해당하는 올바른 무작위화 공식은 다음과 같습니다.

글에서 제안하는 방법은 다음과 같습니다.


올바른 소음 감소를 위한 각 주파수의 기능은 다음과 같습니다.

소음 감소 범례:

샘플링 측면에서 다중 중요도 샘플링이 사용됩니다.

유전체(비금속) 전해질의 경우 다중 중요도 샘플링이 사용됩니다.

최종 효과 비교:

렌더링 패스 및 프로세스는 다음과 같습니다.

요약하면, 비율 추정기: 잡음 없는 편향 분석 + 편견 없는 잡음 무작위, 강력한 잡음 추정으로서의 총 변화(비분산), 분석 음영에 의해 구동되는 그림자 다중 중요도 샘플링, 실시간 레이 트레이싱 GPU에 대한 고려 사항: 활성 상태, 대기 시간 및 점유, 다중 중요도 샘플링 분기, 파면 대 인라인, 혼합 광선 + 래스터 그래픽 예.
레이 트레이싱은 마침내 래스터라이제이션, 셰이딩 및 계산과 긴밀하게 통합된 실시간 그래픽 파이프라인에 진출했습니다. 광선을 추적하는 기능은 최종적으로 실시간 그래픽에서 전체 빛 산란을 정확하게 시뮬레이션할 수 있다는 희망을 제공합니다. 최근 몇 년간 물리 기반 재료가 실시간 그래픽에 혁명을 일으켰던 것처럼, 물리 기반 전역 조명도 이미지 품질과 개발자 및 아티스트 생산성에 유사한 영향을 미칠 수 있는 기회를 갖고 있습니다. 그러나 이를 수행하는 것은 쉽지 않습니다. 현재는 각 픽셀에서 소수의 광선만 추적할 수 있으므로 그래픽 프로그래머 측에서는 많은 주의와 창의성이 필요합니다. 실제 파이프라인을 위한 오프라인 Ray Tracing에서 실시간 Ray Tracing에 대한 교훈 채택에서는 오프라인 파이프라인에서 이 기술을 사용한 경험을 논의하고 실시간 Ray Tracing을 채택하는 개발자가 알아야 할 이 분야에서 개발된 다양한 주요 혁신을 강조합니다.
오프라인 렌더링의 교훈: 약 10년 전 다중 패스 래스터라이제이션는 긴 반복 시간, 투박한 작업 흐름, 가시성 관점에서 아티스트를 위한 렌더링 아티팩트로 인해 중요한 지점에 도달했습니다.
근사치, 사전 베이킹 및 캐시 조명은 작동하는 경우가 많습니다... 작동하지 않을 때까지(╯°□°), 빛 전달을 예상대로 정확하게 시뮬레이션하지 못합니다. 경로 추적 사용: 표면, 머리카락, 볼륨 측정을 포함한 기본 요소 등 모든 것을 처리하는 통합 조명 전송 알고리즘...반사: 모든 유형의 BSDF, BSSRDF...조명: 점 조명, 영역 조명, 환경 맵 조명...
광선을 현명하게 선택하는 방법(및 광선을 선택해야 하는 이유), 신중하게 (비)난수 생성, 가장 유용한 곳에 광선 예산 지출, 오류 이해 및 예방이라는 네 가지 주제를 다룹니다. 먼저 분산의 개념과 공식을 이해해 봅시다.

모든 샘플링 기술은 단위 사각형에서 다른 영역, 반구, 구, 구 주위의 원뿔, 디스크로 임의의 숫자를 뒤틀는 것을 기반으로 합니다. BSDF의 산란 분포를 기반으로 샘플을 생성하거나 IBL 광원의 방향을 선택할 수도 있습니다. 샘플링하는 방법은 엄청나게 많지만 모두 0과 1 사이의 값으로 시작하고 약간의 직교성이 있습니다. "시작하는 값은 무엇입니까?"와 "두 번째 몬테 카를로 추정을 사용하기 위해 샘플링하려는 분포로 이 값을 어떻게 왜곡합니까?"가 있습니다.

해당 샘플링 방법에는 일반적으로 사용되는 방법에는 균일, 저차 시퀀스, 계층화된 샘플링, 요소 간격, 블루 노이즈 디더링 등이 포함됩니다. 낮은 시차는 일반화된 층화와 유사하고 블루 노이즈는 서로 다른 샘플이 서로 얼마나 가까운지와 유사합니다. 절차 모드는 원하는 만큼의 접두사를 사용할 수 있으며 (일부) 접두사는 균등하게 배포됩니다.

분산 기반 샘플링: 지금까지 수집한 샘플을 기반으로 각 픽셀의 분산을 주기적으로 추정합니다. 차이가 큰 경우 오버샘플링하고, 분산/추정이 높은 경우에는 톤매핑 등을 수행한 후에 이 작업을 수행합니다. 오프라인(품질 기반): 픽셀의 분산이 충분히 낮아지면 처리를 중지합니다. 실시간(프레임 속도 기반): 분산이 가장 큰 곳에서 더 많은 샘플을 수집합니다. 표본 분산을 계산합니다(중요 사항: 표본 분산은 실제 분산의 추정치입니다).
float SampleVariance(float samples[], int n)
{
float sum = 0, sum_sq = 0;
for (int i=0; i<n; ++i)
{
sum += samples[i];
sum_sq += samples[i] * samples[i];
}
return sum_sq/(n*(n-1))) - sum*sum/((n-1)*n*n);
}샘플 분산은 단지 추정치일 뿐이며, MC 렌더링 적응형 샘플링 및 재구성의 최근 발전인 노이즈 제거에 많은 작업이 이루어졌습니다. 일반적인 아이디어: 보조 기능(위치, 노멀 등)의 근접성에 따라 가중치를 부여할 수 있는 인근 픽셀에 샘플 분산을 추가합니다.
높은 분산은 저주입니다. 분산이 큰 표본을 도입하면 큰 문제가 발생합니다. 예를 들어 데이터를 균일하게 샘플링하는 것을 고려해 보세요.

6개의 샘플: (1, 1, 1, 1, 1, 100) ≒ 17.5, 그리고 6개의 샘플을 더 채취합니다: (1, 1, 1, 1, 1, 100, 1, 1, 1, 1, 1, 1) ≒ 9.25. 분산은 샘플 수에 따라 선형적으로 감소한다는 점을 기억하십시오. 이렇게 높은 분산 샘플에 직면했을 때 가장 해학적이지만 가장 효과적인 방법은 아래 그림과 같이 고정하는 것입니다.

더 복잡한 옵션: 밀도 기반 이상값 거부[Decoro 2010], 모든 샘플을 저장하고 이상값을 분석 및 필터링합니다. [Zirr 2018]: 밝기에 따라 샘플을 여러 개의 개별 이미지로 분할한 다음 통계 분석에 따라 가중치를 다시 부여합니다.

'Mafia III' 및 그 이후의 실시간 반사에서는 기존 솔루션 및 GPU의 레이 캐스팅을 포함하여 게임 Mafia III의 실시간 반사 솔루션을 설명합니다.
반사 렌더링, 거친 표면의 반사, 결과 등.
당시 기존 솔루션에는 SSR, 사전 필터링된 큐브 맵 조회, SSR + 사전 필터링된 큐브 맵 조회, SSR + 시차 보정 큐브 맵(사전 필터링), 원뿔 추적 등이 포함되었습니다. 기존 솔루션 중 어느 것도 카메라 움직임의 안정성, 우수한 성능 및 메모리 비용, 모든 환경(실내, 도시, 풍경)에서의 원활한 작업, 합리적인 콘텐츠 제작 비용, 실시간 업데이트(장면 변경) 등 모든 요구 사항을 충족하지 못했습니다.
GPU에서의 레이캐스팅: 그리드/BVH에는 분기, 비일관적인 메모리 액세스, 음영 계산 방법 등에 문제가 있고, 복셀에는 메모리 사용량이 많고 중요한 구현 등에 문제가 있으며, 깊이 텍스처는 GPU 친화적이고 일반적인 구현이며 완벽한 공간 적용 범위가 아닙니다.
이 기사에서 사용된 큐브 맵 설정은 8개의 활성 지오메트리 CM, 1개의 스카이 CM(각각 512픽셀의 해상도, 완전한 MIP 체인 포함)입니다. 동적 시간과 날씨가 지원되어야 하므로 CM을 오프라인으로 사전 렌더링할 수 없습니다. 사전 렌더링이 가능하다면 별도의 하늘 CM이 필요하지 않습니다. 최대 시청 거리(각 측면)의 큐브맵 오프라인 사전 계산:

영향을 받는 가장자리에 대한 지오메트리 셰이더 출력을 사용하고 제한된 기능 세트를 사용하여 모든 측면에 대한 장면 쿼리를 수행합니다. 업데이트 측면에서 하늘 CM은 몇 프레임(구름, ToD)마다 업데이트되고, 형상 CM은 동적 조명(루핑)으로 정기적으로 업데이트되고, G 버퍼 및 정적 조명은 캐시되며, 더 나은 CM을 찾은 후 새 CM이 렌더링됩니다.
활성 큐브맵 선택: 각 프로젝트는 다양할 수 있으며 플레이어에 가장 가까운 8개를 사용하지만 2가지 특별한 경우가 있습니다. 최소 하나의 실외 CM, 수직 축에서 바닥 분할의 역효과. 가능한 개선 사항은 경계 상자(내부/외부, 거리)를 사용하고, 폐색 쿼리를 사용하고, 볼륨에 대한 최적의 CM 세트를 미리 계산하는 것입니다.
반사 렌더링 단계:
G-버퍼를 다운샘플링하고 NDF를 적용합니다. 깊이 불연속성을 감지하고, 가장자리가 감지되면 "작은 샘플"을 버리고, 무작위 샘플을 선택하고(시간 필터 활용), 노멀 디더링(NDF 적용), 출력(모두 절반 해상도) RT0(깊이), RT1(디더링된 노멀 및 러프니스), RT2(원래 노멀 및 러프니스).
화면을 추적하고 거리를 출력합니다. 화면 공간 깊이를 추적하고 이동 거리, "완료" 플래그 및 "완료" 플래그에 대한 템플릿 마스크를 출력합니다.

큐브 플롯, 출력 거리 및 인덱스를 추적합니다. 러프니스(HQ/LQ)를 기반으로 한 2차 패스, SSR 끝점에서 시작하여 최고의 CM을 사용하고 추적에 실패하면 체인의 다음 CM으로 전환하고 계속합니다. 모든 CM이 실패하면 폴백을 사용하여 이동 거리와 CM 인덱스(적중이 발견된 위치)를 출력합니다.
색상을 분석합니다. 절반 해상도 채널: SSR 색상 분석, CM 색상 분석. 전체 해상도 채널: 절반 해상도 구문 분석 버퍼를 확대하고, 낮은 러프니스 템플릿 마스크를 생성하고, 낮은 러프니스 픽셀에서 SSR을 구문 분석하고, 낮은 러프니스 픽셀에서 CM을 구문 분석합니다.
확대합니다. 입력 반해상도 색상, 반해상도 지터 없는 노멀, 반해상도 깊이, 전체 해상도 노멀, 전체 해상도 깊이, 출력: 전체 해상도 색상(높은 러프니스 픽셀), 템플릿 마스크, 전체 해상도 노멀 및 깊이와 가장 잘 일치하는 절반 해상도 색상에서 샘플을 선택합니다.
거친 표면의 반사에 대해 현재 솔루션은 중요도 샘플링 50%, 사전 필터링된 MIP(SSR 및 CM) 사용 50%, 5-샘플 BRDF 가중치 화면 공간 흐림, 수정된 샘플 분포, 임시 필터링, Blinn Phong 기반 수학(아직 GGX로 변환되지 않음) 등 3가지 이상의 트릭을 모두 혼합한 것입니다.

리플렉션을 구현하는 과정에서 이웃 샘플이 재사용됩니다. 픽셀 분류와 동일한 패턴, 디더링되지 않은 법선을 사용하여 4개 이웃의 깊이와 법선을 샘플링하고 가중 평균을 계산합니다. 중앙 샘플: 1, 깊이/러프니스 불연속성: 0, 그렇지 않으면 BRDF를 평가합니다.

다중 산란 BRDF 및 영역 조명 구현을 통한 여정에서는 다중 산란 조명 모델 및 영역 조명 기술을 설명합니다.
다중 산란 스페큘러 반사에서는 비금속이 명확하지 않지만 금속은 뚜렷한 차이가 있습니다.

목표는 다중 산란을 고려하여 Lambertian 디퓨즈를 개선하는 것입니다. 디퓨즈는 표면 러프니스에 반응합니다. 디퓨즈는 노멀 분포에 따라 달라집니다. 디퓨즈와 스페큘러 반사 모두 에너지 보존입니다. 이전 조명 모델은 다음과 같습니다.


문제는 다중 산란 간접 스페큘러 반사, 머리카락에 다중 산란 스페큘러 반사, 다중 산란 간접 디퓨즈, 피부에 다중 산란, 다중 산란이 없다는 것입니다. 거울 다중 산란과 관련하여 공식의 유도 및 근사 과정은 다음과 같습니다.

단일 산란의 에너지는 실제로 주변 BRDF의 빨간색과 녹색 채널의 합입니다.

float2 FssEss = envBRDF.x + F0 * envBRDF.y;
float Ess = envBRDF.x + envBRDF.y;
float Ems = 1.0f - Ess;
float Favg = F0 + (1.0f / 21.0f) * (1.0f - F0);
float Fms = FssEss * Favg / (1.0f - Favg * (1.0f - Ess));
float Lss = FssEss * radiance;
// irradianceradiance。
float Lms = Fms * Ems * radiance;
return Lss + Lms;효과 비교:

이 시점에서 다양한 재질에 사용되는 조명 모델을 업데이트할 수 있습니다.


다중 산란 스페큘러 반사의 경우 LTC 진폭과 프레넬은 F0의 선형 의존성에 의존하지만(아래 상단 그림), 이 기사의 다중 산란 BRDF는 비선형 의존성을 갖습니다(아래 하단 그림).

다중 산란 BRDF에 대한 공식이 있습니다. E(μ)는 진폭 및 프레넬 LUT의 빨간색 채널입니다.

효과 비교:

또한 이 기사에는 비틀린 디퓨즈와 LTC를 결합하고 미리 계산된 SSS와 LTC를 결합하는 등의 방법도 포함되어 있습니다.
It Just Works: "Battlefield V"의 Ray-Traced Reflections는 GPU 레이 트레이싱 파이프라인, DXR 엔진 통합, GPU 성능 등을 포함하여 Battlefield V 게임의 레이 트레이싱 관련 기술을 설명합니다.

(단순) 레이 트레이싱 파이프라인:

생성 파이프라인 단계에서는 GBuffer의 텍스처를 읽고 무작위 래스터라이제이션를 사용하여 조명을 생성합니다.

float4 light(MaterialData surfaceInfo , float3 rayDir)
{
foreach (light : pointLights)
radiance += calcPoint(surfaceInfo, rayDir, light);
foreach (light : spotLights)
radiance += calcSpot(surfaceInfo, rayDir, light);
foreach (light : reflectionVolumes)
radiance += calcReflVol(surfaceInfo, rayDir, light);
…
}그러나 이 간단한 조명 추적 파이프라인으로 렌더링된 이미지 품질에는 노이즈, 비효율성, 낮은 조명 기여도 등의 문제가 있습니다.

이제 광선을 생성할 때 가변 속도 추적을 포함하도록 파이프라인을 개선합니다.

변동금리 추적 프로세스는 다음과 같습니다.

가변 속도 추적을 통해 물 위에서 그리고 바라보는 각도에서 더 많은 빛을 얻을 수 있습니다. 하지만 여전히 문제가 있습니다.

Ray Binning(라이트 박스)을 추가하여 화면 오프셋과 각도를 빈의 인덱스로 사용할 수 있습니다.




SSR Hybridization, Defrag, 셀별 광원 목록 조명, 노이즈 감소(BRDF 노이즈 감소, 시간적 노이즈 감소) 등의 최적화를 차례로 추가할 수 있습니다.

SSR 하이브리드화 과정과 결과.

셀별 광원 목록 조명.

BRDF 노이즈 감소 프로세스.
최종 신규 파이프라인 및 소요 시간은 다음과 같습니다.

렌더링 효과:

DXR 기본 사항:

DXR의 성능 최적화에는 인스턴스 수 감소, 추론 휴리스틱 사용, (일부) 사소한 결함 수용이 포함됩니다. 컬링 휴리스틱은 일부 측정이 필요한 다리나 건물과 같은 대형 개체를 제외하고 멀리 있는 개체는 중요하지 않다고 가정합니다. 투영 구 경계 상자,

다양한 임계값의 효과:

컬링 결과: 4도 컬링 사용, 프레임당 5000-->400 BLAS 재구성, 20000-->2800 TLAS 인스턴스, TLAS+BLAS 빌드(GPU): 64밀리초-->14.5밀리초이지만 간헐적인 점프 및 객체 손실과 같은 결함이 발생합니다.
BLAS 업데이트 최적화: BLAS 업데이트는 여전히 비용이 많이 들고 다음 방법을 사용하여 최적화할 수 있습니다.
시차를 두고 전체 및 증분 BLAS 재구성. 완전히 재구성되기 전에 N 프레임이 증가합니다.
D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD를 사용합니다.
반복적인 재구축을 피하세요. CS 입력(본 매트릭스), 400 --> 50, Gbuffer, 섀도우 맵과 같은 GFX와 BLAS 업데이트가 겹치는지 확인하세요.
결과 TLAS + BLAS 빌드(GPU): 14.5ms --> 1.15ms, RayGen(GPU): 0.71ms --> 0.81ms(인터리브 재구성 + 플래그).
불투명도 요약: 항상 ClosestHit 셰이더를 사용하고, 알파 테스트된 개체에만 Any Hit 셰이더를 사용하고, 스키닝 및 파괴에는 컴퓨팅 셰이더를 사용하세요.
광선 페이로드(RAY PAYLOAD)는 광선 교차점에서 반환됩니다. Gbuffer RTV와 동일한 형식을 가지며 재질 데이터, 노멀, 기본 색상, 매끄러움 등을 포함합니다.
struct GbufferPayloadPacked
{
uint data0; // R10G10B10A2_UNORM
uint data1; // R8G8B8A8_SRGB
uint data2; // R8G8B8A8_UNORM
uint data3; // R11G11B10_FLOAT
float hitT; // Ray length
};정확성 확인: 출력 래스터라이제이션, 메인 광선을 장면으로 발사, 페이로드를 Gbuffer와 비교, 0이 아닌 출력? 버그가 있습니다! 오류를 수정하세요.

'God of War'의 간접 조명 파이프라인에서는 전체 파이프라인 개요, 동기 및 장단점, 결정을 내리는 배경/상황, 기술 개요 등을 포함하여 God of War의 간접 조명 렌더링에 대해 설명합니다.
Gl 볼륨은 복셀당 1미터의 세분성으로 저주파 정적 간접 조명을 대상으로 하며 Maya에 느슨하게 배치되고 추가로 구워집니다. 인코딩은 4개의 3D 텍스처(2차 구형 고조파, RGB 바운스 및 하늘 가시성 + 흑백 바운스, Float16 형식)를 사용합니다. 하늘을 분할하고 바운싱하면 방향성이 향상되고 하늘에 구애받지 않으며 별도로 표시되며 런타임 시 Gl과 병합됩니다.

큰 복셀은 자체 폐색 및 빛 누출을 생성하며 G1의 샘플링 위치는 하드웨어 필터링과 호환되는 복셀 법선에 의해 오프셋됩니다.


움직이는 객체의 경우 빛나는 모양을 얻으려면 움직이는 객체에 일반 오프셋을 사용하고, 베이킹되지 않은 동적 객체에는 일반 오프셋을 사용하지 마십시오. 간접 반사 선택적 스크린 스페이스 리플렉션(SSR), 큐브맵(밉 체인의 광택 컨볼루션), 상자 시차 보정, 수동 배치(상자 충돌 포함), 큐브맵 깊이 버퍼에서 최적의 상자 충돌을 찾는 유틸리티, 상자는 유기적 환경에 적합하지 않습니다.
큐브맵 정규화: 목표는 각도 및 공간 세부 사항에 큐브맵을 사용하여 확산 및 반사 주변 조명 사이의 자연스러운 균형을 유지하는 것입니다. 빌드 프로세스 중 큐브맵에서 구형 고조파를 생성하고, 구형 고조파를 사용하여 저주파 세부 정보를 제거하고, 이를 GI의 저주파 세부 정보로 대체합니다.

큐브 정규화 꺼짐(위) 및 켜짐(아래) 비교:

환경 폐색: SSAO, AO 맵, 캐릭터 AO 캡슐은 Last of Us의 고정 아이템 + 방향 아이템과 유사합니다. 갓오브워는 래그돌 캡슐을 사용했는데, 제작 후반기에는 한계를 거의 넘었다.

광 주입: 라이트 맵에 중간 결과를 축적한 원래 기술입니다. 이는 지속적인 Surfel 컬렉션에서 수행되었으며, Surfel이 생성되는 동안 조명은 방출된 상태로 유지되었습니다. 직접 조명은 기본 렌더와 동일한 조명 계산/모델을 사용하여 모든 광선(방출에 추가됨)에 대한 모든 표면에 대해 평가됩니다.
광선 처리: N 광선: 서핑을 연결된 목록으로 프로젝트, 목록 정렬, 목록 반복, 서핑 간에 광선 전송, GI 볼륨으로 구문 분석. 목록 작성: 각 빛 방향에 대해 표면은 연결된 텍스처 목록으로 투영되고, 각 텍셀은 현재 목록 헤드 포인터를 저장하고, 원자 스왑은 새 서펠을 새 헤드로 추가합니다(아래 그림, 왼쪽). 정렬된 목록: 각 조명 방향, 정렬 및 평면화에 대해 각 스레드는 서로 다른 높이의 고유한 연결 목록이 될 수 있으며 프로세스의 가장 느린 부분에는 버블 정렬을 사용합니다(아래 오른쪽 그림).


조명 전송: 각 조명 방향에 대해 정렬된 목록을 반복하고 렌더러의 공유 조명 코드를 사용하여 동일한 방식으로 하늘을 누적하여 이웃의 조명 기여도를 Surfel에 누적하지만 첫 번째 Surfel은 하늘을 광원으로 처리합니다(아래, 왼쪽). 분석 볼륨: 처리가 진행됨에 따라 SH 인코딩은 각 광선 방향, 각 복셀 중심에 대해 즉시 누적되고, 머리 텍스처에 투영되고, 두 서펠 사이를 통과하여 서펠 기여도가 인코딩됩니다(아래 오른쪽 이미지).

이 기사에서는 체적 안개, 반투명도, 가변 해상도 및 기타 기술도 공유합니다.
대규모 장면을 위한 확장 가능한 실시간 전역 조명에서는 대규모 장면을 위한 확장 가능한 실시간 GI 솔루션을 설명합니다. 해결책은 장면의 복셀 표현(예: 복셀 원뿔 추적), 충돌 기하학, 엔터티의 낮은 LOD, 높이 맵 데이터, 화면의 피드백과 같이 카메라 주변의 초기 복셀화된 조명 장면(예: 복셀 원뿔 추적)입니다. GBuffer 복셀화된 조명 장면, 실제 강력한 레이캐스팅(빛 없음)을 사용하여 매 프레임마다 부분적으로 재계산된 가시 방사조도 볼맵(볼륨 맵)입니다.
방사조도 맵: 카메라 주변의 중첩된 볼륨 맵(3d 클립맵)에 방사조도를 저장합니다. 각 캐스케이드는 셀 크기가 0.45m 3^i(또는 저사양 장치에서는 0.9m 3^i)인 ~64x32x64입니다. i는 캐스케이드 인덱스입니다. HL2 환경 큐브 베이스, 직교 베이스가 선택되었지만 GPU는 샘플에 매우 친숙하며 다른 것으로 쉽게 변경할 수 있습니다. 기지.
기본 장면 매개변수화: 장면을 카메라 주변의 중첩된 볼륨 맵(3d 클립맵)에 저장합니다. 각 캐스케이드는 128x64x128이고 셀 크기는

Sponza 장면 매개변수화:

초기 장면 채우기: 카메라가 이동하면 새 복셀이 "링 안에" 채워지고(텍스처 랩과 유사) 새 복셀은 높이 맵 데이터와 충돌 형상(버텍스 음영 처리) 또는 엔터티의 낮은 수준 LOD로 채워집니다. 그런 다음 이 새 복셀을 햇빛, 간접 조명 방사조도 및 해당 영역의 가장 중요한 빛으로 즉시 비춥니다.
장면 피드백 루프: 중간 설정에서 장면은 32k GBuffer 픽셀을 무작위로 선택하여 지속적으로 업데이트됩니다. 무작위로 선택된 각 GBuffer 픽셀에 대해 알베도, 노멀, 위치, 직접광 및 간접 조사량 맵을 사용하여 조명을 받습니다. 이동 평균은 이 새로운 글로우 색상의 복셀화된 장면 표현을 업데이트하는 데 사용됩니다. 이는 장면 복셀이 다시 조명된 GBuffer 픽셀로 업데이트되고, 현재 방사조도 볼륨 맵으로 업데이트되고, 방사조도 볼륨 맵이 현재 장면 복셀로 업데이트되기 때문에 피드백 루프를 제공합니다. 다중 바운스를 제공할 뿐만 아니라 복셀화 문제(벽이 2복셀보다 얇고 정확도가 높음)도 해결하며 환경 프로브(렌더링 시)는 "기본" 카메라가 캡처할 수 없는 더 많은 데이터를 제공합니다.
Illumination초기화(Initialize):image,패딩/채우기 new적리(),의 단계 ,로부터 거침(Rough)의 단계 데이터 ,“”및거침(Rough)의 단계 ,64개 로써 의 ,을(를) 활용하여 magic(“는 계산/산출(Calculate)의 ”)플래그 의 ,따라서 ,활성화 。
방사조도 맵 - 계산 루프: 방사량 맵에서 눈에 보이는 수백 개의 "프로브"(위치)를 무작위로 선택합니다. 선택 확률은 "프로브"의 가시성과 프로브의 수렴 인자(마지막 변경 정도)에 따라 달라집니다. 선택한 "프로브"에 대해 장면에서 1024~2048개의 광선을 캐스팅하고(설정에 따라) 이동 평균 방법으로 결과를 축적합니다.
Irradiance Map - 계산 대기열: 빠른 수렴을 위해서는 Irradiance Map에서 서로 다른 "프로브"에 대해 서로 다른 대기열을 갖는 것이 중요합니다. 처음 볼 때 품질이 낮더라도 가능한 한 빨리 계산되지는 않습니다. 256개의 광선을 사용하지만 대기열에 4096개의 프로브가 있는 분리된 장면 프로브는 조명 전송에 참여하지 않지만 여전히 동적 개체, 볼륨 측정 및 입자에 대해 계산해야 합니다. 1024개의 광선을 사용하면 대기열 크기는 64~128개의 프로브에 불과합니다.
초기화 조명 - 닭고기와 달걀 문제: 카메라가 순간 이동할 때 주변의 모든 캐스케이드가 유효하지 않으므로 초기 장면을 방사조도(두 번째 바운스)로 조명할 수 없으며 초기 장면 없이는 초기 방사조도를 계산할 수도 없습니다. 이 작업은 두 가지 단계로 이루어집니다. 장면을 복셀화하고, 직접 조명으로만 조명하고, 채광창과 두 번째 바운스에 대한 방사조도를 계산한 다음, 거의 발생하지 않는 장면의 크기를 조정합니다(실루엣).
방사조도 맵을 사용한 렌더링: 노멀 부호를 기반으로 6개의 방사조도 볼륨 맵 텍스처 중 3개를 샘플링하려면 최상의 캐스케이드를 선택합니다(HL2 주변 큐브 참조). 경계에서 다음 캐스케이드와 지연 및 전달 패스(및 체적 조명)를 혼합합니다.
또한 볼록 오프셋 필터링을 사용하여 빛 누출 문제를 해결합니다.

내부의 지나치게 어두운 문제의 경우 "구멍/창" 볼륨(복셀로 채워지지 않음)을 추가하여 다음을 해결하세요.

GI 결론: 여러 개의 빛 바운스, 조정 가능한 품질, 게임 플레이를 저하시키지 않는 저가형 PC에서 최고급 하드웨어까지 지원, 확장 가능한 세부 크기 및 레이 트레이싱 품질을 갖춘 일관된 간접 조명. 동적(어느 정도), 벽을 폭파하고, 건물을 파괴하여 빛이 비치도록 하고, 벽을 만들어 반사와 간접 그림자를 만들고, 빠르게 반복합니다.
Call of Duty: Modern Warfare의 사전 계산된 조명 발전은 일반 베이킹 개선, 구면 조화 코딩(구면 고조파에 대한 통찰력에 초점), 새로운 선형 SH 재구성 알고리즘 및 동적 조명 세트 구현 세부 정보를 포함하여 2020년 COD의 사전 계산된 조명 기술을 공유합니다.
일반적인 베이킹 개선 사항에는 광선 안내, 태양 역추적, 대형 맵(채광창, 흐름), 조명 일관성(스티칭된 모델, 병합된 모델, 얇은 모델), 라이트 맵 인코딩 등이 포함됩니다.

새로운 라이트맵 인코딩 비교 및 공식.
SH 차이 함수는 다음을 인코딩하는 데 사용됩니다.

SH가 평행광을 재구성할 때 선형 SH를 사용하는 효과는 그리 좋지 않습니다.

SH를 ZH 베이스로 변환할 수 있습니다.

ZH 계산:

효과 비교는 다음과 같습니다.

데이터 인코딩: LG와 LGV는 모두 간단하고 SH 인코딩은 원래 이 목적으로만 사용되었으며 LM은 리소스 문제인 대부분의 데이터를 읽고 수정하고 쓰는 데 더 까다롭습니다. 새로운 LM 형식은 처음에는 DLS에만 사용할 수 있었으며 Texel 크기는 당시 LM 크기의 절반이었습니다.
DirectX 12 From Theory To Practice가 포함된 VRS Tier 1은 DX12 Tier 1의 가변 속도 셰이딩, Virtual Reality Engine 4의 VRS 및 Chivalry II practice의 VRS를 도입합니다.
VRS 가장자리 보존 설명: 2x2로 렌더링된 16x16 삼각형, 28 2x2 거친 픽셀 + 8 1x1 픽셀 = 120픽셀, 가장자리 픽셀은 거친 픽셀의 중심에서 샘플링되고 적용 범위 외부의 픽셀은 음영 처리되지 않으며 가장자리 보존은 해상도 스케일링의 장점입니다.

VRS Tier 1 제한: SV_Coverage가 VRS Tier 1에 대한 셰이더 입력 또는 출력으로 선언되면 셰이딩 속도가 1x1로 감소됩니다. SampleMask는 완전한 마스크여야 하며, SampleMask가 다른 유형으로 구성된 경우 음영 비율은 1x1로 감소됩니다. EvaluateAttributeAt[Centroid|Sample|Snapped]는 계층 1 VRS와 호환되지 않습니다. 이러한 내장 기능을 사용하면 음영 처리 속도가 1x1로 감소됩니다. 셰이더에서 참조되는 HLSL의 샘플 키워드는 셰이딩 속도를 1x1로 줄입니다.
Unreal Engine 4는 디퍼드 렌더링과 순방향 셰이딩을 통합하고 DirectX 12 RHI 통합에서는 RHICheckVRSSupport가 하드웨어 지원을 결정하고 초기화 시 호출되며 RHISetVRSValues는 제어 구조를 취하고 D3D12CommandList5를 사용하여 셰이딩 속도 값을 명령 목록에 전달하고 메시 채널의 셰이딩 속도를 위한 콘솔 변수 구현, 각 머티리얼 셰이딩 속도에 대한 편집기 통합을 통합합니다.
VRS 메시 채널은 GBuffer 배치 중 음영 처리 속도를 제어합니다. EMeshPass 열거에 의해 정의된 다중 그리드 패스는 BasePass, TranslucencyStandard, TranslucencyAfterDOF 및 TranslucencyAll과 같은 GBuffer 배치에 사용되어 픽셀이 제한된 작업 부하에 대한 성능 향상을 제공합니다. BasePass 및 반투명 패스는 왜곡이 가장 없는 패스입니다. 다른 패스를 사용한 실험에서는 허용 가능한 품질을 달성하지 못했습니다. 메시 패스의 시각적 품질은 가장자리 보존으로 인해 동등한 렌더링 규모보다 높지만 성능은 콘텐츠에 따라 달라집니다.

VRS Grid Pass: 해상도 스케일링에도 비슷한 이점이 있습니까? 해상도 조정은 저전력 그래픽 구성 요소의 프레임 속도를 부드럽게 하는 일반적인 기술입니다. 해상도 스케일링은 여러 파이프라인 단계에서 전체 프레임의 품질에 영향을 미칩니다. 메시가 셰이딩을 통과하는 속도를 제어함으로써 품질과 성능을 비교하는 위치를 더욱 효과적으로 제어할 수 있습니다. 해상도 스케일링은 더 높은 성능을 제공할 수 있지만 메시 채널 셰이딩 속도는 삼각형 가장자리를 보존할 수 있지만 해상도 스케일링은 그렇지 않습니다. DRR의 성능 향상을 위해 메시 채널 셰이딩 속도를 사용할 수 있습니다.
SSR+VRS 실험: VRS를 SSR에 적용하면 시각적 아티팩트가 발생하지만 시각적 품질을 향상시킬 수 있습니까? TAA가 활성화되면 오른쪽 상단의 대각선 결함이 깜박입니다. r.SSR.Temporal을 1로 설정하고 셰이딩 속도 X/셰이딩 속도 Y를 통해 r.TemporalAAFilterSize를 줄이면 깜박임을 줄이고 선명도를 높일 수 있습니다. ScreenSpaceReflections.usf의 음영 비율에 따라 ScreenSpacerReflectionsPS의 StepOffset 값을 조정하면 시각적 손상을 완화할 수 있지만 가장자리 아티팩트는 남아 있습니다.


이 기사의 저자는 최종 제품에서의 사용을 권장하지는 않지만 SSR+VRS가 실현될 수 있는 미래를 지적합니다.
VRS 재질: 하위 채널 재질 시스템. 새로운 머티리얼 속성 - 셰이딩 속도, 인스턴스 재정의를 통한 머티리얼 인스턴스 지원, 머티리얼 뷰포트의 실시간 업데이트, 머티리얼을 공유하는 여러 자산에 셰이딩 속도 적용, 메시 하위 집합에 대한 셰이딩 속도를 지능적으로 제어하는 인스턴스 생성, 가장 높은 셰이딩 속도 1x1을 사용하여 고품질 자산 저장. 덜 중요한 자산의 경우 2x2 또는 4x4와 같은 낮은 음영 비율을 사용하십시오. 머티리얼 셰이딩 비율을 혼합하고 일치시켜 개별 메시의 품질을 선택적으로 유지합니다.

재료 음영 비율 혼합 및 일치: 두 가지 재료를 사용하여 모델별로 음영 비율을 선택적으로 변경합니다(아래 이미지, 왼쪽). 경우에 따라 2x2 또는 4x4를 사용하면 시각적 품질이 저하될 수 있습니다(아래 이미지 참조). 음영 비율을 혼합하면 충실도가 높은 콘텐츠를 보존할 수 있습니다(아래 이미지, 오른쪽).

VRS용 LOD: 가까운(1x1), 중간(1x2) 및 먼(2x2)을 정의하여 각 LOD 레벨에 대한 VRS 재질을 만듭니다. Material Editor에서 LOD 재질을 재질 슬롯에 삽입합니다. 재질 창을 사용하여 VRS 재질을 사용자 정의 LOD에 적용합니다.

VRS 속도 및 카메라 회전:

VRS 볼륨 및 입자:

재료 제한: 모든 것은 적당히... VRS 재료를 과도하게 사용하면 성능이 저하될 수 있습니다. Ice Lake 아키텍처에서 API 성능 저하 및 부분 파이프라인 플러싱을 방지하려면 셰이딩 속도 변경을 최소화하세요. 반복 음영 처리 속도는 드라이버에서 제거되지만 전환 속도에는 여전히 오버헤드가 있습니다. 오버헤드를 줄이기 위해 셰이딩 속도를 렌더러에 정적으로 캐시할 수 있지만 재질 순열이 너무 많으면 성능이 저하될 수 있습니다. 불투명 마스크가 있는 재질(예: 마스크된 재질)은 투명한 영역의 가장자리를 유지하지 않으므로 반투명도를 고려하세요.
게임 Chivalry II에 대한 기본 패스 비교:

VRS 및 렌더 스케일링 비교:



Call of Duty의 대규모 전역 조명에서는 Activision을 통해 미리 계산된 조명 파이프라인, 왜곡된 조도 볼륨, 샘플링된 볼륨 조명, 구형 고조파의 제한된 투영, 조명 데이터 압축, 미리 계산된 광 전송의 이동 기반 분해 등을 포함하여 COD의 대규모 GI에 대해 설명합니다.
왜곡된 방사량: 위와 아래에서 광선을 가져와 높이 포락선을 얻습니다(아래, 왼쪽). 적응형 블록 없는 경계 문제는 높이 맵이 이미 사용 가능한 경우 "무료"일 수 있습니다(아래 이미지, 오른쪽).

샘플링된 체적 조명: 빛 누출은 체적 조명 표현, 즉 큰 복셀과 작은 기하학적 특징 사이의 불일치의 근본적인 문제입니다. 해결책: 내부와 외부를 서로 다른 볼륨으로 나누고[Hill15, Hooker16] 기하학 인식 재구성 필터링을 사용합니다[ST15]. 큰 복셀과 얇은 형상의 경우 각 광선은 HAT 커널의 삼선형 공간을 구성하며 가시성 기반 샘플 검증은 공간 샘플을 생성하고 가시성 광선을 방출하며 가시성이 낮은 샘플을 무효화합니다.

효과 비교:

제한된 구형 고조파: SH 영역에서는 점별 제약 조건을 추론하는 것이 쉽지 않습니다. 예: 비음성은 선형 SH에서 간단하지만 더 높은 차수로 일반화하려면 창의 계수를 검색해야 합니다[Sloan17]. 공간 영역 대 주파수 영역: 공간 영역은 점별 제약 조건을 추론하기 위한 자연스러운 선택입니다. 동일한 방법이 일반 볼록 구속조건에도 적용됩니다. 64-128개의 피보나치 점과 같이 구에 설정된 점을 선택하고 공간 영역에 따라 투영 연산자를 작성합니다. 예: 반구형 도메인 제약 조건. 사용자 정의 반구형 베이스를 내보낼 필요가 없고 베이스 연산자에 변경 사항을 적용할 필요가 없으며 최종 결과는 구형 캡 등과 같은 임의 도메인에서 작동하는 SH 베이스입니다.

다음으로 압축에 대해 알아보겠습니다. 이동 기준 분해(MBD)를 사용하면 효과가 더 부드럽고 작아집니다.


직접 광전송 비교:

간접 광전송 비교:

전반적인 효과 미리보기:

결론: 가시성 기반 샘플 검증, 확률적 관점, 예상 관점 위치를 넘어서는 오류 최소화, 제한된 SH 투영, 색상 제약, 가시성 제약, 도메인 제약 등을 처리하는 RKHS 프레임워크. 이동 기반 분해는 고차원 데이터를 효율적이고 원활하게 압축합니다.
14.5.3.3 모바일 플랫폼
Archean 설계: 룸 규모 및 모바일 VR, AR 및 모든 입력 장치를 위한 동시 구축에서는 Rift, Vive, GearVR, Cardboard, Tango 및 다양한 타사 물리적, 광학적 및 기존 입력을 포함하여 Archean의 광범위한 VR 및 AR 장치를 지원하는 학습 내용과 기술을 다룹니다. 초점은 코드베이스 아키텍처에 있습니다. 이는 개발자가 다른 플랫폼에 대한 추가 작업을 추가하지 않고도 더 많은 플랫폼을 추가하여 더 많은 게임 기능을 추가할 수 있도록 하는 추상화 계층을 생성하거나 편집기 확장 및 SDK 관리자가 플랫폼별 시나리오 및 프로젝트 설정을 자동으로 처리하여 다양한 플랫폼에서 즉각적인 빌드를 가능하게 함으로써 게임 기능에서 하드웨어 지원을 분리하는 것을 목표로 합니다. 기사에서 제안하는 VR 계층 아키텍처는 다음과 같습니다.

SDK별 입력 클래스: 하드웨어/SDK당 하나의 클래스, 프로젝트별 로직 없음! 장치 입력을 듣고, 추상 처리기를 호출하고, 도구를 호출/보류/업하고, 일반 입력을 호출/보류/업합니다.
입력 구성 요소: SDK 특정 구성 요소 클래스에는 하드웨어 기능에 대한 특정 참조가 포함되어 있습니다.
public class ViveControllerComponents : WandComponents
{
public SteamVR_Controller.Device viveController;
}범주별 구성 요소 클래스에는 하드웨어 유형에 대한 공용 속성이 포함되어 있습니다.
public class WandComponents : InputComponents
{
public Transform handTrans;
public override Vector3 Position { get { return handTrans.position; } }
public override Vector3 Forward { get { return handTrans.forward; } }
public override Quaternion Rotation {get{ return handTrans.rotation; }}
}InputComponents 기본 클래스에는 대부분의 추상 데이터가 포함되어 있습니다.
public class InputComponents
{
public virtual bool Valid { get { return true; } }
public virtual Vector3 Position { get { return Vector3.zero; } }
public virtual Vector3 Forward { get { return Vector3.forward; } }
public virtual Quaternion Rotation { get { return Quaternion.identity; } }
}- 도구 기본 클래스.
// 개 SDK의 //
public virtual void DoToolDown_Sixense(SixenseComponents sxComponents)
{
DoToolDown_Wand(sxComponents);
}
public virtual void DoToolDown_Leap(LeapComponents leapComponents)
{
DoToolDown_Optical(leapComponents);
}
public virtual void DoToolDown_Tango(TangoComponents tangoComponents) {
DoToolDown_PointCloud(tangoComponents);
}
// 개 의 //
public virtual void DoToolDown_Wand(WandComponents wandComponents)
{
DoToolDown_Core(wandComponents);
}
public virtual void DoToolDown_Optical(OpticalComponents opticalComps)
{
DoToolDown_Core(opticalComps);
}
public virtual void DoToolDown_PointCloud(PCComponents pcComponents)
{
DoToolDown_Core(pcComponents);
}
// 함수
DoToolDown_Core
DoToolDownAndHit*
DoToolHeld_Core
DoToolUp_Core
DoToolDisplay_Core
public virtual void DoToolDown_Core(InputComponents comp)
{
if (Physics.Raycast(comp.Position, comp.Forward, out hit, dist, layers))
{
DoToolDownAndHit(comp);
}
}- 특정 도구 유형.
// 로써 DoToolDown_Core,구현 플랫폼로직
public class MoveTool : Tool
{
protected override void DoToolHeldAndHit(InputComps comps)
{
selectedTrans.position = hit.point;
}
}
// 로써 또는 SDK의 ,로써 구현 의 로
public class MoveTool : Tool
{
// ...
protected override void DoToolHeld_Optical(OpticalComps comps)
{
// Move mechanic that’s more appropriate for optical control
}
}- 하드웨어 입력 기본 클래스. 일반적인 게임 기능 및 일회성 상호 작용에 적합한 비도구 추상 입력, 세 가지 처리 방법:
// Unity의 입력
bool HardwareInput.ButtonADown/Held/Up
// 개 의
event HardwareInput.OnButtonADown
// 내에서 입력/로직
void HardwareInput.HandleButtonADown()- 게임플레이/일반 입력 카테고리….
// 회 입력
public class GameplayController : MonoBehaviour
{
void Update()
{
if(HardwareInput.TriggerDown)
{
WorldConsole.Log("Fire ze missiles!");
}
}
void Awake()
{
HardwareInput.OnButtonADown += HandleButtonA;
}
void HandleButtonA()
{
WorldConsole.Log("Boom!"); // Btw: use a “world console”!
}
}
// 의 입력, 갱신(Update)의 메서드 :
// 추가(Add)입력/위치 /
HardwareInput.ButtonADown/Held/Up
// 의 이벤트 파라미터
HardwareInput.OnButtonADown(args)
HandleButtonADown(components)모든 SDK는 Libs/dir 형식으로 프로젝트에 존재합니다.

SDK가 너무 많습니다! SDK 간의 AndroidManifest와 플러그인 충돌은 경우에 따라 매니페스트를 병합하여 해결할 수 있습니다(예: Cardboard+Nod). 대부분의 경우 충돌하는 SDK를 빌드 파이프라인에 연결할 수 있는 자산 폴더 안팎으로 이동하면 됩니다. 다중 SDK 장면 설정의 경우 모든 SDK를 지원하도록 장면을 설정하고 Player 개체에는 ViveInput, GamepadInput, CardboardInput, NodeInput, LeapInput, TangoInput...에 대한 구성 요소가 포함됩니다. 장면 간에 작업 중복이 없고 모든 장치를 동시에 활성화할 수 있다는 이점이 있습니다(예: Vive+Leap). 이점은 여러 장치 유형이 상호 작용한다는 것은 새로운 디자인 과제를 의미하고, 더 많은 플랫폼 == 더 복잡한 장면을 의미하며, 플레이어를 더 관리하기 쉬운 프리팹으로 분할할 수 있고 이러한 프리팹을 런타임에 또는 편집기 스크립트를 사용하여 조립할 수 있다는 것입니다. SDK Manager 편집기 스크립트의 경우 편집기에서 또는 빌드 시 플랫폼별로 구성 요소 및 개체를 활성화/비활성화합니다.
public void SetupForCardboard()
{
Setup(
// Build settings
bundleIdentifier: "io.archean.cardboard",
vrSupported: false,
// GameObjects
cameraMasterActive: true,
sixenseContainerActive: false,
// MonoBehaviours
cardboardInputEnabled: true
);
}또한 사용자 정의 가능한 입력 모듈을 통해 uGUI에 새로운 하드웨어 지원을 추가할 수 있습니다. 블록 및 포인터 UI(블록 및 포인터 UI)를 클릭하거나 누르면 <device>는 UI(예: Vive) 또는 단순 충돌(예: Leap)에 광선을 투사합니다. 맞춤 버튼 구성요소:

ButtonHandler 클래스에는 모든 작업을 매핑하는 거대한 스위치 문이 있습니다.
switch(button.action)
{
case ButtonStrings.Action_TogglePalette: TogglePalette(button, state); break;
case ButtonStrings.Action_ChangePage: ChangePage(button, state); break;
case ButtonStrings.Action_ChangePagination:ChangePagination(button); break;
case ButtonStrings.Action_SelectProp: SelectProp(button, state); break;
case ButtonStrings.Action_SelectTool: Tool.HandleSelectToolButton(button); break;
…조작을 위한 상수 문자열이 포함된 파일도 있습니다.
public const string Action_TogglePalette = "togglePalette";
public const string Action_ChangePage = "changePage";
public const string Action_ChangePagination = "changePagination";
public const string Action_SelectProp = "propSelect";
public const string Action_SelectTool = "toolSelect";
....매개변수 필드를 통해 더욱 발전되고 재사용 가능한 기능을 얻을 수 있고, 사용자 인터페이스 코드가 중앙 집중화되었으며, 버튼이 모든 데이터 유형을 전달할 수 있어 매우 편리합니다. 멀티 플랫폼 VR 앱을 만들고 싶은데요...정말인가요? SteamVR&Cardboard에는 Unity의 기본 VR 지원이 추가되었으며 처음부터 멀티 플랫폼으로 계획되었습니다.
고급 VR 렌더링 성능에서는 다중 GPU, 포비티드 렌더링 및 방사형 밀도 마스킹, 재투영, 적응형 품질 등을 포함한 2016년 VR 렌더링 최적화 기술에 대해 설명합니다.
단일 GPU의 경우 단일 GPU가 모든 작업을 수행하고 스테레오 렌더링은 다양한 방식으로 수행될 수 있으며(이 예에서는 순차 렌더링 사용) 그림자 버퍼가 두 눈 간에 공유됩니다. 다중 GPU 선호도 API, AMD 및 NVIDIA에는 선호도 마스크를 사용하여 GPU 전체에 그리기 호출을 브로드캐스트하고, 각 GPU에 대해 서로 다른 셰이더 상수 버퍼를 설정하고, GPU 전체에 렌더 대상의 하위 사각형을 전송하고, 대상 GPU가 렌더링되는 동안 전송 펜스를 사용하여 비동기적으로 전송하는 여러 GPU 선호도 API가 있습니다. 2개의 GPU를 사용하면 각 GPU가 한쪽 눈을 렌더링하고 두 GPU 모두 섀도우 버퍼를 렌더링하며 전송 버블에서 "왼쪽 커밋" 및 "응용 프로그램 창"이 수행되어 성능이 30~35% 향상됩니다. 4개의 GPU, 각 GPU가 눈의 절반을 렌더링하고 모든 GPU가 섀도우 버퍼를 렌더링하는 경우 PS 비용은 선형적으로 증가하지만 VS 비용은 그렇지 않으며 드라이버의 CPU 비용이 높을 수 있습니다.

위에서 아래로: 1, 2, 4 GPU 렌더링 다이어그램.
프로젝션 매트릭스 대 VR 광학: 프로젝션 매트릭스는 우리가 원하는 것과 반대되는 픽셀 밀도 분포를 가지며, 프로젝션 매트릭스는 가장자리에서 각도당 픽셀 밀도를 증가시키고, VR 광학은 중앙에서 픽셀 밀도를 증가시키며 결국 가장자리의 픽셀을 과도하게 렌더링하게 됩니다. NVIDIA의 "다중 해상도 셰이딩"을 사용하면 더 적은 CPU 오버헤드로 약 5~10% 추가 GPU 성능을 얻을 수 있습니다.

방사형 밀도 마스킹: 현재 GPU 아키텍처와 일치하도록 2x2 픽셀 정사각형의 체커보드 패턴 렌더링을 건너뜁니다.

필터를 재구성하는 과정은 다음과 같습니다.

방사형 밀도 마스킹 단계:
렌더링 시 2x2 픽셀 정사각형을 잘라내거나 2x2 체커보드 패턴을 사용하여 템플릿이나 깊이를 채운 다음 렌더링합니다.
재구성 필터.
Aperture Robot Repair에서 5~15%의 성능 절감, 다양한 콘텐츠와 다양한 셰이더를 사용하여 더 높은 이득을 얻을 수 있습니다. 픽셀을 재구성하고 건너뛰는 오버헤드가 픽셀 쿼드를 건너뛰는 데 따른 픽셀 셰이더 절약을 초과하지 않는 경우에는 세척입니다. 저사양 GPU에서는 거의 항상 많은 작업이 절약됩니다.
누락된 프레임을 처리하기 위해 엔진이 프레임 속도에 도달하지 않은 경우 VR 시스템은 마지막 프레임의 렌더링된 이미지를 재사용하고 재투영할 수 있습니다. 누락된 프레임을 채우기 위해 재투영을 사용하는 회전 재투영, 위치 및 회전 재투영만 최후의 수단 안전망으로 간주되어야 합니다. 대상 사용자가 애플리케이션의 최소 사양보다 낮은 GPU를 사용하지 않는 한 프레임 속도를 유지하기 위해 재투영에 의존하지 마십시오.
회전 전용 재투영: 지터는 카메라 변환, 애니메이션 및 추적된 컨트롤러에 의해 이동되는 개체로 인해 발생합니다. 지터는 평균을 낸 두 개의 서로 다른 이미지로 나타납니다.

회전 재투영은 머리 중심이 아닌 눈 중심이므로 잘못된 위치에서 재투영되며, 재투영 시 회전량에 따라 ICD(카메라 간 거리)가 인위적으로 감소됩니다.

긍정적인 측면: 이 알고리즘은 수십 년 동안 잘 이해되어 왔으며 현대 연구를 통해 개선될 가능성이 높습니다. 알려진 부작용이 있더라도 단일 드롭 프레임을 매우 잘 처리합니다. 따라서... 누락된 프레임에 대한 최후의 수단 안전망이 될 만큼 충분히 좋은 매우 중요한 절충안이 있습니다. 이는 프레임을 잃는 것보다 낫습니다.
위치 재투영: 여전히 큰 관심을 끄는 해결되지 않은 문제입니다. 기존 렌더러에서는 하나의 깊이만 사용할 수 있으므로 반투명도를 표현하는 것이 어렵습니다(입자 시스템). 깊이는 해결된 색상의 MSAA 깊이 버퍼에 저장되어 잠재적으로 색상 오버플로가 발생할 수 있습니다. 표현되지 않은 픽셀의 경우 구멍 채우기 알고리즘은 유효한 입체 쌍의 프레임이 많더라도 망막 경합을 유발할 수 있습니다. 사용자가 웅크리거나 일어서서 수직으로 이동하면 간격을 채워야 합니다.
비동기식 재투영: GPU에 따라 드로우 콜 경계에서 선점할 수 있는 현재 세대 GPU와 동일하거나 더 나은 선점 세분성을 요구하는 이상적인 안전망
, 현재 vsync가 제때에 다시 출시될 수 있다는 보장은 없습니다. 애플리케이션은 선점 세분성을 이해해야 합니다.
인터리브 재투영 힌트: 이전 GPU는 비동기 재투영을 지원할 수 없으므로 대안이 필요합니다. OpenVR API에는 인터리브 재투영 힌트가 있습니다. 기본 시스템이 상시 비동기 재투영을 지원하지 않는 경우 애플리케이션은 매번 프레임 회전 전용 재투영을 요청할 수 있습니다. 애플리케이션은 ~18ms/프레임 렌더링을 가져옵니다. 기본 VR 시스템은 애플리케이션이 목표 프레임 속도 아래로 떨어지면 자동으로 활성화되는 안전망으로 인터리브 재투영을 사용할 수도 있습니다. 매 프레임마다 다시 투영하는 것은 좋은 절충안입니다.
프레임 속도를 유지하는 것은 어렵습니다. 가상 현실은 사용자가 카메라를 너무 많이 제어할 수 있고 많은 상호 작용 모델을 통해 사용자가 세계를 재구성할 수 있기 때문에 기존 게임보다 더 어렵습니다. 사용자가 콘텐츠를 쉽게 재구성할 수 있으므로 렌더링 및 콘텐츠를 90fps로 조정하지 않아도 됩니다. Aperture Robot Repair는 경험의 최악의 20%를 조정하여 달성한 프레임 속도를 달성했습니다.
적응형 품질: 렌더링 설정을 동적으로 변경하여 GPU 활용도를 최대화하는 동시에 프레임 속도를 유지합니다. 목표는 유휴 GPU 주기가 있을 때 프레임 삭제 및 재투영 가능성을 줄이고 품질을 향상시키는 것입니다. 예를 들어, Aperture Robot Repair VR 데모는 두 가지 다른 방법을 사용하여 NVIDIA 680에서 목표 프레임 속도로 실행됩니다. 이점은 응용 프로그램에 사용할 수 있는 최소 GPU 사양, 아트 자산 제한 증가입니다. 이제 아티스트는 프레임 속도를 유지하기 위해 재투영에 의존하지 않고도 약간 낮은 충실도의 렌더링과 높은 다각형 자산 또는 더 복잡한 재질을 교환할 수 있으며 예상치 못한 이점도 있습니다. 응용 프로그램이 모든 하드웨어에서 더 좋아 보입니다.
VR에서 조정할 수 없는 것: 스페큘러 반사 같은 시각적 기능은 전환할 수 없으며 그림자도 전환할 수 없습니다. 조정할 수 있는 항목: 렌더 해상도/뷰포트(동적 해상도라고도 함), MSAA 수준 또는 앤티앨리어싱 알고리즘, 포비티드 렌더링, 방사형 밀도 마스킹 등 적응형 품질 예(굵은 글씨는 기본 구성):

GPU 작업 부하 측정: GPU 작업 부하가 항상 안정적인 것은 아니며 거품이 있을 수 있습니다. VR 시스템 GPU 작업 부하가 가변적입니다: 렌즈 왜곡, 색수차, 결합 경계, 적용 범위 등. 애플리케이션이 아닌 VR 시스템에서 타이밍을 가져옵니다. 예를 들어 OpenVR은 모든 GPU 작업을 계산하는 총 GPU 타이머를 제공합니다.

GPU 타이머 - 지연, GPU 쿼리에 이미 1개의 프레임이 있고 대기열에 수정할 수 없는 프레임이 1~2개 있습니다.

구현 세부 사항 - 70%-90% GPU 활용도 유지를 목표로 하는 3가지 규칙.
높은 GPU 사용률 = 프레임의 90%(10.0ms), 큰 감소: GPU 프레임의 90% 임계값 이후 마지막 프레임의 렌더링이 완료되면 2레벨 감소하고 2프레임을 기다립니다.
낮은 GPU 사용률 = 프레임의 70%(7.8ms), 보수적으로 증가: 마지막 3프레임이 GPU 프레임의 70% 임계값 미만으로 완료되면 1레벨 증가하고 2프레임을 기다립니다.
예측 = 프레임의 85%(9.4ms), 빠른 성장을 예측하기 위해 마지막 두 프레임의 선형 외삽을 사용합니다. 마지막 프레임이 85% 임계값을 초과하고 선형 외삽의 다음 프레임이 높은 임계값(90%)을 초과하는 경우 2레벨을 떨어뜨리고 2프레임을 기다립니다.
10% 유휴 규칙: 90%라는 높은 임계값은 거의 모든 프레임에서 다른 처리를 위해 GPU의 10%를 유휴 상태로 남겨 두는 것입니다. 이는 좋은 것입니다. Windows 데스크톱에서 몇 프레임마다 GPU가 필요한 경우에도 GPU는 다른 처리와 공유되어야 합니다. GPU 예산에 대한 정신 모델은 작년에 프레임당 11.11ms에서 현재 프레임당 10.0ms로 변경되었으므로 다른 처리를 위해 GPU 주기가 거의 중단되지 않습니다.
CPU와 GPU 성능을 분리하여 렌더링 스레드를 자율적으로 만들고 CPU가 새 프레임을 준비하지 않은 경우 재투영하지 마세요! 대신, 렌더링 스레드는 업데이트된 HMD 포즈와 동적 해상도에 대한 최저 적응형 품질 지원을 사용하여 GPU 워크로드의 마지막 프레임을 다시 제출합니다. 애니메이션 지터 문제를 해결하려면 렌더링 스레드에 애니메이션을 업데이트된 상태로 유지하기 위해 두 애니메이션 프레임 사이에 보간될 수 있는 두 개의 애니메이션 프레임을 제공합니다. 그러나 사소하지 않은 애니메이션 예측은 어려운 문제입니다. 그런 다음 보다 복잡한 시뮬레이션을 위해 GPU 프레임 속도의 1/2 또는 1/3로 CPU를 실행하거나 저가형 CPU에서 실행하도록 계획할 수 있습니다.
요약하자면, 모든 VR 엔진은 다중 GPU(최소 2개의 GPU)를 지원해야 하며, 포비티드 렌더링 및 방사형 밀도 마스킹은 광학 대 프로젝션 매트릭스 전투를 상쇄하는 데 도움이 되는 솔루션입니다. 적응형 품질은 다른 프로세스에 GPU의 10%를 사용하면서 충실도를 높이거나 낮추며, 최소 사양 프레임 속도를 달성하기 위해 재투영에 의존하지 않습니다! 엔진이 렌더링 스레드에서 다시 제출하여 CPU와 GPU 성능을 분리하는 방법을 고려하세요.
품질 저하 없는 고해상도 및 'PlayStation VR Worlds'의 다른 교훈은 텍스처 스트리밍, 바인딩 없음, SRT, 드로잉 검증, 해상도 그라데이션, 소스 코드 레벨 셰이더 디버깅, 적응형 해상도 등을 포함한 PS의 VR 렌더링 기술을 설명합니다.
픽셀 좌표는 더 이상 조회, 즉 뷰 공간의 효율적인 타일링을 수행하는 데 사용되지 않으므로 데칼 타일링에 사용된 결합된 프러스텀를 사용하여 두 눈에 대해 한 번만 수행하면 됩니다.

하이브리드 블록 전달 및 지연의 단점: 전달 이점이 사라집니다. MSAA에 대한 지연 방법을 채택하는 것도 중요합니다. 가상 현실 세계에는 MSAA가 없습니다. 그러나 결과는 훌륭하고 모델을 다시 조명할 때 유연성을 제공합니다. 성능은 좋으며 이미지 해상도에서 조명 타일 해상도를 분리하는 것은 큰 승리입니다.
부분적으로 상주하는 텍스처의 경우 하드웨어는 매핑되지 않은 메모리를 읽었음을 사용자에게 알리는 내부 셰이더 메커니즘을 제공하며 그런 다음 해당 정보를 사용하여 작업을 수행할 수 있습니다. 예를 들어, 실패 정보를 기록하고 나중에 해당 페이지를 가져올 수 있습니다.
가상 메모리 시스템: Aaron MacDougall이 제안한 시스템을 최대한 활용하여 텍스처는 2바이트 크기의 거듭제곱으로 그룹화되고, 두 크기의 각 거듭제곱에는 자체 슬롯 할당자가 있으며, 각 슬롯 할당자에는 총 36GB를 사용하는 4GB의 가상 메모리가 있습니다. 그런 다음 게임은 사용자가 사용할 수 있는 대규모 물리적 페이지 백을 제공하며, 그 수는 필요에 따라 런타임에 변경될 수 있습니다.

텍스처 품질이 향상되고 64KB 페이지에 매핑되면 텍스처의 최소/최대 밉 필드가 즉시 변경되고 새 웨이브프런트는 이 프레임에서 이러한 변경을 볼 수 있습니다. 텍스처 품질이 떨어지면 최소/최대 밉 필드가 즉시 변경되지만 다음 프레임에서는 페이지가 매핑 해제됩니다. 페이지 매핑이 변경되지 않은 상태로 유지되므로 뚜렷한 지연이 없습니다. 복사나 조각 모음이 필요하지 않으며, 가상 메모리 조각화, 물리적 조각화에 관심이 없으며 텍스처 매핑된 그리기 호출 확인이 쉽습니다. 즉, 가상 메모리를 사용하면 텍스처 스트리밍이 더 쉬워집니다! 그리고 다른 많은 이점을 제공합니다. 셰이더에서 PRT는 악몽이지만 밉 기반 PRT는 관리하기가 매우 쉽습니다. 또한 PRT는 CS 및 VS에서도 작동한다는 것을 잊지 마십시오.
드로우콜 검증(Draw Call Verification): 부득이하게 문제가 생겼을 때, 문제 해결에 도움이 되는 것들을 만드는데 많은 시간을 투자하는 것을 드로우콜 검증이라고 합니다. 무승부를 보내기 전에 명백한 오류를 찾아내십시오. GPU 충돌 및 시간 초과는 디버깅하기 어렵고 모든 오류가 그렇게 명백하고 직접적인 오류로 이어지는 것은 아닙니다. GPU가 충돌하면 디버깅에 상당한 시간이 소요됩니다. 당시의 도구는 이것을 매우 어렵게 만들었습니다. 어떤 추첨이 실패했나요? 왜? 추적하는 데 일주일이 걸렸고 수정하는 데 몇 분이 걸렸을 것입니다.
GPU Protection fault. Access Read: Unmapped page access: Addr(VA)0x000000000433e000대부분의 결함은 미묘(충돌 아님), 보이지 않는 개체, 깨진 재질, 빈 질감이며 개체가 보이지 않으면 문제를 놓치거나 아티스트가 의도한 것이라고 생각할 수도 있습니다. 하지만 여전히 충돌이 발생합니다. GPU 보호 오류입니다. 액세스 읽기: 매핑되지 않은 페이지 액세스: Addr(VA)0x000000000433e000, 프로그램 카운터 없음, 셰이더 ID 없음, 그리기 ID 없음. 명령 버퍼를 시작한 후 상태가 손상될 수 있고, 메모리가 매핑되지 않을 수 있으며, 날카로운 물체가 버려지고 코드가 여전히 손상될 수 있습니다. 충돌이 발생하는 대로 지침에 따라 이를 포착할 수 있다면 추측이 그리 많지 않을 것입니다. 일반 디버거를 사용하는 것처럼 활성화 상태를 확인하여 무엇이 잘못되었는지 확인할 수 있으며 셰이더에서 확인할 수 있습니다.

패킹된 셰이더 코드: 벡터 로딩 예제는 벡터 로딩을 새 코드 조각으로 이동하는 것으로 대체합니다.
새로운 코드 조각: V#에서 기본 주소와 버퍼 크기를 계산하고, 범위가 매핑되었는지 확인하고, 각 페이지에 대한 권한을 확인하고, 만족되면 원래 명령을 실행하고 반환하고, 그렇지 않으면 PC를 메인 메모리에 쓰고 CPU와 사용자에게 신호를 보냅니다.

요약하면 검증은 수행할 가치가 있고 수행하기 쉬우며 시간을 절약해 줍니다! 비동기 페이지 오류를 포착하는 것은 까다롭지만 중요한 기간이 되기 전에 인프라를 개발하는 것은 가치가 있습니다.
다음으로 해상도 그라데이션(Resolution Gradient)에 대해 이야기해 보겠습니다. VR 화면 변형 과정과 예상 해상도의 관계는 다음과 같습니다

더 높은 내부 해상도: PlayStation VR의 경우 원래 픽셀 수의 두 배에 해당하는
따라서 하드웨어 지원 없이 중앙에 여러 픽셀을 가변 해상도로 렌더링하고 주변 영역을 줄이는 방법을 찾아야 합니다. 한 가지 방법은 두 가지 패스를 사용하는 것입니다. 중앙 부분을 고해상도로 렌더링하고 나머지 부분을 낮은 해상도로 렌더링하고 이를 결합하고 혼합합니다(아래 이미지). 그러나 각 뷰에서 추가 지오메트리 패스를 사용해야 하며 높음 또는 낮음의 두 가지 수준만 있으며 모양은 그다지 유연하지 않습니다.

이미지에 적용할 디더링 템플릿 마스크를 구성하면 더 많은 제어가 가능하고 추가 지오메트리 패스가 필요하지 않습니다(고해상도 보간 방법이 필요함). 평소처럼 중앙에 음영을 준 다음 중앙에서 멀어질수록 점차적으로 더 많은 픽셀을 음영 처리합니다. 이미지 외부에서는 픽셀의 1/4만 렌더링됩니다(아래 오른쪽 이미지).


쿼드 오버드로를 방지하기 위해 2x2 픽셀 격자를 마스크하면 모든 것이 무의미해진다는 것을 눈치챘을 것입니다. 쿼드 세분화 마스킹: 쿼드의 일부 픽셀을 마스크하는 경우에도 동일하게 적용됩니다. 따라서 이점을 얻으려면 마스킹이 픽셀이 아닌 쿼드(2x2 픽셀 블록) 단위로 이루어져야 합니다. 그런 다음 확대 패스를 사용하여 구멍을 채우고 가장 가까운 음영 픽셀(아래) 위에 복사하면 됩니다.

대부분의 경우 가장 가까운 유효한 픽셀을 선택하기 위해 셰이더의 샘플 위치를 조정하여 "요청 시" 채우는 것이 더 빠릅니다. 더 이상 별도의 팽창 패스가 필요하지 않습니다. 여러 패스의 추가 ALU는 일반적으로 모든 셰이더 코드를 수정하는 데 필요한 추가 읽기/쓰기보다 저렴합니다!
프리패스 후 마스킹: 장면의 지오메트리와 깊이 복잡성에 따라 때로는 전처리 중에 마스크하지 않는 것이 더 빠릅니다. 이로 인해 전처리가 약간 느려지지만 전처리 음영 처리가 가볍고 깊이를 확장할 필요가 없어 비용을 절약할 수 있으므로 그리 많지는 않을 것입니다.
시간 마법: 프레임당 TAA 기여도를 누적하도록 디더링 모드를 변경하여 모든 픽셀이 더 낮은 시간 주파수에서 기여하도록 보장하고 기존 TAA를 거의 변경하지 않고 시간 해상도를 공간 해상도로 교환합니다.

1/4 해상도 영역에서도 결과는 놀라울 정도로 좋습니다! 쿼드 단위로 마스킹도 가능합니다! 16.6ms 프레임에서 약 4ms를 절약합니다!


MSAA 남용: 쿼드 세분화된 마스킹은 고주파수 영역의 불안정성을 악화시키고 움직임이 더 눈에 띄지만 픽셀 세분화에서 마스크하는 방법을 찾았습니다! Mark Cerny의 통찰력 덕분에 그리기 문제가 전혀 발생하지 않습니다. 4XMSAA(MSAA 샘플 위치 조정) 및 1/4 해상도(1/2 x 1/2)의 샘플링 빈도로 렌더링해도 여전히 동일한 수의 샘플이 있지만 쿼드를 구성하는 샘플은 이제 해상도 이미지에서 더 멀리 떨어져 있습니다. 그림

최고 수준의 마스킹 프로세스. A: 2x2 픽셀 그리드, 오른쪽에 각각 4개의 샘플. B: 각 픽셀의 해당 샘플을 사용하여 구축된 픽셀 쿼드. 첫 번째 쿼드는 2x2 픽셀 그리드에 있는 각 픽셀의 첫 번째 샘플로 구성됩니다. C: 다른 픽셀도 유사하다. D: 이전과 같이 녹색과 노란색으로 표시된 쿼드를 마스크하면 픽셀 세분화된 마스킹이 나타납니다!


MSAA 트릭 난제: 이를 처리하는 코드가 모든 셰이더 및 런타임 코드, 특히 주문형 확장으로 번지기 시작하고, 그래픽 디버깅 도구를 사용하기가 더 어렵고, 이미지가 4개의 샘플로 분할되며, 이를 제대로 시각화하려면 결정이 필요합니다.
고해상도 및 저지연 그래픽은 VR 사용자에게 진정한 몰입형 경험을 제공하는 데 핵심입니다. Unreal Engine과 Oculus를 사용한 고품질 모바일 VR은 UE4의 모바일 VR에 대한 팁과 모범 사례, UE4의 최신 렌더링 기술, 그래픽 파이프라인이 모바일 폼 팩터를 최대한 활용할 수 있는 방법을 공유합니다. 또한, 모바일 VR 기술이 어떻게 발전하고 있으며, 미래에 무엇을 기대할 수 있는지에 대해 논의합니다.
VR 모범 사례: PC 및 콘솔에 비해 모바일 장치는 더 많은 제한 사항을 갖고 있으며 가장 접근하기 쉬운 개발 환경이자 가장 까다로운 플랫폼입니다. 배터리 수명과 냉각이 주요 관심사이며 최고 성능은 빠르게 실행되지만 무한정 실행될 수는 없습니다. 최적화는 PC 및 콘솔보다 더 복잡하며 프레임 속도를 유지하는 것만으로는 충분하지 않습니다. Android N 지속 성능 모드는 더 낮은 성능 수준에서 무기한 실행을 보장합니다.
자산 예산 및 권장 사항: 전체 장면의 평균 삼각형 수는 50-60,000개, 최대 100,000개, 눈당 DC 50개, 재질 및 메시 병합, 인스턴스 사용, 멀티뷰로 이를 개선했습니다! 메모리에 미치는 영향을 고려하여 LOD를 집계합니다. 머티리얼 및 라이트맵 공유를 위한 버텍스 데이터를 유지하는 새로운 자동 LOD 생성 예제 출력(아래) 머티리얼은 125개 이하의 디렉티브, 동적 조명이나 그림자가 없어야 하고 굽거나 가짜여야 하며, 포스트 프로세스 없이 LDR을 사용하고, 대표 콘텐츠로 테스트 레벨을 생성하고, 예산을 확인하기 위해 출시할 장치에 대한 프로필, 세션 기간 동안의 테스트 예산을 포함해야 합니다.

콘텐츠 제안: 사용자에게 보이지 않는 삼각형 제거, 뒷면 제거, 대형 모델 세분화, 원거리 환경을 스카이박스에 굽기, 최적으로 샘플링된 Oculus 큐브 환경 레이어 사용, 중간 영역에 모노스코픽을 사용할 수 있습니다. 완전히 거친 존재감, 가짜 주변 반사. 가려진 객체를 렌더링하고 DC 및 기본 컬링 시간을 낭비하는 대신 그리기 거리를 최소화하도록 장면을 설계하고 미리 계산된 가시성 볼륨을 사용하며 장면 정보를 사용하여 보이지 않는 객체를 사전에 수동으로 숨깁니다. 투명한 오버드로를 최소화하고 여전히 100% 투명한 개체를 그립니다. 가시성 플래그를 설정하세요! MSAA를 최소 2배, 가능하다면 최소 4배 사용하세요. 사후 처리 앤티앨리어싱을 피하고, 텍스처 압축에 ASTC를 사용하고, 블록 크기를 최대화하고, MIP 맵을 생성하고, 복잡한 필터링 옵션을 피하십시오. 틱 개체 수를 추적하고 필요하지 않으면 틱하지 마십시오. 객체를 생성하는 것은 매우 비용이 많이 들고 로드 시 생성되며 여러 프레임에 걸쳐 상각됩니다. 개체를 공유하기 위한 관리자 구축을 고려하고, 스크립트 VM 오버헤드를 줄이기 위해 기본 청사진을 사용해 보세요.
스테레오 레이어: 엔진에서 렌더링되지 않고 컴포지터에서 레이 트레이싱되며 한 번만 샘플링됩니다! 쿼드, 원통 및 큐브 맵, 헤드 잠금, 추적기 잠금 또는 월드 잠금과 같은 잠금 모드, 솔리드 레이어 구성 요소를 지원하고 UMG와 함께 작동합니다!

당시 UE는 모노스코픽 파 필드 렌더링과 모바일 멀티뷰 렌더링을 추가했습니다.
모노스코픽 렌더링: 두 눈을 렌더링하면 위치 차이로 인해 양안 시차가 발생하고 투영 차이로 인해 양안 시차가 발생하며 깊이가 동일합니다. CPU 사용량이 두 배로 늘어나고 버텍스/조각 사용량이 두 배로 늘어나는 성능 문제가 있습니다.

거리가 증가할수록 위치 차이는 덜 중요해집니다. 세 번째 카메라, 30피트 떨어진 평면에 있는 두 개의 스테레오 카메라, 평면에서 30피트 떨어진 곳에 카메라가 있는 단일 렌즈 카메라, 엄격한 픽셀 순서 및 새로운 렌더링 파이프라인을 추가합니다.

새로운 파이프라인의 문제점: 사용되지 않는 픽셀을 렌더링하는 단일 렌즈 카메라, 프러스텀 선별된 먼 대상을 그리는 스테레오 카메라, 아티팩트 합성(주로 투명도), 세 번째 카메라 실행 시 성능이 저하됩니다. 결과: 성능은 환경에 따라 크게 달라집니다. 경우에 따라 20% 이상 증가하고 CPU 및 GPU에 영향을 미치며 성능 저하, 켜기/끄기 및 보기 거리를 포함한 동적 시스템, vr.FarFieldRenderingMode 0/1/2/3/4를 유발합니다.
모바일 멀티뷰(Multiview) 렌더링: 기본 세분성에서 뷰 간의 차이가 최소화됩니다. 다음은 일반 및 다중 보기 모드에 대한 CPU-GPU 타임라인입니다.

소모품: PC용 인스턴스화된 입체 렌더링, PS4 인스턴스화된 입체 멀티뷰 확장, Nvidia의 단일 패스 입체 렌더링, AMD의 DirectX 11 멀티뷰 확장, OpenGL ES 멀티뷰 확장.
UE4 구현: PC/PS4 인스턴스화된 스테레오 및 PS4 멀티뷰, 파이프라인 기반 표준 그래픽, 인스턴스화된 드로우 콜, 변형, 컬링, 버텍스 셰이더 클리핑, 버텍스 셰이더 작업을 줄이기 위한 PS4용 작은 확장. 모바일 멀티뷰: 그리기 호출 인스턴스와 버텍스 작업은 시스템을 통합하기 위해 인스턴스 입체 뷰를 사용하여 드라이버에 의해 완전히 수행됩니다. 다중 보기의 CPU 성능:

OpenGL ES 관련 확장:
GL_OVR_multiview: gl_ViewID_OVR의 사용을 gl_position 계산으로 제한합니다.
GL_OVR_multiview2: gl_ViewID_OVR 사용에는 제한이 없으며 gl_ViewID_OVR은 조각 및 버텍스 셰이더 단계에서 사용할 수 있습니다.
OVR_multiview_multisampled_render_to_texture: EXT 멀티샘플링 렌더링의 멀티뷰 버전입니다.
다중 뷰를 지원하는 버텍스 셰이더:

애플리케이션에서 다중 보기 사용:

UE4의 머티리얼 컴파일 및 렌더링 프로세스는 다음과 같습니다:

드라이버 지원 환경: 여러 GPU 공급업체, 모든 공급업체의 초기 구현에 있는 많은 드라이버 버그, 드라이버 업데이트와 최종 사용자 장치의 가용성 사이의 긴 지연, 드라이버 버그로 인해 응용 프로그램이 중단되지 않도록 장치에 알려진 문제가 있는 경우 응용 프로그램 초기화 중에 셰이더에서 멀티뷰 코드가 제거됩니다. 예를 들어 Samsung Galaxy S6, Samsung Galaxy S7 Mali(Android M 및 N), S7 Adreno(Android N)가 있습니다.
현재 개발 작업 흐름:

포비티드 렌더링은 4개 보기의 다중 보기입니다.

포비티드 포인트 렌더링에 4뷰 멀티뷰를 사용하면 2뷰에 비해 작업 부하를 65% 줄일 수 있습니다.

결과 비교:

Mali Graphics Debugger(MGD)를 사용하면 상세하고 심층적인 멀티뷰 및 VR 렌더링 디버깅을 수행할 수 있습니다.

Shading of 'Spellsouls': Achieving AAA Quality on Mobile에서는 PBR, 특수 효과, 스키닝, 최적화 등을 포함하여 모바일 단말기에서 AAA 수준의 렌더링 품질을 달성하는 방법을 공유합니다. PBR은 사실적인 모양, 다양한 조명 조건을 가지고 있지만 표준 GGX 방법은 비싸고 표준화된 Blinn-Phong입니다. 여기서 정규화된 Blinn-Phong은 다음과 같이 계산됩니다.

선형 색 공간은 PBR의 요구 사항이지만 2018년에는 모바일 장치의 50%만이 이를 지원했습니다. 조명 측면에서 4개의 점 광원이 지원된다고 가정하면 조명별 계산을 사용해야 할까요, 아니면 Forward+를 사용해야 할까요? Forward+는 이미 컴퓨팅 셰이더를 통해 Spotty에서 지원되지만 GPU 제한이 있습니다. 최적화하는 방법? 깊이 프리패스를 제거하고, CPU를 사용하여 광원을 제거하고, 64x64 픽셀 타일을 사용하고, 구로 광원 영역을 근사화합니다.

경계원은 원근감이 강하지 않을 때 사용할 수 있습니다. 투영에서는 카메라가 직각이라고 가정하고 안전 반경을 늘립니다. 투영이 강하면 AABB로 투영하세요.

그림자의 경우 움직이는 물체에는 동적 그림자가 사용되고 환경에는 정적 그림자가 사용됩니다. 동적 그림자는 동적 그림자 맵을 사용하고, 하드웨어 4샘플 PCF를 사용하며, 정적 그림자는 구운 조명 맵을 직접 사용합니다. 지형을 렌더링할 때 라이트맵 색상과 동적 그림자 색상이 결합되어 각 픽셀에 대해 평가됩니다.
color = albedo.rgb * lightmap.rgb;
color = color * lerp(lightColor, shadowColor, lightmap.a * min(NdotL, dynamicShadow);
특수 효과 측면에서 후처리를 제거하고 파티클 시스템은 비용이 많이 들며 스프라이트 아틀라스를 사용하십시오! 스프라이트 아틀라스는 모션 벡터를 사용하여 최적화할 수 있습니다.
동일한 UV 좌표에서 현재 프레임 픽셀과 모션 벡터 값을 읽습니다.
모션 벡터를 사용하여 다음 프레임에서 읽을 UV 좌표를 결정합니다.
현재 픽셀과 다음 프레임 픽셀 사이를 보간합니다.

왼쪽: 스프라이트 아틀라스의 색상; 오른쪽: 스프라이트 아틀라스의 모션 벡터.

스프라이트 아틀라스의 모션 벡터 데이터: R 및 G 채널은 다음 픽셀의 UV를 저장하고 B 채널은 UV의 스케일링 계수를 저장합니다.
스키닝의 경우 CPU 스키닝은 2개의 전체 코어를 차지하며 매 프레임마다 메시를 GPU에 업로드하면 성능에 영향을 미칩니다. GPU 스키닝, GPU 없는 메시 업로드를 시도할 수 있으며 인스턴스화를 지원하며 빠릅니다. **TRS(텍스처 기반 매트릭스 팔레트)**GPU 스키닝을 사용할 수도 있습니다. 정기적으로 뼈대 TRS 샘플을 수집하고 뼈대 TRS를 텍스처로 굽습니다. 3x4 부동 소수점에는 3개의 텍스처가 필요하며 각 인스턴스 데이터에는 1개의 부동 소수점과 U 좌표가 있습니다.

TRS GPU 스키닝의 보간 프로세스: 두 개의 키 프레임을 읽고, 행렬을 재구성하고, 보간합니다. 이러한 각 뼈는 6개의 텍스처 읽기에 영향을 미칩니다!

해결해야 할 문제: 6개의 텍스처 읽기, 3개의 텍스처, 보간 수학. 듀얼 쿼터니언, 2개의 텍스처(세 번째 크기 조정 텍스처는 선택 사항), 이중선형 필터링을 사용하고 낮은 샘플링 속도(15FPS)에서도 좋아 보이는 텍스처 기반 듀얼 쿼터니언 GPU 스키닝을 사용하여 최적화할 수 있습니다. 그러나 혼합 애니메이션을 구현하려면 텍스처 읽기를 두 배로 늘려야 합니다.
프레임 속도, 발열, 배터리 수명 및 기타 측면에 최적화되었습니다. 셰이더 명령의 경우 고정 정밀도가 사용되지 않습니다. 정밀도 간 변환 시 주의하고 명령어 개수(No-ops)에 주의하세요.
// 250개
float4x4 sum = (boneMatrices[index0] * weight0) + (boneMatrices[index1] * weight1);
// 180개 ,28%。
float4x4 matrix0 = boneMatrices[index0];
float4x4 matrix1 = boneMatrices[index1];
float4x4 sum = (matrix0 * weight0) + (matrix1 * weight1);열 조절:
장치가 안정적인 상태(25FPS)에 들어갈 때까지 기다립니다.
목표 프레임 속도를 결정합니다(이 경우 30FPS).
FPS가 목표(40FPS)보다 30% 높도록 그래픽 품질을 설정합니다.
프레임 속도를 -30FPS로 제한합니다.

열 보호의 이점: 장치의 모든 컴퓨팅 리소스를 사용하지 않고 GPU 결정 품질 설정을 기반으로 프레임 시간 피크를 상각합니다.
성능 추적: 평균 FPS, 배터리 소모, 발열과 관련된 배터리 소모를 분석하고 추적합니다.
모바일 게임 개발에서는 모바일 게임을 개발하는 이유, 방법, 단계, 엔진 등 모바일 게임 개발의 일부 기술을 설명합니다. 2020년 모바일 시장 점유율은 미화 770억 달러에 달했으며, 새로운 왕관의 안개에도 불구하고 여전히 추세를 거스르고 전년 대비 13.3% 성장했습니다.

게임 개발 프로세스의 다학제적 특성은 오디오, 시각 예술, 애니메이션, 제어 시스템, 인공 지능(AI) 및 인적 요소를 결합하여 소프트웨어 게임 개발 방식을 기존 소프트웨어 개발과 다르게 만듭니다. 게임 개발 및 설계에 사용되는 다양한 방법 중에서 애자일 방법은 현재 디지털 게임 개발 관리를 위해 가장 널리 사용되고 일반적으로 사용되는 소프트웨어 엔지니어링 프레임워크입니다. 이 개발 방법은 반복 및 증분 방법을 기반으로 합니다. 생산 단계는 가장 중요한 기능에 초점을 맞춰 여러 개의 작은 반복으로 나누어집니다. 모바일 게임 개발의 주요 단계는 프리프로덕션, 프로덕션, 포스트프로덕션입니다.

모바일 게임 개발에 적합한 엔진으로는 Unreal Engine, Unity, Monogame, Solar2D, Titanium, Amazon Lumberyard, Cocos2d-x, Haxe, Gideros, Godot, CRYENGINE, Phaser, Defold, Starling 등이 있습니다.
Roblox 최적화: 모바일 개발자를 위한 Vulkan 모범 사례에서는 로드/저장 작업, 서브패스, 파이프라인 장벽, MSAA, Roblox CPU 최적화, 명령 버퍼 관리, 렌더링 채널, 파이프라인 상태, 설명자 관리 등을 포함하여 Vulkan을 사용하여 Roblox 게임을 최적화하는 기술을 설명합니다. 다음은 즉시 모드와 블록 모드의 GPU 아키텍처 비교 차트입니다.


Vulkan의 RenderPass와 Subpass의 관계는 다음과 같습니다.

다중 패스 디퍼드 렌더링을 구현하기 위해 Vulkan을 사용하는 예는 다음과 같습니다.

Subpass를 활용하면 추가 메모리 읽기 및 쓰기를 크게 줄일 수 있습니다.

장벽 종속성 마커를 사용하면 셰이더 단계 간의 중첩을 늘려 대기 시간을 줄일 수 있습니다.

이렇게 하면 프레임 시간이 56% 단축됩니다.

타일(아래 그림 왼쪽) 내에서 MSAA 데이터를 구문 분석하면 메모리 읽기 및 쓰기가 크게 줄어들 수 있습니다(각각 261% 및 440% 감소!!).

그리기 호출 최적화: 공통 렌더링 인터페이스에 Vulkan을 구현하면 합리적인 노력으로 최대 성능을 어떻게 얻을 수 있습니까? 안정된 상태의 성능에 집중하고 쉽게 캐시할 수 있는 모든 것을 캐시하세요. 일반 프레임 구조를 사용하고, 그리기 호출을 최소화하고, 사용 용이성과 성능 사이의 절충안을 찾고, 구현을 최대한 최적화하고, 스레드 친화적인 구현을 수행하고, 각 스레드가 독립적으로 그리기 호출을 기록하도록 허용합니다.
// 1. Command buffer management
DeviceContext* ctx = device->createCommandBuffer();
PassClear passClear;
passClear.mask = Framebuffer::Mask_Color0;
// 2. Render passes
ctx‐>beginPass(fb, 0, Framebuffer::Mask_Color0, &passClear);
// 3. Pipeline state
ctx‐>bindProgram(program.get());
// 4. Descriptor management
ctx‐>bindBuffer(0, globalDataBuffer.get());
ctx‐>bindBufferData(1, ¶ms, sizeof(params));
ctx‐>bindTexture(0, lightMap, SamplerState::Filter_Linear);
// 5. General optimizations
ctx‐>draw(geometry, Geometry::Primitive_Triangles, 0, count);
ctx‐>endPass();
device->commitCommandBuffer(ctx);명령 버퍼 관리: 간단해 보이지만... createCommandBuffer() => vkAllocateCommandBuffers, commitCommandBuffer() => vkQueueSubmit... 실제로는 매우 복잡합니다. 각 스레드에는 할당을 위해 별도의 VkCommandPool이 필요하며, VkCommandPool에서 할당된 명령 버퍼가 실행 중이면 VkCommandPool을 사용할 수 없으며, vkAllocateCommandBuffers는 무료가 아니며, vkFreeCommandBuffers는 명령 메모리를 항상 회수하지 않으며, vkQueueSubmit은 비용이 많이 들 수 있습니다. 명령 풀: createCommandBuffer()는 중요 섹션에서 VkCommandPool을 훔치거나 생성합니다. 명령 버퍼를 해제하지 않고 할당된 명령 버퍼를 재사용합니다. 일괄 명령 버퍼 제출, commitCommandBuffer()는 명령 버퍼를 프레임 목록에 추가하고 submitCount=1을 사용하여 프레임 끝에 vkQueueSubmit 풀을 반환합니다. 명령 풀 재활용: 프레임을 기록한 후 보류 중인 명령 버퍼가 있는 모든 풀을 전역 풀에서 제거합니다. 프레임이 완료된 후 모든 풀을 다시 전역 풀에 넣습니다. 할당된 모든 명령 버퍼를 자동으로 재설정하고 준비 상태로 전환하는 vkResetCommandPool을 실행하는 것을 잊지 마세요.
일반 최적화: 드라이버는 일반적인 GL 드라이버보다 훨씬 가벼워서 이전에는 사소하거나 눈에 띄지 않았던 것들을 드러냅니다! 필요한 경우가 아니면 vk* 함수를 호출하지 말고, 쉽게 캐시할 수 있는 모든 콘텐츠를 캐시하고, 중복된 상태 바인딩을 필터링하세요. 캐시 누락을 적극적으로 제거하고 추상화에서 할당 및 간접을 줄입니다. 모든 기하학 상태에 대해 OpenGL VAO 구조체와 유사한 GeometryVulkan을 사용합니다. 대부분의 함수는 vkGetDeviceProcAddr에서 얻은 포인터를 통해 호출됩니다. volk 로더는 우리를 위해 이 작업을 수행하며 일부 성능 향상을 얻을 수 있습니다.
결과: 모든 공급업체에서 GLE에 비해 CPU 성능이 2~3배 향상되었으며, 실제 콘텐츠와 함께 프레임을 엔드 투 엔드로 렌더링했습니다. 모바일 테스트 수준, 840 그리기 호출, 단일 코어, 2.4GHz Cortex-A73, Mali-G72, GLES는 38ms가 걸렸고, Vulkan 단일 코어: 13ms, 우수한 멀티 코어 확장 기능! 큰 코어와 작은 코어에 주의하세요.
14.5.3.4 병렬 기술
컴퓨터 하드웨어는 점점 더 병렬화되고 있습니다. 동시성을 활용하려면 동시성을 이해해야 합니다. 동시 프로그래밍을 이해하려면 하드웨어와 커널을 이해해야 합니다! 병렬성 및 동시 프로그래밍에서는 최신 병렬 컴퓨팅 하드웨어, 동시 프로그래밍 기술 및 이를 적용하여 고성능 게임 엔진을 구축하는 방법에 대해 자세히 소개합니다.
동시성은 공유 데이터의 다중 읽기 및/또는 쓰기를 통해 프로세스, 스레드, 파이버 등을 공유하는 다중 제어 흐름에 의한 공유 데이터 파일의 변환으로 정의될 수 있습니다. 데이터 "파일"은 무엇이든 될 수 있습니다. 스레드 간에 공유되는 전역 부울 변수, 공유 대기열, 데이터 파일은 멀티 스레드 프로세스의 가상 메모리 공간, 컴퓨터 내의 가상 메모리 페이지를 공유하는 여러 프로세스, 물리적 RAM을 공유하는 GPU 및 CPU, 두 프로세스 간의 파이프라인, 여러 컴퓨터에서 액세스할 수 있는 네트워크 드라이브에 존재하는 파일 등 어디에나 저장할 수 있습니다. 데이터가 공유되지 않으면 동시성이 아니며 단지 "동시" 계산일 뿐입니다.


동시성은 공유 데이터에서 실행되는 여러 제어 흐름을 의미합니다. 병렬성은 여러 하드웨어 구성 요소가 동시에 실행되는 것을 의미합니다. 싱글코어 CPU에서도 선점형 멀티태스킹 등 동시성이 가능하다. 마찬가지로 병렬 하드웨어는 암시적 병렬성(파이프라인 또는 수퍼스칼라 CPU 아키텍처)을 통해 단일 스레드 코드의 성능도 향상시킬 수 있습니다.
병렬성은 암시적 병렬성과 명시적 병렬성으로 나누어진다. 현재 하드웨어 아키텍처는 기본적으로 명시적 병렬성입니다. 명시적 병렬 처리는 병렬 컴퓨팅 하드웨어의 존재를 프로그래머 및/또는 컴파일러에게 노출시킵니다. 2002년부터 멀티프로세서 컴퓨터, 멀티코어 CPU, x86(SSE)의 SIMD 벡터 처리 장치, 멀티코어 GPU(SIMT)를 비롯한 가전제품에 사용된 명시적 병렬 처리는 동시성을 지원합니다.
명령어 세트 아키텍처(ISA): 각 CPU는 서로 다른 ISA를 제공합니다. ISA 정의: CPU가 인식하는 일련의 opcode, 레지스터의 수와 이름, CPU가 지원하는 주소 지정 모드, 공개된 하드웨어의 일부 세부 정보: CPU에 FPU가 포함되어 있습니까? VPU? I/O는 어떻게 이루어지나요? 메모리 매핑? 등록 기반? 클록당 여러 명령을 내릴 수 있나요? (VLIW) 특권 모드가 지원됩니까? 보호링은 몇개인가요? CPU의 실행 컨텍스트는 다음과 같습니다.


메모리 캐시 계층 구조는 시간적, 공간적 지역성을 활용하여 평균 메모리 액세스 대기 시간을 줄입니다. 시간적 지역성: 데이터는 짧은 시간 내에 반복적으로 액세스되는 경우가 많습니다. 프로그램이 주소 x에 액세스하면 가까운 시일 내에 주소 x에 다시 액세스할 가능성이 높습니다. 공간적 집약성: 데이터는 순차적으로 또는 블록 단위로 액세스되는 경우가 많으며, 프로그램이 주소 x에 액세스하면 주소 x+n(더 작은 |n|의 경우)에도 액세스할 가능성이 매우 높습니다.

캐시는 주 메모리를 라인으로 나누어 작동하며 일반적인 캐시 라인은 64바이트 또는 128바이트입니다. 메인 RAM의 행을 캐시로 읽을 수 있으며 캐시에 있으면 CPU가 데이터에 더 빠르게 액세스할 수 있습니다.

캐시에 라인이 있으면 그 라인이 어떤 메모리 라인에서 왔는지 어떻게 알 수 있나요? 태그는 라인 인덱스(64바이트 캐시: 주소 & 0x3F, 128바이트 캐시: 주소 & 0x7F)와 태그(64바이트 캐시: 주소 >> 6, 128바이트 캐시: 주소 >> 7)를 기반으로 각 캐시 라인에 저장되어 메모리 내 원래 위치를 추적할 수 있습니다(아래 이미지).

CPU가 행 인덱스의 주소로 변환된 데이터 항목(1바이트 이상)을 읽을 때 메모리 컨트롤러는 L1 캐시를 확인합니다. 캐시에 이미 행이 포함되어 있습니까? 적중이면 해당 행에서 데이터를 가져오고, 실패하면 다음 레벨 캐시(L2)에서 가져옵니다. 플러시하고 주 메모리에 도달할 때까지 반복합니다. 멀티 코어 시스템에서는 동일한 레벨의 다른 코어에서도 읽기 요청을 완료할 수 있습니다.
CPU가 행 인덱스의 주소로 변환된 데이터 항목(1바이트 이상)을 쓸 때 메모리 컨트롤러는 L1 캐시를 확인합니다. 캐시에 이미 행이 포함되어 있습니까? 적중되면 해당 항목을 행에 기록하고 해당 행을 수정된 것으로 표시합니다(멀티 코어 시스템에서는 이 작업이 더 복잡해집니다...). 누락된 부분이 있는 경우 라인은 L2, L3... 메인 메모리에서 가져와 수정된 것으로 기록되고 표시되며, 기록된 캐시 라인이 반드시 메인 RAM에 즉시 다시 기록되는 것은 아닙니다. 연속 쓰기 작업은 다음에 캐시 라인을 읽거나 무효화할 때 쓰기 저장을 트리거하여 캐시를 우회할 수 있습니다.
위에서 설명한 것은 메모리의 각 라인이 충돌할 수 있는 캐시의 라인(예: 주소 0x80, 0x100 및 0x180)에 매핑되는 직접 매핑 캐시입니다. 완전 연관 캐시는 메모리의 모든 라인을 캐시의 어느 곳에나 배치할 수 있으며 캐시에서 라인을 찾으려면 태그의 선형 검색이 필요합니다. n방향 집합 연관 캐시는 메모리의 각 라인을 캐시의 n개 라인에 매핑하여 두 가지 장점을 모두 제공합니다. 즉, 라인 충돌을 n배로 줄이고 검색을 제한합니다(전체 캐시가 아닌 경로만 검색함). 예를 들어 양방향 세트 연관 캐시를 사용하면 메모리의 각 행이 캐시의 두 행에 매핑됩니다.

캐시가 가득 차면 어떻게 되나요? 공간을 확보하려면 이전 데이터를 삭제해야 하며, 캐시 라인 교체 전략: 선입선출(직접 매핑된 캐시에서만 옵션), NMRU(최근 사용되지 않음): 그룹당 1비트, LRU(최근에 사용되지 않음): n>2일 때 더 비쌈, LFU(가장 덜 자주 사용됨), 의사 무작위.
그렇다면 왜 캐싱에 관심을 가져야 할까요? 캐싱은 과도한 캐시 누락을 방지하기 위해 데이터를 구조화하고, 비희소 배열에 데이터를 패킹하고, 메모리 점프를 방지하는 최적화 도구라는 점을 이해하십시오.
이 기사에서는 커널, 프로세스, 스레드, 가상 메모리 등의 개념도 자세히 소개합니다. 가상 메모리가 각 프로세스가 가지고 있는 메모리의 개인 "뷰"인 경우 사용자 공간 프로그램은 가상 주소를 기반으로 모든 메모리 액세스를 수행하고 CPU와 커널은 런타임에 가상 주소를 물리적 주소에 매핑하기 위해 함께 작동합니다.


스레드와 프로세스 간의 관계:

스레드 스케줄링의 여러 상태:

스레드 컨텍스트 전환:


프로세스 컨텍스트 전환:


초기 CPU는 한 번에 한 명령씩 직렬로 실행되었습니다. CPU 내부의 구성요소들은 잘 분리되지 않았고, 명령이 실행될 때 많은 구성요소들이 유휴 상태였습니다. 최신 CPU는 파이프라인을 통해 각 명령이 잘 정의된 단계를 거치며 각 단계는 CPU 코어의 구성 요소에 해당합니다. 구성 요소 간의 명확한 구분은 코어의 서로 다른 구성 요소를 사용하여 여러 명령을 동시에 "실행"할 수 있도록 하여 모든 구성 요소를 바쁘게 유지합니다.
다양한 CPU는 4~5단계, 딥 파이프라인 CPU의 경우 최대 30단계까지 단계를 다르게 정의합니다. 기본 단계:
가져오기: 메모리에서 명령어(F)를 가져옵니다.
디코드: 명령어를 opcode 및 피연산자로 디코드합니다(D).
레지스터: 레지스터 액세스(R), D와 R이 결합(D/R)된다고 가정합니다.
실행: ALU에서 명령어(E)를 실행합니다.
메모리: 메모리 읽기/쓰기(M).
레지스터 쓰기 저장(Register Writeback): 결과를 레지스터(W)에 저장하는 등의 레지스터 쓰기 저장입니다.
각 단계를 바쁘게 유지하기 위해 각 시계마다 새로운 명령이 발행됩니다.

파이프라이닝은 ILP(명령어 수준 병렬 처리)의 한 형태이며 성능은 처리량(단위 시간당 무효화된 명령 수)과 대기 시간(명령어를 무효화하는 데 걸리는 시간)을 통해 측정됩니다.

지연은 모든 단계가 바쁜 상태로 남아 있지 않은 상황, 즉 일부 종속성으로 인해 다음 명령을 실행할 수 없는 상황으로 정의됩니다. CPU 파이프라인에는 세 가지 종속성이 있습니다.
데이터 종속성: 한 명령어에서 사용된 레지스터가 다음 명령어에서 다시 사용됩니다.
분기 종속성: 명령어의 작동은 이전 명령어(예: BZ)의 결과에 따라 달라집니다.
리소스 종속성: 특정 유형의 명령어는 특정 하드웨어(예: 정수 ALU)에서만 실행될 수 있습니다.
종속성은 명령 스트림의 속성이며 종속성은 CPU 파이프라인(일시 중지)에 해를 끼칠 수 있습니다.
데이터 의존성은 데이터 위험을 초래합니다. 이 명령을 발행하려면 이전 명령의 결과가 필요합니다.
분기 종속성은 제어 위험으로 이어집니다. 조건식의 결과가 알려지기 전에 분기를 예측해야 합니다.
구조적 위험을 유발하는 리소스 종속성: 문제를 해결하고 싶었지만(예: 정수 추가) ALU가 사용 중이었습니다.

데이터 위험의 예.

OOO 실행을 통해 CPU는 명령어 A, B, C, D(추가 전에 수행됨)를 재정렬하여 추가 명령어와 mul 명령어 사이에 있도록 합니다.
숨겨진 메모리 대기 시간: 메모리 대기 시간으로 인해 정지가 발생할 수도 있습니다. mov r3, [r1+8]은 4, 40 또는 400주기가 걸릴 수 있습니다! (L1, L2, 메인 RAM). OOO 실행은 또한 메모리 컨트롤러가 응답할 때까지 기다리는 동안 지연 슬롯에서 다른 독립적인 명령을 실행하여 메모리 지연을 숨기는 데 도움이 됩니다. 멀티스레딩은 한 스레드가 메모리를 기다리는 동안 다른 스레드가 CPU 코어를 사용하도록 예약하여 메모리 대기 시간을 숨기는 또 다른 방법입니다.
조건부 분기 명령이 발생하면 CPU는 무엇을 해야 합니까? 문제가 언제 발생하는지 아직 알 수 없는 상황으로 인해 파이프라인 깊이가 10+ 수준에 도달할 수 있으므로 조건부 분기에서는 10+ 사이클 지연이 발생합니다. 이를 분기 페널티, 컨트롤 페널티라고 하며 원시 데이터 페널티의 특별한 경우입니다.

가지 손상 문제에 대한 해결책:
- 소프트웨어:
테스트 수가 적을 경우 실행 길이를 늘리기 위해 루프 풀기.
"분기"를 최소화하기 위해 코드를 재정렬합니다.
하드웨어:
지연 슬롯. 스톨(OOO 실행) 중에 실행할 명령을 선택합니다.
- 두 가지 중 하나를 선택하고 예측 가능하게 실행합니다. 예측이 정확하면 지연이 발생하지 않습니다. 예측이 잘못된 경우 파이프라인을 플러시하고 중간 결과를 반환한 후 올바른 분기에서 다시 시작하세요.
CPU는 어떻게 추측해야 할까요? 간단한 아이디어: 역방향 분기는 항상 실행되고 순방향 분기는 절대 실행되지 않는다고 가정합니다. for 루프의 매우 일반적인 패턴:
for (i = 0; i < count; ++i)
{
// do work...
if (special_case)
break;
// forward branch (rare)
} // backward branch (common)또 다른 아이디어는 if 문에 대한 사람의 라벨링에 의존하는 것입니다.
for (i = 0; i < count; ++i)
{
// do work...
if (UNLIKELY(special_case))
break;
}
// gcc definitions:
#define LIKELY(x) __builtin_expect((x), 1)
#define UNLIKELY(x) __builtin_expect((x), 0)또 다른 아이디어는 CPU 칩에 분기 예측 논리를 포함하여 어떤 분기가 수행되었는지 기록하는 것입니다. 논리는 매우 복잡해질 수 있으며 일부 CPU는 Y, N, Y, N, Y, N 등과 같은 패턴을 감지할 수 있습니다. 트랜지스터 수와 회로 복잡성이 크게 증가하므로 추측 실행을 위해서는 계산 결과를 임시로 저장해야 합니다.
또 하나의 아이디어: 전혀 분기하지 마세요! 대신 분기의 양쪽이 항상 실행되지만 각 명령어에는 이와 관련된 조건(예측)이 표시됩니다. 조건(예측)이 참일 때 CPU는 실제로 조건자 명령어의 결과를 커밋합니다. 이 접근 방식을 예측이라고 합니다. 더 간단한 형태: 부분 예측, 조건부 이동, 조건부 선택 지침.
PowerPC의 fsel 및 isel 명령어와 같은 조건 선택: isel RR, RA, RB, predicate_code, 예측 비트가 1이면 RA -> RR로 이동하고 예측 비트가 0이면 RB -> RR로 이동합니다.

전체 예측은 아래와 같습니다.

수퍼스칼라:

파이프라인 CPU와 슈퍼스칼라 CPU의 비교는 다음과 같습니다.


1966년 스탠포드 대학의 Michael J. Flynn이 제안한 플린의 분류법은 병렬성을 명령 수준 병렬성(ILP)과 데이터 수준 병렬성(DLP)으로 나눕니다.
단일 명령어 단일 데이터(SISD).
MIMD(다중 명령어 다중 데이터).
SIMD(단일 명령어 다중 데이터).
MISD(다중 명령 단일 데이터).
GPU용 SIMT(단일 명령어 멀티스레딩).

직렬, 하이퍼스레딩 및 멀티코어 CPU의 아키텍처 비교는 다음과 같습니다.

GPU 아키텍처는 SIMD와 MIMD의 하이브리드입니다. SIMD 코어는 단일 명령 스트림(스레드)을 여러 데이터 "채널"에 병렬로 적용합니다. 대기 시간을 숨기기 위해 많은 스레드가 시간 분할을 통해 SIMD 코어를 공유합니다. Nvidia는 이를 SIMT(Single Instruction Multithreading)라고 부릅니다.
또한 컴퓨터 클러스터: 여러 개의 동종 컴퓨터가 근처에 랙에 장착되어 있으며 빠른 로컬 네트워크로 연결되어 있습니다. 그리드 컴퓨팅: 느슨하게 결합된 이기종 컴퓨터(예: SETI@home). 클라우드 컴퓨팅: 주문형 컴퓨팅 및 스토리지, SaaS(Software as a Service), 유연하고 확장 가능하며 비용 효율적이며 필요한 것만 사용하고 사용한 만큼 지불합니다.
동시 프로그래밍은 순차 프로그래밍보다 훨씬 어렵습니다. 순차 프로그램에서 잘 작동하는 많은 가정, 기술 및 데이터 구조가 동시 상황에서는 무너집니다. 새로운 종류의 버그: 새로운 문제, 새로운 제한 사항. 데이터 중심의 사고방식이 필요하며, 대상 하드웨어에 대한 이해가 필요합니다. 동시에 데이터 액세스는 동시성 문제이며 이 문제를 해결하려면 새로운 기술이 필요합니다!
경쟁 조건은 소프트웨어(또는 하드웨어) 시스템의 동작이 이벤트의 순서나 타이밍에 따라 달라지는 상황입니다. 모든 경쟁 조건이 부정적인 영향을 미치는 것은 아닙니다. 예를 들어 단일 프레임 내에서 무기 레이캐스트가 처리되는 순서는 중요하지 않습니다. 심각한 경쟁 조건은 잘못된 동작을 유발하는 조건입니다. 데이터 경합은 특정 경합 조건입니다. 공유 데이터에서 실행되는 두 개 이상의 명령 스트림(스레드)은 특정 시간에 따라 공유 데이터 읽기 또는 쓰기 결과가 일치하지 않게 됩니다. 데이터 경쟁은 동시성 문제입니다!
세분화된 데이터 경합: 증분 경합은 멀티 코어 시스템에서 진정한 병렬 처리로 발생할 수 있지만 그 이유는 약간 다릅니다. 이제 동일한 명령이 두 개 이상의 스레드에서 동시에 실행될 수 있으며 명령을 실행하는 데 여러 클록 사이클이 필요하므로 명령 간의 중첩이 완전하거나 부분적일 수 있습니다.

대략적인 데이터 경합: 공유 디스크 파일 읽기/쓰기 여러 프로세스 간에 데이터 경합이 발생할 수도 있습니다. 읽기 1회, 쓰기 1회, 쓰기 다중 읽기, 다중 쓰기(예: 두 프로세스가 공유 파일에 32kib 블록을 쓰고, 프로세스 A가 파일을 열고 첫 번째 4kb 블록을 쓰고, 프로세스 B가 파일을 열고 첫 4kb 블록을 쓰고, 그 동안 A가 계속 쓰기 때문에 데이터 손상이 발생합니다!)
점유율 카운터를 늘리는 문제의 핵심은 무엇입니까? 증분 작업은 중간에 중단될 수 있으며, 데이터 경합을 방지하려면 특정 중요한 작업을 원자성(중단 불가능)으로 만드는 방법이 필요합니다. 이러한 기본 요소를 사용하는 것을 잠금 기반 프로그래밍이라고 하며 이는 안정적이지만 비용이 많이 듭니다(뮤텍스에는 커널 호출이 포함됨). 또한 제대로 작동하기가 훨씬 어렵고 잠금 기반 접근 방식보다 더 나은 성능과 내결함성을 갖춘 잠금 없는 알고리즘을 작성하는 것도 가능합니다.
이 기사에서는 원자성, 뮤텍스, 임계 섹션, 세마포어, 범위 잠금, 조건 변수 및 스레드 안전 기능과 같은 기술도 다룹니다. 스레드로부터 안전한 함수는 원자 연산의 환상을 제공하기 위해 내부적으로 뮤텍스를 잠그는 함수입니다. 편리하기는 하지만 프로그래머가 오랫동안 잠금을 유지하는 경향이 있을 수 있습니다. 이러한 함수는 재진입이 불가능합니다. a()가 b()를 호출하고 c()를 호출합니다... a()가 이미 잠금을 보유하고 있기 때문에 a()를 호출하면 교착 상태가 발생합니다! 스레드로부터 안전한 기능의 문제를 완화하기 위한 아이디어: 가능한 한 "잠금 없음"에 가까워지는 것을 목표로 가능한 가장 짧은 시간 동안 잠금을 유지합니다.
// 의 코드
void NotGreat(args)
{
g_mutex.lock();
// do huge amount of work...
g_mutex.unlock();
}
// 의 코드
void Better(args)
{
g_mutex.lock();
WorkItem workItem(args);
g_workQueue.enqueue(workItem);
g_mutex.unlock();
}
void ProcessWorkItems()
{
for (workItem : g_workQueue)
// do huge amount of work...
}작업을 원자적으로 수행해야 하는 경우 안전하지 않은 버전을 작성하고 재진입 호출을 지원하거나 재진입 잠금을 사용하는 안전한 버전에서 호출하세요.
// 의 함수 ()
void DoWorkNoLock()
{
if (conditionA)
return;
for (auto x : collection)
{
if (!IsValid(x))
return;
DoStuff(x);
}
}
// 의 함수 ()
void DoWork()
{
g_mutex.lock();
// 호출(Call)의 함수
DoWorkNoLock();
g_mutex.unlock();
}또한 이 기사에서는 로드 링크/저장 조건, LL/SC 및 캐시 라인, 장벽, 메모리 장벽, 원자 변수, 메모리 순서, 스핀 잠금(Spin Lock), 읽기/쓰기 잠금(Reader/Writer Lock), 재진입 잠금(Reentrant Lock) 및 기타 기술도 다룹니다.
잠금 기반 동시성은 공유 메모리 시스템에서 스레드를 동기화하는 가장 간단하고 안정적인 방법입니다. 그러나 단일 스레드 프로그램에서는 발생하지 않는 문제(lock-free 또는 wait-free 알고리즘을 사용하여 피할 수도 있음)인 교착 상태, 라이브 잠금, 기아 상태, 우선 순위 반전 등의 문제가 발생하기 쉽습니다.
식사하는 철학자 문제도 있습니다. 다섯 명의 철학자가 테이블 주위에 앉아 있습니다. 테이블 위에는 각 철학자 사이에 하나씩 총 5개의 포크가 있습니다. 각 철학자는 생각하거나 먹는 두 가지 상태 중 하나에 있을 수 있습니다. 식사 상태에 들어가기 위해 철학자는 양 손에 하나씩, 두 개의 포크를 획득해야 합니다. 음식이 나오면 포크 중 하나를 잡을 수 있습니다. 식사 상태를 떠날 때 그는 두 포크를 모두 내려 놓습니다. 철학자들은 결코 서로 이야기하지 않습니다. 문제 설명: 모든 철학자가 배고프지 않고 무한히 생각하고 먹을 수 있도록 하는 행동 패턴(병렬 알고리즘)을 설계합니다. 순진한 해결책: 항상 왼쪽 포크를 먼저 잡은 다음 오른쪽 포크를 잡고, 모든 철학자가 동시에 왼쪽 포크를 잡으면... 누구도 오른쪽 포크를 잡을 수 없습니다! 교착 상태라는 상황이 발생합니다.


연결된 그래프를 그려서 교착상태를 설명할 수 있습니다. 노드는 스레드(

리소스 그래프 및 대기 그래프.
Livelock은 스레드가 로컬 처리를 얻을 수 있지만 전역 처리를 얻을 수 없는 상황입니다. 다중 스레드 프로그램에서는 스레드가 물러났다가 다시 시도하여 교착 상태를 피하려고 할 때 발생합니다. 예를 들어 스레드가 모두 종료된 다음 동일한 시간 후에 다시 시도합니다. 즉, 시스템 상태는 개선될 수 있지만 어떤 스레드도 실제 작업을 수행할 수 없으며 스레드는 리소스를 잠그고 다시 시도하는 데 모든 시간을 소비합니다.

라이브록 예시.
교착 상태 문제를 해결하려면 항상 다음 네 가지 필요 충분 조건 중 하나 이상을 제거해야 합니다.
상호 배제를 제거합니다. 예를 들어 각 스레드에 자체 리소스를 제공합니다.
대기를 취소합니다. 예를 들어, 잠금 없는 알고리즘과 같이 한 번에 두 개 이상의 잠금을 보유하지 마십시오.
잠금 선점을 허용합니다. 예를 들어, 커널 또는 감독자 스레드는 교착 상태를 감지하고 잠금을 선점하여 스레드가 다시 시도하도록 강제하여 "실패를 수정"할 수 있습니다.
루프 대기를 제거했습니다. 예를 들어 전역 순서/리소스 우선순위를 설정합니다.
우선순위 반전: 우선순위가 낮은 스레드 L이 리소스 A에 대한 잠금을 획득했지만 리소스 B를 기다리는 동안 절전 모드로 전환되면 어떻게 되나요? 우선순위가 높은 스레드 H는 리소스 A에 대한 잠금을 얻을 수 없으므로 스레드 L의 우선순위는 스레드 H의 우선순위보다 높은 것으로 나타나며 우선순위는 반대가 됩니다. 중간 우선순위 스레드 M이 리소스 a에 대한 잠금을 유지하는 동안 스레드 L을 선점하는 경우 우선순위 반전이 발생할 수도 있습니다. 스레드 L은 리소스 A를 잠그고 스레드 M은 스레드 L을 선점하여 L을 절전 모드로 전환합니다. 스레드 H는 다시 리소스 a에 대한 잠금을 얻을 수 없습니다.
우선순위 반전으로 인해 발생할 수 있는 결과:
아니요. 스레드 L이 리소스를 빠르게 해제하면 스레드 H가 실행될 수 있으며 반전이 감지되지 않을 수 있습니다.
시스템 속도 저하가 감지되었습니다. 스레드 H가 오랜 기간 동안 리소스에 대한 액세스가 부족하면 시스템이 느리게 나타날 수 있습니다(예: 스레드 H가 사용자 입력에 응답하는 경우).
시스템 오류. 스레드 H는 리소스에 액세스할 수 없어(예: 실시간 기한 누락) 시스템 오류를 일으킬 수 있습니다.
게임 엔진의 동시성은 초보자부터 고급까지 다음과 같은 형태를 취합니다.



노드 그래프는 종속성을 가질 수 있으며 각 종속성은 동기화 지점을 생성합니다. 이는 여러 병렬 작업이 순서대로 동기화되어야 하는 시점입니다. 완료되는 첫 번째 작업은 마지막 작업이 완료될 때까지 기다려야 하며, 각 동기화 지점에서는 시스템 리소스(하드웨어 유휴 시간)가 비효율적으로 사용될 수 있습니다.

게임 객체를 동시에 업데이트하기: 이러한 아이디어를 게임 객체 업데이트에 적용해 보겠습니다. 게임 객체를 동시에 업데이트하려면 어떻게 해야 할까요? 대부분의 게임 엔진은 이 문제를 해결할 수 없습니다. 단일 스레드 방식으로 작성된 레거시 코드이기 때문입니다. 어렵기 때문입니다! 게임 개체는 종종 서로 의존합니다.

게임 개체 종속성을 처리하는 한 가지 방법: 버킷 업데이트.
enum Bucket
{
kBucketVehiclesPlatforms,
kBucketCharacters,
kBucketAttachedobjects,
kBucketCount
};
void UpdateBucket( Bucket bucket)
{
// ...
for (each gameObject in bucket)
gameObject.PreAnimUpdate(dt);
g_animationEngine.CalculateIntermediatePoses(bucket, dt);
for (each gameObject in bucket)
gameObJect.PostAnimUpdate(dt);
g_ragdollSystem.ApplyskeletonsToRagDolls(bucket);
g_physicsEngine.Simulate(bucket, dt) // ragdolls etc.
g_collisionEngine.DetectAndResolveCollisions(bucket, dt);
g_ragdollSystem.ApplyRagDollsToSkeletons(bucket);
g_animationEngine.PinalizePoseAndMatrixPalette(bucket);
for (each gameObject in bucket)
gameObject.FinalUpdate(dt);
// ...
}
void RunGameLoop()
{
while (true)
{
// ...
UpdateBucket(kBucketVehiclesAndPlatforms);
UpdateBucket(kBucketCharacters);
UpdateBucket(kBucketAttachedobiects);
// ...
g_renderingEngine.RenderSceneAndswapBuffers();
}
}
동시 작업에는 항상 대기 시간이 수반되며, 동시에 생각하려면 각 작업을 호출과 응답(완료)으로 나누어야 합니다.

시스템의 처리량 요구 사항은 무엇입니까? 일반적으로 처리량을 위해 대기 시간을 교환하고 대기 시간을 늘리고 클라이언트가 결과를 기다릴 수 있는 경우(대기 시간 증가) 처리량을 늘릴 수 있으며 잠금에 대한 경합이 줄어들고 대기 시간이 줄어들며 동기화 지점이 줄어들고 처리량이 높아집니다.
또한 이 기사에서는 운영 체제 병렬 처리, 잠금 없는 대기열, 비차단 보장, 원자 스냅샷 개체, SIMD 및 GPU 프로그래밍 및 기타 기술을 다룹니다. 동시 프로그래밍에 대한 종합적인 입문서라고 할 수 있다. GPU 프로그래밍 모델: 기하학, 버텍스, 픽셀 셰이더(그래픽용) 작성 또는 컴퓨팅 셰이더(GPGPU) 작성, 대량의 데이터에 대해 상대적으로 간단한 단일 작업을 수행하는 루프가 GPU에 적합한 경우 N 데이터 항목을 반복하고 처리하는 루프를 고려하십시오. 일반적인 작업 흐름: CPU 루프를 작성하고, 테스트하고, 작동하게 만듭니다. 루프 본문을 GPU 커널로 변환합니다. GPU는 하나 이상의 CU 내의 SIMD 장치에서 루프 본문을 N번 병렬로 실행합니다. 프로그래머는 "단일 스레드" 커널을 작성하고 GPU에서 실행을 시작합니다. 단일 스레드 커널은 컴파일러/GPU에 의해 벡터화되므로 CU의 SIMD에서 병렬로 실행될 수 있습니다. 각 "레인"을 스레드라고 하며 SIMD에서 실행되는 스레드 집합을 웨이브프런트라고 합니다.

CPU와 GPU 프로그래밍 모델의 비교.
GCN 웨이브프런트(GCN Wavefront): Radeon GCN의 웨이브프런트는 64스레드(레인) 너비이지만 각 SIMD는 실제로 너비가 16스레드에 불과하다는 것을 알고 있습니다. 무슨 일이야? 답변: 루프 명령 처리! 16레인 SIMD는 클럭 사이클당 하나씩, 16개 스레드로 구성된 4개 그룹을 실행하여 4클럭 사이클에서 64레인으로 구성된 웨이브프론트를 실행합니다.
요약: SIMD 장치는 4, 8 또는 16개 데이터 레인에서 단일 명령 스트림을 병렬로 실행하고 더 많은 레인을 통해 루프할 수 있습니다(예: 16개 스레드로 구성된 4개 그룹, SIMD당 64개 스레드를 통해 루프). 컴퓨팅 유닛(CU)에는 여러 개의 SIMD가 있으며, 각 CU 시간은 정지를 숨기기 위해 여러 스레드 간에 분할되며, 분기에 대한 추측 처리를 사용하여 루핑이 가능하지만 전체 웨이브프론트/워프가 루프되어야 합니다. GPU에는 여러 CU가 있습니다.
전통적으로 CPU의 SIMD 벡터화는 플랫폼별 내장 함수를 사용하여 수행됩니다. Intel ISPC를 사용하면 이런 일은 과거의 일이 됩니다. 업계 표준 LLVM 컴파일러를 기반으로 하는 Intel ISPC는 작성하기 쉬운 벡터 코드 언어입니다. SSE, AVX, AVX-512, ARM NEON 등 다양한 명령어 세트에 대한 고성능 벡터 코드를 생성합니다. 사용이 간단하고 기존 코드 기반과 통합하기 쉬우며 C와 매우 유사하게 보이고 작동합니다.
Unreal Engine 4의 Intel® ISPC: A Peek Behind the Curtain은 Intel ISPC가 이제 Unreal Engine 4에서 구현되는 방법을 설명합니다. Intel이 Epic Games와 협력하여 물리 및 애니메이션 시스템을 최적화하는 방법과 Unreal 개발자가 이를 사용하여 게임을 개선할 수 있는 방법에 대해 알아보세요.
최신 하이엔드 시스템에서도 카오스와 애니메이션에서 최고의 성능을 얻으려면 병렬성을 활용하는 것이 중요합니다. 작업 병렬 처리에는 멀티스레딩, 멀티 코어가 있고 SIMD 병렬 처리에는 SIMD 벡터 명령이 있고 자동 벡터화는 제어하기 어렵습니다. 모든 사람이 벡터 내장 함수를 작성하는 방법을 배우고 있다면 닌자 프로그래머가 아니더라도 모든 오류를 쉽게 해결할 수 있는 것을 만들 시간이 없을 것입니다. 인텔의 ISPC(SPMD 프로그래밍 컴파일러)를 사용하면 이러한 어려운 문제를 해결할 수 있습니다! 아이스레이크U(10세대) 쿼드코어 CPU, 노란색 원은 마법이 일어나는 CPU 실행 유닛을 나타냅니다!

ISPC란 무엇입니까? 인텔 SPMD 프로그래밍 컴파일러(SPMD==단일 프로그램, 다중 데이터 프로그래밍 모델)는 벡터(SIMD) 코드 작성을 위한 컴파일러이자 언어입니다. 많은 SIMD를 위한 LLVM 기반 오픈 소스 언어 및 컴파일러 아키텍처로 SSE/AVX/AVX2/AVX 512/NEON...(실험적)과 같은 많은 벡터 ISA에 대한 고성능 벡터 코드를 생성합니다. 언어는 C와 매우 유사하며 사용하기 쉽고 C 함수 호출을 통해 기존 코드 기반과 쉽게 통합됩니다.
왜 ISPC인가? 기존 C++ 코드를 빠르게 가속화하기 위해 SIMD를 사용하는 내장 기능은 하드웨어 가속 및 명령어 세트별로 이루어지며, AVX를 추가하면 또 다른 순열이 가능해집니다. Unreal은 플랫폼 추상화에서 SSE2의 본질을 사용하고 엔진에 통합되어 Embree Lightmass(정적 조명), ISPC 텍스처 압축기(BC6H/BC7/ASTC)와 같은 다른 엔진과 통합된 성숙한 기술을 통해 Unreal(Win, Mac, Linux, PS4, Xbox, ARM)의 모든 위치에 적합한 엔진에 통합되어 있습니다.
ISPC 프로그래밍 모델: ISPC는 "자동 벡터화" 컴파일러가 아니며 스칼라 루프를 분석하고 변환하여 벡터 코드를 생성하지 않습니다. 이는 WYSIWYG 벡터화 컴파일러와 비슷합니다. 프로그래머는 벡터가 무엇인지, 스칼라가 무엇인지 ISPC에 알려주고, 벡터 유형이 명시적이며, SIMD 벡터와 작업 프로그래밍 모델이 명확하게 분리되어 있으며, 기존 C/C++ 메모리 할당 및 데이터 버퍼에 적합합니다.
ISPC는 C와 매우 비슷해 읽고 이해하기 쉽고, 코드는 순차적으로 보이지만 병렬로 실행되고, 스칼라와 벡터 계산을 쉽게 혼합하며, 명시적 벡터화를 위해 균일하고 가변적인 두 개의 새로운 ISPC 언어 키워드를 사용합니다. 마찬가지로 ISPC는 자동 벡터화 컴파일러가 아닙니다.
export void rgb2grey(uniform int N, uniform float R[], uniform float G[], uniform float B[], uniform float grey[])
{
foreach(i=0 ... N)
{
grey[i] = 0.3f*R[i] + 0.59f*G[i] + 0.11f*B[i];
}
}uniform은 스칼라 데이터에 사용되며 결과는 스칼라 레지스터(eax, ebx, ecx 등)에 있으며 모든 SIMD 스레드는 동일한 값을 공유합니다. Varying은 벡터 데이터에 사용되며 결과는 SIMD 벡터 레지스터(XMM, YMM, ZMM 등)에 있으며 기본값은 Varying이며 각 SIMD 스레드는 고유한 값을 가지며 너비는 대상에 따라 다릅니다.

ISPC에는 내부변수, 제어흐름, 배열, 구조 등의 개념과 키워드가 포함되어 있습니다. 메모리와 성능 측면에서 ISPC는 코드 생성에는 뛰어나지만 코드를 재배열할 수 없고 메모리 액세스 속도를 높일 수 없기 때문에 데이터 레이아웃이 중요하고 데이터가 캐시에 있어야 하며 올바른 레이아웃에 있어야 합니다. 수집/분산 명령은 어려울 수 있습니다. 벡터 로드/저장, Mike Acton, 데이터 지향 설계 및 C++를 생성하는 SoA 또는 AoSoA 메모리 레이아웃을 선호합니다.
ISPC는 논리 연산자, 비트 연산, 수학, 클램핑 및 포화 알고리즘, 초월 연산, RNG(가장 빠르지는 않음!), 마스킹/크로스 스레드 연산, 축소 등 다양한 운영 표준 세트를 제공합니다. ISPC는 포인터 및 메모리 할당, SoA 도우미 함수에 대한 AoS, C++와 유사한 참조, 구조(+, --, *, /, <<,>>)에 대한 이진 연산자 오버로드, 내장 작업 시스템, 다중 수학 라이브러리(표준, 고속, SVML, 시스템) 언어 기능 등 여기서 다루지 않은 다른 기능을 제공합니다.
Unreal ISPC 통합: ISPC는 Unreal 버전 4.23에서 사용할 수 있으며, 4.25에는 Chaos 물리 및 애니메이션 시스템에 대한 콘솔 지원이 추가되어 사용자 정의 사용을 지원합니다. build.cs에 ISPC 모듈을 포함하고, 프로젝트에 ispc 파일을 추가하고, 생성된 C++ 헤더를 포함하면 Unreal 빌드 도구가 나머지를 처리합니다.

언리얼에서는 언제 ISPC를 사용하나요? 물리 교차 테스트, 천 또는 CPU 버텍스 변환과 같이 수학 부담이 큰 계산 집약적인 워크로드에 이상적입니다. Unreal TArray와 같은 지속적인 메모리 로딩, 작업, 저장을 사용하는 것이 가장 좋습니다. 작업 간에 데이터 종속성을 갖지 않는 것이 가장 좋으며, 특히 병렬 및 일괄 처리와 결합할 때 유용합니다.
Chaos를 위한 ISPC의 이점: ISPC는 SIMD를 사용하여 성능 최적화를 위한 간단한 셰이더 언어와 유사한 인터페이스를 제공하고, 플랫폼별 내장 코드 없이도 크로스 플랫폼에서 작동하며, Fortnite와 Destruction 모두에서 Chaos가 적극적으로 사용합니다.

강체 스키닝: 입력 버텍스 버퍼를 사용하여 변환 정점을 생성하고 뼈대 배열을 기반으로 변환합니다. 뼈대는 종종 반복됩니다. foreach_unique를 사용하여 필요한 변환 작업 수를 줄이고, 짧은 벡터 배열을 압축하고, aos_to_soa를 사용하여 집계를 제거합니다.

경계 상자: 사용자 지정 축소, 문제는 합계가 필요한 큰 경계 상자 배열의 경우 때로는 합계가 음수일 수 있다는 것입니다. Reduce_min 및 Reduce_max를 수행하는 것이 올바른 것 같습니다. 상자가 유효하지 않으면 어떻게 됩니까? 그런 다음 Foreach_active에 원하는 값 대신 0(기본 초기화)으로 고정하고 연산자 + 직렬화하여 해당 사례를 처리합니다.

시나리오 쿼리: 목록의 여러 요소를 동시에 처리하며 cpp 코드는 ispc에서 직접 호출할 수 있으며 성능은 목록 크기에 따라 달라질 수 있습니다. 확장성은 좋지만 오버헤드가 있으므로 요소가 많을수록 더 좋습니다.

견고한 체인: 최적의 성능을 위해 모든 데이터를 유니폼으로 변환하는 간단한 수학 및 무거운 계산으로 기본 명령에 비해 비용이 들지 않으며 총 15~20% 더 빠른 캐릭터 스키닝이 가능합니다.

UE4의 애니메이션: 언리얼 엔진은 현재 8개의 플랫폼을 지원하며, 그 중 10개는 차세대 콘솔과 함께 제공됩니다. 모든 대상에서 SIMD 코드를 유지 관리하는 것은 애니메이션 팀이 역사적으로 완료할 시간이 없었던 큰 작업입니다. 성능 개선은 고급 알고리즘 변경 또는 멀티스레딩에 중점을 두었습니다. 이전에는 애니메이션의 유일한 벡터화는 UE4의 공통 라이브러리 코드에서 나왔습니다.
Fortnite의 애니메이션: Fortnite는 다수의 캐릭터(BR의 경우 100개), LTM(예: Team Rumble/50v50과 같이 대규모 플레이어 팀이 근접해 있는 경향이 있음), 정상적인 성능을 방해하는 "트릭"을 통해 엔진 전반에 걸쳐 캐릭터 성능 개선을 추진하고 있습니다. 새로운 게임플레이(예: NPC)가 도입되면서 애니메이션에 대한 성능 요구 사항이 계속해서 증가하고 있습니다. 캐릭터를 2배로 실행할 수 있다면 어떤 새로운 게임이 잠금 해제될까요?
ISPC: 애니메이션에서는 성능이 항상 중요합니다(더 복잡한 캐릭터, 동시에 화면에 더 많은 캐릭터 등). 한 번에 코드를 작성하고 모든 대상 플랫폼에 도달할 수 있다는 것은 큰 승리입니다. 팀이 동일한 로직의 N 버전을 유지하는 대신 애니메이션 기술 구축에 집중하게 하세요.
UE4 애니메이션에서 ISPC를 사용할 때 먼저 런타임 핫스팟(포즈 블렌딩, 추가 포즈 변환, 정규화된 회전, 애니메이션 데이터 압축 풀기, 컴포넌트 공간 변환 빌드, 렌더러를 위한 뼈대 변환 준비)에 집중하세요. 포즈 블렌딩은 ISPC에 이상적인 시나리오입니다. 두 개의 뼈 변환 배열과 가중치가 주어지면 세 번째 변환 배열이 생성됩니다. 이전 최적화 작업에서는 연속적인 변환 배열이 이미 실행되고 있음을 의미했습니다. 테스트에서 ISPC 성능이 거의 2배 향상되는 것으로 나타났습니다.

압축 해제: UE4에서 압축 해제는 애니메이션 성능 비용의 큰 부분을 차지하며, 엔진에서 지원되는 모든 압축 형식에는 이를 위해 작성된 ISPC 코드가 있습니다. 테스트에서는 사용된 압축 유형에 따라 1.5배~2배의 성능 향상이 관찰되었습니다.


14.5.3.5 특수 기술
게임 프로그래머를 위한 수학: 복셀 서핑(Voxel Surfing)은 볼륨 표현과 복셀에 대한 지식, 응용 및 최적화를 자세히 소개합니다.
연속 함수

연속 함수, 대수 함수, 방향성 거리 필드(CSG 트리, 그리드의 삼선형 샘플링) 및 밀도 함수(그리드의 삼선형 샘플링)만 필요합니다.

밀도를 사용하는 것은 훨씬 쉽습니다(로컬 변경). 그러나 거리 필드에 대한 일부 유용한 작업(예: 확대, 볼륨 축소, 고품질 그라데이션 계산)에서는 실패합니다. 밀도는 약 하나의 샘플 셀에 대한 클램핑 거리를 갖는 거리 필드로 생각할 수 있습니다.
암시적 표면 또는 파라메트릭 메시를 복셀화하는 프로세스: 1. 메시에서 샘플링. 2. 각 셀의 표면을 대략적으로 계산합니다. 3. 표면이 셀 경계와 정렬되어 있는지 확인하십시오. 복셀화의 이상적인 특성은 구현 용이성, 로컬 독립성, 부드러움, LOD에 대한 적응성/맞춤성, 삼각형 막대 최소화, 날카롭고 얇은 특징 유지입니다.
간단한 큐브의 경우 각 그리드 셀의 중심에서

복셀화의 이상적인 특성에 있어서 이 표현방법의 장점과 단점은 다음과 같다.
구현이 용이함 지역 독립 부드러운 적응형 LOD 삼각형 최소화 날카로운 얇은
++ +
- 마링 큐브: 각 셀의 모서리에 있는 샘플
는 삼각형 토폴로지의 모서리 기호를 사용하여 보간 0점에서 가장자리를 따라 꼭지점을 배치합니다.

복셀화의 이상적인 특성에 있어서 이 표현방법의 장점과 단점은 다음과 같다.
구현이 용이함 지역 독립 부드러운 적응형 LOD 삼각형 최소화 날카로운 얇은
- 트랜복셀 알고리즘: 각 셀의 모서리에 있는 샘플
은 셀의 가장자리를 한 번 세분화할 수 있도록 하며(인접한 LOD 레벨을 연결하기 위해) 삼각형 토폴로지에 샘플링 포인트 기호를 사용하고 보간된 0 포인트의 가장자리를 따라 정점을 찾습니다.

Transvoxel은 이동하는 큐브가 다양한 LOD 레벨에 걸쳐 있을 수 있도록 하는 방법입니다. 모서리 조합의 세분화를 처리하기 위해 총 71개의 토폴로지 방법이 사용됩니다.
복셀화의 이상적인 특성에 있어서 이 표현방법의 장점과 단점은 다음과 같다.
구현이 용이함 지역 독립 부드러운 적응형 LOD 삼각형 최소화 날카로운 얇은
- 이중 윤곽선: 각 셀의 모서리에서
샘플, 각 가장자리의 교차 위치에서 샘플, 윤곽선의 각 셀에서 이상적인 점을 찾고 인접한 셀의 두 점을 연결합니다(다중 LOD 해상도 지원).

복셀화의 이상적인 특성에 있어서 이 표현방법의 장점과 단점은 다음과 같다.
구현이 용이함 지역 독립 부드러운 적응형 LOD 삼각형 최소화 날카로운 얇은
~
Dual Marching Cube: 미세한 그리드에서

복셀화의 이상적인 특성에 있어서 이 표현방법의 장점과 단점은 다음과 같다.
구현이 용이함 지역 독립 부드러운 적응형 LOD 삼각형 최소화 날카로운 얇은
Cubical Marching Square: 모든 복셀(모든 옥트리 수준)에 대해 오류 세분화(DMC와 유사)가 있는 옥트리를 구성합니다. 복셀을 펼치고 각 측면을 별도로 봅니다. 행진 큐브를 사용하여 곡선을 만들고 오류가 발생하면 테셀레이션합니다. 양면을 함께 접어 삼각형을 만듭니다.

구현이 용이함 지역 독립 부드러운 적응형 LOD 삼각형 최소화 날카로운 얇은
Windborne의 복셀화 개요:

결합되면 각 기능은 레이어가 되며 각 레이어는 빼거나 추가됩니다. 알파 블렌딩 밀도:

조합 외에도 뺄셈, 중첩, 합집합, 윤곽선 표시, 메시 밀도(광학 흐름, AO 등 동적 조명에 사용 가능), 노출 매개변수, 활용 기능 등의 연산이나 응용도 있습니다. 자세한 내용은 원문을 참조하세요.
Unreal Engine 4의 Aggregate G-Buffer Anti-Aliasing은 Nvidia에서 선보인 것으로, UE4에 구현된 앤티앨리어싱을 달성하기 위해 Aggregate GBuffer를 사용하는 특수 기술을 설명합니다.

왼쪽에서 오른쪽으로: 4xTAA, 4xSSAA, 4xAGAA. 그 중 AGAA는 1.7배 더 빠르다.
TAA는 품질을 크게 향상시키지만[Karis 2014], 최적의 품질을 위해 SSAA와 결합해야 하는 잔상, 깜박임, 지나치게 부드러운 시각적 특징(반사 하이라이트 등) 문제가 있습니다.
**AGAA(Aggregate G-Buffer Anti-Aliasing, Aggregate Geometry Buffer Anti-Aliasing)**는 G-버퍼 샘플 수에서 음영 처리율을 분리하고 동적 사전 필터링을 사용하며 4x 또는 8x MSAA/SSAA로 래스터라이제이션하고 픽셀당 최대 2x를 비춥니다.

하위 픽셀 세부 사항의 모양을 캡처하거나 재현하기 위한 사전 필터링, 슈퍼샘플링, 사후 필터링, 다양한 기하학적 스케일을 필터링하기 위한 다양한 도구. 프로세스는 다음과 같습니다.

AGAA 파이프라인의 개략적인 보기:

조명 사전 필터링 집계: 목표는 집계된 공간에 대한 평균 반사율을 대략적으로 계산하는 것이며, 음영 함수에 대한 입력은 각 집계에 대해 독립적으로 사전 필터링됩니다. 텍스처 공간 및 복셀 공간 사전 필터링 방식, 속성 역상관 가정, 원거리 가정에서 영감을 얻었습니다. 집계별 통계: 평균 다수 음영 매개변수, 정규 분포 함수(NDF) 구축, 그림자의 평균 감소.

원거리 필드 가정.
집계 생성: 클러스터링. 목표는 관련 속성, 조명 모델, 노멀, 깊이/위치와 같은 거리 측정항목으로 인해 발생하는 셰이딩 오류를 최소화하는 것입니다. 클러스터링된 샘플은 기본 요소와 개별 표면에 걸쳐 있을 수 있습니다.

다음은 집계입니다. 샘플-집계 매핑이 완료되면 나머지 단계는 슈퍼샘플링된 G 버퍼의 데이터를 사용하여 집합별 셰이딩 속성 필터링을 수행하는 것입니다. 요약하면, 대부분의 셰이딩 속성은 평균화되고 각 샘플의 노멀 및 러프니스 정보는 BRDF 모델과 관련된 정규 분포 표현으로 변환되므로 이를 선형으로 결합하고 집계 공간에서 분산을 대략적으로 계산할 수 있습니다.

UE4에는 셰이딩을 수행하는 데 가능한 렌더링 경로가 여러 개 있으며, 그 중 하나가 타일형 디퍼드 셰이딩입니다. 이 문서에서 엔진은 가능할 때마다 타일형 지연 경로를 사용하도록 구성되었으며 AGAA 집계 및 조명은 타일형 디퍼드 렌더링 계산 셰이더에서 구현되었습니다. 최적의 성능을 위해 현재 타일에 대해 처리된 모든 조명의 집계된 속성을 재사용하기 위해 이 컴퓨팅 셰이더의 셰이딩 단계 시작 부분에 G 버퍼 집계 단계가 구현됩니다.
클러스터링 패스는 각 픽셀의 모든 ShadingModel ID, 깊이 및 법선을 가져와 샘플 ID에서 집계 ID로의 매핑을 계산합니다. 픽셀당 집계가 2개만 있으므로 각 샘플 집계 ID는 샘플당 1비트로 저장될 수 있습니다. 다음으로, 각 GBuffer 샘플에 대해 셰이딩 매개변수는 GBuffer 데이터(집합 셰이딩에 사용되는 형식)를 기반으로 재구성되어 각 집합의 모든 샘플에서 이러한 셰이딩 매개변수의 평균을 냅니다. 한 가지 예외가 있습니다. 월드 공간 위치의 경우 먼저 각 집합의 평균 뷰 공간 깊이를 계산한 다음 해당 위치의 화면 공간 XY 좌표가 픽셀 중심에 있다고 가정하여 월드 공간 위치를 재구성하는 것이 훨씬 빠릅니다. 이 근사치는 테스트 시 눈에 띄는 아티팩트를 발생시키지 않습니다.

사전 필터링 G 버퍼 샘플은 일반 맵 사전 필터링(Toksvig 2005) 및 기하학적 곡률 필터링(Kaplanyan 2016)을 사용합니다.
float3 GetAgaaAverageQuadNormal(FMaterialPixelParameters MaterialParameters, float3 N)
{
int2 PixelPos = MaterialParameters.SVPosition.xy;
N -= ddx_fine(N) * (float(PixelPos.x & 1) - 0.5);
N -= ddy_fine(N) * (float(PixelPos.y & 1) - 0.5);
return N;
}
// 필터링 (Kaplanyan 2016)
float2 GetAgaaKaplanyanFilteringRect(FMaterialPixelParameters MaterialParameters)
{
// Shading frame
float3 T = MaterialParameters.TangentToWorld[0];
float3 ShFrameN = normalize(MaterialParameters.TangentToWorld[2]);
float3 ShFrameS = normalize(T - ShFrameN * dot(ShFrameN, T));
float3 ShFrameT = cross(ShFrameN, ShFrameS);
// Use average quad normal as a half vector
float3 hppW = GetAgaaAverageQuadNormal(MaterialParameters, ShFrameN);
// Compute half vector in parallel plane
hppW /= dot(ShFrameN, hppW);
float2 hpp = float2(dot(hppW, ShFrameS), dot(hppW, ShFrameT));
// Compute filtering region
float2 rectFp = (abs(ddx_fine(hpp)) + abs(ddy_fine(hpp))) * 0.5f;
// For grazing angles where the first-order footprint goes to very high values
rectFp = min(View.AgaaKaplanyanRoughnessMaxFootprint, rectFp);
return rectFp;
}
float GetAgaaKaplanyanRoughness(FMaterialPixelParameters MaterialParameters, float InRoughness)
{
float2 rectFp = GetAgaaKaplanyanFilteringRect(MaterialParameters);
// Covariance matrix of pixel filter's Gaussian (remapped in roughness units)
// Need to x2 because roughness = sqrt(2) * pixel_sigma_hpp
float2 covMx = rectFp * rectFp * 2.f * View.AgaaKaplanyanRoughnessBoost;
// Since we have an isotropic roughness to output, we conservatively take the largest edge of the filtering rectangle
float maxIsoFp = max(covMx.x, covMx.y);
return sqrt(InRoughness * InRoughness + maxIsoFp); // Beckmann proxy convolution for GGX
}
GBuffer NDF 사전 필터링 해제(왼쪽) 및 설정(오른쪽) 비교.
4xAGAA의 비디오 메모리 소비는 다음과 같습니다.
AGAA 패스렌더링 대상비디오 메모리 바이트
AGAA 클러스터링 AGAA 메타데이터 WxHx1 R16_UINT
AGAA 조명 및 반사 집계별 조명 색상 WxHx2 R11G11B10F
이미시브 병합 픽셀당 조명 색상 + 발광 WxHx4 R11G11B10F
총 VRAM 오버헤드: 26바이트/픽셀
해상도의 경우 자체 조명은 샘플당 해상도로 유지되며 항상 톤매핑된 색상을 해결합니다[Karis2014].
4xAGAA(GPU 시간(ms))의 성능은 다음과 같습니다.
스테이지4xSSAA4xAGAAAGAA 4개/SSAA 4개
Z 프리패스 0.13 0.13 1.0배
G버퍼 채우기 1.26 1.26 1.0배
조명 4.71 2.85 1.65x
포스트 프로세스 0.55 0.55 1.0배
프레임 6.65 4.79 1.39x
또는 잠재적으로 복잡한 재료 맵을 사용하여 재료 정의를 제어하여 4xMSAA를 달성할 수 있습니다(아래). 이러한 그래프에는 삭제 호출, 거듭제곱 함수, 클램핑, 마스크, 조건 및 텍스처 공간의 사전 필터링을 파괴하는 이러한 작업의 다양한 조합과 같은 많은 비선형 작업이 포함될 수 있습니다.

MSAA를 더욱 실현 가능하게 만듭니다. GBuffer 패딩에 MSAA를 사용하면 슈퍼샘플링(~2x)보다 더 나은 성능 향상을 얻을 수 있습니다. 그러나 픽셀 셰이더가 삭제 또는 비선형 수학을 사용하는 경우 조각별 셰이딩으로 인해 아티팩트가 발생할 수 있습니다. 제안된 솔루션: 1. 아티스트가 비선형 재료 노드(pow, 클램프 등)를 피하도록 권장합니다. 2. 비선형성이 있는 GBuffer 속성의 선택적 슈퍼샘플링.
AGAA의 한계는 조명 채널의 속도만 향상시키고 UE의 비표준 셰이딩 모델을 테스트하지 않았으며 픽셀당 2개 이상의 셰이딩 모델을 테스트하지 않았다는 것입니다. 요약하면 AGAA는 오버샘플링된 조명을 가속화하고, 4x AGAA 조명은 4x SSAA보다 1.7배 빠르며, 8x AGAA 조명은 8x SSAA보다 2.6배 빠르며 TAA와 함께 사용하거나 단독으로 사용할 수 있습니다.
2015년 DirectX 12, Vulkan 등 최신 그래픽 API가 출시된 이후 게임 엔진, 게임 애플리케이션 등이 이를 지원하고 호환되기 시작했습니다. DirectX 12를 사용한 명시적 다중 GPU 프로그래밍에서는 DirectX 12에서 다중 GPU의 명시적 프로그래밍을 구현하는 방법을 설명합니다.
과거에는 다중 GPU가 암시적으로 프로그래밍되었습니다. 이상적인 상태는 드라이버가 마법을 수행하고 제대로 작동하며 개발자가 드라이버의 세부 사항에 대해 걱정할 필요가 없다는 것입니다. 그러나 현실은 드라이버에 정리, 삭제, 공급업체별 API와 같은 많은 힌트가 필요하고 개발자는 드라이버가 수행하려는 작업을 이해해야 하지만 여전히 성능이 항상 향상되는 것은 아닙니다. . .
명시적 다중 GPU는 예상치 못한 암시적 전송 없이 GPU 간 전송을 제어하고 AFR(대체 프레임 렌더링)뿐만 아니라 각 GPU에서 수행되는 작업을 제어할 수 있습니다. DirectX 12 기반의 명시적 다중 GPU에는 더 이상 드라이버 마법이 없으며 AFR에는 드라이버 수준 지원이 없으며 이제 애플리케이션 계층 개발은 훨씬 더 좋지는 않더라도 자체적으로 훨씬 더 나은 작업을 수행할 수 있으며 공급업체별 API가 필요하지 않습니다. DX12에는 링크 노드 어댑터(아래 그림 상단)와 멀티 어댑터(아래 그림 하단)의 두 가지 모드가 있습니다.

두 모드에서는 명령 대기열, 리소스 관리, 동기화 및 적용 방법이 다릅니다.
크로스 프레임 렌더링의 경우 이전 파이프라인에 대한 종속성이 있을 수 있습니다. 새로운 프레임 파이프라인은 하나의 GPU에서 프레임을 시작하고 작업을 다음 GPU로 전송하여 렌더링과 렌더링을 완료합니다. GPU와 복사 엔진은 파이프라인을 형성합니다.

성능 저하 없이 타이밍 기술을 사용할 수 있습니다.

간단히 말해서, 더 이상 드라이버 마법이 없습니다. AFR을 마음대로 제어하고, 파이프라인에 시간 기술을 사용하고, 복사 엔진을 최대한 활용하고, 추가 GPU로 원하는 모든 작업을 수행할 수 있습니다!
GPU에서의 실시간 BC6H 압축은 GPU에서 실시간 압축을 위해 BC6H를 사용하는 기술을 설명합니다. BC6H는 FP16 HDR 텍스처용으로 설계된 블록 기반 손실 압축이며, DX11 및 현세대 콘솔부터 지원되는 하드웨어, 4x4 고정 크기 텍셀 블록, 알파 없음, 6:1 압축 비율(텍셀당 8비트), RGBE, RGBM, RGBK와 같은 블랙 코드를 효과적으로 대체합니다. . .
텍스처에 대한 몇 가지 트릭이 있습니다: 부호 있는 또는 부호 없는 반부동, 세 가지 알고리즘의 혼합: 끝점 및 지수, 델타 압축, 파티셔닝, 블록당 다른 압축 모드 선택.
BC6H 엔드포인트 및 인덱스: 각 블록은 2개의 엔드포인트와 16개의 인덱스를 저장합니다. 끝점은 RGB 공간의 선 세그먼트를 정의하고 인덱스는 세그먼트의 블록에 있는 각 텍셀의 위치를 정의합니다(아래 왼쪽 이미지). BC6H Delta Compression: 첫 번째 끝점은 더 높은 정밀도로 저장되어 두 번째 끝점 대신 끝점 사이의 부호 있는 오프셋을 저장하여 유사한 값을 가진 블록의 품질을 향상시킵니다(아래 오른쪽 이미지).

BC6H 분할: 블록당 두 개의 별도 선 세그먼트를 허용하고, 큰 색상 변경이 포함된 블록의 품질을 향상시키며, 사전 정의된 32개의 파티션 중 하나를 사용하여 두 선 세그먼트 중 하나에 현재 텍스처를 할당합니다(아래 이미지, 상단). 델타 압축을 사용한 BC6H 파티셔닝: 하나의 기본 끝점은 직접 저장되고, 다른 3개는 기본 끝점의 부호 있는 오프셋으로 저장되므로 끝점 정밀도가 제한되는 데 도움이 됩니다(아래 그림 참조).

BC6H에는 파티셔닝이나 델타 압축을 사용하지 않는 1가지 모드, 델타 압축만 사용하는 3가지 모드, 파티셔닝만 사용하는 1가지 모드, 파티셔닝과 델타 압축을 사용하는 9가지 모드 등 14가지 모드가 있습니다. 모드는 끝점 정확도와 오프셋 정확도 사이에서 서로 다른 균형을 선택합니다. 최적의 압축은 어렵습니다. 10개의 분할 모드가 있으며, 각 분할은 4개의 끝점과 16개의 최적 지표(32개의 분할이 있음)를 찾아야 하며, 거대한 검색 공간이 있습니다.
GPU의 실시간 압축의 일반적인 예: 동적 환경 그래프, 런타임 시 다른 형식에서 전사된 HDR 텍스처, 사용자 생성 콘텐츠, GPU 기반 압축은 CPU-GPU 동기화 및 CPU와 GPU 간 데이터 전송을 방지합니다. 사용 사례에는 동적 조명 조건, 절차적 세계 기하학, 카메라 이동 중 주변 맵 생성, 생성된 환경 맵을 BC6H로 실시간 압축, 조밀한 환경 맵 배치 활성화 등이 포함됩니다.
실시간 압축에는 성능과 품질 간의 균형이 필요합니다. 성능이 중요하고 품질이 최고일 필요는 없으며 품질이 중요하며 압축에는 밀리초가 걸릴 수 있습니다. "빠른" 사전 설정은 어떤 모드를 사용합니까? 파티션 모드는 너무 느리고 델타 압축만 사용하는 모드는 빠르지만 몇 가지 특정 경우에만 향상됩니다. 모드 11에는 10비트 부동 소수점, 16개 인덱스(각각 4비트)의 두 끝점으로 양자화된 끝점과 지수만 있습니다. 끝점은 최소값과 최대값을 끝점으로 사용하여 블록 텍스처 [Waveren06]의 RGB 경계 상자를 계산합니다.

RGB BBox 그림, 정확도를 높이기 위해 RGB BBOX를 작은 크기로 삽입했습니다(아래 이미지, 위). HDR 데이터로 인해 오프셋이 매우 커집니다(아래 하단 이미지).

두 번째로 작은 R, G, B를 사용하여 bbox를 재구성하는 RGB BBox 개선:

끝점 사이의 선분에 있는 16개의 보간 색상 중 하나를 선택하고 선분에 투영하고 가장 가까운 인덱스를 선택해야 합니다(아래 그림, 왼쪽). 이는 보간 가중치가 고르지 않게 분포되는 것(아래 그림, 오른쪽)만큼 간단하지 않습니다.

간단한 근사는 최소 오류로 방정식을 맞추는 것입니다.

고정 인덱싱: 첫 번째 인덱스의 MSB는 암시적으로 0으로 가정되고 저장되지 않습니다. 이 속성은 끝점을 교환하여 보장되어야 합니다.

빠른 사전 설정과 품질 사전 설정의 효과 비교:

DX11 구현: R32G32A32A32보다 16배 작은 임시 대상으로 렌더링, 픽셀 셰이더 실행 및 압축된 블록을 픽셀로 출력, 결과를 BC6H 텍스처(CopyResource)에 복사, 최신 API 사용: 복사 단계 건너뛰기, 비동기 계산으로 구현. 셰이더 최적화: 소스 텍스처에 "수집"을 사용하고, 16비트 정수 수학을 부동 소수점 수학으로 대체하고, 조회 테이블을 부호 없는 정수로 꽉 채운 비트를 사용합니다.
Uncharted 4의 Rendering Rapids에서는 Uncharted 4의 급류 렌더링 기술에 대해 이야기합니다. 수역 시뮬레이션 측면에서 FFT, 파동 입자, 흐름 다이어그램 및 기타 기술이 사용되며 수역 메쉬는 **CDLOD(Continuous Distance-Dependent Level of Detail Level of Rendering Heightmaps, 연속 거리 관련 세부 수준 렌더링 하이트맵)**를 사용합니다.

강 지오메트리의 고정된 쿼드 세트로 시작하여 범위별로 쿼드 LOD 수준을 결정하고, 카메라 전환을 위한 높이 맵 범위 bbox를 사용하고, 카메라의 xz 위치를 기반으로 각 기본 쿼드를 세분화하고, 높이 맵 + 웨이브를 사용하여 정점을 위쪽으로 변위합니다. 물 위의 보트와 같은 객체 변형의 경우 객체 경계 상자를 사용하고 교차하는 각 쿼드 정점에 대해 필터링하여 마스크를 기반으로 쿼드의 정점을 오프셋합니다.

입자의 변형은 상대적으로 더 복잡하며 파이프라인은 다음과 같습니다.

Crest: 오픈 소스 프레임워크의 새로운 해양 렌더링 기술은 Unity3D에서 구현된 오픈 소스 해양 렌더러인 Crest를 보여주며 메시 생성, 모양 표현 및 표면 음영 처리에 대한 많은 새로운 기술을 시연합니다. 형상을 생성하기 위해 클립 매핑은 연속적인 세부 수준으로 확장되고 스커트 형상은 프러스텀 컬링을 지원하는 겹치지 않는 타일로 구성된 표면을 사용하여 수평선까지 확장됩니다. 화면 공간에서 그리드 밀도를 유지하기 위해 카메라 높이가 변경될 때 눈에 띄는 점프 없이 그리드의 크기를 수평으로 조정하는 방법을 보여줍니다. 보는 사람 앞에 세부 중심을 배치하기 위한 간단한 경험적 방법도 구현되어 있으며, 이는 모든 뷰 위치 및 방향에 대해 견고합니다. 바다 모양을 GPU의 변위 텍스처로 렌더링하여 지오메트리 LOD의 밀도와 위치를 일치시킵니다. 각 모양 텍스처의 파장이 너무 짧은 경우 앨리어싱 및 불필요한 작업을 피하기 위해 추가되는 Gerstner 파동열의 수가 제한됩니다. 탁구 렌더 타겟은 동적 모션 레이어를 추가하기 위해 파동 방정식을 시뮬레이션하는 데에도 사용됩니다. 셰이딩의 경우 지오메트리 LOD 링을 사용하여 노멀 맵 UV의 크기를 조정하여 뷰어에 가까운 디테일을 달성하는 동시에 중장거리에서 디테일이 부족한 유리 같고 평평한 모양을 방지하고 가시적인 중복을 제거할 수 있습니다. 폼의 경우 추가 렌더 타겟이 모양 텍스처 옆에 추가되었고 피드백 렌더링 패스가 소산을 시뮬레이션하는 데 사용되었습니다. 마지막으로, 여러 표면을 통해 중요하지 않은 광 전송 경로를 달성하기 위해 깊은 필링을 적용한 결과도 제시됩니다.

잘린 이미지의 모션 시각화.

CD 작물의 동작 시각화.

수평 확대 시각화.
CDLOD 비교: 세부 정보 구동을 위한 유클리드 거리, 기하학 타일을 배치하기 위한 쿼드트리, 부드러운 기하학 전환, Uncharted 4: Gonzalez-Ochoa.
CDLOD CD클립맵
유클리드 거리 택시(택시) 거리
쿼드트리 CPU 최소화
스커트 기하학? 스커트 기하학
형태 없는 연결 모양 연결

왼쪽: CDLOD의 유클리드 거리; 오른쪽: CDClipmap의 택시 거리.
모양 측면에서 GPU 파이프라인은 다음과 같습니다.

수학적으로 모델링할 수 있는 다른 모든 항목을 렌더링할 수 있습니다.

또한 폼과 뎁스 필링(Depth Peeling)도 지원됩니다.

깊이 제거 프로세스: 최전방 수층의 깊이를 얻고, 후속 레이어를 렌더링하고, 산란/흡수를 축적하고, 최전방 레이어를 렌더링합니다. 일반적인 굴절 셰이더이지만 올바른 산란을 사용하면 수중 후처리에 적용할 수 있습니다.

레이어를 렌더링한 후 가장 뒤쪽 표면의 깊이가 장면 색상과 결합되어 가장 뒤쪽 깊이와 물 내에서의 흡수 및 산란이 계산되며 화선과 같은 수중 포스트 프로세스 파이프라인만 적용할 수 있습니다.


최종 효과:

Unity의 신속한 UI 생성을 위한 데이터 바인딩 아키텍처에서는 UI를 생성하기 위해 Unity에서 데이터 바인딩을 구현하는 아키텍처와 기술을 설명합니다. UI를 만드는 기존 방식은 Photoshop에서 작업하는 아티스트, 마법을 적용하는 UI 개발자, 버그를 찾는 QA 간의 순환이었습니다.

이 접근 방식에는 "내 문제가 아니다"라는 태도, UI 아티스트 역할을 하는 개발자, 테스트되지 않은 스파게티(복잡한) 코드, 긴 개발 주기 등 많은 문제가 있습니다. Lost Survivor의 아키텍처: 아티스트는 Unity에서 직접 작업하고 개발/아트 리소스는 분리되며 개발/아트 작업은 동시에 진행됩니다. 관련 기술에는 MVC 모델이 포함됩니다.

객체는 재사용하기 쉽고 인터페이스 정의도 더 쉽습니다. 기본 iOS SDK 지원, 우려사항 분리, XCode의 비주얼 디자이너. MVVC 모델도 있습니다:

ViewModel은 데이터 바인딩을 기반으로 모델 뷰당 하나의 뷰인 뷰 서비스를 제공합니다. Lost Survivor의 아키텍처는 다음과 같습니다.

클래스 다이어그램:

데이터 바인딩 예:

// bind toggles to method calls
Subscribe<SettingsConfigurationModel>()
.BindToggle(MusicToggle, _audioService.MuteMusic, true)
.BindToggle(SfxToggle, _audioService.MuteSfx, true)
.BindToggle(PushNotificationToggle, SetPushEnabled)데이터 바인딩을 맞춤설정할 수도 있습니다.
Subscribe<CharacterModel>()
.BindModelChangeAction(UpdateBuffObjects)
.BindButton(HealButton, CurrentBuffSubview, (model, script) => ...)
...
.Finish();
...
private void UpdateBuffObjects(CharacterModel model)
{
for (int i = 0, count = model.ActiveStageBuffs.Count; i < count; i++)
{
InstantiateNewBuffGameObject(CurrentBuffSubview, model.ActiveStageBuffs[i]);
}
...
}성능 영향: 반영을 기준으로 초기 단계에서만 가비지 수집 압력이 없습니다. 분리된 테스트, 빠른 반복, 종속성 감소를 달성할 수 있으며 모든 것을 시뮬레이션할 수 있습니다. 즉, 개발/아트가 서로 집중하고, 객체를 시뮬레이션하고, 통합하고 협업하고, 단위 테스트, 사용자 인터페이스 테스트 등을 수행할 수 있다는 것을 실현할 수 있습니다.
데스티니 파티클 아키텍처는 표현력과 유연성, 1초 미만의 반복 및 성능을 포함한 데스티니 엔진 파티클 효과의 아키텍처를 설명합니다.

데스티니의 입자는 스크립트와 시각적 아키텍처를 채택합니다.
component c_emitter_shape:ring
{
c_initial_velocity_type:* initial_velocity_type;
float radius;
#hlsl
float3 calculate_initial_position()
{
float2 circle_point= random_point_on_unit_circle();
return float3(0, circle_point * radius);
}
#end
}
데이터 계층 구조는 다음과 같습니다.

파티클의 메모리 레이아웃은 다음과 같습니다:

표현식 및 바이트코드 변환 프로세스와 1초 미만의 반복은 다음과 같습니다.

그렇다면 실행 속도는 충분히 빠른가? CPU 파티클(최대값은 일반적으로 약 3k)의 경우 개발 목적으로는 충분합니다.

또한 GPU 바이트코드 및 베이크된 HLSL 솔루션도 시도했습니다. 속도와 반복 간의 관계는 다음과 같습니다.

"그래픽 엔진을 위한 프로그래밍 가능 모델의 진화"는 Unity 엔진의 아키텍처 진화 역사를 알려줍니다. 한 가지 (나쁜) 접근 방식은 자산별, 플랫폼별 기준으로 코드를 작성하는 것인데, 이는 분명히 확장되지 않으므로 실제로는 그렇게 하는 방법이 아닙니다.

디커플링은 애플리케이션 계층의 특정 인터페이스 매핑을 사용하여 달성할 수 있습니다.

혁신에 기여하는 원칙: 재현 가능한 실행 동작을 쉽게 공유하고, 광범위한 인프라 지원 서비스를 제공해야 하며, 게임 엔진은 이를 쉽게 만들고, 프레임워크는 유연해야 하며, 과도한 인프라 계층은 혁신을 방해해서는 안 됩니다. 당시 엔진은 일반적으로 하위 수준 API 레이어, 엔진 추상화 레이어, 렌더링 채널 추상화 레이어로 나누어졌습니다.

렌더링 파이프라인의 복잡성이 몇 배나 증가했습니다. 논리 기반 렌더링 제어에는 게임 논리 및 콘텐츠 제어를 위한 렌더링 옵션이 포함됩니다.

그래픽 개발의 반복을 위해 하위 수준 API 및 엔진 추상화 레이어는 최대한 수정하지 않고 렌더링 채널 및 게임 로직 레이어에 수정 사항이 배치되기를 바랍니다. 각 기능에 작은 C++ 커널이 포함되어 API를 C# 레이어에 노출하고 C# 언어의 구현 세부 정보를 제공하는 그래픽 엔진 프로그래밍의 패러다임 전환입니다. Unity가 렌더링 프레임워크에서 기대하는 바는 다음과 같습니다. 미래 지향적: 최소 표면적, 테스트 용이, 느슨한 결합; 사용자 중심: 사용자의 프로젝트 공간에 배치되고, 신속하게 디버그하기 쉽고, 확장 및 수정이 쉽습니다. 최적: 성능이 매우 빠르며, 특정 플랫폼 애플리케이션 유형에 대한 최적화를 통해 사용자는 의도한 목표를 달성하는 데 필요한 작업만 수행할 수 있습니다. 명확함: 더도 덜도 말고 마법도 없이 명확한 API로 말하는 대로 정확하게 수행됩니다. 이를 위해 Unity는 새로운 SRP(스크립트 렌더링 파이프라인)를 제안했습니다.

SRP 고급 개념: 필터링된 그리기 호출은 스크립트에서 호출되고, 셰이더는 특정 렌더링 파이프라인을 위해 설계될 수 있으며, 표시되는 개체 목록, 조명 등과 함께 사용되어 렌더링 파이프라인을 위한 상위 수준 코드를 크게 단순화합니다. 그 원칙은 심층 구성, 암시적 가정 없음, 검색 가능성, 유연성, 신속한 개발 반복 및 고성능입니다. C++ 계층은 개체 집합의 선별, 정렬/배치/렌더링, GPU 명령 버퍼 생성, 내부 그래픽 플랫폼 추상화 및 하위 수준 리소스 관리 등 성능이 중요한 영역을 담당합니다. C#은 카메라 설정, 조명/그림자 설정, 프레임 렌더링 채널 설정/논리, 포스트 프로세스 논리 등 상위 수준 지침을 담당합니다. 셰이더는 재질 정의, 조명 및 응용 프로그램, 그림자 생성, 전체 화면 프로세스, 컴퓨팅 셰이더 등 GPU 작업을 담당합니다.
데이터(그래프/구성 파일)여야 할까요, 아니면 코드(C#/Lua)여야 할까요? 일부 결정은 분기와 게임 상태에 따라 달라집니다. Unity는 이미 Unity의 핵심 디자인 원칙인 C#을 선호합니다. 코드는 그래픽 프로그래머의 편안한 영역이며, 스크립트 핫 로딩을 통한 빠른 반복은 훌륭합니다.
SRP의 장점: 새로운 알고리즘의 초고속 반복, Unity 엔진 프레임워크의 모든 이점, 아키텍처 구축보다는 알고리즘 자체에 집중, 낮은 수준의 린 실행의 모든 성능 이점, 스크립트의 핫 리로딩의 모든 이점. 명령 버퍼 스케줄링, 모든 것이 대기열에 추가되고 Submit이 자동으로 두 번 호출되어 작업을 추가하는 순서대로 실행됩니다. 각 명령은 작업입니다. SRP는 지연/전달//전달+(예: G-버퍼 레이아웃/패키징 변경), 조명 아키텍처 변경, 그림자 알고리즘, 조명 유형 연구(영역 조명 등), 재료 모델, 포스트 프로세스 변경, 클러스터링 변경에 적합합니다.
스크립팅 가능한 렌더링 파이프라인의 이점은 훌륭한 엔진 프레임워크, 그래픽 기술 개발의 신속한 반복, 내장된 성능 분석, 효율적인 멀티 플랫폼 실행, 손쉬운 기술 공유, 새로운 파이프라인 개발을 위한 훌륭한 출발점을 기반으로 구축되었습니다. 사용자에 대한 제한은 기본 플랫폼 APL 또는 엔진 레이어 추상화를 다루어야 하는 변경 사항에는 C++ 소스 코드가 필요하다는 것입니다. 이러한 변경은 불가능하지는 않지만 핵심 엔진의 변경이 필요합니다.
Battlefield 1과 Mass Effect Andromeda의 4K 체커보드는 Battlefield 1의 4K 수준 체커보드 렌더링을 설명합니다.
EQAA(AMD)는 깊이 조각보다 더 적은 수의 색상 조각을 저장할 수 있는 MSAA의 상위 집합입니다. 즉, 색상 <= ID <= 깊이입니다. 4K 보드는 1x 컬러 타일, 2x ID 타일, 2x 깊이 타일 등의 구성을 활용합니다. 음영 블록에는 두 가지 유형이 있습니다: 2x 컬러 4x 깊이, 1x 컬러 2x 깊이:

EQAA 보드 레이아웃은 다음과 같습니다.

또한 COD는 객체 및 기본 ID 버퍼, 기울기 조정, 무게 중심 평가 및 알파 확장과 같은 기술을 사용합니다. 최적화 측면에서는 PS 호출, FP16, EQAA 심층 분석 등이 사용됩니다. 후처리에는 체커보드 분석, 공간 구성 요소, 색상 경계 상자, 다양한 블렌딩 작업, 개체 및 기본 ID, 시간 구성 요소, 속도 기반 재투영 및 선명 필터링과 같은 기술이 사용되었습니다.

체스판 분석 과정.
또한 이 기사에서는 렌더 타겟 오버랩, 동적 해상도 스케일링 및 성능도 다룹니다.
A Life of a Bokeh에서는 특히 산란 및 수집, 혼합 산란, 구멍 채우기, 약간의 초점 흐림, 조리개 시뮬레이션, 성능 결과 및 확장성을 포함하여 UE의 Bokeh 심도 효과의 구현, 단계 및 관련 최적화를 공유했습니다. UE의 뎁스 오브 필드(DoF) 목표는 고급 품질, 하드웨어 확장성 및 실시간 렌더링입니다. UE의 DOF 처리 흐름은 다음과 같다.

샘플링 패턴에서 균일한 패턴이 너무 분산되어 있습니다. 작은 샘플 CoC를 사용해 보고 더 큰 코어를 사용하십시오. 근처의 대형 화면에 초점이 맞지 않고 일부 픽셀만 교차하므로 임의 코어 오프셋에 따라 밉 레벨이 낮을수록 더 많이 표시됩니다.

전체 수정 전에 각 샘플 무게가 배럴 무게로 변경되지 않고 링 간에 밀도 변화가 발생하도록 샘플링 밀도 변화를 수집합니다.

BGD-MIN-COC 확장과 BGD MIN INTERSECTABLE COC 확장 간의 비교:

간접 산란 패스: 전경 및 배경의 경우 지원되는 플랫폼의 직사각형 목록 토폴로지로 최적화된 독립 스프라이트를 산란하며 산란할 스프라이트 수를 다양하게 하고 간접 그리기 호출 [Kawase15.3]:

이웃 비교: 1/4 해상도 버퍼를 사용하고 분산된 픽셀을 검정색으로 클러스터링하고 RGB 추가 렌더 대상 블렌딩을 사용하여 감소 패스에서 이웃과 색상을 비교합니다.

채널을 재구성하는 과정은 다음과 같습니다.

전경에 대한 미러링된 구멍 채우기: 전경 수집 채널만 각 샘플의 기여도를 반영합니다[Jimenez14]. 교차 전에 수행된 2개의 반대편 환형 샘플의 CoC에서 최소값을 취합니다.

구멍 채우기 전용 컬렉션 채널: 전경 불투명도가 0이 아니고 1이 아닌 경우에만 적용 가능하고, 더 가까운 전경의 불투명도를 찾고, 배경 부드러운 전환을 사용하고, RGBA를 출력하고, 재구성 프로세스 중에 불투명도 수정을 허용합니다.

반해상도 초점 수집: 확장 채널에서 수집되는 비닝을 파악하여 반경 3반해상도 픽셀, 색상 및 불투명도로 모든 입력 샘플을 수집합니다.

재조합: RGBA는 전체 해상도 수집을 클램프하고, 가장 가까운 2x2 반해상도 무차별 대입 수집 출력을 사용하고, 깜박이는 하이라이트를 안정화하기 위해 RGB를 사용하며, 머리카락과 같이 흔들리는 재질에서 불투명도를 안정적으로 유지합니다. 재구성에서 모든 자원을 무작위로 수집하고, Sobol 기반 무작위 생성기 [OlanoXX], 디스크에 사각형 분포 매핑 [Reynolds17], 교차 모델의 경우 하위 픽셀 정확도를 달성해야 합니다. 메인 TAA 채널을 포스트 필터로 사용하세요. 최종 효과 및 성능 비교는 다음과 같습니다.

실시간으로 Burley의 정규화된 확산을 사용한 효율적인 화면 공간 하위 표면 산란은 효율적이고 고품질의 화면 공간 하위 표면 산란을 달성하기 위해 Burley의 정규화된 확산을 사용하는 방법을 보여줍니다.
과거에는 분리 가능한 하위 표면 산란에서는 분리 가능한 가우시안 컨볼루션을 사용했는데, 이는 매우 빠르고 평면에서 필터링할 때만 분리할 수 있었습니다. 양방향 필터링을 통해 컨볼루션이 "의사 분리 가능"해졌고 결과는 시각적으로 신뢰할 수 있었습니다. 그러나 가우스 혼합 공식은 분명히 분리 가능하지 않으며, 각 가우시안 함수가 2개의 컨볼루션 패스를 수행하지 않는 한, 이는 콘텐츠 측면에서 복구해야 하는 아티팩트로 이어질 수 있습니다. 실제로 2개의 가우스를 사용하는 4개의 패스는 너무 비쌉니다. 가우스 혼합은 예술가에게 적합하지 않습니다. 가우스는 단지 수학적 개념일 뿐이며 예술가는 측정된 데이터 또는 "눈알"의 수치적 적합을 사용해야 하며, 자유도가 너무 높으며 대부분의 조합은 의미가 없습니다.
Burley 정규화 확산 모델(Disney SSS라고도 함)은 MC 데이터(1995)의 곡선 피팅을 참조하여 Brent Burley와 Per Christensen[Burley 2015]에 의해 개발되었으며 매체의 단일 및 다중 산란을 포함합니다.

확산 프로파일은 표준화되어 있으며 PDF로 제공됩니다.

표면 아래 산란 구현: 확산 BRDF는 디즈니 확산 BRDF 공식을 사용하여 확산 전송 동작을 정의하는 SSS의 원거리 근사치입니다[Burley 2015]. 이는 물리적으로 합리적이지는 않지만 Lambert 분포를 가정하는 것보다 낫습니다.

반사광 없는 전송(단일 및 다중 산란만)은 지원되지 않습니다. Diffuse BRDF는 표면 알베도를 볼륨 알베도로 사용하는 SSS의 원거리 근사이며 2가지 텍스처 옵션을 제공합니다.
: 포스트 프로세스 산란 텍스처(출구 위치의 알베도), 전처리 및 포스트 프로세스 산란 텍스처.

효과 비교:

확산 프로파일은 정규화되었으며 양측 필터를 사용하여 화면 공간에서 근사화되는 기하학적 표면을 따라 효과적으로 에너지를 절약하는 흐림 효과입니다.

샘플링 확산 프로파일: 피보나치 수열 Hannay 균일 샘플링 각도를 사용하는 확산 곡선을 기반으로 하는 디스크 샘플링은 일반적으로 구와 디스크에 분산된 다른 저차이 시퀀스보다 더 나은 성능을 발휘합니다. 확산 곡선과의 컨볼루션은 샘플 값과 가중치의 내적입니다.


양방향 필터링을 사용하면 비평면 표면에 걸쳐 필터링할 수 있습니다.

샘플 위치가 이전 "플랫" PDF에 따라 이미 분산되어 있으므로 PDF를 수정하는 것은 그렇게 간단하지 않습니다. 대신 에너지 보존(단위 분할을 충족하도록 가중치를 정규화)을 수행합니다.


또한 얇고 두꺼운 반투명 객체의 시뮬레이션도 지원됩니다.


최적화: SSS는 R11G11B10 버퍼를 통과하는 전체 화면 CS로 구현됩니다. SSS 패스 CS는 16x16 스레드 그룹 크기에 대해 32 VGRS, 38 SGPR, 6656바이트 LDS와 같은 GCN의 높은 점유율에 최적화되어 있습니다. LDS를 20x20 이웃에 대한 L0 캐시로 사용하여 VRAM 전송을 줄이고, SoA에 라디오시티 및 선형 깊이를 저장하여 뱅크 충돌을 줄이고, GCN 렌더 대상의 메모리 레이아웃과 일치하도록 Z 순서 곡선[Morton 1966]을 따라 스레드를 배열합니다. G-Buffer 패스는 템플릿에 재료 유형 태그를 지정하고 초기 컬링을 위한 Htile 정보를 추출합니다. 조명 패스는 재료 분류[Garawany 2016]를 사용합니다. SSS 재질은 확장된 표준 조명 셰이더를 사용하고 SSS 버퍼에 태그를 지정하여 SSS 패스 중에 템플릿을 읽지 않도록 합니다. 조명 패스에서는 입구 및 출구 지점 전송이 모두 적용됩니다. 개념적으로는 틀렸지만 시각적 차이는 작습니다. 내부 셰이더 개별 LOD 시스템 구현, 최대 반경이 1픽셀 풋프린트 이내인 디스크 - 컨볼루션 없음, 최대 반경이 4x4픽셀 이내인 디스크 - 더 적은 수의 샘플 사용, 최대 반경이 4x4픽셀 풋프린트를 초과하는 디스크 - 더 많은 샘플 사용, 일관된 비주얼, LOD 점프 없음. 무작위 커널 회전을 사용한 언더샘플링 비교 [Jimenez 2014](왼쪽은 Jimenez, 오른쪽은 Burley):

성능 측면에서는 기본 PS4에서 1080p, 픽셀당 21개 샘플, CS가 컨볼루션 및 조합을 수행하고 반사 조명을 사용하여 테스트한 결과 GPU 시간이 1.16밀리초였습니다. 제한 사항: 언더샘플링은 시각적 노이즈(아래)를 유발할 수 있으며, 산란 거리를 더 큰 값으로 설정하면 성능이 저하될 수 있으며, 두꺼운 개체 반투명도는 더 큰 두께 값에 대해 그다지 정확하지 않습니다.

당신의 스프라이트가 당신의 기억을 날려버릴까요? 스프라이트 애니메이션을 사용하는 게임이 직면하는 일반적인 문제는 프레임당 사용되는 텍스처 메모리의 양이며, 이는 모바일 장치에서 특히 심각한 제한 사항입니다. 이 문제를 해결하기 위해 스프라이트 패킹과 아틀라스를 사용하여 메모리를 보다 효율적으로 사용할 수 있지만 이러한 솔루션은 아틀라스의 공간을 완전히 채울 수 없는 낭비되는 결과를 가져올 수 있습니다. Secret Labs 팀이 Night in the Woods의 모바일 포트를 위해 작성한 도구인 Grabthar's Hammer는 스프라이트 다이싱을 사용하여 최소한의 낭비로 아틀라스 활용을 극대화함으로써 이 문제를 보다 효율적인 방법으로 해결합니다. Grabthar's Hammer의 저서인 What a Savings: Making the Most of Texture Memory with Sprite Dicing은 이 기술을 소개하고 Night in the Woods가 이 기술을 사용하도록 어떻게 조정되었는지, 메모리 예산에서 최대 스프라이트 수를 얻기 위해 비디오 압축 기술을 사용하여 스프라이트 다이싱을 추가로 활용한 방법을 설명합니다.
스프라이트 텍스처의 일반적인 최적화에는 다음이 포함됩니다.
텍스처 압축. PVRTC, ASTC와 같은 다양한 텍스처 형식을 다양하게 지원합니다.
벡터 추적. 매우 컴팩트하며 작은 세부 사항을 잘 보존하지 못하며 최상의 결과를 얻으려면 수동 조정이 필요한 경우가 많습니다.
텍스처 아틀라스. 포장이 불완전할 때 공간을 낭비하는 PVRTC 압축에 매우 적합합니다.
이 기사에서는 Sprite Dicing이라는 특별한 방법을 사용합니다. 단계는 다음과 같습니다:
-엘프를 작은 조각으로 자릅니다.
작은 투명 조각은 폐기하십시오.
이 작은 조각들을 지도책으로 포장하세요.
스프라이트 슬라이싱은 아틀라스 적용 범위가 더 좋고 투명한 영역이 제거되며 모든 타일이 저장되는 것은 아닙니다. 구체적인 프로세스 다이어그램은 다음과 같습니다.

위의 그림과 결합하여 숫자를 왼쪽에서 오른쪽으로, 위에서 아래로 정렬합니다. 이에 대한 설명은 다음과 같습니다.
스프라이트가 오목한 경우 간단한 트리밍으로는 제거할 수 없는 투명한 픽셀이 많이 포함되어 있습니다.
여기의 녹색 부분은 간단한 트리밍으로 제거할 수 있습니다. 빨간색 부분은 투명하지만 장식틀 안에 위치해 있어서 손으로 만질 수는 없습니다.
여기에 녹색으로 표시된 것은 모두 버릴 수 있는 것입니다. 버려질 수 있는 불필요한 투명 영역이 일부 있다는 점에 유의하세요. 이는 이러한 부분이 32x32이기 때문입니다.
각 조각이 16x16일 이유가 없으므로 가장 작은 단일 직사각형으로도 잘라냅니다.
이것은 투명한 부분을 모두 제거하고 각 부분을 개별적으로 다듬어 앨범에 넣은 720x720 이미지입니다. 512x512에 맞고 넉넉한 부분이 남아 있습니다. PVRTC에는 2개의 텍스처의 거듭제곱이 필요하므로 512x512여야 합니다.
단점은 메시 밀도가 정점당 약 18바이트로 약간 증가한다는 것입니다. 그러나 추가 메시 비용은 더 적은 수의 픽셀에 대한 텍스처 데이터를 저장하는 비용 절감보다 훨씬 적습니다.
이 접근 방식의 장점은 더 나은 아틀라스 적용 범위, 압축 가능한 아틀라스 텍스처, 낮은 셰이더 복잡성입니다. 단점은 전처리 패스, 아틀라스 크기 제한, 더 높은 다각형 개수, 패딩 필요, Unity에서 기본 제공 지원 없음 등입니다.
또한 중복성을 찾고 제거하여 추가 최적화를 수행할 수 있습니다. 중복성 유형에는 공간 중복성(동일한 이미지의 여러 복사본)과 시간적 중복성(이미지 시퀀스의 여러 복사본)이 포함됩니다. 공간 중복성을 찾는 과정은 다음과 같습니다.

우리는 두 개의 동일한 조각이 멀리 떨어져 있을 가능성이 적다는 사실을 이용합니다. 따라서 우리는 서로 가까운 패치 쌍만 테스트합니다.
똑같나요?
고유한 쌍만 확인하세요.
시간적 중복성을 찾는 과정은 다음과 같습니다.

두 이미지 모두에서 동일한 위치에 패치가 있는지 확인하겠습니다. 모든 패치 위치와 모든 이미지 쌍에 대해 반복합니다(또는 작업 속도를 높이려면 순서대로 서로 이어지는 이미지 쌍 사이에서 반복).
다음 단계는 클러스터를 찾는 것입니다.

이제 블록 다이어그램이 생겼습니다.
...그리고 그 연결 - 이러한 연결은 동일한 이미지의 블록 사이 또는 여러 이미지의 블록 사이에 있을 수 있습니다. 유사성 점수가 충분히 높으면 블록이 다른 블록에 "연결된" 것으로 간주됩니다. 그런 다음 "강하게 연결된 블록 집합"을 찾을 수 있습니다. 각 그룹 내에서 모든 블록은 매우 유사하므로 그 중 하나를 선택하고 나머지 블록은 해당 블록의 텍스처 데이터를 사용하고 Tarjan의 알고리즘을 사용하여 강하게 연결된 세트를 찾습니다.
알타스 텍스처 문제: 최대 텍스처 크기는 8192x8192 픽셀이고, 아틀라스는 정사각형이어야 하며, 모든 블록을 항상 하나의 아틀라스에 넣는 것은 불가능하며 공간 낭비입니다.
결과는 23개의 720x720 RGBA 스프라이트, PVRTC 4bpp 압축, 16x16 타일 크기이며 잘린 원본 버전은 2.68mb이고 잘린 버전은 1.5mb(원본의 55%)입니다. 106개의 1024x512 스프라이트가 있는 경우 잘린 원본 버전은 9.76mb이고 잘린 버전은 1.5mb(원본의 15%)입니다.
Bungie의 자산 파이프라인: 'Destiny 2' 및 Beyond는 Destiny Engine의 자산 파이프라인, 변경 사항, 반복적 개선 등을 공유합니다. 데스티니 엔진의 자산 파이프라인 프로세스는 다음과 같습니다.

사용된 종속성 그래프는 다음과 같습니다.

원래 자산 파이프라인 흐름:

핵심 문제는 수많은 작업과 데이터 통계입니다. Destiny 1에는 전 세계적으로 910만 개의 작업과 1,930만 개의 데이터 요소가 있습니다. 추적 구조는 매우 크고 검사/이해하기 어렵습니다. 세분성은 캐싱 메커니즘을 강조합니다.
데스티니 가디언즈의 워크플로 목표는 더 많은 콘텐츠를 더 빠르게 제작하는 것입니다. 이제는 더 큰 변화를 꾀해야 할 때입니다. 하지만 여전히 소스 콘텐츠의 하위 호환성과 제작 비용 최소화가 필요합니다. 데스티니 가디언즈 자산 파이프라인의 큰 변경 사항은 그래프를 여러 개의 더 작은 자산별 그래프로 분할하는 것입니다. 작업 수가 줄어들고 상황별 작업 범위가 더 빨라지고 자산 그래프 작업을 병렬로 실행하며 더 작은 단일 자산 그래프를 검사하고 이해하기가 더 쉽고, 더 합리적인 캐시 세분화가 가능해지며 자산 간 데이터 종속성을 도입하기가 더 어려워지고 워크플로의 영향을 더 쉽게 이해하여 로드 시 자산 참조를 수정할 수 있습니다. DESTINY 2의 자산 파이프라인 흐름:

DESTINY 2 자산 파이프라인의 병렬화:

제한 사항: 이전 버전과의 호환성/최소 생산 비용:

요약하자면, 단일 대규모 종속성 그래프의 스케일링 문제는 자산 수준 세분성을 도입하고 로드 시간 수정이 포함된 자산 참조를 도입합니다. 이러한 새로운 도구를 사용하면 효율적인 워크플로를 구축하고, 기존 워크플로를 계속 및 업그레이드/최적화하고, 비용이 많이 드는 데이터 종속성을 제거/줄이고, 새 자산을 정의하고, 자산 경계를 조정할 수 있습니다. 자산별 및 종속성 그래프 기반 데이터 파이프라인의 주요 이점을 결합할 수 있지만 데이터 종속성을 추가하기 전에 영향을 이해하는 것이 중요합니다.
'Far Cry 5'의 지형 렌더링에서는 하이 필드 렌더링(기본 원리, GPU 파이프라인), 셰이딩, 절벽 셰이딩, 하이트 필드 너머, 화면 공간 셰이딩 및 지형 기반 효과를 포함하여 Far Cry 5의 지형 렌더링에 대해 설명합니다.

하이트 필드의 기본과 프로세스는 다음과 같습니다.

지형 쿼드트리: 섹터 64m x 64m, 월드 160 x 160 섹터, 총 10km x 10km, 지형 해상도 0.5m x 0.5m.

쿼드트리의 노드는 아틀라스에 저장됩니다.

지형 렌더링 과정은 다음과 같습니다.

스트리밍 쿼드트리 노드 다이어그램은 다음과 같습니다.

노드를 순회하고 제거하는 과정은 다음과 같습니다.

위 그림의 3단계는 모두 GPU에서 실행됩니다. 동기는 데이터가 GPU에서만 사용되므로 CPU 비용을 없애고 GPU 비용을 줄이는 것입니다! 최대 버텍스 컬링을 활성화하여 나무, 바위, 풀 등에 대한 지형 데이터를 다른 GPU 시스템에서 사용할 수 있도록 합니다. GPU의 데이터 구조는 다음과 같습니다.
지형 쿼드트리. 노드 로드/언로드 시 지속적인 업데이트.
지형 노드 목록. 쿼드트리 탐색으로 생성된 노드 목록은 프레임당 한 번씩 구성됩니다.
지형 LOD 지도. 세계의 각 파티션에서 사용되는 형상 LOD는 지형 노드 목록에서 모든 프레임을 재구성합니다.
표시되는 렌더링 배치 목록입니다. 렌더링할 최종 선별 노드 목록으로, 렌더링된 뷰당 한 번씩 생성됩니다.




지형 음영 처리의 경우 스퍼터 맵이 사용됩니다.

전경색을 지정하는 단계는 다음과 같습니다.

가상 텍스처의 처리 과정은 다음과 같습니다.

절벽 셰이딩의 경우 무작위 샘플링과 셰이딩이 사용되었습니다.

스크린 공간 지형 셰이딩은 시청 거리에 따라 비용이 달라지는 셰이딩 구성표입니다.

스크린 공간 지형 셰이딩을 위한 패스는 다음과 같습니다:

'God of War'의 대화형 바람과 식물은 바람 흐름 시뮬레이션, 바람 트리거, 바람 수신기, 그리드 데이터 및 계산 세부 사항, 생성 및 모범 사례를 포함하여 God of War의 현실적인 바람 시뮬레이션을 설명합니다.

풍계량.

풍장 볼륨 해상도.
Wind는 또한 오디오, 천, 입자, 메쉬 및 기타 개체와의 상호 작용을 지원합니다.

바람받이는 아래와 같이 5개의 부품으로 구성됩니다. 정점별 데이터는 모델의 어떤 부분이 움직이고 어떤 부분이 움직이지 않는지 정의하고, 모델 매개변수는 움직이는 부분의 동작을 설명합니다.

바람 메시 매개변수에는 밀도, 모션 스케일링, 굽힘, 확장, 강성, 흔들림 스프링, 흔들림 감쇠, 나무 모드, 나무 굽힘, 나무 모션 스케일링, 리프 지연 등이 포함됩니다.

바람에 대한 그리드 스트레치 매개변수 비교.
바람은 프랙탈 노이즈 함수를 사용합니다.


또한 이 기사에는 트리 단순화 기술, 알려진 좌표계의 모든 카드 평면 테스트 및 가장 가까운 면을 평면화하는 내용도 포함되어 있습니다. 장점은 왜곡된 면의 최대 및 최소 = 최대 전체 평면 면적이며, 가장 좋은 카드에 대한 면을 구하고 반복한다는 것입니다(아래 왼쪽 그림). 6D에서 2D로: 카드 방향에서 카드까지의 거리, 카드 공간 이산화, 반구 방향의 거리 측정, 일괄 병렬 카드 처리, 카드는 모델 경계와 교차해야 합니다(아래 그림). 텍스처로 렌더링: 정사영 카메라의 재질 전달, 카메라와 카드 경계 일치, 클리핑 평면 일치 근접성, Python 이미지 라이브러리 + Maya UV 자동 레이아웃, 마지막으로 카드 재획득 면(아래 오른쪽 그림).

UE 버전의 구현 소스 코드는 언리얼 엔진 4의 "Interactive Wind and Vegetation in 'God of War'"에 있습니다.
Frostbite의 가닥 기반 헤어 렌더링은 라인 기반 헤어 렌더링 및 시뮬레이션을 공유합니다.
인간의 머리카락은 큐티클이라고 불리는 비늘로 덮여 있는 대략 원통형의 단백질 필라멘트입니다. 모발 섬유는 약 17~181μm로 매우 가늘며, 주로 백색/투명 케라틴으로 구성되어 있습니다. 검은 머리카락은 머리카락의 멜라닌 농도에 따른 결과입니다. 사람의 머리에는 약 10만 개의 머리카락이 있습니다. 이전 게임들은 일반적으로 헤어 카드나 쉘을 사용했는데, 이는 비용이 많이 드는 제작 비용, 제한된 헤어스타일, 빈약한 사실적 시뮬레이션, 단순한 컬러링 등의 단점이 있었습니다. 라인 기반 헤어 시뮬레이션은 위의 문제를 방지하고 보다 복잡하고 사실적인 헤어 시뮬레이션을 달성할 수 있습니다.

라인 기반 헤어의 개요는 다음과 같습니다.

헤어 시뮬레이션: 라인은 제약 조건, 오일러 및 라그랑지안 시뮬레이션의 조합, 메쉬 계산, 마찰, 볼륨 보존, 공기 역학을 사용한 체인 체인 상호 작용, 각 포인트에서 별도로 통합한 다음 제약 조건과 충돌체를 반복하여 포인트를 해결하는 일련의 점으로 시뮬레이션됩니다. 렌더링 개요는 다음과 같습니다.

단일 흡수는 R, TRT, TT 및 기타 구성 요소를 고려하여 Marschner03의 음영 모델을 사용합니다.

모발 흡수, 매끄러움 및 기타 특성을 달성할 수 있습니다.

이 기간 동안 종방향 산란

관점은 3D LUT로 근사화됩니다.

다중 산란은 빛에서 카메라까지의 모든 가능한 경로를 고려하여 사실감을 위해 중요합니다. 이중 산란 근사법[Zinke08]을 사용하면 실시간으로 수행할 수 없습니다. 로컬 산란은 음영 지점에 가까운 산란을 설명하고 전역 산란은 머리카락 볼륨에서 빛의 전파를 설명합니다.

깊이 불투명 맵 [Yuksel08]은 전역 산란광 경로의 머리카락 수를 추정하는 데 사용되며 그림자에도 사용됩니다.

렌더링할 때 머리카락은 표면을 기준으로 너비가 일반적으로 픽셀 크기보다 작은 삼각형 줄무늬로 세분화되며 세분화에서는 픽셀 크기를 고려해야 합니다.

MSAA를 활성화하는 것만으로는 실제로 도움이 되지 않습니다. 가시성 버퍼 + MSAA가 필요합니다.

착색 시 유사한 샘플을 한 번만 착색하면 성능이 약 2배 향상됩니다.

렌더링 개요는 다음과 같습니다.

Forza Horizon 4를 통해 Playground Games는 분광 광도계를 기반으로 하는 새로운 물리적 보정(PBC) 파이프라인을 개발하여 거의 900개에 달하는 실제 자동차 페인트의 게임 내 외관을 전례 없는 정확도로 일치시켰습니다. 물리적 기반 보정: 'Forza Horizon 4'의 새로운 접근 방식의 정확한 재료 생산은 컴퓨터 그래픽의 주요 과제를 극복하고 자동차 산업의 색상 관리 기술에서 영감을 얻었으며 다양한 렌더링 시스템의 다양한 재료 표현에 쉽게 적용될 수 있습니다. 분광광도법 및 비색법에 대한 이전 연구를 기반으로 하는 새로운 보정 방법은 재료 재현에서 가장 체계적인 오류를 과학적으로 제거하고 현실 세계에서 "실제" 재료의 모양을 정확하게 복제하는 최상의 셰이딩 모델 입력을 안정적으로 찾습니다. 새로운 물리 기반 보정 기술은 획기적인 발전으로 간주되며 가상 환경에서 재료를 정확하게 복제하는 미래에 중요한 영향을 미칩니다.
자동차 페인트는 "보이지 않습니다":

기사는 인식 기반 접근 방식에서 물리적 기반 접근 방식으로 변경됩니다.

실제 측정과 게임 내 측정 비교:

반사 분포에 관한 모든 것, 반사 분포를 일치시키고 재질을 일치시킬 수 있습니다. 사과 대 사과 – 정량적 색상 분석:

"Digital Masters" XML을 사용하여 SPD를 추정합니다.

ASTM E 308 표준: SPD(분광 전력 분포)부터 색상 정보, SPD --> XYZ까지:

SPD에서 XYZ 색상으로:

메타메리즘:

XTZ에서 연구실까지:

Lab 및 sRGB 색상 공간 비교:

게임 측정부터 실험실까지:

교정 파이프라인:

구형과 신형의 비교:


새로운 렌더링:

Marvel’s Spider-Man을 위한 맨해튼 절차적 제작에서는 Spider-Man 게임에서 맨해튼 장면을 절차적으로 제작하는 기술을 설명합니다.
스파이더맨의 장면은 6km x 3km, 9개의 구역, 544개의 도로, 1202개의 골목, 8300개의 건물, 3250개의 건물 조립식, 350개의 상점, 3000명의 범죄자, 3000개의 에피소드로 스토리, 작업, 영웅, 악당 등을 포함합니다. 절차적 시스템 계획: 도로 및 골목 정의, 지상 개조, 타일 및 ID, 표면, 지상 세부 정보, 건물, 등등

또한 장면에는 수많은 개체, 특수 효과 및 기술이 포함되어 있습니다.

프로그래밍된 시스템 파이프라인 통합:

대부분의 콘텐츠를 절차적으로 생성합니다.

전통적인 수동 처리:

한눈에 보는 효과:

Red Dead Redemption 2의 분위기 있는 세계 만들기: 완벽하고 통합된 솔루션에서는 Rockstar의 Red Dead Redemption 2 게임에 구름/안개 렌더링, 체적 효과, 하늘의 간접 조명을 나타내는 주변 조명 모델 등의 하늘 렌더링 기술을 소개합니다. 이 기술 모음은 팀이 Red Dead Redemption 2의 오픈 월드에서 어떻게 자연스러운 분위기를 조성하고 있는지를 보여줍니다. 이러한 기술은 물리학과 빛 전달의 법칙을 모두 준수하도록 고안되고 설계되었으며, 중요한 것은 강력한 즉각성 수단을 제공하여 아티스트가 자연 환경을 신중하게 설계하여 항상 게임의 스토리, 임무 및 분위기를 지원하고 향상시키는 강력한 분위기를 만들 수 있도록 한다는 것입니다.

안개 볼륨, 주변 조명, 무지개 렌더링, 지역 조명, 번개 등이 지형 처리에 사용됩니다. 광산란에 대한 개요는 다음과 같습니다.

산란 과정에는 프러스텀 복셀 그리드, 그림자 볼륨, 재료 볼륨, 산란광 볼륨, 프러스텀 볼륨 및 빛 행진과 같은 기술이 사용됩니다.

재료량.
Replays를 세계로 가져오세요. of Tanks: Mercenaries에서는 시간과 공간의 흐름에 대한 기존 게임 엔진 가정이 더 이상 유지되지 않을 때 클라이언트 측 문제에 대한 아키텍처 솔루션을 포함하여 서버 측 게임 녹화 및 재생을 활성화하는 데 필요한 인프라에 대한 개요를 제공합니다. WoT는 프레임 업데이트를 다음 부분과 경로로 분할합니다.

그리고 객체 이동에는 보간이 사용됩니다.

또한 이 기사에서는 구현 프로세스의 많은 문제에 대한 안정적이고 효과적인 솔루션을 제시합니다. 재생 시스템에 관심이 있는 아동용 신발은 원본 기사를 클릭하여 자세히 읽어볼 수 있습니다.
2014년 초, Frostbite 팀은 쿼드 기반 Bioware 캐릭터 모델을 위한 자체 LOD 기술 개발을 시작했습니다. 오늘날 이 기술은 전장에서 식물 및 좀비에 이르기까지 전자 예술 분야의 스튜디오에서 사용되는 도구를 강화합니다. 쿼드 기반 모델은 업계에서 널리 사용되며 아티스트는 토폴로지 및 에지 흐름에 큰 관심을 기울입니다. 그러나 사변형 메시의 단순화는 문헌에서 덜 연구되었습니다. 널리 사용되는 LOD 도구는 토폴로지를 무시하고 메시를 삼각측량합니다. LOD는 일회성으로 간주되는 경우도 있지만 토폴로지를 양호하게 유지하면 후속 수동 편집, 조명 및 애니메이션이 쉬워집니다. 이러한 이유로 Bioware는 역사적으로 각 모델에 대한 캐릭터 LOD를 제작하는 데 며칠을 보냈습니다. 이러한 노력의 목표는 대부분의 경우 아티스트가 만든 모델처럼 보이는 LOD를 절차적으로 생성하여 게임당 수십만 달러를 절약하는 것입니다. Frostbite의 쿼드 메시 단순화에서는 위 목표를 달성하는 방법을 설명합니다.
Garland와 Heckbert 2차 오류 측정법을 사용한 가장자리 접기 연산자의 전후 비교:

복합 문자열 접기만 사용한 LOD 결과:

브러시를 사용하여 정점의 우선 순위를 변경할 수 있습니다. 다음 그림은 우선순위와 해당 LOD 비교 효과를 시각화한 것입니다.

하위 복합 코드 접기를 사용한 LOD 결과:

우선순위 도면은 대칭을 무시할 수 있습니다.

대칭 하위 복합 코드 접기를 사용한 LOD 결과:

Lima Oscar Delta!: 'Call of Duty: Modern Warfare'의 콘텐츠 스케일링은 COD의 오프라인 LOD 처리, 모델 패키징, 런타임 LOD 처리, 월드 프록시 LOD 및 기타 기술을 공유합니다. LOD 오프라인 처리의 첫 번째 부분: 일반적인 지오메트리 축소를 위한 솔루션("쉬운 부분"이라고도 함) 찾기, 두 번째 부분은 그 밖의 모든 것입니다.

몇 개의 LOD 레벨이 필요합니까? 최대 5개의 추가 개별 항목을 지원하는 것은 모든 모델에 대해 모든 슬롯을 사용하는 것은 낭비입니다.

감소 대상은 버텍스, 삼각형, 정규 분산, 윤곽선 보존, 흐름 중요도 가중치 등입니다. 언제 LOD를 전환해야 합니까? 모델은 게임에서 어떻게 사용되나요? 영웅, 간단한 소품, 가장자리, 뷰 모델, 구조 등. 충돌체는 렌더링 LOD 또는 기타 콘텐츠와 일치해야 합니다. LOD 수, 감소 목표, 전환 거리, 게임 컨텍스트, 충돌 등을 최대한 최적화합니다. 첫 번째 시도: 모든 것을 자동화하세요! 1. 기하학적 편차가 특정 임계값을 초과할 때까지 메쉬를 줄입니다.

- 특정 픽셀 수의 스위칭 거리를 소비하는 임계값을 계산합니다.

- 생성된 스위칭 거리가 이전 스위칭 거리에 "너무 가까운" LOD를 건너뜁니다.

- 생성된 스위칭 거리에서 LOD가 "너무 작아"질 때까지 이 작업을 반복합니다.

위의 첫 번째 구현은 (프로그래머에게) 의미가 있고 결정론적인 성능과 시각적 효과를 제공하며 아티스트에게는 완전히 둔감합니다.
두 번째 시도: 혼합 솔루션. 자동으로 생성된 LOD 설정을 유지하되 편의를 위해서만 사용하세요. 원하는 경우 아티스트가 거의 모든 것을 다룰 수 있습니다. 1. DCC 도구에서 일부 모델 형상을 내보냅니다. 2. 자산 관리 도구에서 새 모델 자산을 생성합니다. 3. "기술적으로 이상적인" LOD 번호, 전환 거리 등을 생성하기 위해 백그라운드 프로세스를 시작합니다. 4. 이러한 값을 사용하여 자산 관리 도구에 GUI 양식을 포함합니다. 5. 아티스트가 보는 것이 마음에 들면 더 이상 할 일이 없습니다. 그렇지 않으면 필요에 따라 미세 조정할 수 있습니다.

두 번째 시도 하이브리드 솔루션은 주어진 실행의 효율성을 평가하는 데 도움이 되는 직관적인 시각적 피드백을 제공합니다.

LOD 패키징: LOD를 별도의 스트리밍 가능한 청크로 분할합니다.

객체 공간 위치의 정량화:

강체 애니메이션의 표면을 부드러운 스킨으로 업그레이드하고 병합된 형상과 재질을 집계합니다.
(다이어그램 - 원본 이미지 404 소실)
LOD가 실행 중일 때 LOD 선택 기준: 생성 전환 거리, 개략도는 다음과 같습니다.

LOD 선택 기준: FOV 변경. 수직 시야를 사용하면 디스플레이 종횡비(4:3, 16:9, 16:10, ...)에 관계없이 동일한 결과가 보장됩니다.

LOD 선택 기준: 장면 해상도 스케일링. 런타임 시 한 번 계산됩니다(defaultFOV=65.0, defaultScreenHeight=1080.0).


궁극적으로 LOD 선택 기준에는 창의적인 전환 거리, FOV, 장면 해상도, 버텍스 처리 효율성, 일반 GPU 성능, 예산 기반 오프셋 및 기타 요소가 포함됩니다. 계산식은 다음과 같습니다.
또한 작은 객체 거부, 모션 프로그래밍, 정적 모델을 최대한 공평하게 유지, 스트리밍 로딩과 같은 요소도 고려할 수 있습니다.
에이전트 LOD의 "Warzone" 개요: 200명의 플레이어, 지상 및 공중 기계, 대부분의 10v10 맵 영역의 120배이지만 밀도는 동일하고 시야가 깁니다. 프록시 LOD는 월드 메시 셀의 단일 모델을 나타내며 해당 셀에 있는 모든 정적 지오메트리 구성 요소를 다시 분할한 것입니다. 자동화된 FTW 사용:

입력: 1000가지의 독특한 모델, 다른 세계의 기하학과 창조물, 수천만 개의 삼각형! 출력: 월드 셀의 중거리 및 장거리 버전을 나타내는 각각의 재질이 포함된 한 쌍의 모델입니다. LOD 프록싱의 어려움: 재료 모델 일치, 건물 내부 처리, 투명한 표면, 나무, 큰 개체, 작은 개체, 큰 개체를 구성하는 작은 개체, 캐싱, 새 하드웨어(+사양).
요약하자면, 런타임 시각적 목표와 성능 목표 사이의 적절한 균형을 유지하는 기하학적 콘텐츠를 생성하려면 강력한 도구 세트가 필수적입니다. 이러한 도구의 핵심 동작은 효율성뿐만 아니라 움직이는 대상을 사용하여 작업하고 있지 않다는 점을 아티스트에게 확신시키기 위해 조기에 해결되어야 합니다. 이러한 도구는 아티스트에게 강제하기보다는 실행 가능한 피드백을 제공해야 합니다. 최적의 런타임 지오메트리 LOD 선택은 카메라와의 거리뿐만 아니라 다양한 동적 기준을 기반으로 해야 합니다. 대규모 월드 LOD에는 균형을 맞춰야 하는 다양한 요구 사항이 있습니다. 월드 LODing에 대한 모든 입력은 미세 조정되므로 이 프로세스를 (거의) 완전히 자동화하는 것이 바람직합니다.
협동적인 캐릭터 행동을 만드는 것은 모든 규모의 스튜디오에서 매우 어렵고 비용이 많이 듭니다. 심층 강화 학습은 개발자가 원하는 목표를 명확하게 표현하고 기계가 최적의 동작을 학습하여 잠재적으로 게임 개발의 경제성에 영향을 미칠 수 있기 때문에 훌륭한 접근 방식입니다. 그러나 대부분의 DRL 알고리즘은 단일 행위자의 작업을 해결하도록 설계되어 있으므로 행위자 간의 협업이 없습니다. 그러나 게임에서 공동 캐릭터 행동을 생성하는 데 사용할 수 있는 중앙 집중식 평가와 같은 공동 DRL 도구에는 새로운 발전이 있습니다. 심층 강화 학습을 사용하여 협력적인 캐릭터 행동 생성 Vincent는 이러한 주제를 검토하고 심층 강화 학습을 사용하여 게임에서 협력적인 캐릭터를 생성하는 한 스튜디오의 실제 사례를 설명합니다.
캐릭터들의 협동적 행동은 늘 어려운 문제였습니다. 행동의 복잡성, 캐릭터의 수, 캐릭터 간의 협력 정도가 증가합니다.

기존 AI와 딥러닝 AI 비교:

심층 강화 학습:

집중 학습: 집중 학습을 통해 캐릭터는 자신뿐만 아니라 팀원의 상태와 행동에 가치를 부여할 수 있습니다.

동기식 의사결정과 비동기식 의사결정:

에이전트 j의 이점 계산:

서쪽에서 불어오는 바람: 'Ghost of Tsushima'의 바람 시뮬레이션은 Ghost of Tsushima 게임에 사용된 바람 시뮬레이션을 공유합니다. 바람 시뮬레이션 모델에는 벡터 + 소음 + 와류 + 변위가 포함되며, 와류 시뮬레이션 프로세스는 다음과 같습니다.

바람은 입자, 나뭇잎, 풀, 천 및 기타 물체와 상호 작용할 수 있습니다. 잔디 시뮬레이션 과정은 다음과 같습니다.

바람과 천의 상호작용 과정은 다음과 같다.


FidelityFX 초해상도(FSR)는 AMD의 고화질 초해상도 기술을 보여줍니다.
EASU(Edge Adaptive Spatial Upsampling)는 FSR 1.0의 업샘플링 알고리즘입니다. EASU는 CAS+ 하드웨어 스케일링보다 더 나은 스케일링, 품질 개선, 셰이더 스케일링으로 인한 더 높은 비용을 제공하는 것을 목표로 합니다. 스캔 출력의 하드웨어 스케일링은 수평 및 수직 Lanczos와 시각적으로 일치합니다. EASU는 국소 적응형 Lanczos형 타원형 필터입니다. 방향 적응성으로 인해 EASU에서는 입력에 우수한 앤티앨리어싱 기능이 필요합니다. EASU 알고리즘: 고정 12탭 커널 창 사용, 12탭 = 양호한 상한, 단일 채널 알고리즘(방사형/타원형 필터링), 12탭 * 3채널 = 36 VGPR(FP32), 64 VGPR(양호한 상한) - 36 = 로직용 28 VGPR, 알고리즘은 분석 및 필터링을 위해 12탭 모두 필요합니다. 루마(r+2g+b)에서 내부 2x2 쿼드의 각 "+" 패턴을 분석합니다.

분석은 이중선형 보간이며 최종 필터 커널을 형성하는 데 사용됩니다.

EASU 샘플링: Vega/Navi/Xbox Series S |

EASU 분석: 중심 차이를 기반으로 모서리 방향을 추정하고, 기울기 반전 정도를 점수로 계산하여 피처 길이를 추정합니다.

EASU 대 색상 공간: 대부분의 콘솔은 가장자리에서 지각적으로 균일한 그라데이션으로 끝나므로 방향 분석은 게임의 지각 공간에서 더 잘 작동합니다. 선형에서 지각으로의 변환은 비용이 많이 들고 12개의 탭이 필요하기 때문에 지각 공간에서 EASU를 실행하는 것이 좋습니다.
EASU 커널 형성: 보간 후 분석은 {방향, 길이}, {축 정렬-대각선} 방향의 {1.0에서 sqrt(2.0)} X 스케일링, {작은 피처 길이에서 큰 피처 길이}의 {1.0에서 2.0} Y 스케일링을 산출합니다.
EASU 커널: Lanczos에 다항식 근사를 사용하고 기본*창을 사용하여 최적화된 근사를 사용합니다.

EASU 디링잉: 로컬 2x2 텍셀 쿼드{min, max}는 EASU 출력을 고정하고 모든 링잉을 제거하며 12탭 제한 창의 일부 결함 또는 커널 적응의 일부 결함을 제거하는 데 사용됩니다. Unity의 HDRP 포스트 프로세싱 파이프라인은 다음과 같습니다.

Unity에 통합되면 EASU는 래스터라이제이션 중에 색상, 깊이, 모션 벡터 및 법선을 출력한 후 즉시 스케일링을 적용합니다.

Unity에는 앨리어싱을 처리하는 두 가지 방법이 있습니다. 즉, 메모리 섹션을 살펴보고 다른 해상도로 래스터라이제이션할 수 있습니다. 첫 번째는 소프트웨어 기반으로 dx11, dx12, Vulkan, Metal 및 GNM과 같은 렌더링 플랫폼에 적합하며 기본적으로 HDRP에서 모든 기능을 지원합니다. 두 번째는 하드웨어 기반이며 리소스 설명자에 대한 직접 액세스, 텍스처/리소스 중첩과 같은 고급 기능을 포함하는 렌더링 API의 하위 집합을 처리합니다.

소프트웨어 기반 응용 프로그램의 경우 이 기술은 매우 간단합니다. 샘플링 중에 x 및 y 축에 스케일링을 적용하고 샘플링된 텍스처의 UV만 스케일링하면 경계가 처리됩니다. 래스터라이제이션의 경우 소프트웨어에서 수행하는 작업은 최종 대상 크기의 하위 집합인 뷰포트를 설정하는 것입니다. Unity에서는 렌더 그래프에 이러한 설정이 있습니다. 렌더 그래프에서는 일반적으로 소프트웨어 스케일링을 사용하여 가상 뷰 또는 소프트웨어 뷰를 생성하는 렌더 타겟에 있는 모든 카메라의 최대 해상도인 렌더 타겟을 유지합니다.

소프트웨어 DRS에서 섹션을 샘플링하기 위해 텍스처 샘플러를 사용할 때 UV를 고정해야 합니다.
float2 borderUv(float2 uv, float2 texelSize, float2 scale)
{
// texelSize = 1.0/resolution.xy
float2 maxCoord = 1.0f - 0.5f * texelSize.xy;
return min(uv, maxCoord) * scale;
}
float2 borderUvOptimized(float2 uv)
{
//innerFactor => 1.0f / (1.0f - 0.5f*texelSize.xy)
//outerFactor=> scale * (1.0f - 0.5f*texelSize.xy)
return saturate(uv * innerFactor) * outerFactor;
}하드웨어 기반 톱니파의 경우 수행되는 작업이 약간 다릅니다. Unity의 C++ 측에는 배치된 리소스가 기본적으로 할당되는 매우 큰 힙이 있습니다. 현재 필요한 솔루션에 따라 이러한 리소스를 요청 시 힙에 배치하기 시작하면 중복이 발생합니다. 이 접근 방식의 유일한 까다로운 점은 승수나 뷰포트를 사용할 필요가 없고 실제로 하드웨어 수준에서 기본 해상도를 처리할 필요가 없기 때문에 소프트웨어 기반 접근 방식보다 훨씬 빠르다는 것입니다. 그러나 문제는 발생하는 모든 솔루션에 대해 설명자가 생성되고 CPU 구현에서 이러한 설명자가 재활용되고 메모리가 부풀어오르고 CPU 성능 비용이 발생하지 않도록 매우 주의해야 한다는 것입니다.

효과 체인의 경우, 당신이 해야 할 일은 블룸 이후, 톤매핑 이후에 나오는 모든 것인 우버 포스트 프로세스를 시작하는 것입니다. 렌더 대상에 대해 제곱근을 수행하므로 출력은 공간 인식 색 공간이라고 할 수 있는 제곱근 공간이 되며, 이는 색 공간을 소비하고 업샘플러를 적용하는 EASU 알고리즘으로 들어갑니다. 업샘플러에서 출력한 후 선형 공간으로 돌아가도록 확인한 다음 RCAS 알고리즘을 적용하여 이전에 손실되었을 수 있는 가장자리와 디테일을 개선합니다.

효과 비교:

EASU 런타임 소비: EASU 및 RCAS(PS4로 이식 가능)용 FP32 경로, EASU용 0.43ms 격리 타이밍, RCAS용 0.16ms 격리 타이밍을 사용하는 PS4 Pro의 4k 출력 해상도에서 Unity Spaceship 데모.
14.5.4 렌더링 기술
14.5.4.1 가시성 버퍼
4K 렌더링 혁신: 필터링 및 선별 가시성 버퍼는 가장 일반적인 해상도를 사용하는 기존 렌더링 시스템보다 훨씬 더 나은 성능을 발휘하는 필터링 및 선별 가시성 버퍼라는 새로운 렌더링 시스템을 도입합니다. G-버퍼에 데이터를 저장하는 대신 가시성 버퍼에 삼각형 데이터를 저장합니다. 이는 화면 해상도가 크게 증가함에 따라 증가합니다. 이 버퍼에 저장된 삼각형의 수량과 품질을 최적화하기 위해 전처리 단계에서 삼각형 필터링 및 컬링이 적용됩니다. 또한 삼각형 및 컬링 전처리 단계에서는 섀도우 맵 렌더링과 같은 다른 모든 읽기 뷰를 준비합니다.
포워드 렌더링은 삼각형 제출 순서에 따라 모든 조각을 음영 처리하여 최종 이미지에 기여하지 않는 픽셀에 대한 렌더링 성능을 낭비합니다. 디퍼드 렌더링은 두 단계로 이 문제를 해결합니다. 첫째, 표면 속성이 화면 버퍼 -> G 버퍼에 저장되고, 둘째, 셰이딩은 보이는 조각에 대해서만 계산됩니다. 그러나 디퍼드 렌더링은 화면 버퍼(노멀, 깊이, 알베도, 재질 ID 등)에 대한 메모리 대역폭 소비를 증가시킵니다. G 버퍼 크기는 고해상도에서 어려워집니다. 다음 그림은 다양한 세대의 디퍼드 렌더링 및 가시성 버퍼를 비교한 것입니다.



다음은 가시성 버퍼와 GBuffer의 메모리 소비를 비교한 것입니다.




VisibilityBuffer 채우기 단계:
가시성 버퍼 생성 단계.
화면의 각 픽셀에 대해:
(알파 마스크 비트, drawID, 원시 ID)를 32비트 UINT로 압축합니다.
화면 크기의 버퍼에 씁니다.
튜플(알파 마스크 비트, drawID, 원시 ID)을 사용하면 셰이더가 셰이딩 단계 동안 삼각형 데이터에 액세스할 수 있습니다.
VisibilityBuffer 색상 지정 단계:
- 화면 공간의 각 픽셀에 대해 다음을 수행합니다.
drawID/triangleID 픽셀 위치를 가져옵니다.
VB에서 3개의 버텍스 데이터를 로드합니다.
삼각형 그라디언트를 계산합니다.
그래디언트를 사용하여 픽셀 포인트의 버텍스 어트리뷰트을 보간합니다(삼각형/객체 공간 조명 가능).
속성은 w를 사용하여 위치에서 올바르게 보간된 원근을 계산합니다.
해당 포지션에는 MVP 매트릭스가 적용됩니다.
모든 데이터가 이미 준비되어 있습니다: 최종 색상을 채색하고 계산합니다.
VisibilityBuffer의 장점: 가시성과 셰이딩의 더 나은 분리, 파생 계산은 셰이딩 단계와 별도로 수행될 수 있으며(현재 단계에 포함), 다양한 주파수 또는 품질로 셰이딩될 수 있습니다. 메모리 효율성 향상, 캐시 활용도 향상, 메모리 액세스 일관성(높은 캐시 적중률), G 버퍼는 각 화면 공간 픽셀에 대한 데이터를 저장해야 하며 그 중 일부는 버텍스/인덱스 버퍼에 비해 중복되며 텍스처, 버텍스 및 인덱스 버퍼에 대한 가시성 버퍼의 99% L2 캐시 적중률을 볼 수 있습니다. PBR과 같은 복잡한 조명 모델의 경우 g-버퍼에 비해 더 적은 데이터가 저장됩니다. 가시성 버퍼에 대한 PBR 데이터는 버텍스 구조의 재질 ID로 인덱싱된 구조 상수 메모리입니다. 이 구조는 다양한 PBR 텍스처의 텍스처 배열에 인덱스를 저장합니다. 또한 BRDF를 구동하는 데 필요한 자료 설명도 포함되어 있습니다. 픽셀당 변경되는 모든 데이터는 구조에서 참조하는 텍스처에 저장됩니다. 화면 해상도에서 버퍼 공간을 분리하여 고해상도(2K, 4K, MSAA)에서 성능을 향상시킵니다. 대역폭이 제한된 플랫폼에서 성능을 향상시킵니다.
조명을 수행하는 방법? 선호하는 조명 구조(지연된 타일, 앞으로 타일 등)를 선택할 수 있습니다. Forward Blocking 또는 Forward++는 컬링, 필터링 및 가시성 검사를 통해 감소된 버텍스 수의 이점을 누리고 불투명하고 투명한 개체에 일관된 조명을 제공하므로 자연스럽게 일치하는 것처럼 보입니다. 삼각형이나 물체 공간의 조명도 가능합니다.
게임의 다각형 복잡성은 매년 증가하므로 삼각형을 효과적으로 제거하는 것이 중요합니다. 2개의 컬링 단계: 1. 클러스터 컬링: 삼각형 그룹을 GPU로 보내기 전에 컬링합니다. 2. 삼각형 필터링: 개별 삼각형을 GPU로 보낸 후 선별합니다.
클러스터링 컬링: 삼각형은 방향이 비슷한 256개 삼각형의 작은 패치로 그룹화됩니다. 패치에는 연관된 모델 매트릭스가 있습니다(이동 가능). 각 패치는 GPU로 전송되기 전에 빠른 가시성 테스트인 콘 테스트를 통과해야 합니다.

빠른 클러스터링 컬링을 위한 콘 테스트. 눈이 안전 영역에 있으면 삼각형이 다른 쪽을 향하고 있기 때문에 삼각형을 볼 수 없습니다.

구체적인 과정과 분석은 다음과 같습니다.

1: 클러스터의 중심을 찾습니다.
2: 클러스터 중심에서 시작하여 음의 방향으로 정규값을 누적합니다.
3: 첫 번째 정상값 이후에 두 번째 정상값을 음수로 누적합니다.
4: 다음 것을 축적합니다.
5: 마지막 볼륨을 누적한 후 제외된 볼륨의 시작점과 방향을 얻습니다.
다음으로, 다음 그림과 결합하면 원뿔의 개방 각도와 계산된 제외 부피를 계산하는 데 사용되는 가장 엄격한 삼각형 평면입니다.

클러스터링 제거 효율성: 효율성은 클러스터의 면 방향에 따라 달라집니다. 방향이 유사할수록 제외/제거 볼륨이 커집니다. 삼각형을 기준으로 제외된 볼륨을 계산할 수 없으며 클러스터링 제거에 사용된 클러스터링이 유효하지 않으므로 건너뛰어야 합니다.

계산 기반 삼각형 필터링: 그래픽 파이프라인 실행 중에 비동기 계산을 사용하여 삼각형이 그래픽 파이프라인에 들어가기 전에 삼각형을 추출하는 것이 동기입니다. 계산 기반 필터링, 스레드당 하나의 삼각형, 퇴화된 삼각형 컬링, 뒷면 컬링, 프러스텀 컬링, 작은 기본 컬링, 깊이 컬링(거친 깊이 버퍼 필요)을 포함하는 필터링된 삼각형, 이러한 테스트를 통과하는 삼각형 인덱스가 인덱스 버퍼에 추가됩니다. 계산된 삼각형 필터링:
- 퇴화된 삼각형 컬링. 보이지 않는 영역이 없는 삼각형을 컬링할 수 있습니다. 비용: 빠른 테스트(최소 두 개의 삼각형 지수가 동일하면 포기), 효율성: 낮음.
cull = (indices[0] == indices[1] || indices[1] == indices[2] || indices[0] == indices[2] );뒷면 컬링. 테셀레이션을 사용하는 경우 뷰어에서 멀리 떨어져 있는 삼각형을 컬링할 수 있습니다. 최대 패치 높이를 고려해야 합니다. 비용: 3x3 행렬의 행렬식을 계산합니다. 효과: 높음(기하학의 50%가 제거될 수 있음)
프러스텀 컬링을 봅니다. 근거리 및 원거리 평면을 고려하여 클리핑 큐브 외부에 투영된 삼각형을 컬링할 수 있습니다. 비용: 모든 정점이 클립 공간 큐브의 음수 쪽에 있는지 확인합니다. 효과: 중간-높음(장면 크기와 눈 위치에 따라 다름).
작은 기본 요소가 제거됩니다. 너무 작아서 보이지 않는 삼각형은 제거할 수 있고, 투영 후 샘플링 지점에 닿지 않는 삼각형, 샘플에 닿지 않는 가는 삼각형도 제거되어 하드웨어 리소스를 보다 효율적으로 사용합니다. 비용: 삼각형이 모든 하위 픽셀 샘플에 닿습니다. 효과: 중간(삼각형 크기 및 화면 해상도에 따라 다름)

- 딥 컬링. 장면에 의해 가려진 삼각형을 컬링할 수 있습니다. 이 테스트에는 대략적인 깊이 버퍼가 필요합니다. 비용: 지도 및 확인 삼각형/BB 교차점에서 깊이 값을 로드합니다. 효과: 중간-높음(장면 복잡도 및 삼각형 크기에 따라 다름)

계산 기반 삼각형 필터링의 개요는 다음과 같습니다.

삼각형 필터링은 256개의 삼각형 그룹(배치)에서 수행됩니다. -> 빈 그리기, 그리기 일괄 압축이 구출되고 컴퓨팅 셰이더에서 병렬로 실행될 수 있으며 빈 그리기는 다중 간접 그리기 버퍼에서 제거됩니다.

삼각형/클러스터 필터링을 위한 프레임 단계를 추가합니다.
[CPU] 클러스터 컬링을 사용하여 보이지 않는 형상을 조기에 폐기합니다.
[CS] 삼각형 필터링(스레드당 하나의 삼각형)을 사용하여 검열되지 않은 인덱스 및 다중 그리기 간접 버퍼를 생성합니다.
이전과 같이 실행합니다.
삼각형/클러스터링 필터링을 위한 데이터 관리 추가: 이 정적 장면의 경우 삼각형 컬링 및 필터링을 통해 생성된 대규모 버텍스 버퍼와 인덱스 버퍼입니다. 배치 그리기, 각 배치는 하나의 재료에 대한 형상 조각을 저장합니다. 두 개의 "재료" 불투명 및 알파 마스크 투명 개체와 기타 재료만 동일한 버퍼에 저장됩니다. 동적 개체의 경우 각 개체에 전용 VB/IB 쌍이 사용됩니다. 선택 과목.
컴퓨팅 기반 삼각형 필터링의 이점: 삼각형을 그래픽 파이프라인으로 보내기 전에 컬링을 허용하고, 그래픽 파이프라인(래스터라이저)의 압도적인 부분을 차지하는 것을 방지하며, 그래픽 파이프라인이 표시되는 삼각형(래스터라이제이션 효율성, 명령 프로세서 등)을 더 잘 활용할 수 있고, 그래픽 파이프라인과 겹치는 비동기 계산을 활용할 수 있습니다.
삼각형 필터 결과는 여러 보기/렌더링 패스에 재사용될 수 있습니다. 인덱스/정점을 한 번 로드하고 각 뷰의 정점을 변환하여 다양한 N 보기에서 테스트하도록 알고리즘을 일반화합니다.

재사용을 위해 삼각형 필터 데이터를 추가하는 단계:
[CPU] 어떤 뷰에서도 보이지 않는 지오메트리를 조기에 삭제하려면 클러스터링 컬링을 사용하세요.
[CS] N개의 뷰에서 삼각형 필터링을 사용한 테스트는 N개의 인덱스와 N개의 다중 그리기 간접 버퍼(스레드당 하나의 삼각형)를 생성합니다.
내가 사용하는 각 뷰에 대해(i번째 인덱스 버퍼와 i번째 MDI 버퍼):
[Gfx] 가시성 및 깊이 버퍼가 명확해졌습니다.
[VS, PS] 가시성 버퍼 채널, [PS] 출력 삼각형/인스턴스 ID.
[PS] 그라디언트 및 음영 처리된 픽셀의 속성을 보간합니다.
결과:



요약:

가상 현실은 어떻습니까? 기아 문제가 해결되고 있으며 매우 높은 해상도로 넓은 시야를 표시할 수 있으며 가시성 버퍼는 성능을 크게 향상시킵니다. 모든 보기 및 섀도우 맵 보기에 대한 데이터 필터링 및 준비를 한 번에 수행할 수 있으며 포워드+가 제공되므로 투명성 문제를 처리할 필요가 없습니다.
요약하자면, 확립된 렌더링 시스템은 다양한 뷰(예: 메인 뷰, 섀도우 뷰, 반사 뷰, GI 뷰 등)에 대해 삼각형을 클러스터링하고 필터링하며, 최적화된 삼각형은 화면 공간 가시성 버퍼를 채우거나 더 많은 뷰를 위한 추가 가시성 버퍼를 채우는 데 사용됩니다. 그런 다음 가시성 기반의 최적화된 형상을 사용하여 조명, 그림자 및 반사광을 렌더링합니다. 형상의 가시성과 음영 빈도를 구별할 수 있습니다. 조명은 각 삼각형 또는 소위 물체 공간에서 계산될 수 있습니다.
14.5.4.2 필름 SMAA
Filmic SMAA: Sharp Morphological and Temporal Antialiasing은 블리자드에서 근무하는 안티앨리어싱의 창시자인 Jorge Jimenez가 발표하고 Filmic SMAA의 최신 성과에 대해 이야기했습니다.
SMAA의 목표는 선명도, 견고성 및 고성능입니다. 시간적 슈퍼샘플링(SMAA T2x), 공간적 멀티샘플링(SMAA S2x) 및 결합(SMAA 4x)을 추가하는 형태학적 안티앨리어싱(SMAA 1x)은 블리자드 게임에는 적용되지 않습니다. Filmic SMAA는 Filmic 필터링(Filmic 변형)입니다. Filmic SMAA 1x, Filmic SMAA T2x – PS4 및 XB1의 경우 시간 필터링 ≠ 시간 슈퍼샘플링입니다.
먼저 다음과 같은 형태학적 앤티앨리어싱의 기본 사항을 검토하세요. 아래 그림과 결합하여 먼저 선의 왼쪽과 오른쪽 끝을 검색한 다음 선 양쪽의 교차 모서리를 구합니다. 거리와 교차 모서리를 통해 재구성된 선 아래의 면적을 계산하는 데 충분한 정보가 있습니다.

형태적 앤티앨리어싱 개선에는 품질(형태적 가장자리 억제, 윤곽선 감지, U자형 스무딩) 및 성능(지연 대기열, LDS 사용, 양면 블렌딩)이 포함됩니다. 기사에서 논의된 품질 지식 포인트에는 국부 대비 가장자리 억제, 형태학적 가장자리 억제, 윤곽선 감지 및 U자형 평활화가 포함됩니다. 성능 지식 포인트에는 형태학적 다중 채널 방법, Compute를 사용하여 하나의 채널로 단순화, 픽셀 셰이더의 비효율성, 템플릿 제거의 비효율성, 지연 대기열, 반복 패턴 검색, SMAA의 CS 문제 해결 방법, LDS 사용, 이중선형 획득 및 디코딩 등이 포함됩니다.

로컬 에지 억제 범례. 오른쪽 이미지에 빨간색으로 표시된 것과 같이 특정 가장자리에 대해 가까운 가장자리를 확인하고 대비가 우세한 다른 가장자리가 발견되면 억제됩니다.

현재 에지를 통과하는 패턴(왼쪽)과 통과하지 않는 패턴(오른쪽)의 비교. 오른쪽의 방법은 어느 쪽이 더 높은 점수(강도)를 가지고 있는지 확인하고, 현재 엣지의 패턴으로 이기지 못하면 엣지를 억제합니다.

세 가지 기본 U자형 패턴입니다. 작은 U자형 패턴은 일시적으로 불안정하므로 이를 부드럽게 하거나 제거하려면 인식에 따라 조정할 수 있는 LUT를 사용하세요.

SMAA 형태학적 다중채널 방법.

지연 대기열 범례. 위: 감지된 가장자리가 추가/소비 버퍼에 추가되고, 버퍼를 사용하기 위해 간접 디스패치가 수행되어 모든 스레드가 실제 작업을 수행할 수 있습니다. 하단: 전체 화면 스텐실 버퍼를 읽지 마십시오. 경우에 따라 분산된 가장자리 분포로 인해 계층적 스텐실이 항상 최적이지는 않습니다. 우리는 유사한 접근 방식을 사용하도록 SMAA를 조정하여 성능을 크게 향상시키고 시간이 지남에 따라 작업을 수행했습니다.
또한 이 기사에서는 디더링, 샘플링 모드, 재투영, 속도 등과 같은 TAA의 기본 사항은 물론 분리 및 속도 가중치도 다룹니다. 불일치는 새 프레임의 픽셀이 이전 프레임에 존재하지 않았음을 의미합니다. 해결책은 속도 차이가 너무 크면 블렌딩하지 않는 것이며, 속도가 없는 픽셀에는 작동하지 않습니다(알파 블렌딩).

색상 정보는 속도 가중치와 함께 불일치에도 사용될 수 있습니다. 이는 현재 프레임과 이전 프레임을 비교할 수 없게 하지만 다른 지터로 인해 정적 이미지에서도 종종 거부됩니다. 해결책은 N 프레임을 N-2 프레임과 비교하고 속도 없이 개체의 고스팅을 줄이는 것입니다(알파 블렌딩).

지수 기록/지수 이동 평균: SMAA T2x 및 두 프레임(

지수 누적 버퍼를 활용할 수 있습니다.

다중 프레임 이동 평균 [Karis2004]과 유사하게 유효 하위 샘플 수 증가, 피드백 루프.

지수 누적 버퍼링 기술은 앨리어싱을 제거하기 위해 이웃 클램핑을 사용하는 경우가 많으며[Lottes2011] 기본 형식은 다음과 같습니다.

시간 지터와 함께 이 클램핑을 사용하면 깜박임이 발생할 수 있습니다.

이 경우 기하학이 매우 작은 점을 고려하면 두 번째 프레임에서는 사라지고 프레임 간에 색상의 인접 범위가 변경됩니다. 출력을 다르게 만들어 정적 이미지에 깜박이는 아티팩트를 생성합니다.

최근 속도: 지수 이력 평활화 및 앤티 앨리어싱, 새로운 프레임 속도 앨리어싱(재투영 시 앨리어싱 도입), 솔루션은 호수 지역 최전방 이웃 속도입니다[Karis2014].

TAA에 대한 지식 포인트에는 모양 이웃의 YCoCg 클리핑 [Karis2014], 소프트 이웃 클램핑 [Drobot2014], 고차 리샘플링 [Drobot2014], 분산 클리핑 [Salvi2016]이 포함됩니다.
이전에도 SMAA 1TX [Sousa2013], Unreal Engine 4 TAA [Karis2014], HRAA [Drobot2014] 등 관련 연구가 많이 있었습니다. 기사에서 제시된 핵심 사항은 시간적 필터링과 AA 디커플링입니다. 지수 히스토리를 사용하는 것은 하위 픽셀 디더링을 위한 슈퍼샘플링과 분리될 수 있는 프로세스입니다. 이제부터는 이미지를 일시적으로 필터링(또는 흐리게 하는) 임시 필터링이라고 합니다. 시간적 하위 픽셀 지터를 흐리게 하거나 평균화하는 결과, 움직이는 객체는 지터가 없더라도 각 프레임에서 자연스럽게 서로 다른 하위 샘플링 위치에 놓이게 된다고 생각할 수 있습니다. 움직이는 물체는 지터가 없어도 AA를 갖습니다. Filmic SMAA T2x와 SMAA T2x의 비교는 다음과 같습니다.
필름 SMAA T2xSMAA T2x
서브샘플링: 2x(선택적 대비 인식 Quincunx ~4x) 가장자리: 형태학 시간 필터링: 예 서브샘플: 2x 가장자리: 형태학 시간 필터링: 아니요
고스팅 감소소규모 성능 예산샤프 정지 이미지에서도 안정적 속도가 없는 물체에 고스트 현상 발생 정지 이미지에서도 안정적
기사에서 다루는 일시적인 앤티앨리어싱 개선 사항:
시간적 슈퍼샘플링과 시간적 필터링을 분리합니다.
시간 필터 선명도.
시공간 대비 추적.
FPS 기반 시간 도메인 필터링.
깊이 테스트를 통한 확장된 인접 클램핑.
시간적 오버샘플링 리샘플링이 개선되었습니다.
향상된 시간 Quincunx.
슈퍼샘플링된 파생상품.
색상 가중치가 개선되었습니다.
로우 프로파일 속도 버퍼.
최근 속도가 빨라졌습니다.
시간적 업샘플링.
Drobot2014의 단일 채널과 Filmic의 듀얼 채널 비교:

방법 및 효과 비교:

시간적 선명도를 위해 Bicubic Resampling이 사용되며 최적화된 Catmull Rom은 9개의 이중선형 샘플을 사용하여 4x4 영역을 처리합니다. 최종 해결책은 매우 유사한 결과를 산출하는 4개의 모서리를 무시하고 샘플 수를 9개에서 5개로 줄이는 것이었습니다. 다른 분야에서는 작은 수치 오류가 적용될 수 있습니다.

왼쪽: 원래의 바이큐빅; 오른쪽: 대략적인 방법이 5개 샘플로 축소되었습니다.

두 가지 방법 사이에 오류가 있습니다.
// 5의 샘플링메서드 shader코드
float3 SMAAFilterHistory(SMAATexture2D colorTex, float2 texcoord, float4 rtMetrics)
{
float2 position = rtMetrics.zw * texcoord;
float2 centerPosition = floor(position - 0.5) + 0.5;
float2 f = position - centerPosition;
float2 f2 = f * f;
float2 f3 = f * f2;
float c = SMAA_FILMIC_REPROJECTION_SHARPNESS / 100.0;
float2 w0 = -c * f3 + 2.0 * c * f2 - c * f;
float2 w1 = (2.0 - c) * f3 - (3.0 - c) * f2 + 1.0;
float2 w2 = -(2.0 - c) * f3 + (3.0 - 2.0 * c) * f2 + c * f;
float2 w3 = c * f3 - c * f2;
float2 w12 = w1 + w2;
float2 tc12 = rtMetrics.xy * (centerPosition + w2 / w12);
float3 centerColor = SMAASample(colorTex, float2(tc12.x, tc12.y)).rgb;
float2 tc0 = rtMetrics.xy * (centerPosition - 1.0);
float2 tc3 = rtMetrics.xy * (centerPosition + 2.0);
float4 color = float4(SMAASample(colorTex, float2(tc12.x, tc0.y )).rgb, 1.0) * (w12.x * w0.y ) +
float4(SMAASample(colorTex, float2(tc0.x, tc12.y)).rgb, 1.0) * (w0.x * w12.y) +
float4(centerColor, 1.0) * (w12.x * w12.y) +
float4(SMAASample(colorTex, float2(tc3.x, tc12.y)).rgb, 1.0) * (w3.x * w12.y) +
float4(SMAASample(colorTex, float2(tc12.x, tc3.y )).rgb, 1.0) * (w12.x * w3.y );
return color.rgb * rcp(color.a);
}향상된 임시 오버샘플링 리샘플링:

다양한 부드러운 곡선을 시도해보고 아래 그림의 윗줄 오른쪽 곡선이 S자 형태가 가장 강하기 때문에 선택했습니다. 다음으로 해야 할 일은 클램핑과 크기 조정을 사용하여 3차 평활화로 이를 근사화하는 것입니다. 이는 맨 아래 줄 오른쪽 그림입니다.

효과는 다음과 같습니다.

기사에서 Quincunx 샘플링이 개선되었습니다. 아래 그림과 결합하면 Quincunx의 정의는 다음과 같습니다.

그 중 주황색은 단일 샘플이고, 이중선형을 사용하면 파란색 샘플을 모두 얻을 수 있습니다. Quincunx는 텍스처 좌표 이동이 되며, 이는 2x와 동일한 성능을 갖습니다. 대비 인식 Quincunx의 아이디어: 로컬 대비에 따라 텍스처 좌표의 오프셋을 조정하고, 낮은 대비(텍스처 세부 사항)에 2x를 사용하고, 높은 대비(가장자리)에 Quincunx를 사용하고, 대비를 결정하기 위해 Quincunx 하위 샘플을 사용하고, 대비가 낮으면 2x 오프셋을 사용하여 다시 가져오고, 낮은 오버헤드: ~0.02ms PS4@1080입니다.

이 기사에는 또한 많은 기술적 개선 세부 사항과 비교 내용이 포함되어 있습니다. 관심 있는 어린이 신발에 대해서는 원본 기사를 클릭하여 읽을 수 있습니다. 간단히 말해서 Filmic SMAA T2x의 하이라이트는 뛰어난 선명도, 높은 견고성 및 고성능입니다.
14.5.4.3 높은 동적 범위 이미징
HDR(High Dynamic Range) 이미지와 비디오에는 기존 표준 동적 범위 이미지보다 더 넓은 범위의 색상과 밝기를 표현할 수 있는 픽셀이 포함되어 있습니다. 이 "더 나은 픽셀"은 시각적 콘텐츠의 전반적인 품질을 크게 향상시켜 시청자에게 더욱 현실적이고 매력적으로 보이게 합니다. HDR은 미래 이미징 파이프라인의 핵심 기술 중 하나이며 디지털 시각적 콘텐츠가 표현되고 조작되는 방식을 변화시킬 것입니다.
HDR(High Dynamic Range) 이미징은 HDR 방법 및 기술에 대한 광범위한 검토를 제공하고 HDR 이미지 인식의 기본 개념을 소개합니다. 또한 HDR 영상 기술의 현황을 검토합니다. 카메라로 HDR 콘텐츠를 캡처하고 컴퓨터 그래픽 방법으로 콘텐츠를 생성하는 것과 관련된 주제를 다룹니다. HDR 이미지 및 비디오의 인코딩 및 압축; 표준 동적 범위 디스플레이에 HDR 콘텐츠를 표시하기 위한 톤매핑; HDR 디스플레이에 표시하기 위해 기존 콘텐츠를 업스케일하는 데 사용되는 역톤매핑 HDR 범위를 제공하는 디스플레이 기술; 마지막으로 HDR 콘텐츠에 적합한 이미지 및 비디오 품질 지표입니다.

왼쪽 사진: 투명한 고체는 사람의 눈에 보이는 전체 색역을 나타냅니다. 낮은 밝기 수준에서는 색상 인식이 감소함에 따라 솔리드가 아래쪽으로 점차 기울어집니다. 비교의 용이성을 위해 내부의 빨간색 실선은 고품질 모니터에서 생성되는 표준 sRGB(Rec. 709) 색 영역을 나타냅니다. 오른쪽: CRT 및 LDR 모니터에 표시되는 밝기 범위와 비교한 실제 밝기 값입니다. 대부분의 디지털 콘텐츠는 일반적인 디스플레이의 동적 범위를 최대한 보존하는 형식으로 저장됩니다.
애플리케이션 관점에서 볼 때 HDR 이미지는 LDR보다 품질이 더 높은 경향이 있습니다. 아래 그림은 HDR과 LDR 시각적 콘텐츠 간의 잠재적인 차이를 보여줍니다. 아래 표에 제시된 수치는 단지 예시일 뿐이며 정확한 기준은 아닙니다.

JPEG2000, JPEG XR 또는 선택한 H.264 프로필과 같은 표준 높은 비트 심도 코덱을 사용하여 HDR 이미지 또는 비디오 콘텐츠를 인코딩합니다. HDR 픽셀은 색상 채널의 적절한 역상관과 인코딩된 값의 지각적 일관성을 보장하기 위해 하나의 루마 채널과 두 개의 크로마 채널로 인코딩되어야 합니다. 선택적으로 표준 압축을 확장하여 선명한 대비 가장자리를 더 효과적으로 인코딩할 수 있습니다.

아래 이미지는 HDR 압축과의 하위 호환성을 위한 일반적인 인코딩 방식입니다. 진한 갈색 상자는 H.264 또는 JPEG와 같은 비디오 코덱의 표준(일반적으로 8비트) 이미지를 나타냅니다.

순방향 비전 모델을 기반으로 한 톤매핑을 위한 일반적인 처리 파이프라인은 다음과 같습니다. 원시 이미지는 시각적 모델을 사용하여 추상적 표현으로 변환된 다음 디스플레이로 직접 전송됩니다.

순방향 및 역방향 비전 모델을 기반으로 한 톤매핑을 위한 일반적인 처리 파이프라인은 아래 그림에 나와 있습니다. 원시 이미지는 추상적 표현으로 변환되고, 선택적으로 전방 비전 모델을 사용하여 편집된 다음 후방 디스플레이 모델을 통해 물리적 이미지 영역으로 다시 변환됩니다.

톤매핑을 위한 일반적인 처리 파이프라인은 제한된 매핑 문제를 해결하고 기본 매개변수를 사용하여 이미지를 톤매핑한 다음 시각적 측정항목을 사용하여 표시된 이미지를 원본 HDR 이미지와 비교합니다. 그런 다음 메트릭의 스칼라 오류 값은 반복 최적화 루프에서 사용되어 최적의 톤매핑 매개변수를 찾습니다. 실제로 해는 종종 단순화되어 2차 계획법으로 공식화되거나 폐쇄형 해법을 갖기도 한다는 점에 유의하십시오.

HDR 디스플레이에서 저해상도 백라이트 변조기와 고해상도 전면 LCD 패널을 구동하는 데 필요한 이미지 처리 흐름은 다음과 같습니다.

HDR-VDP-2 메트릭의 처리 단계에서는 테스트 이미지와 참조 이미지가 유사한 시각적 모델링 단계를 거친 후 개별 공간 및 방향 선택 대역(BT 및 BR) 수준에서 비교됩니다. 이 차이는 가시성(감지 확률)이나 품질(인지된 왜곡 정도)을 예측하는 데 사용됩니다.

동적 범위 독립적 메트릭(상단)은 톤매핑된 사진(하단)에 대해 예측되며 녹색은 가시적 대비 손실을 나타내고 파란색은 보이지 않는 대비 증폭을 나타내고 빨간색은 대비 반전을 나타냅니다.

14.5.4.4 텍스처 스트리밍
'Titanfall 2'의 효율적인 텍스처 스트리밍은 Titanfall 2의 효율적인 텍스처 스트리밍 기술을 공유합니다. 텍스처 스트리밍은 동적으로 로드되어 이미지 품질을 향상시킵니다. 개념적으로는 압축의 한 형태입니다. 일반적인 방법에는 수동 분할, 경계 기하학 테스트 및 GPU 피드백이 포함됩니다. 워크플로 요구 사항은 디자인 및 아트의 수동 작업을 최소화하고, 아티스트는 텍스처를 자유롭게 매핑할 수 있고(고정 밀도 없음), 다른 텍스처를 손상시키지 않고 MIP를 추가할 수 있으며, 전처리가 안정적이어야 하고, 몇 가지 좋은 수동 힌트가 있어야 하며, 핫 스와핑을 포함하여 "자산 베이커리"와 함께 작업합니다.
알고리즘 개요: 64k 미만의 MIP는 영구적이며, 미리 계산된 정보를 사용하여 중요/중요하지 않은 콘텐츠 목록을 작성하여 MIP를 하나씩 추가/제거할 수 있으며 각 프레임은 이 목록에 대해 작동합니다.
"히스토그램"이란 무엇입니까? 단순히 "예/아니요"가 아닌 화면에서 처리하는 픽셀 수(적용 범위)를 기준으로 밉의 우선 순위를 지정하려는 경우 '히스토그램'은 머티리얼당 MIP당 적용 범위이며 16스칼라 '빈'(일반적으로 부동 소수점) - MIP당 하나입니다. 화면 해상도가 256 x 256인 4k x 4k 텍스처를 가정하고 해상도를 변환 및 크기 조정하고 모델을 이동합니다. 저밀도 텍스처 맵을 사용하여 작고 폐색되거나 뒷면을 향한 삼각형에 적절한 가중치를 부여합니다.
알고리즘 - 미리 계산됨: 각 재료에 대한 히스토그램을 계산하고, 정적 개체의 경우 GPU를 사용하여 세계의 각 열을 렌더링하고 파일에 넣습니다. 동적 개체의 경우 로드 시 각 모델: 각 삼각형의 텍스처 그라데이션을 계산하고 MIP의 히스토그램 영역에 삼각형 영역을 추가하며 다른 각도에서 프로젝트를 수행할 계획이지만 그럴 가치가 없으며 정적 데이터와 일치하도록 배율 인수를 수동으로 조정합니다.
각 프레임마다 무슨 일이 발생하나요? 디스크에서 플레이어의 "열"을 재생하고, 모델 적용 범위를 추가하고, 적용 범위를 텍셀 수로 나누고, "표시기"를 가져오고, 더 미세한 MIP의 계단식을 사용하여 가장 중요하고 가장 덜 중요한 MIP 목록을 생성합니다(거칠수록 >= 더 미세함). 가장 중요한 MIP를 로드하고, 가장 덜 중요한 MIP를 제거하고, 실행 횟수 및 프레임당 삭제되는 바이트 수의 상한을 캡처하고, 더 중요한 것을 로드하지 않는 한 항목을 삭제하지 마세요!
프로브를 선택하는 방법은 무엇입니까? "rstream.exe"를 실행하고, 모델을 인스턴스화하고, 경계를 계산하고, 위쪽 삼각형 위의 눈 높이에 프로브가 있는 16피트 x 16피트 열로 형상을 자르고, 팁 프로브를 추가하고(근처 열에서도 Z 사용), k-평균을 사용하여 열당 최대 8개의 프로브로 결합하고, 디버깅용으로 로그 파일에 프로브 위치를 저장합니다.
프로브를 렌더링하는 방법은 무엇입니까? 정적 형상 정보를 GPU에 한 번 업로드하고 N개 프로브의 UAV를 렌더링합니다.
float2 dx = ddx( interpolants.vTexCoord ) * STBSP_NOMINAL_TEX_RES; // STBSP_NOMINAL_TEX_RES is 4096.0
float2 dy = ddy( interpolants.vTexCoord ) * STBSP_NOMINAL_TEX_RES;
float d = max( dot( dx, dx ), dot( dy, dy ) );
// miplevel is log2 of sqrt of unclamped_d. (MATERIAL_HISTOGRAM_BIN_COUNT is 16.)
float mipLevel = floor( clamp( 0.5f * log2(d), 0.0f, (float)(MATERIAL_HISTOGRAM_BIN_COUNT - 1) ) );
InterlockedAdd( outHistogram[interpolants.vMaterialId * MATERIAL_HISTOGRAM_BIN_COUNT + (uint)mipLevel], 1 );큐브 면당 한 번 수행(누적 결과), 쓰기 깊이에 따라 불투명, 테스트만 투명, 프레임 버퍼 없음!
프로브 데이터 컴파일: 이제 각 자료에 대한 프로브에 각 MIP의 적용 범위가 있습니다. 각 열 내에서 최대 모드로 프로브를 결합하고, 자료 ID, MIP 수, 적용 범위(4바이트)를 기록하고, 열당 512개의 가장 중요한 레코드를 저장하고, 4x4 열을 약 32,000개의 스트리밍 가능한 페이지로 그룹화하고, 안정적인 전역 자료 ID 및 위치에 대한 색인을 생성하고, 각 레벨에 대해 하나의 '.stbsp' 파일을 생성합니다.
텍스처 리소스 관리: 각 압축(및 회전) 텍스처 파일에는 레벨에 대해 빠르게 로드되는 "rpak" 파일을 빌드할 때 두 번째 "starpak" 파일로 집계되는 "스트리밍 가능한" 조각이 있을 수 있습니다. 릴리스 빌드의 경우 공유 스타팩이 모든 레벨에서 사용되며 <64k MIP만 디스크에 복사되고 스타팩에는 정렬되고 로드할 준비가 된 데이터가 포함됩니다.
// Crediting World Textures
Compute column (x,y integer), Ensure active page is resident (cache 4 MRU), or request it.
totalBinBias = Log2(NOMINAL_SCREEN_RES * halfFovX / (NOMINAL_TEX_RES * viewWidthInPixels) )
For each material represented in column,
For each texture in that material
For each record (<material,bin,coverage>) in column (up to 16)
If texture->lastFrame != thisFrame,
texture->accum[0..15] = 0, and texture->lastFrame = thisFrame
mipForBinF = totalBinBias + record->bin + Log2(textureWidthInPixels)
mipForBint = floor( max( 0.0, mipForBucketF ) ), clamped to (16-1).
texture->accum[mipForBin] += record->coverage * renormFactorForStbspPage;
// Crediting Models
float distInUnits = sqrtf( Max( VectorDistSqr( pos, *pViewOrigin ), 1.0f ) );
if ( distInUnits >= CUTOFF ) continue;
float textureUnitsPerRepeat = STREAMINGTEXTUREMESHINFO_HISTOGRAM_BIN_0_CAP; // 0.5f
float unitsPerScreen = tanOfHalfFov * distInUnits;
float perspectiveScaleFactor = 1.0f / unitsPerScreen;
// This is the rate of pixels per texel that maps to the cap on bin 0 of the mesh info.
// ( Exponentiate by STREAMINGTEXTUREMESHINFO_HISTOGRAM_BIN_CAP_EXPBASE for other slots )
float pixelsPerTextureRepeatBin0 = viewWidthPixels * textureUnitsPerRepeat * perspectiveScaleFactor;
Float perspectiveScaleAreaFactor = perspectiveScaleFactor * perspectiveScaleFactor;
pixelsPerTextureRepeatBinTerm0 = (int32)floorf(-Log2( pixelsPerTextureRepeatBin0 ); // Mip level for bin 0 if texture were 1x1.
For each texture t:
if first use this frame, clear accum.
if high priority, t->accum[clampedMipLevel] += HIGH_PRIORITY_CONSTANT (100000000.0f)
For dim 0 and 1 (texture u,v):
const int mipLevelForBinBase = (i32)FloorLog2( (u32)textureAsset->textureSize[dim] ) + pixelsPerTextureRepeatBinTerm0 ;
For each bin
// Log2 decreases by one per bin due to divide by two. (Each slot we double pixelsPerTextureRepeatBin0, which is in the denominator.)
const int32 clampedMipLevel = clamp(mipLevelForBinBase - (i32)binIter, 0..15 )
t->accum[clampedMipLevel] += modelMeshHistogram[binIter][dim] * perspectiveScaleAreaFactor;
If accum exceeded a small ‘significance threshold’, update t’s last-used frame.
// Prioritization
For each texture mip,
metric = accumulator * 65536.0f / (texelCount >> (2 * mipIndex));
If used this frame:
non-resident mips are added to ‘add list’, with metric.
resident mips are added to ‘drop list’ with same metric.
If not used this frame:
all mips added to ‘drop list’ with metric of ( -metric + -frames_unused.)
(also, clamped to finer mips’ metric + 0.01f, so coarser is always better)
Then partial_sort the add and drop lists by metric to get best & worst 16.
// Add/Drop
shift s_usedMemory queue
for ( ; ( (shouldDropAllUnused && tDrop->metric < 0.0f) || s_usedMemory[0] > s_memoryTarget) && droppedSoFar <16MiB && tDrop != taskList.dropEnd; ++tDrop ) { drop tDrop, increase droppedSoFar; }
for ( TextureStreamMgr_Task_t* t = taskList.loadBegin; t != tLoadEnd; ++t ) { // t points into to add list
if ( we have 8 textures queued || t->metric <= bestMetricDropped ) break;
if ( s_usedMemory[STREAMING_TEXTURES_MEMORY_LATENCY_FRAME_COUNT - 1] + memoryNeeded <= s_memoryTarget ) {
for ( u32 memIter = 0; memIter != STREAMING_TEXTURES_MEMORY_LATENCY_FRAME_COUNT; ++memIter ) {
s_usedMemory[memIter] += memoryNeeded; }
if ( !begin loading t ) { s_usedMemory[0] -= memoryNeeded; } // failure eventually gets the memory back
} else for ( ;; ) { // Look for ‘drop items’ to get rid of until we'll have enough room.
if ( planToLoadLater + memoryNeeded + s_usedMemory[0] <= s_memoryTarget ) {
planToLoadLater += memoryNeeded; break; }
if ( droppedSoFar >= 16MiB || tDrop >= taskList.dropEnd || t->metric <= tDrop->metric ) { break; }
bestMetricDropped = Max( bestMetricDropped, tDrop->metric );
drop tDrop, increase droppedSoFar;
++tDrop; } }텍스처 크기를 조정하는 방법은 무엇입니까? Windows/DirectX에서 원래 CPU는 텍스처, 맵을 작성하고, 새 MIP를 읽고, GPU 텍스처를 생성하고, GPU가 새 MIP와 기존 MIP를 복사할 수 있었습니다. 이제 이를 힙에 로드하고 CreateTexture에 전달하기만 하면 됩니다. 콘솔에서 새 MIP를 직접 읽고 3개 프레임을 큐에 넣어 파이프라인을 새로 고칩니다.
비동기 I/O: 비동기 스레드, 2개 요청 실행, 다중 우선순위 큐, 텍스처 우선순위가 낮음, 오디오 우선순위가 높음, 중단 가능성을 개선하기 위해 읽기는 64kb 데이터 블록에서 수행됩니다.
14.5.4.5 프레임 그래프
FrameGraph: Extensible Rendering Architecture in Frostbite에서는 2017년 Frostbite의 진화 역사를 설명하고, 마침내 프레임 그래프 방식을 채택했습니다.

2007년(왼쪽)과 2017년(오른쪽) Frostbite 엔진의 렌더링 시스템 비교.
렌더링 시스템의 단순화된 다이어그램은 다음과 같습니다.

WorldRenderer는 코드 기반 아키텍처를 사용하여 모든 렌더링을 조정합니다. 이는 주요 월드 지오메트리(쉐이딩 시스템을 통해), 조명, 포스트 프로세스(렌더링 컨텍스트를 통해), 모든 뷰 및 렌더링 패스를 관리하고 시스템 간 설정 및 리소스를 관리하며 리소스(렌더 대상, 버퍼)를 할당합니다.
WorldRenderer는 명시적인 즉시 모드 렌더링, 명시적인 리소스 관리, 사용자 정의, 수작업 ESRAM 관리, 다양한 게임 팀의 다중 구현, 렌더링 시스템 간의 긴밀한 결합 등 많은 문제에 직면해 있습니다. 제한된 확장성으로 인해 게임 팀은 사용자 정의를 위해 분기/분산해야 하며 4k에서 15k SLOC로 성장해야 하며 단일 기능은 2k SLOC를 초과하므로 유지 관리, 확장 및 병합/통합에 비용이 많이 듭니다.
WorldRenderer 모듈화의 목표는 높은 수준의 지식 프레임워크, 향상된 확장성, 분리 및 구성 가능한 코드 모듈, 자동 리소스 관리, 더 나은 시각화 및 진단입니다. 새로운 아키텍처 구성요소는 다음과 같습니다.

h3.png)
그중 프레임 그래프는 렌더링 채널과 리소스를 상위 수준으로 표현하여 전체 프레임을 완벽하게 제어합니다. 임시 자원 시스템은 자원 할당과 메모리 중복을 담당합니다. 그 목표는 전체 프레임에 대한 높은 수준의 정보를 설정하고, 리소스 관리를 단순화하고, 렌더링 파이프라인 구성을 단순화하고, 비동기 계산 및 리소스 장벽을 단순화하고, 독립적이고 효율적인 렌더링 모듈을 허용하고, 복잡한 렌더링 파이프라인을 시각화 및 디버깅하는 것입니다.

엔진 리소스의 수명 주기 보기는 참조하기가 매우 복잡합니다.
프레임 그래프의 디자인은 즉시 모드 렌더링을 피하고, 코드를 채널 렌더링으로 분할하고, 설정 단계, 컴파일 단계, 실행 단계 등 여러 단계에서 모드 렌더링 API를 유지하는 것입니다. 각 프레임은 처음부터 코드 기반 아키텍처로 구축됩니다.
설정 단계에서는 렌더링/계산 패스를 정의하고 각 패스에 대한 입력 및 출력 리소스를 정의하며 코드 흐름은 즉시 모드 렌더링과 유사합니다.
// 리소스
RenderPass::RenderPass(FrameGraphBuilder& builder)
{
// Declare new transient resource
FrameGraphTextureDesc desc;
desc.width = 1280;
desc.height = 720;
desc.format = RenderFormat_D32_FLOAT;
desc.initialSate = FrameGraphTextureDesc::Clear;
m_renderTarget = builder.createTexture(desc);
}
// 설정(Set)
RenderPass::RenderPass(FrameGraphBuilder& builder, FrameGraphResource input, FrameGraphMutableResource renderTarget)
{
// Declare resource dependencies
m_input = builder.read(input, readFlags);
m_renderTarget = builder.write(renderTarget, writeFlags);
}고급 프레임 그래프 작업: 리소스 지연 생성, 리소스 조기 선언, 최초 실제 사용 시 할당, 사용량에 따른 자동 리소스 바인딩 플래그. 리소스 매개변수를 파생시키고, 입력 크기/형식을 기반으로 렌더 패스 출력을 생성하고, 사용량을 기반으로 바인딩 플래그를 파생시킵니다. 하위 리소스를 이동하고, 한 리소스를 다른 리소스로 전달하고, 자동으로 하위 리소스 보기/겹침을 만들고, "시간 여행"을 허용합니다.

모바일 하위 리소스의 예.
참조되지 않은 리소스와 채널은 컴파일 단계에서 제거됩니다. 이는 선언 단계에서 약간 어려울 수 있으며, 구성의 복잡성을 줄이고 조건부 전달을 단순화하며 렌더링 디버깅 등을 목표로 합니다. 컴퓨팅 리소스 수명 주기. 사용량에 따라 특정 GPU 리소스를 할당하고, 단순한 욕심 많은 할당 알고리즘을 사용하고, 처음 사용하기 전에 획득하고, 마지막 사용 후 해제하고, 비동기 컴퓨팅의 수명 주기를 연장하고, 사용량에 따라 리소스 바인딩 플래그를 파생합니다.

위 그림은 디버깅을 위한 특수 렌더링 모드이므로 빨간색 상자 안의 채널과 리소스는 제거됩니다.
실행 단계에서는 각 렌더링 패스에 대해 콜백 함수를 실행합니다. 즉시 모드 렌더링 코드는 익숙한 RenderContext API를 사용하여 상태, 리소스, 셰이더, 그리기 호출 및 디스패치를 설정하고 설정 단계에서 생성된 핸들에서 실제 GPU 리소스를 얻습니다.
비동기식 계산: 종속성 그래프에서 자동으로 파생될 수 있으며 수동 제어가 필요합니다. 성능을 절약할 수 있는 잠재력이 크지만 메모리를 늘리고 부적절하게 사용할 경우 성능에 영향을 미칠 수 있습니다. 렌더링 패스가 선택적으로 추가될 때마다 기본 타임라인에서 시작하여 다른 큐의 출력 리소스가 처음 사용되는 동기화 지점에서 리소스 수명 주기가 동기화 지점까지 자동으로 확장됩니다.

비동기 컴퓨팅 동기화 지점의 개략도.
// 비동기 설정(Set)
AmbientOcclusionPass::AmbientOcclusionPass(FrameGraphBuilder& builder)
{
// The only change required to make this pass
// and all its child passes run on async queue
builder.asyncComputeEnable(true);
// Rest of the setup code is unaffected
// …
}렌더링 모듈:
- 렌더링 모듈에는 두 가지 유형이 있습니다.
독립적인 무상태 기능. 입력 및 출력은 Frostbite에서 가장 일반적인 모듈 유형인 중첩 렌더링 패스를 생성할 수 있는 프레임 그래프 리소스 핸들입니다.
영구 렌더링 모듈. 일부 영구 리소스(LUT, 히스토리 버퍼 등)가 있을 수 있습니다.
WorldRenderer는 여전히 고급 렌더링을 조정하고 있습니다. GPU 리소스가 할당되지 않습니다. 높은 수준에서 렌더링 모듈을 시작하면 확장이 더 쉽고 코드 크기가 15K에서 5K SLOC로 줄어듭니다.
모듈 간 통신: 모듈은 구성 요소 유형 ID를 통해 액세스되는 구성 요소 해시 테이블인 Blackboard를 통해 통신할 수 있으므로 제어된 결합이 가능합니다.
void BlurModule::renderBlurPyramid(FrameGraph& frameGraph, FrameGraphBlackboard& blackboard)
{
// Produce blur pyramid in the blur module
auto& blurData = blackboard.add<BlurPyramidData>();
addBlurPyramidPass(frameGraph, blurData);
}
#include ”BlurModule.h”
void TonemapModule::createBlurPyramid(FrameGraph& frameGraph, const FrameGraphBlackboard& blackboard)
{
// Consume blur pyramid in a different module
const auto& blurData = blackboard.get<BlurPyramidData>();
addTonemapPass(frameGraph, blurData);
}UE의 RDG는 칠판 개념이 없고, 모든 정보는 FRDGBuider(FrameGraph와 유사)에 담겨있습니다.
Transient 리소스 시스템: Transient는 버퍼, 깊이 및 색상 타겟, UAV 등 1프레임 이하에서만 활성화되는 리소스입니다. 1프레임 내에서 리소스 사용 시간을 최소화하고, 리프 노드 렌더링 시스템에서 직접 리소스를 사용하는 곳에 할당하고, 가능한 한 빨리 할당을 해제하여 독립적인 기능을 더 쉽게 작성할 수 있습니다. 프레임 다이어그램의 핵심 구성 요소입니다.
임시 자원 시스템의 구현은 플랫폼 기능, 물리적 메모리 중복(XB1), 가상 메모리 중복(DX12, PS4), 개체 풀링(DX11)에 따라 다릅니다. 버퍼용 원자 선형 할당자는 중첩이 없으며 주로 GPU로 데이터를 전송하기 위해 메모리를 빠르게 전송하는 데만 사용됩니다. 텍스처 메모리 풀.

다음은 다양한 플랫폼의 임시 리소스 할당 메커니즘에 대한 다이어그램입니다.



메모리 중복 고려 사항: 매우 주의하고, 유효한 리소스 메타데이터 상태(FMASK, CMASK, DCC 등)를 확인하고, 빠른 정리를 수행하거나 리소스를 삭제/다시 작성하거나 메타데이터를 비활성화하고, 리소스 수명 주기가 올바른지 확인하고, 생각보다 어려운지 확인하고, 컴퓨팅 및 그래픽 파이프라인에 대해 생각하고, 비동기식 계산을 고려하고, 물리적 페이지가 재사용 전에 메모리에 기록되는지 확인하세요.
리소스 폐기 및 지우기: 새로 할당된 리소스에 대한 첫 번째 작업이어야 하며, 리소스가 렌더링 대상 또는 깊은 쓰기 상태에 있도록 요구하고, 리소스 메타데이터(HTILE, CMASK, FMASK, DCC 등)를 초기화합니다. 빠른 지우기를 수행하는 것과 유사하며, 리소스 콘텐츠는 정의되지 않습니다(실제로 지워지지 않음). 가능하면 리소스를 지우는 것보다 리소스를 삭제하는 것이 좋습니다.
앨리어싱 장벽: GPU 작업 간 동기화 추가, 필요한 캐시 플러시 추가, 정확한 장벽을 사용하여 성능 비용 최소화, 어려운 상황에서 와일드카드 장벽 사용 가능(그러나 IHV 분할 예상), DirectX 12에서 기타 모든 리소스 장벽 일괄 처리!

겹치는 장벽의 예. 위: 파이프라인 CS 및 PS 작업으로 인해 발생할 수 있는 잠재적인 중복 위험. CS와 PS는 서로 다른 D3D 리소스를 사용하므로 전환 장벽이 충분하지 않습니다. PS를 새로 고치거나 CS 리소스 수명 주기를 연장해야 합니다. 하단: 직렬 계산은 메모리가 겹칠 때 정확성을 보장하기 위해 작동하며, 이는 경우에 따라 성능에 영향을 미칠 수 있습니다. 중첩이 성능에 중요한 경우 명시적 비동기 계산을 사용합니다.

720p에서 오버랩 메모리를 사용하기 전(위)과 후(아래) 비교. 아래 그림은 DX12의 메모리 오버랩 레이아웃을 보여줍니다. 이는 메모리 사용량을 거의 50% 절약할 수 있으며, 4k 해상도에서는 50% 이상을 절약할 수 있습니다.
요약하면, 풀 프레임 정보에는 리소스 중첩을 통한 상당한 메모리 절약, 반자동 비동기 계산, 단순화된 렌더링 파이프라인 구성, 뛰어난 시각화 및 진단 도구, 그래프는 렌더링 파이프라인의 매력적인 표현, CPU 작업 그래프 또는 셰이더 그래프와 유사한 직관적이고 친숙한 개념, 최신 C++ 기능으로 유지 모드 API의 어려움을 완화하는 많은 이점이 있습니다. 자세한 내용은 다음을 참조하세요.
언리얼 렌더링 시스템 분석(02) - 멀티스레드 렌더링
언리얼 렌더링 시스템 분석(11) - RDG
언리얼 렌더링 시스템 분석(13) - RHI 보충 자료: 최신 그래픽 API의 미스터리와 지침
14.5.4.6 디스플레이 지연 시간
'Call of Duty'의 컨트롤러 디스플레이 지연 시간은 컨트롤러 디스플레이 지연 시간, 즉 플레이어가 버튼을 누른 후 화면에서 누른 결과를 볼 때까지의 최소 시간에 대해 자세하고 심도 있게 논의합니다. 또한 Call of Duty 게임에 추가된 동적 조정 기능을 도입하여 컨트롤러에서 디스플레이까지의 대기 시간을 줄이는 궁극적인 목표와 함께 입력 대기 시간에 영향을 미치는 균형을 제어합니다. 지연 시간을 측정하는 방법에 대한 논의를 시작으로 스로틀을 고려해야 하는 엔진의 특정 측면을 자세히 살펴보겠습니다. 플레이어가 제어 버튼을 누른 후부터 화면이 표시될 때까지의 과정에는 실제로 다음과 같은 단계 또는 단계가 포함됩니다.

위의 컨트롤러/OS 샘플, 게임 엔진 쿼리, 게임 로직 및 렌더링, 비디오 스캔 아웃은 게임 엔진과 관련된 단계입니다.
우선, 지연이 성능과 동일하지 않다는 점을 이해해야 합니다. 지연은 성능 변화에 대한 적응성일 뿐입니다. 전체 렌더링 파이프라인의 지연 흐름도와 단순화된 다이어그램은 다음과 같습니다.

대기 시간을 줄이기 위해 COD가 채택할 전략은 샘플을 입력하기 전에 스로틀을 도입하는 것입니다. 여기에 지연을 추가하면 입력 샘플이 프레임 끝 부분에 가깝게 압축됩니다.

이 제한 사항을 더 쉽게 고려할 수 있도록 지연 기간을 두 가지 범주로 나눌 수 있습니다. 첫 번째는 작업입니다. 이는 특정 프레임에 대한 무언가(예: 게임 로직 또는 렌더링)에 적극적으로 작업하는 데 소요되는 시간이며 아래 이미지의 색상 상자에 표시된 시간입니다.

일을 제외한 다른 모든 것은 "슬롭"이라고 부를 수 있습니다.

Slop은 유휴 시간일 필요는 없습니다. 일반적으로 한 타임라인이 이전 프레임에서 작동 중인 클립이거나 한 타임라인이 공유 리소스를 해제하기 위해 다른 타임라인을 기다리는 클립입니다. 일반적인 생산자-소비자 시스템을 살펴보면 생산자는 작업 단위를 실행하고 결과를 소비자에게 전달한 후 다음 작업 단위 생성을 시작합니다. 소비자가 생산자보다 지속적으로 느린 경우 시스템은 "소비자 바인딩"이 됩니다. 소비자의 타임라인은 그대로 유지되어 생산자를 따라잡으려고 노력하지만 생산자는 최대한 앞서 나갈 수 있습니다. 이것이 바로 슬롭이 존재하는 이유입니다. 생산자가 소비자보다 앞서 있으므로 생산자가 끝나는 시점과 소비자가 시작하는 시점 사이에 간격이 있습니다. 생산자가 얼마나 앞서는지는 생산자와 소비자 사이에 허용되는 버퍼링의 양과 버퍼링된 데이터에 대한 액세스를 획득하고 해제하는 정확한 시간에 따라 달라집니다.

반면, 생산자 제한이 적용되면 일반적으로 슬롭이 사라집니다. 소비자의 타임라인이 공개되므로 제작자가 장면을 마치자마자 소비자는 즉시 시작할 수 있으며 공백이 발생하지 않습니다.

입력 샘플을 지연하면 슬롭이 사라질 때까지 첫 번째 세그먼트에서 돌출되기 시작한 다음 두 번째 세그먼트로 이동하는 식입니다. 반면에 작업은 시간상 앞으로 이동하는 반면 프레임 전체의 총 작업 기간은 이상적으로 동일하게 유지됩니다.

레이턴시 = 작업 + 슬롭, 높은 슬롭 ⟷ 높은 레이턴시, 낮은 슬롭 ⟷ 낮은 레이턴시.
먼저 지연 기간이 끝나면 어떤 일이 발생하는지 살펴보겠습니다. 게임은 최종 이미지를 프레임 버퍼라는 메모리에 렌더링합니다. 그런 다음 비디오 스캐닝 하드웨어는 프레임 버퍼를 위에서 아래로 한 줄씩 읽고 케이블을 통해 픽셀 데이터를 디스플레이로 전송합니다. 스캔 출력은 모니터의 새로 고침 빈도와 일치하는 속도로 지속적으로 전송됩니다. 오늘날 기존 모니터의 새로 고침 빈도는 60Hz이므로 프레임 버퍼도 일반적으로 60Hz 또는 16.6ms마다 스캔합니다. 16.6ms의 대부분은 가시 픽셀 데이터를 능동적으로 전송하는 데 사용되지만 전송된 데이터가 가시 픽셀과 일치하지 않을 때 잠시 일시 중지됩니다. 먼저, 각 줄의 끝에는 HBLANK라고 하는 일시정지가 있고, 마지막 줄 뒤에는 VBLANK라고 하는 일시정지가 있습니다. 이러한 일시 중지는 이전 CRT 모니터에서 물리적으로 필요했지만 레거시 이유와 전송 메타데이터로 인해 오늘날에도 여전히 존재합니다.

이것을 타임라인에 놓으면 스윕 다음에 vblank, 스윕 다음에 vblank 등이 모두 고정된 60Hz 주파수에서 발생합니다.

이제 우리는 지연 시간의 끝이 고정되어 있다는 것을 알고 있습니다. 이는 16.6밀리초마다 발생합니다. 즉, 이 프레임의 스캔이 언제 시작될지 미리 정확하게 예측할 수 있습니다. 이제 우리의 목표는 고정된 스캔을 기준으로 다른 타임라인이 어디에 있는지 알아내는 것입니다. 위로 이동하면 GPU가 이미지를 프레임 버퍼로 렌더링합니다.

Scanout은 지속적으로 프레임 버퍼에서 데이터를 읽고 데이터를 디스플레이로 보냅니다. 이는 동일한 메모리에서 동시에 읽고 쓰는 것을 의미합니다. 즉, 경쟁 조건입니다. 전통적인 솔루션은 이중 버퍼링입니다. 두 개의 프레임 버퍼를 할당하고 각 프레임의 대체 버퍼에 렌더링합니다. 프레임 버퍼 A로 렌더링할 때 프레임 버퍼 B가 스캔됩니다. 그런 다음 프레임 버퍼 B로 렌더링하고 프레임 버퍼 A에서 스캔합니다.
GPU에서 프레임을 사용한 후 즉시 뒤집는 것(렌더링이 완료되었다고 가정), 즉시 뒤집기, A가 스캔을 시작하고 B가 렌더링을 시작하는 것만으로는 충분하지 않습니다. A의 스캔이 끝나기 전에 B가 렌더링을 완료합니다. 지금 반전이 발생하면 B가 렌더링을 마친 후에는 어떻게 되나요? 그러면 스캔 출력은 스캔 라인 위치를 재설정하지 않고 A에서 읽는 도중에 B에서 읽는 것으로 전환됩니다. 화면의 결과 이미지는 위쪽 절반은 버퍼 A에서 스캔되고 화면 아래쪽 절반은 버퍼 B에서 스캔됩니다. 이 아티팩트를 테어링이라고 하며 게임 카메라가 회전할 때와 같이 A와 B 사이에 큰 수평 이동이 있을 때 가장 눈에 띕니다. 이 문제를 해결하려면 또 다른 규칙이 필요합니다. 즉, 스캔이 완료된 후에만 뒤집습니다. 즉, VBLANK 중에만 뒤집습니다. 이 규칙을 VSyync(수직 공백 동기화)라고 합니다.

즉, 중간 스캔 렌더링은 이중 버퍼링으로 수정되고, 찢어짐은 vblank 플립을 기다리면서 수정됩니다. 60Hz 및 vsync의 이중 버퍼링을 사용하면 vblank 동안 스캔할 때마다 프레임 버퍼 A와 B 사이에 반전이 발생합니다.

아래 그림과 결합하면 GPU가 프레임 버퍼 A로 렌더링한다고 가정할 때 GPU가 A를 터치할 수 없는 기간은 큰 파란색 직사각형 안의 영역입니다. 첫 번째 단계에서 GPU는 프레임 버퍼 A가 사용 가능해질 때까지 유휴 상태여야 합니다. A의 스캔이 완료된 후 A로의 렌더링을 시작할 수 있습니다. GPU가 렌더링을 완료한 후에는 찢어질 수 있으므로 즉시 뒤집을 수 없습니다. 대신 GPU는 "플립을 대기열에 넣습니다". 이는 A가 다음 vblank에서 뒤집을 준비가 되었음을 나타냅니다. 이것이 플립 큐와 실제 플립 사이의 첫 번째 슬롭 소스입니다.

슬롭 기간을 계산하면 약 16.6ms에서 GPU의 총 작업 시간을 뺀 값입니다. 하지만 우리는 가능한 한 많은 하드웨어를 사용하고 싶어하며, GPU 주기는 GPU의 작업 부하가 지속적으로 낮을 경우 낭비되는 특히 귀중한 리소스라는 점을 기억하십시오. 작업을 잘 수행하면 더 높은 해상도에서 더 많은 그래픽을 그릴 수 있습니다. GPU 부하가 높을 경우 경사는 어떻게 되나요?

GPU 작업량이 가득 차면 16.6ms에 가까워 슬롭이 사라진다. 그러나 스로틀은 지연 기간에서 슬롭을 짜내야 한다는 점을 기억하십시오. 여기에 경사가 없다면 애초에 스캔을 위해 GPU를 살펴보는 게 무슨 의미가 있을까요?

사실 상황은 조금 더 복잡하며 GPU에 과부하가 걸린 경우에도 실제로 엄청난 슬롭 소스가 있습니다. 그 이유는 프레임 그리기의 대부분이 프레임 버퍼가 아닌 다른 곳에서 렌더링되기 때문입니다. 거의 모든 GPU 시간은 오프스크린 버퍼를 렌더링하는 데 소비되며 대부분의 3D 드로잉은 "장면 버퍼"라고 불리는 세 번째 오프스크린 버퍼에 렌더링됩니다. 장면 버퍼는 최종 디스플레이 해상도보다 낮은 해상도를 가질 수 있으며 다른 색상 인코딩을 사용할 수 있습니다. 장면 렌더링이 완료된 후 장면 버퍼는 프레임 버퍼로 업샘플링되며 일반적으로 업샘플링 중에 템포럴 안티앨리어싱(TAA)을 적용합니다. 업샘플링 후 UI 요소는 디스플레이 해상도에서 프레임 버퍼로 렌더링된 다음 반전을 위해 대기됩니다. 여기서 가장 중요한 점은 대부분의 GPU 프레임 시간이 3D 장면을 렌더링하는 데 사용되며 프레임 버퍼는 나중에 프레임에서 업샘플링될 때까지 건드리지 않는다는 것입니다. 장면 버퍼가 모니터로 스캔되지 않으므로 이는 정확히 삼중 버퍼링이 아닙니다. 그러나 타이밍 결과는 삼중 버퍼링과 유사하므로 이를 "의사 삼중 버퍼링"이라고 부릅니다.

원래 이중 버퍼링 설정에서 GPU는 GPU 타임라인을 스캔아웃 타임라인과 동기화하기 위해 프레임 시작 부분에서 프레임 버퍼를 기다려야 했습니다. 이제 의사 삼중 버퍼링을 사용하면 GPU는 업샘플링하기 전에 프레임 후반부에서 프레임 버퍼를 기다리기만 하면 됩니다.

엄격한 이중 버퍼링의 경우 프레임 버퍼 A는 파란색 직사각형 사이의 기간 동안에만 렌더링되도록 허용됩니다.

이제 GPU 워크로드는 장면 렌더링(프레임 버퍼 사용 안 함)과 프레임 버퍼 렌더링(프레임 버퍼 사용)의 두 부분으로 나뉩니다. 프레임 버퍼 렌더링 부분은 스캔 중간 렌더링을 피하기 위해 여전히 두 개의 파란색 직사각형 사이에 있어야 하지만 장면 렌더링 부분은 언제든지 시작할 수 있습니다.

모든 것은 시간상 뒤로 이동할 수 있으며, GPU는 마지막 프레임이 완료되자마자 장면 렌더링을 시작하고, 프레임 버퍼 렌더링은 여전히 스캔 출력과 동기화되어야 하지만 장면 렌더링에 의해 남겨진 공간으로 다시 이동됩니다.

엄격한 이중 버퍼링에서 슬롭은 ~16.6ms에 총 GPU 작업 시간을 뺀 값에 불과하며, GPU 작업 부하가 증가하면 슬롭이 사라집니다.

이제 의사 삼중 버퍼링을 사용하면 슬롭이 두 부분으로 분할됩니다. 첫 번째 슬롭 기간은 프레임 버퍼 대기입니다. 장면 렌더링 끝과 프레임 버퍼 렌더링 시작 사이는 16.6ms에서 GPU의 총 작업 부하를 뺀 것과 같고, 두 번째 슬롭 기간은 플립 큐와 실제 플립 사이에서 약 16.6ms에서 프레임 버퍼 렌더링 작업 부하를 뺀 값입니다.

전체 GPU 워크로드는 일반적으로 더 많은 장면 렌더링을 의미합니다. 즉, 더 많은 3D 객체와 더 높은 장면 해상도, 프레임 버퍼 렌더링은 일반적으로 짧습니다. 따라서 GPU 작업 부하가 가득 차면 첫 번째 슬롭은 여전히 사라지고 두 번째 슬롭은 오랫동안 남아 있을 수 있습니다.

완전 활용하더라도 슬로프가 많이 발생할 수 있습니다.
그러나 의사 삼중 버퍼링에는 또 다른 결과가 있습니다. 지금까지 우리는 GPU가 작업 부하에 대해 항상 16.6ms보다 빠르다고 가정했습니다. 그러나 GPU를 최대한 바쁘게 사용하려면 실수로 GPU를 과도하게 사용하여 프레임 속도를 늦추기 쉽습니다. 엄격한 이중 버퍼링 하에서 프레임 B가 16.6ms보다 느리게 렌더링된다고 가정합니다. 프레임은 다가오는 vblank 간격 전에 스캔할 준비가 되어 있지 않으므로 "vblank를 놓칩니다". 뒤집기를 위해 대기 중인 프레임 버퍼가 없으므로 다음 vblank 중에 뒤집기가 발생하지 않습니다. 대신, 스캔 아웃은 프레임 버퍼 A를 계속 가리키며, A는 다시 스캔 아웃되고, B의 스캔은 다음 vblank가 시작될 때까지 기다려야 합니다. 이제 A가 두 번째로 스캔되므로 GPU는 A 렌더링을 시작하기 위해 다음 뒤집기까지 기다려야 합니다. 프레임 A 렌더링도 느리면 또 다른 vblank를 놓치게 됩니다.

GPU 렌더링 시간이 새로 고침 빈도보다 지속적으로 느린 경우(마이크로초라도) 모든 vblank가 누락되고 프레임 속도는 60Hz가 아닌 30Hz로 고정됩니다. 이는 매우 비참한 결과입니다. 특히 GPU의 작업 부하를 최대한 최대로 유지하려고 할 경우 더욱 그렇습니다.

이제 의사 삼중 버퍼링의 경우 첫 번째 vblank가 여전히 누락되었다고 가정하면 프레임 버퍼 A는 여전히 두 번 스캔되어야 합니다. 그러나 이제는 GPU가 오프스크린 버퍼에 렌더링할 수 있는 시간에 제한이 없기 때문에 A가 여전히 스캔 중이더라도 즉시 A의 장면 렌더링을 시작할 수 있습니다. 이는 GPU가 다음 vblank까지 유휴 상태여야 하는 이중 버퍼의 경우와 매우 다릅니다. GPU의 작업 부하가 여전히 16.6ms보다 크더라도 A는 다음 vblank를 놓치지 않습니다.

축소하여 여러 프레임에 걸친 동작을 확인합니다(고정된 16.6ms 미만의 GPU 워크로드를 가정). 첫 번째 프레임은 vblank를 놓치고 A는 두 번 스캔되지만 다음 프레임, 다음 프레임, 다음 프레임 모두 Vblank가 생성됩니다. 결국 vblank는 다시 무시되지만, 6개의 느린 프레임이 vblank를 놓치지 않고 통과할 때까지는 그렇지 않습니다.

의사 삼중 버퍼링을 사용할 때 평균 프레임 속도가 30Hz에 도달하지 않습니다. 대신 평균 프레임 속도가 60Hz에서 50Hz로 천천히 떨어졌습니다.

아래쪽에 있는 중괄호를 보십시오. 이는 플립 대기열과 각 프레임의 실제 플립 사이에서 측정된 경사입니다. 첫 번째 누락된 vblank 이후에는 경사가 높습니다. 느린 프레임이 지날수록 기울기는 점차 감소합니다. 각각의 느린 프레임은 슬롭이 결국 0 아래로 떨어지고 vblank가 손실될 때까지 사용 가능한 슬롭을 소비합니다. 이는 slop의 중요한 측면을 보여줍니다. slop은 vblank를 잃지 않고 느린 프레임이 통과하도록 허용하는 버퍼 공간 역할을 합니다.

50Hz를 유지할 수 있는 것이 30Hz로 떨어지는 것보다 낫지만 여전히 몇 프레임마다 프레임이 누락되는 불쾌한 효과가 발생합니다. 우리는 동적 해상도가 필요한 안정적인 60을 유지하는 것을 선호합니다. 게임에서 GPU 시간이 임계값 미만임을 감지하면 엔진이 작동합니다.

하지만 이제 동적 해상도가 있으므로 유사 삼중 버퍼링의 타임라인을 다시 살펴보겠습니다. 여러 프레임이 한 프레임도 놓치지 않고 천천히 지나갔습니다. Slop은 매우 낮아지지만 결국 해상도는 떨어집니다. 이제 GPU의 프레임 시간이 16.6ms보다 빨라졌습니다. 빠른 프레임이 통과하면 슬롭이 다시 안전한 수준으로 누적됩니다. 느린 프레임이 경사를 차지하고 빠른 프레임이 이를 다시 구축한다는 아이디어입니다. 의사 삼중 버퍼링으로 인한 추가 슬롭을 사용하면 느린 프레임 임계값이 거의 16.6ms까지 증가할 수 있으며 해당 임계값을 초과하는 스파이크에서 살아남는 것이 가능합니다. 이 속성은 동적 해상도가 실행 가능한 기술이 되기 위해 매우 중요합니다.

낮은 슬롭은 낮은 대기 시간을 의미하지만 느린 프레임에서는 Vblank를 놓치기 쉽습니다. 높은 슬롭은 지연 시간이 길고 몇 개의 느린 프레임을 견딜 수 있는 버퍼 공간이 있음을 의미합니다.
- 일반적인 상황에서는 경사를 최대화합니다. 버퍼링 측면에서 추가 메모리에 대한 절충안은 버퍼링 범위에서 슬롭을 최대화하는 것을 고려하는 것입니다.
다음은 실제로 슬롭을 최대화하는 방법에 대한 최근 Call of Duty 게임의 매우 간단한 예입니다. HDR 지원이 추가되면 장면 버퍼-프레임 버퍼 분할이 변경되었습니다. 첫 번째 장면 렌더링은 일반적으로 장면 버퍼로 수행되고 장면 버퍼는 디스플레이 해상도로 업샘플링되지만 이번에는 디스플레이 해상도에서 다른 오프스크린 버퍼로 UI가 오프스크린 버퍼의 디스플레이 해상도로 렌더링되고 마지막으로 프레임 끝에서 이 버퍼가 최종 색상 공간의 실제 프레임 버퍼로 트랜스코딩됩니다. 실제 프레임 버퍼에 대한 첫 번째 노출은 트랜스코딩 전입니다. 프레임 버퍼는 프레임 시간의 작은 부분(1080p에서 약 170마이크로초)에만 사용됩니다.
한 플랫폼에서는 프레임 버퍼가 처음에 프레임의 맨 처음에 가져오므로 의사 삼중 버퍼링의 이점이 완전히 무효화되어 엄격한 이중 버퍼링과 동일하게 작동합니다. 프레임이 느리면 vblank가 손실되어 동적 해상도의 효율성이 저하됩니다.

다른 플랫폼에서는 상황이 더 좋아졌습니다. 장면이 렌더링된 후 대기 프레임 버퍼가 삽입되었지만 HDR 지원이 추가되었을 때 이 대기는 이동되지 않았습니다. 이 설정은 이전 사례보다 더 나은 성능을 발휘하지만 여전히 프레임 버퍼 섹션이 필요한 것보다 길어집니다. 엄격한 이중 버퍼링을 사용하는 것보다 프레임이 더 일찍 시작되도록 허용하더라도 슬롭이 최대화되지 않아 Vblank가 누락될 확률이 최적보다 높아집니다.

트랜스코딩 직전에 프레임 버퍼의 올바른 위치를 얻으면 슬롭이 최대화되고 VBlank를 버릴 가능성이 최소화됩니다.

가능한 한 늦게 프레임 버퍼를 기다리도록 코드를 확인하는 것이 좋습니다. 보통은 단일 기능이지만, 프레임의 구조가 바뀌면 vsync가 꺼지면 성능이나 타이밍에 영향을 주지 않기 때문에 옮기는 것을 잊어버리기 쉽습니다. DX12의 경우 프레임 버퍼 리소스에서 현재 상태에서 렌더 대상(또는 다른 쓰기) 상태로 전환 장벽을 수행하는 동안 대기가 발생합니다.
D3D12_RESOURCE_STATE_PRESENT → D3D12_RESOURCE_STATE_RENDER_TARGET다른 플랫폼에서도 유사한 기능을 사용할 수 있습니다. 또한 이러한 호출에 GPU 타임스탬프를 고정하여 이러한 대기 시간을 측정하고 측정값을 GPU 타이밍 시스템에 통합하는 것이 좋습니다. vsync가 활성화되면 동적 해상도에 대한 정확한 프레임 타이밍을 얻으려면 총 GPU 시간에서 이러한 값을 빼야 합니다.
CPU 워크로드의 상당 부분은 GPU에 수행할 작업을 알려주는 데 사용됩니다. 즉, 상태 변경 로깅, GPU에서 사용할 명령 버퍼에 그리기 및 디스패치, 동적 꼭지점 및 인덱스 버퍼와 같은 관련 렌더링 데이터 생성을 의미합니다. CPU가 쓰고 GPU가 읽는 버퍼는 일반적으로 이중 버퍼링되거나 링에서 할당됩니다. CPU가 명령 버퍼를 구축한 후 "킥"을 통해 처리를 시작하도록 GPU에 지시합니다. 이 킥 이벤트는 GPU와 스캔 출력 간의 프레임 버퍼 전환과 유사합니다. GPU가 스캔할 때와 마찬가지로 CPU 시작과 GPU가 실제로 시작될 때 프레임 사이에 슬롭이 누적될 수 있습니다.

그러나 GPU 스캐닝 시스템과 달리 CPU는 GPU가 사용하는 순서와 거의 동일한 순서로 명령을 기록합니다. 예를 들어, CPU의 프레임은 프리패스 명령, 그림자 명령, 불투명 명령 등을 기록하는 것으로 구성될 수 있습니다. 킥 후에 GPU도 이 순서대로 그립니다.

우리는 이 사실을 활용하여 CPU와 GPU 사이의 버퍼를 프레임보다 더 세밀하게 분할합니다. CPU는 전체 프레임에 대한 모든 데이터를 미리 생성하고 전체 프레임을 한 번에 실행할 필요가 없지만 각 프레임에서 여러 개의 작은 실행을 수행할 수 있습니다. 예를 들어, 프리패스 전반부에 대한 데이터를 기록한 후 즉시 CPU를 시작할 수 있습니다. GPU는 프리패스 처리를 시작하는 동시에 CPU는 프리패스의 후반부에 대한 데이터를 기록하는 등의 작업을 수행합니다. 이를 통해 CPU와 GPU 프레임 간에 상당한 중복이 허용됩니다. 이 중첩 사례에서 지연이 어떻게 작동하는지 올바르게 해석하려면 경사와 작업의 정의를 수정해야 합니다.

겹치지 않는 슬롭은 CPU 프레임 끝에서 GPU 프레임 시작까지의 세그먼트입니다. 슬롭 및 작업의 정의를 검토합니다. 조절된 경우 작업은 시간이 지나면서 앞으로 이동하지만 줄어들지는 않는 지연 기간의 일부입니다. 슬롭은 단축되는 지연 기간의 일부입니다.

이제 겹치는 부분이 있으므로 CPU를 처음 시작한 직후 GPU가 작동을 시작할 수 있으며 Slop은 CPU의 첫 시작과 GPU 시작 프레임 사이의 범위로 정의해야 합니다. 작업은 그 밖의 모든 것입니다. 즉, CPU 프레임 시작과 첫 번째 시작 사이의 기간에 전체 GPU 프레임 시간을 더한 것입니다. 단순히 중첩을 허용함으로써 측정 노력이 크게 줄어듭니다.

CPU와 GPU가 강제로 겹쳐진다는 뜻은 아닙니다. CPU 프레임 끝과 GPU 프레임 시작 사이에는 여전히 지연이 있을 수 있습니다. GPU가 더 일찍 시작될 수 있으므로 슬롭 측정이 훨씬 높아집니다. 오버랩을 허용하면 스로틀이 겹치지 않는 경우보다 더 많이 조이는 것이 가능해집니다.

성능에 대해 이야기 해 봅시다. GPU 사이클은 종종 가장 귀중한 하드웨어 리소스입니다. Call of Duty에서는 CPU보다 GPU에서 무거운 작업을 수행할 가능성이 더 높습니다. 이상적인 세계에서는 CPU가 항상 GPU가 소비하는 것보다 빠르게 명령을 기록하므로 GPU가 유휴 상태가 되지 않습니다.

그러나 CPU 세그먼트 중 하나가 너무 늦게 실행되면 GPU가 유휴 상태가 될 수 있습니다. 이를 GPU 버블이라고 합니다. GPU와 CPU가 크게 겹치고 GPU가 CPU보다 약간만 뒤쳐져 있는 경우 특히 프레임 초기에 거품이 발생할 위험이 더 높습니다. 거품은 비효율적이며 유휴 GPU 주기를 나타내지만 동적 해상도에 대한 GPU 프레임 시간 측정을 왜곡하여 불필요한 해상도 저하를 초래합니다.

그러나 GPU와 CPU 사이에 약간의 슬롭이 있는 경우 이 슬롭을 버퍼 공간으로 사용하여 CPU 스파이크를 최소화하거나 더 작은 버블을 생성하거나 버블을 모두 방지할 수 있습니다.

낮은 슬롭 - 중첩이 많을수록 대기 시간이 낮아지고 거품에 대한 민감성이 낮아집니다. 높은 경사 - 겹치는 부분이 적을수록 대기 시간이 길어져 스파이크를 흡수하고 버블링을 방지할 수 있는 충분한 공간이 확보됩니다. 거품 방지: 병렬 명령 버퍼 생성, 그리기 목록 분할 조정, 경합을 피하기 위해 신중하게 작업 일정을 계획합니다. 그리기 호출 수를 줄이고 CPU 컬링, 인스턴스화 및 다중 그리기를 활성화합니다. 머티리얼 정렬, 바인딩리스 등의 드로우 콜 오버헤드를 줄입니다.
이제 우리는 여러 코어에서 광범위하게 실행되는 초고속 명령 버퍼 생성 기능을 갖게 되었습니다. 하나의 스레드는 완성된 명령 버퍼를 추출하여 이를 GPU로 보냅니다. 이상적인 세계에서는 GPU가 CPU보다 느리게 실행되므로 안정적으로 유지되고 전체 프레임에 대한 데이터를 제공합니다.

불행히도 이상적인 상황이 항상 발생하는 것은 아닙니다. 그리기 작업 중 하나가 늦게 시작되었거나, 시스템 스레드에 의해 코어에서 쫓겨났거나, 할 일이 너무 많았을 수도 있습니다. 제출 스레드는 명령 버퍼를 시작하기 전에 작업이 완료될 때까지 기다려야 합니다. 너무 오래 기다리면 GPU가 유휴 상태가 되어 거품이 생성됩니다.

하지만 코드베이스에서 거품을 피하는 것에는 멋진 점이 있습니다. 제출 스레드에 그리기 작업 대기 시간이 초과되었습니다. 작업이 시간 내에 완료되지 않으면 작업을 중지하도록 알리기 위해 중단 신호가 전송됩니다. 작업은 주기적으로 신호를 확인하고 중단이 감지되면 반복을 중지하고 명령 버퍼를 닫습니다. 그런 다음 제출 스레드가 작업을 인계받아 해당 작업이 수행해야 했던 모든 작업을 수행합니다. 그런데 이번에는 한 번이 아니라 마지막 출근이었습니다. 더 자주 실행하면 제출 스레드가 작업이 완료되기를 기다리는 시간보다 일찍 GPU에 작업이 가득 차게 됩니다. 이는 더 빈번한 킥으로 인해 추가 CPU 및 CP 오버헤드가 발생하지만 거품의 영향을 줄이거나 완전히 피할 수 있습니다.

CPU 작업의 단일 프레임에는 여러 시스템의 상호 작용이 포함됩니다. 다음은 매우 간단한 요약입니다. 먼저 서버에서 권한 있는 게임 상태를 가져와 클라이언트 게임 상태를 업데이트합니다. 그런 다음 입력이 샘플링되고 입력 요소가 클라이언트 게임 시뮬레이션에 반영됩니다. 마지막으로 게임 시뮬레이션 결과를 렌더링하는 데 필요한 모든 작업이 완료되었습니다. 렌더링 부분에 집중해 보겠습니다.

렌더링은 장면 그래프 탐색, 컬링, 모델에 대한 LOD 선택 등을 포함한 많은 작은 작업으로 나뉩니다. 이러한 모든 작업의 최종 출력은 보이는 표면 목록입니다. 그런 다음 각 개별 목록을 반복하도록 작업이 할당되고 이러한 작업은 명령 버퍼 및 관련 렌더링 데이터를 생성합니다. 마지막으로 작업은 완료된 모든 명령 세그먼트를 수집하여 GPU로 보냅니다. 이 작업은 표면 목록에 포함되지 않은 명령(표면 압축 풀기, 포스트 프로세스 및 2D 그래픽)도 기록합니다.

개념적으로 이 모든 작업은 장면 준비, 드로잉, GPU 제출이라는 세 그룹으로 나눌 수 있습니다.

프레임에 대한 모든 작업은 다중 스레드로 이루어지며 가능한 한 광범위하게 실행됩니다. 하지만 평균적으로 장면 준비와 플롯팅은 대규모 실행에서 가장 큰 이점을 얻는 부분입니다. 프레임의 시작과 끝에서는 사용 가능한 코어에 비해 사용률이 낮아져 유휴 CPU 주기가 더 많이 남습니다.

CPU 코어를 보다 일관되게 포화시키기 위해 그리기 작업과 제출 작업이 분리됩니다. 그런 다음 이 프레임에 대한 장면 준비가 끝나면 다음 프레임이 즉시 시작될 수 있습니다. 이렇게 하면 다음 프레임의 시작 부분이 해당 프레임의 그리기 및 제출과 겹치므로 속도가 상당히 향상될 수 있습니다.

개념적으로 전체 장면 준비 프로세스의 모든 것을 "클라이언트 프레임"이라고 부를 수 있으며, 전용 클라이언트 스레드가 모든 관련 작업을 조정합니다. 두 번째 렌더 스레드는 모든 명령 버퍼 제출, PostFX, 2D 드로잉 등을 수행하며 두 번째 병렬 "렌더 프레임"을 포함합니다. 이 두 타임라인 사이에는 명령 버퍼를 생성하는 모든 그리기 작업이 있으며, 클라이언트는 이러한 작업을 시작하고, 렌더링 스레드는 이를 기다리고 결과를 시작합니다.

다른 생산자-소비자 쌍과 마찬가지로 slop은 클라이언트와 렌더링된 프레임 사이에 누적될 수 있습니다.

하지만 이 두 타임라인 간의 동기화와 이것이 슬롭에 어떤 영향을 미치는지 집중적으로 살펴보겠습니다. 첫째, 클라이언트는 장면 렌더링과 공유되는 버퍼에 쓰기 때문에 GPU와 동기화되어야 합니다. 이러한 리소스는 이중 버퍼링되므로 클라이언트가 프레임을 시작하기 전에 두 프레임 전의 GPU 장면이 완료될 때까지 기다려야 합니다. 이 데이터는 클라이언트와 렌더링 스레드 간에도 공유됩니다. 처음에는 렌더링 스레드가 다음 클라이언트 프레임이 시작될 때까지 프레임을 시작할 수 없습니다.

축소하면 하단에 GPU 타임라인이 표시됩니다. 클라이언트 프레임의 시작은 두 프레임 전 렌더링된 GPU 장면의 끝과 동기화됩니다. 그러면 렌더링된 프레임의 시작이 다음 클라이언트 프레임의 시작과 동기화되어 클라이언트 프레임의 끝과 렌더링된 프레임의 시작 사이에 약간의 경사가 생성됩니다. 파이프라인이 렌더 프레임에 연결되어 있지 않은 경우 이 슬롭이 존재하는 이유는 무엇입니까?

렌더링 프레임은 정당한 이유 없이 여기에서 시작할 수 없습니다. 현재 클라이언트 프레임의 끝에서 바로 시작됩니다. 이렇게 변경해도 전체 대기 시간에는 영향이 없습니다. 프레임 전체의 총 경사는 동일하게 유지되며 렌더링된 프레임의 왼쪽에서 오른쪽으로만 이동합니다.

- 프레임의 뒤쪽으로 경사를 이동합니다.
슬롭은 스파이크로부터 보호하지만 모든 슬롭이 가능한 모든 스파이크로부터 동일하게 보호하는 것은 아닙니다.

예를 들어 클라이언트 프레임이 급증하는 경우 프레임 후반부의 모든 슬롭 소스를 사용하여 급증을 흡수하고 프레임 누락을 방지할 수 있습니다.

그러나 GPU 스파이크가 발생하면 GPU 프레임 뒤의 경사만 스파이크를 흡수할 수 있습니다.

모든 작업은 가능한 한 빨리 시작되어야 합니다.
클라이언트 프레임이 완료되는 즉시 렌더링 프레임을 시작할 수 있도록 동기화가 변경되었습니다. 이제 렌더 프레임과 클라이언트 프레임이 동시에 실행될 수 없는 이유를 기억하십시오. 클라이언트는 렌더링 스레드가 읽는 버퍼에 쓰기 때문입니다.

실제로 프레임 렌더링을 더 일찍 시작할 수 있으므로 클라이언트 프레임이 끝나기 전에 작업을 시작할 수 있습니다. 이 중복은 코드 분기에서 구현되며 CPU-GPU 중복만큼 대기 시간을 크게 줄이지는 않지만 여전히 몇 밀리초를 얻을 수 있습니다. 이러한 중복은 클라이언트와 렌더러 간의 공유 데이터를 분할하고 분할 간의 종속성을 최소화함으로써 달성됩니다. 중첩 정도는 클라이언트 프레임 종속성 내에서 데이터 분할이 얼마나 수행될 수 있는지에 따라 달라집니다.

클라이언트와 렌더링된 프레임 사이의 슬롭 정의는 이러한 중복을 고려하여 수정되어야 합니다. 이제 클라이언트에서 렌더링 스레드를 더 일찍 깨우고 렌더링 프레임이 실제로 시작되는 사이의 지연입니다.

동기화에 대한 마지막 사항입니다. GPU가 두 프레임 전에 장면을 완료하여 CPU와 GPU 간에 공유되는 이중 버퍼 데이터에 대한 액세스를 보호할 때까지 클라이언트는 시작할 수 없다는 점을 기억하십시오. 그러나 이러한 버퍼는 렌더링 관련 작업(장면 준비, 그리기 및 제출) 중에만 CPU에 의해 기록됩니다. 프레임의 전반부 동안 모든 클라이언트 측 시뮬레이션 작업은 GPU 표시 버퍼에 닿지 않습니다(아래 상단 이미지). 이는 공유 버퍼가 기록되기 직전에 대기가 나중 프레임으로 이동할 수 있음을 의미합니다. (아래 사진 아래)

이 변경으로 인해 클라이언트 프레임은 GPU와 동기화하기 전의 부분과 GPU와 동기화한 후의 두 부분으로 분할됩니다. 이제 GPU는 입력 샘플 이후를 기다리므로 지연 경로에 새로운 슬롭이 도입됩니다.

이제 우리는 엔진의 모든 주요 타임라인을 살펴보고 지연 경로의 모든 작업과 슬롭 부분을 식별했습니다.


이제 이 모든 것을 스로틀 구현에 통합해 보겠습니다. 입력 샘플 앞에 스로틀을 도입하여 샘플과 후속 작업이 지연되고 오른쪽으로 이동합니다.

슬로프가 왼쪽부터 어떻게 돌출되는지 확인하세요. 그러나 전체 작업은 동일하게 유지됩니다.


이제 클라이언트, 렌더러 및 GPU 사이에 더 이상 슬롭이 없으며 스로틀이 충분히 길어졌습니다. 남은 유일한 슬롭은 GPU와 스캔아웃 사이입니다.

더 이상 지연하면 GPU 작업의 끝이 vblank를 넘어 밀려 프레임을 놓칠 것입니다.

따라서 문제는 조절을 얼마나 오래 기다려야 하는가입니다. 스로틀은 클라이언트 프레임 중앙, 입력 예제 바로 앞에 있습니다. 지연 기간의 끝은 향후 vblank 동안이며, 이때 프레임이 뒤집힙니다. 지금과 예상되는 반전 사이의 시간은 우리가 해결하고 있는 스로틀과 프레임의 나머지 부분에 대한 작업 및 경사입니다. 스로틀을 계산하면 지금부터 vblank까지의 기간에서 총 작업 및 슬롭을 뺀 값을 얻습니다. 그러나 스로틀은 프레임 시작 부분에 가깝고 스로틀이 실행될 때까지 얼마나 많은 작업과 경사가 있을 것인지 알 수 없다는 점을 명심하십시오.

대신 이전 프레임 데이터를 기반으로 이 프레임이 얼마나 많은 작업을 수행할지 추정해야 하며, 이 프레임을 달성하기 위한 목표 경사 값을 미리 결정해야 합니다. 문제는 다음과 같습니다: 목표량의 경사가 주어지면 스로틀은 얼마나 오랫동안 휴면 상태를 유지해야 합니까?

먼저 예상 롤오버 시간을 찾는 방법을 살펴보겠습니다. 롤오버가 의도된 경우 vblank의 절대 시간을 계산해야 합니다. vblank는 16.6ms마다 발생하므로 이전 프레임 타이밍을 기반으로 향후 프레임에 대한 vblank를 추론할 수 있습니다.

롤오버 시간: GPU 인터럽트 이벤트를 기다리고 API 자체에서 제공하는 타임스탬프 또는 타임스탬프를 사용하는 우선순위가 높은 전용 스레드입니다. Xbox One의 플립 타임 프로세스: 1. 현재 상태에서 엔진의 프레임 인덱스를 전달합니다.
DXGIX_PRESENTARRAY_PARAMETERS params
params.Cookie = [internal frame index]
...
DXGIXPresentArray( ..., ¶ms )- 시간을 얻기 위해 프레임 통계를 쿼리합니다.
DXGIX_FRAME_STATISTICS stats[4]
DXGIXGetFrameStatistics( 4, stats )그런 다음 첫 번째 유효한 stats[i].Cookie 및 stats[i].CPUTimeFlip을 가져옵니다.
이 프레임의 작업 부하를 예측하려면 이전 프레임에서 작업 세그먼트의 타임스탬프를 수집해야 합니다. 스로틀이 열리기 전에 최신 측정값을 수집하고 집계하여 이전 프레임에서 전체 노력 추정치를 얻어야 합니다. 스로틀은 클라이언트 타임라인에 있기 때문에 클라이언트 작업 측정은 이중 버퍼링될 필요가 없으며 대신 완료가 보장되므로 마지막 프레임에서 직접 읽을 수 있습니다. 그러나 클라이언트 프레임은 렌더링 및 GPU 프레임과 동시에 실행되므로 타임스탬프가 수집되는 동안 작업 기간이 실행되어 시작 타임스탬프가 종료 타임스탬프 이후가 될 수 있습니다. 대조적으로, 비클라이언트 타임라인의 타임스탬프는 이중 버퍼링될 수 있습니다. 각 타임스탬프 쌍 중 적어도 하나는 완전해야 합니다. 두 쌍의 시작 시간과 종료 시간을 비교하여 가장 최근의 유효한 타임스탬프 쌍을 결정할 수 있습니다.

newEstimate = estimate * smooth + work * (1 - smooth)목표 경사: 지연 시간을 줄이고 프레임 누락 위험을 줄이시겠습니까? 가치판단; 그 일은 얼마나 스트레스를 받는가? 작업 가치의 이력으로부터 차이를 추정합니다. 조정 가능한 슬롭, 분산을 기준으로 조정됨, 슬롭이 임계값 미만인 경우 조절되지 않은 상태로 설정됨.
차이 감소: 주기적인 재방문, 엔진 내 측정이 필요한 지속적인 문제는 부실하게 계획된 작업(예: 종속성 재배치, 중요한 작업이 실행될 수 있는 코어 제한, 작업 분할/병합)으로 인해 발생하는 경우가 많습니다.
이제 스로틀을 계산하는 데 필요한 모든 항목에 대해 논의했습니다. 이전 프레임의 측정값을 평활화하여 다음 프레임이 반전되어야 하는 시간을 이전 프레임에서 추론할 수 있으며, 해당 프레임에 대한 전체 작업을 예측할 수 있으며, 이 프레임에 허용되는 슬롭은 관찰된 분산을 기반으로 휴리스틱으로 결정할 수 있습니다. 이러한 용어를 사용하여 입력을 샘플링하기 전에 클라이언트 프레임이 대기해야 하는 시간을 계산할 수 있습니다.

한발 물러서서 왜 엔진 내 모든 작업 소스와 슬롭을 식별하는 과정을 거쳐야 하는지 복습해 보겠습니다.

작업과 경사를 올바르게 정의하면 스로틀이 이러한 값에 미치는 영향을 매우 예측 가능하게 됩니다. 이를 통해 목표 경사에 따라 적절한 스로틀을 쉽게 계산할 수 있습니다. 그러면 측정된 경사는 한 프레임 내에서 목표 근처로 빠르게 수렴됩니다.

저자는 처음 지연을 연구했을 때 엔진을 큰 블랙박스로 취급하고 그 안에 있는 모든 것을 큰 블랙박스 작업이라고 불렀다. 유일한 문제는 엔진 내부의 모든 추가 슬롭 소스를 무시하고 대기열 전환에서 전환까지의 기간이었지만 작업 측정이 훨씬 쉬워졌습니다.

문제는 스로틀을 더 이상 예측할 수 없다는 것입니다. 초기 스로틀 압착 중 일부는 효과적이지만 경사에는 영향을 미치지 않습니다.

더 이상 선형이 아니며 여러 프레임을 검색해야 합니다.


결과: 감사된 데이터 스트리밍 및 동기화를 통해 CPU 집약적인 장면의 프레임 속도가 향상되고 버그가 수정되었으며 스로틀 측정이 향상되었습니다. 스로틀이 있는 플랫폼 1에서: 평균 프레임에서 ~5밀리초의 대기 시간이 절약되고, 프레임 버퍼를 미리 이동하여 대기합니다. 무거운 장면에서 vblank 누락을 방지합니다. 스로틀이 있는 플랫폼 2에서는 프레임당 대기 시간이 평균 약 22밀리초 감소하고 프레임 버퍼 대기가 프레임에서 지연되었습니다. 향후 작업: 콘텐츠 및 솔루션 작업 예측, 가변 새로 고침 빈도 지원, 지연된 입력 샘플 재투영에 중점을 둡니다. 권장 사항: 기본적으로 Vsync의 구성 파일을 켜고, 엔진 내 타이머를 사용하여 대기 시간을 시각화하고, 입력 샘플에서 스캔 출력까지 데이터 경로를 매핑하고, 동기화가 최대한 긴밀하게 이루어지도록 하고, 중복 기회를 찾고, 차이를 측정하고 줄입니다.
14.5.4.7 메시 셰이딩
메쉬 셰이딩: 지오메트리 처리의 효율성 향상을 위해 간략한 역사, 배경 및 역학, 메쉬 셰이딩 프로그래밍 모델, 새로운 애플리케이션 및 향후 방향을 포함하여 메쉬 셰이더 기술을 공유합니다. 그래픽 파이프라인과 컴퓨팅 셰이더는 GPU의 분리된 성격입니다.

계산을 래스터로 파이프라인하면 어떨까요?

기본 메쉬 셰이딩 모델:

Meshlet은 화면 공간을 위한 표준화된 인터페이스입니다.

메시 셰이더 프로그래밍 모델: 계산, 출력 메시의 공동 생성, 버텍스 및 지오메트리 셰이딩과 결합, 고정된 면 대 버텍스 비율 가정, 제한된 동적 확장과 같은 애플리케이션 정의 스레드 역할.

입력 표현은 애플리케이션 정의, 사용자 정의 압축, 비B-rep 구성표입니다. 메쉬 셰이더 ID를 사용하여 직접 주소를 지정할 수 있습니다. 파이프라인 상단의 고정 기능이 사라졌습니다. 인덱스 중복 제거도, 버텍스 어트리뷰트 추출도 없습니다. 직렬화 지점 방지 - 확장성, 버텍스 재사용을 담당하는 애플리케이션은 런타임 시 작업 중복 없이 최적화된 프리미티브 클러스터링을 미리 계산하여 전력을 절약할 수 있습니다.
동적 확장: 기하학적 합성은 증폭을 지원해야 하며, 세분화 확장 모델이 승격되고, 고정 기능 토폴로지 생성이 삭제됩니다.

작업 및 메시 셰이더가 포함된 형상 파이프라인:

작업 및 메시에는 이전 셰이더 단계가 포함되어 있습니다.

메시 셰이더 컬링: 작업 셰이더 컬링 기본 클러스터링, 프러스텀, 뒷면, 서브픽셀, 프리미티브별 FF 컬링. 사전 계산 활용, 원시 클러스터링 지역화, 알고리즘 라인 분포 예측 등을 수행합니다. 인덱스 버퍼보다 25-50% 적은 메모리로 더욱 컴팩트합니다!

동적 로드 밸런싱: 프레임당 5천만 개 이상의 삼각형이 포함된 Nvidia의 "Asteroid" 데모는 작업 셰이더에 동적 LOD를 사용하며 CPU 개입 없이 렌더링할 메시 셰이더를 생성하기 위해 미리 계산된 LOD 세트 중에서 선택합니다!
적응형 테셀레이션: 동적 삼각형 테셀레이션 형식, 바이너리 키를 사용한 효율적인 인코딩, 여러 프레임에 대한 증분 개선, 단일 패스 파이프라인을 위한 메시 셰이더 지원, 암시적 테셀레이션을 통한 작업 셰이더 업데이트, 바이너리 키에서 메시 셰이더 디코딩.

dx11 세분화도 시뮬레이션할 수 있습니다. 요약하자면, 지오메트리를 위한 새로운 프로그래밍 모델인 메시 셰이딩은 계산의 유연성과 파이프라인 스케줄링의 효율성을 결합하고, 직렬 병목 현상을 제거하여 파이프라인을 최적화하고, 지오메트리 처리의 효율성과 제어를 향상시키고, LOD 관리, 데이터 구조 순회, 지오메트리 합성 및 절차화와 같은 메시 셰이딩의 새로운 응용 프로그램에 대한 기회를 지원합니다.
14.5.4.8 나나이트
Nanite 가상화된 기하학에 대한 심층 분석은 siggraph2021 서밋에서 Epic Games의 Brian Karis와 다른 사람들이 발표하여 UE5 Nanite의 구현 세부 사항을 설명했습니다.
텍스처를 사용하는 것처럼 지오메트리를 가상화하지만 더 큰 예산 없이, 영화 품질의 소스 아트를 직접 사용하고, 수동 최적화 없이, 품질 손실 없이 지오메트리를 가상화하는 것은 항상 업계 개발자들의 꿈이었습니다. 그러나 메모리 관리뿐만 아니라 기하학적 세부 사항의 직접적인 영향으로 인해 가상 텍스처보다 구현하기가 더 어렵습니다. 나나이트 팀은 복셀, 테셀레이션, 변위 매핑, 포인트 클라우드, 삼각형 등의 표현을 비교한 결과, 마침내 삼각형보다 품질이 높거나 빠른 솔루션을 찾았습니다. 삼각형을 사용하는 것이 Nanite의 핵심입니다(그러나 구현의 다른 측면에는 다른 표현을 사용할 수도 있습니다).
GPU 기반 파이프라인: 렌더러는 여전히 보존 모드에 있으며 GPU 장면 표현은 여러 프레임에서 동일하게 유지되고 상황이 변경되는 경우 거의 업데이트되지 않으며 모든 버텍스/인덱스 데이터가 단일 대규모 리소스에 있습니다. GPU 인스턴스 컬링, 트라이앵글 래스터라이제이션는 뷰별로 수행되며 깊이만 그리면 1 DrawIndirect를 사용하여 전체 장면을 그릴 수 있습니다. 삼각형 군집화 및 제거 방법은 먼저 삼각형을 군집으로 나누고 각 군집별로 경계 데이터를 구성한 후 프러스텀 제거, 교합 제거 등 경계를 기준으로 군집을 제거하는 방법입니다.
그 중 오클루전 컬링은 HZB(Hierarchical Z Buffer) 오클루전 컬링을 기반으로 합니다. 화면 직사각형은 경계에서 계산됩니다. 화면 직사각형이 4x4 픽셀보다 작거나 같으면 가장 낮은 밉이 테스트됩니다. HZB를 만드는 방법은 무엇입니까? 이 프레임에 대해서는 아직 아무것도 렌더링되지 않았습니다. 이전 프레임에서 현재 프레임으로 Z 버퍼를 다시 투영하시겠습니까? 유용하게 사용하려면 구멍을 채워야 하는데 이는 보수적이지 않습니다. 마지막으로 2채널 크롭 컬링을 사용하면 마지막 프레임에 보이는 개체가 이 프레임에도 계속 표시될 수 있습니다. 이는 적어도 신체를 가리는 데 좋은 선택입니다. 2채널 솔루션: 이전 프레임에 보이던 것을 그리고, HZB를 구성하고, 지금은 보이지만 마지막 프레임에는 보이지 않는 것을 그리세요. 거의 완벽한 오클루전 컬링입니다! 보수적인 시각적 아티팩트는 가시성의 급격한 변화 중에만 발생합니다.
래스터라이제이션 프로세스 중 셰이더 전환, 재료 계산 오버드로잉, 오버드로잉을 방지하기 위한 깊이 프리패스, 조밀한 그리드로 인해 발생하는 픽셀 쿼드의 비효율성을 제거하기 위해 재료에서 가시성을 분리합니다. 선택적 솔루션에는 REYES, 텍스처 공간 음영 처리 및 지연된 재료가 포함됩니다.
가시성 버퍼: 화면에 기하 데이터 쓰기(깊이, 인스턴스 ID, 삼각형 ID), 픽셀당 재질 셰이더: 버퍼 로드, 인스턴스 변환 로드, 버텍스 인덱스 3개 로드, 위치 3개 로드, 위치를 화면으로 변환, 픽셀의 무게중심 좌표 내보내기, 속성 로드 및 보간. 미친 소리야? 캐시 적중이 많고 오버드로나 픽셀 쿼드 비효율성이 없기 때문에 보이는 것만큼 느리지는 않습니다. 머티리얼 채널은 GBuffer에 기록되고 다른 디퍼드 셰이딩 렌더러와 통합됩니다. 이제 깊이 프리패스뿐만 아니라 뷰당 한 번씩 삼각형을 래스터라이제이션하는 것이 아니라 완전히 GPU 기반의 1개의 그리기 호출을 사용하여 모든 불투명한 형상을 그릴 수 있습니다.
하위선형 스케일링: 가시성 버퍼는 이전보다 훨씬 빠르지만 여전히 인스턴스 및 트라이앵글 수에 따라 선형적으로 스케일링됩니다. 인스턴스의 선형 스케일링은 괜찮습니다. 최소한 일반적으로 로드하려는 레벨의 스케일링 범위 내에서는 괜찮습니다. 여기서는 백만 개의 인스턴스를 쉽게 처리할 수 있으며 삼각형의 선형 확장은 적절하지 않으며 선형으로 확장하면 "아무리 노력해도 성공"이라는 목표를 달성할 수 없습니다. Ray Tracing은 LogN으로, 훌륭하지만 충분하지 않습니다. 렌더링 속도가 충분히 빠르더라도 이러한 장면의 모든 데이터를 메모리에 저장할 수는 없습니다. 가상 기하학 부분은 메모리와 관련되어 있습니다. 그러나 레이 트레이싱은 Nanite의 목표를 달성할 만큼 빠르지 않으며 메모리에 적합하더라도 logN보다 나은 성능이 필요합니다.
다르게 말하면 화면에는 너무 많은 픽셀이 있습니다. 픽셀 대신 삼각형을 더 많이 그리는 이유는 무엇입니까? 클러스터의 경우 개체 수나 밀도에 관계없이 모든 프레임에 동일한 수의 클러스터를 그리려고 합니다. 일반적으로 지오메트리 렌더링 비용은 장면의 복잡성이 아니라 화면 해상도에 따라 조정되어야 합니다. 장면 복잡도 측면에서 이는 상수 시간을 의미하고 상수 시간은 LOD를 의미합니다.
LOD에 대한 솔루션은 클러스터를 기반으로 LOD를 결정하고 계층적 LOD를 설정하는 클러스터 계층 구조입니다. 가장 간단한 것은 클러스터 트리로, 여기서 상위 노드는 하위 노드의 단순화된 버전입니다(아래 그림 왼쪽). LOD 런타임은 지각 차이의 시점 의존성을 기반으로 LOD 트리의 원하는 컷을 찾습니다(아래 중간 이미지). 스트림을 사용하면 전체 트리를 동시에 메모리에 저장할 필요가 없습니다. 나무의 어떤 부분이라도 나뭇잎으로 표시한 다음 나머지 부분을 버리고 가상 텍스처와 유사하게 렌더링 중에 요청 시 데이터를 요청할 수 있습니다(아래 그림 오른쪽).

각 클러스터가 이웃 클러스터와 독립적으로 LOD를 결정하면 균열이 나타납니다! 대략적인 해결책: 단순화 중에 공유 경계 가장자리를 잠그고 독립 클러스터가 항상 경계에서 일치합니다. 잠긴 경계: 특히 깊은 하위 나무 사이에서 조밀한 파편을 수집합니다.

이러한 경우는 클러스터를 그룹화하여 빌드 프로세스 중에 감지할 수 있습니다. 클러스터가 동일한 LOD 결정을 내리도록 하면 이제 공유 가장자리를 자유롭게 잠금 해제하고 축소할 수 있습니다.

다양한 LOD의 전환 프로세스에 대한 개략도는 다음과 같습니다.

LOD 크랙 옵션:
- 인접한 정점을 직접 인덱싱합니다.
평행 뷰와 관련된 상세 수준 컨트롤입니다.
아웃 오브 코어 프로그레시브 메쉬와 관련된 평행 뷰.
종속성이 없는 병렬 프로그레시브 메싱.
모든 상태에서 경계 꼭지점을 인덱싱할 수 있어야 하며, 정확성 문제로 인해 균열이 불가능하고, 계산 및 메모리 측면에서 복잡하고 비용이 많이 들고, 삼각형이 너무 세밀합니다.
치마.
이웃과의 부드러운 관계.
복셀에 균열이 없는데 왜 안 되나요? 경계 표현이 아닌 솔리드 볼륨 데이터는 메시를 솔리드 볼륨으로 취급하며 적어도 이동 범위 내에서는 클러스터링이 닫혀 있어야 합니다.
청크 LOD.
경계가 직선 공간 분할인 경우에만 해당됩니다.
암시적 종속성. 공간은 노드 간의 종속성을 의미합니다.
프로그레시브 버퍼. 필요한 데이터가 존재하지 않으면 어떻게 되나요?
적응형 테트라퍼즐.
레벨 X의 노드를 특정 크기나 모양으로 강제합니다.
명시적인 종속성. 노드 간의 종속성은 빌드 및 저장 중에 결정됩니다.
빠른 VDR.
- 일괄 다중 삼각 측량.
공동 배치 다중 삼각 측량은 좋은 이론적 프레임워크이지만 Brian Karis는 이 논문이 너무 추상적이고 이론적이어서 이해하기 매우 어렵다는 것을 알았습니다. 몇 년이 지나서야 QuickVDR을 부분적으로 구현한 후 Brian Karis는 이를 다시 읽으려고 시도했고 그것이 여러 시나리오의 슈퍼 컬렉션으로서 얼마나 통찰력이 있는지 발견했습니다. 빌드 단계의 세부 내용은 몇 가지 수정 사항을 제외하고 다음에 다룰 기본 단계와 동일합니다. 이전 작업에서는 삼각형 자체를 그룹화하여 각 그룹의 삼각형 수가 가변적이 되도록 했습니다. 그러나 정확히 128개의 클러스터로 분할하려면 128개의 삼각형의 배수가 필요하며, 이는 (삼각형 대신) 클러스터를 그룹화하여 얻을 수 있습니다.
빌드 작업: NumClusters > 1인 경우 원래 삼각형 클러스터링: 공유 경계를 정리하기 위해 클러스터를 그룹화하고, 그룹의 삼각형을 공유 목록으로 병합하고, 삼각형 수를 50%로 줄이고, 축소된 삼각형 목록을 클러스터(128개 삼각형)로 분할합니다.

병합 및 분할하여 트리 대신 DAG로 만듭니다.

DAG: 어떤 클러스터를 그룹화해야 합니까? 공유된 경계 모서리가 가장 많고 잠긴 모서리가 적은 개체를 그룹화하는 문제를 그래프 분할이라고 합니다. 에지 절단 비용 최소화 그래프 분할 최적화, 그래프 노드 = 클러스터, 그래프 에지 = 직접 연결된 삼각형으로 클러스터 연결, 그래프 에지 가중치 = 공유된 삼각형 에지 수, 클러스터를 공간적으로 닫는 데 사용되는 추가 그래프 에지, 아일랜드 케이스에 대한 공간 정보 추가, 최소 그래프 에지 절단 최소 잠긴 에지, METIS 라이브러리를 사용하여 해결.
그래프 분할: 두 개를 선택하고 나머지는 해결되기를 바랍니다. 클러스터 경계 모서리 수, 각 클러스터의 삼각형 수 <= 최대값입니다. 클러스터 그룹화 문제와 마찬가지로 그래프는 그리드의 이중입니다. 파티션 크기에 대한 엄격한 상한이 필요합니다. 그래프 분할 알고리즘은 이를 보장할 수 없습니다. 강제로 적용하려면 약간의 여유와 폴백을 사용해 보세요.
메시 단순화: 가장자리 접기, 먼저 최소 오류 가장자리 선택, QEM(Quadratic Error Metric)을 사용하여 계산된 오류 사용, 오류를 최소화하기 위해 새 정점의 위치 최적화, 고도로 정제, 도입된 오류 추정값 반환, 나중에 화면에 투영된 픽셀 수의 오류도 가장 어려운 부분입니다.
오류 측정: 기본 2차식은 면적에 대한 거리^2 오류의 적분이며, 속성이 있는 2차식은 모든 오류를 가중치와 혼합하여 완전한 경험적 해킹입니다. 더 잘할 수 있을까? 하우스도르프 그리드 거리? 결과를 렌더링하고 이미지 기반 인식을 사용하시겠습니까? 비율왜곡 최적화 개념은 없습니다. 가져오기 및 빌드 시간도 중요합니다. Nanite 빌더의 모든 코드는 고도로 최적화되어 있으며 반환된 픽셀 오류와 동일한 측정 항목에 대해 최적화하기 위해 접혀 있습니다. 크기 독립성, 무게를 알기 위해 화면 크기를 알아야 함, 닭과 달걀 문제, 대부분의 클러스터가 일정한 화면 크기로 그려진다고 가정, 표면적 정규화, 가장자리 길이 제한, 많은 조정, 부동 소수점 정밀도에 매우 주의, 2차 표면의 많은 부분에 본질적으로 치명적인 상쇄가 있음.
다음은 런타임 뷰와 관련된 LOD에 대한 설명입니다. 첫 번째는 LOD의 선택입니다. 경계는 동일하지만 LOD가 다른 두 개의 하위 그래프는 화면 공간 오류, 화면에 투사된 단순화기에 의해 계산된 오류, 구 경계에서 최악의 경우 지점의 거리 및 각도 왜곡을 수정하는 기준으로 두 하위 그래프 중에서 선택합니다. 그룹의 모든 클러스터는 동일한 LOD 결정, 동일한 입력 => 동일한 출력을 내려야 합니다.
LOD 병렬 선택: LOD 선택은 DAG 전단에 해당합니다. 병렬로 계산하는 방법은 무엇입니까? 런타임에 DAG를 반복하고 싶지 않습니다. 컷을 정의하는 것은 상위 노드와 하위 노드 간의 차이입니다. 클러스터는 다음과 같은 경우에 그려집니다. 상위 노드의 오류가 너무 높고 현재 노드의 오류가 작아서 병렬로 평가할 수 있습니다(왼쪽 아래 그림)! 고유한 컷이 있는 경우에만 오류를 단조롭게 만들고 상위 뷰 오류 >= 하위 뷰 오류로 런타임 수정도 단조롭게 되도록 주의 깊게 수행됩니다(아래 오른쪽 이미지).

원활한 LOD: 상위 또는 하위의 이진 선택으로 인해 명백한 점프가 발생하지 않습니까? 원활한 전환이 필요하십니까? 기하학적 전환(Geomorphing) 및 클러스터 간 전환을 포함합니다. 오류가 1픽셀 미만인 경우 약간 다른 것으로 TAA는 모든 차이를 앨리어싱으로 처리합니다.
표면 각도 기반 LOD: 단순화는 방향을 알 수 없는 개체 공간에서 스칼라인 클러스터 오류를 생성하며 위치 오류는 방향성이 있을 수 있으며 속성 오류의 혼합으로 인해 이를 어렵게 만듭니다. 화면에 대한 투영에서는 밉맵이 단순히 거리의 함수인 경우 테셀레이션 요소 계산에 적용되는 것과 유사하게 표면 각도를 고려하지 않습니다. 구획의 스위핑 각도 표면을 나타냅니다. 이 솔루션에는 이방성 LOD가 필요하며 클러스터 선택을 통해서는 불가능합니다. 클러스터 선택은 밉 선택과 마찬가지로 등방성이어야 합니다. 포인트 기반 오버드로잉, SDF 및 SVO의 표면 판독과 같은 다른 솔루션에도 스캔 각도 비용이 발생합니다.
계층적 LOD 선택: 표시되는 클러스터는 가깝거나(모두 단일 인스턴스에서) 멀리 떨어져 있을 수 있습니다(다른 인스턴스의 모든 루트 클러스터). 계층 구조가 필요하지만 DAG 순회가 복잡합니다. 기억하세요: LOD 결정은 완전히 로컬이므로 속도를 높이고 싶은 모든 데이터 구조를 사용할 수 있습니다!
계층적 선별: LOD는 언제 클러스터를 선별할 수 있습니까?

ParentError<=임계값, ClusterError가 아닌 ParentError를 기반으로 한 트리입니다! BVH8: 하위 노드의 최대 ParentError, 내부 노드: 8개의 하위 노드, 리프 노드: 그룹의 클러스터 목록.
영구 스레드: 이상적인 상황은 상위 노드가 끝나자마자 하위 노드를 시작하고 컴퓨팅에서 직접 하위 스레드를 생성하는 것입니다. 반대로, 영구 스레드 모델은 새 스레드를 생성하여 재사용할 수 없습니다! 스레드 간 통신을 위한 간단한 MPMC(Multi-Producer Multi-Consumer) 작업 대기열을 사용하여 GPU를 채우기에 충분한 작업자 스레드로 자체 작업 대기열, 싱글샷 예약을 관리합니다. 계층적 제거: 작업 대기열이 비어 있지 않으면 대기열에서 노드가 추출되어 테스트되고 테스트를 통과한 하위 노드가 대기열에 추가됩니다. 단일 디스패치, 재귀 깊이 또는 팬아웃 제한 없음, GPU를 반복적으로 소모할 필요가 없어 장면 복잡도에 따라 10~60%(보통 약 25%)가 절약됩니다. 스케줄링 동작에 따라 다르며, 그룹이 실행을 시작하면 무기한 중단되지 않아야 하며, 스케줄링 동작은 D3D 또는 HLSL에 의해 정의되지 않고 콘솔 및 테스트된 모든 관련 GPU에서 작동하며 최적화 요구 사항일 뿐이며 Nanite의 요구 사항은 아닙니다. 군집 제거: 잎은 공통 부모를 가진 군집입니다. 유사한 제거 검사가 노드로 수행되고 가시적인 클러스터가 출력됩니다. 동일한 영구 셰이더에서 클러스터 컬링을 수행하면 한 번에 GPU를 채울 만큼 활성 BVH 노드가 충분하지 않을 수 있으며, 실행 시간은 가장 깊은 탐색의 깊이에 따라 결정될 수 있습니다. 클러스터 컬링 작업을 일찍 시작하고 이를 사용하여 구멍을 채웁니다. 노드 큐에 노드가 나타날 때까지 기다리는 두 개의 큐는 클러스터 큐에서 처리되어 64개의 배치로 병합됩니다.
2채널 오클루전 컬링: 이전에 표시된 상태를 명시적으로 추적하는 것은 복잡해지고, LOD 선택이 다를 수 있으며, 이전 프레임에 표시된 클러스터가 더 이상 메모리에 없을 수 있습니다! 이전 변환을 사용하여 이전 HZB를 테스트하여 현재 선택한 클러스터가 마지막 프레임에 표시되었는지 여부를 테스트합니다.

선별 개요:

다음으로 래스터라이제이션에 대해 이야기해 보겠습니다.
픽셀 수준의 디테일: 1픽셀보다 큰 삼각형을 사용하여 픽셀 수준의 디테일을 얻을 수 있습니까? 얼마나 매끄러워졌는지에 따라 다르지만 일반적으로 그렇지 않습니다. 픽셀 크기의 삼각형을 그려야 합니다. 작은 삼각형의 경우 일반적인 래스터라이저를 사용하는 것은 너무 끔찍합니다. 일반적인 래스터라이저: 큰 타일의 경우 비닝, 마이크로 타일의 경우 4x4, 삼각형이 아닌 평행한 픽셀 높이를 사용하여 2x2 픽셀 쿼드를 출력합니다. 최신 GPU는 최대 4개의 삼각형/시계를 설정하며 SV_PrimitiveID를 출력하면 상황이 더욱 악화됩니다. 소프트웨어 래스터라이저가 하드웨어 래스터라이저를 이길 수 있습니까? 실제로 소프트웨어 래스터라이저는 하드웨어 래스터라이저보다 3배 빠릅니다! ! !

작은 삼각형의 경우 삼각형을 비닝하는 것은 마지막 픽셀을 쓰는 것만큼 어렵고 단일 벡터 찌르기조차도 작은 삼각형에 대한 낭비적인 테스트이므로 기본 경계 상자가 더 빠릅니다. 깊이 및 ROP를 처리하기 위한 타일 수준의 직렬화, 출력 2x2 픽셀 쿼드, 일반적인 VS+PS 스케줄링, 출력 형식, 정렬, 블렌딩, 클리핑... 여러 픽셀을 포함하는 더 큰 삼각형에 최적화되고, 광범위하게 픽셀에서 실행되고, 많은 픽셀이 있는 삼각형을 원하고, 삼각형 3에서 실행됩니다.
작은 소프트웨어 래스터라이저: 128개의 삼각형 클러스터 => 스레드 그룹 크기 128, 정점당 스레드 1개, 위치 변환, 그룹 공유에 저장, 정점이 128개를 초과하는 경우 루프(최대 2개). 삼각형당 스레드 1개, 인덱스 가져오기, 변환된 위치 가져오기, 가장자리 방정식 및 깊이 그라데이션 계산, 화면 경계 사각형 계산, 직사각형의 모든 픽셀에 대해 모든 변 안에 있는 경우 픽셀을 씁니다.

for( uint y = MinPixel.y; y < MaxPixel.y; y++ )
{
float CX0 = CY0;
float CX1 = CY1;
float CX2 = CY2;
float ZX = ZY;
for( uint x = MinPixel.x; x < MaxPixel.x; x++ )
{
if( min3( CX0, CX1, CX2 ) >= 0 )
{
WritePixel( PixelValue, uint2(x,y), ZX );
}
CX0 -= Edge01.y;
CX1 -= Edge12.y;
CX2 -= Edge20.y;
ZX += GradZ.x;
}
CY0 += Edge01.x;
CY1 += Edge12.x;
CY2 += Edge20.x;
ZY += GradZ.y;
}하드웨어 래스터라이제이션: Big Triangle은 클러스터별로 소프트웨어 또는 하드웨어 래스터라이제이션를 선택하고 UAV에 대한 64b 원자 쓰기를 위해 하드웨어 래스터라이저를 사용합니다.
스캔라인 소프트웨어 래스터라이저: 얼마나 큰가요? 예상보다 훨씬 크고 가장자리가 32픽셀보다 작은 클러스터는 소프트웨어 래스터라이제이션되어 직사각형의 많은 수의 픽셀을 반복적으로 테스트합니다. 최상의 경우에는 절반이 포함되고 최악의 경우에는 없음(왼쪽 아래)이 포함됩니다. 스캔라인이 더 빨라질 수 있나요? 전통적인 사다리꼴은 설정과 가장자리 통과가 많아 더 복잡합니다(아래 오른쪽 그림).

for( uint y = MinPixel.y; y < MaxPixel.y; y++ )
{
float CX0 = CY0;
float CX1 = CY1;
float CX2 = CY2;
float ZX = ZY;
for( uint x = MinPixel.x; x < MaxPixel.x; x++ )
{
// 의 x는 ?
if( min3( CX0, CX1, CX2 ) >= 0 )
{
WritePixel( PixelValue, uint2(x,y), ZX );
}
CX0 -= Edge01.y;
CX1 -= Edge12.y;
CX2 -= Edge20.y;
ZX += GradZ.x;
}
CY0 += Edge01.x;
CY1 += Edge12.x;
CY2 += Edge20.x;
ZY += GradZ.y;
}
// 개선
float3 Edge012 = { Edge01.y, Edge12.y, Edge20.y };
bool3 bOpenEdge = Edge012 < 0;
float3 InvEdge012 = Edge012 == 0 ? 1e8 : rcp( Edge012 );
for( uint y = MinPixel.y; y < MaxPixel.y; y++ )
{
// 는 포인트 ,는 。
float3 CrossX = float3( CY0, CY1, CY2 ) * InvEdge012;
float3 MinX = bOpenEdge ? CrossX : 0;
float3 MaxX = bOpenEdge ? MaxPixel.x - MinPixel.x : CrossX;
// 의 x
float x0 = ceil( max3( MinX.x, MinX.y, MinX.z ) );
float x1 = min3( MaxX.x, MaxX.y, MaxX.z );
float ZX = ZY + GradZ.x * x0;
x0 += MinPixel.x;
x1 += MinPixel.x;
// 오직 패딩/채우기 픽셀(Pixel)
for( float x = x0; x <= x1; x++ )
{
WritePixel( PixelValue, uint2(x,y), ZX );
ZX += GradZ.x;
}
...
}래스터라이제이션된 오버드로: 삼각형별 컬링 없음, 픽셀의 하드웨어 HiZ 컬링 없음, 이전 프레임의 소프트웨어 HZB, 픽셀 대신 클러스터 컬링, 클러스터 화면 크기 기반 해상도. 오버드로는 큰 클러스터, 겹치는 클러스터, 집계, 빠른 동작, 오버드로 비용(작은 삼각형 - 버텍스 변환 및 삼각형 세트 경계, 중간 삼각형 - 픽셀 적용 범위 테스트 경계, 큰 삼각형 - 원자 제약 조건)에서 발생합니다.

작은 예: 전체 그리드가 몇 개의 픽셀만 포함하면 어떻게 되나요? DAG는 1개의 루트 클러스터, 128개의 삼각형으로 끝나고 해상도 조정은 없습니다. 너무 어릴 때 컬링을 하시나요? 블록으로 구성되어 있는 경우에는 그렇지 않습니다. 병합은 어느 시점에서 분명히 수행되어야 하며, 렌더링이 선형적으로 확장되더라도 메모리는 그렇지 않습니다. 인스턴스 메모리는 10M * float4X3 = 457MB로 빠르게 누적되며 향후 필요한 계층적 인스턴스화, 인스턴스의 인스턴스가 필요합니다. Nanite에는 병합을 위한 특별한 솔루션이 없으며, 병합을 위한 유일한 프록시는 극단적인 거리에 있는 인스턴스를 교체해야 하며, 주요 개선 사항은 이 거리를 더욱 확장하는 것입니다.
가시성 버퍼 대체(임포스터): 아틀라스의 12 x 12 뷰 방향, 뷰 방향에 매핑된 XY 아틀라스 위치 팔면체, 지터 방향 양자화. 방향당 12 x 12 픽셀, 직교 투영, 메시 AABB의 최소 범위, 8:8 깊이 및 삼각형 ID, 메시당 40.5K가 항상 상주합니다. 광선은 방향 사이의 시차를 조정하기 위해 이동합니다. 시차가 작기 때문에 몇 단계만 거치면 됩니다. 보이는 인스턴스 목록을 우회하여 인스턴스 컬링 채널에서 직접 그립니다. 더 나은 방법을 생각해 보세요.

다음으로 지연된 재료 평가에 대해 이야기하겠습니다.
Material ID: 이 픽셀은 어떤 재질로 만들어졌나요? VisBuffer 디코딩:
VisibleCluster => 인스턴스ID, 클러스터ID.
ClusterID+TriangleID => MaterialSlotID.
InstanceID+MaterialSlotID=>MaterialID.

머티리얼 셰이딩: 각 고유 머티리얼에 대한 전체 화면 쿼드, 이 머티리얼 ID와 일치하지 않는 픽셀을 건너뛰고, CPU는 일부 머티리얼에 눈에 보이는 픽셀이 없는지 알지 못하며 어쨌든 머티리얼 그리기 호출을 발행합니다. 불행한 GPU 드라이버의 부작용입니다. 효과적으로 수행하는 방법은 무엇입니까? 각 픽셀이 각 재질 채널의 재질 ID와 일치하는지 여부를 테스트하지 마세요.
머티리얼 컬링: 템플릿 테스트? 각 자료마다 재설정하고 싶지 않습니다. 깊이 테스트 하드웨어, 재질 ID->깊이 값을 사용할 수 있습니다. 재료 깊이 버퍼를 빌드합니다. CS는 모든 재료에 대해 두 깊이 버퍼 모두에 대해 표준 깊이와 HTILE도 출력합니다. 전체 화면 쿼드를 그립니다. 쿼드의 Z = 재료 깊이, 깊이 테스트는 동일하게 설정됩니다.

UV 파생물: 여전히 일관된 픽셀 셰이더이므로 유한 차분 파생물이 있습니다. 픽셀 쿼드 스팬(삼각형), 좋습니다! 또한 깊이 불연속성, UV 이음새, 다양한 개체에 걸쳐 있습니다(나쁜!). 분석 파생물: 체인 규칙을 사용하여 재료 노드 그래프에 전파되는 분석 파생물, 삼각형의 속성 그라데이션을 계산합니다. 도함수를 분석적으로 계산할 수 없는 경우 유한 차분으로 대체합니다. 유한 차분은 SampleGrad를 사용하여 텍스처를 샘플링하는 데 사용됩니다. 추가 비용은 재료 채널 비용의 2% 미만으로 최소화되며 이는 텍스처 샘플링 계산에만 영향을 미치며 가상 텍스처 코드는 SampleGrad에서 완성되었습니다.

파이프라인 번호:

성능: 4k로의 업샘플링은 평균 약 2496x1404였으며 당시에는 TAAU를 사용했고 현재는 TSR을 사용합니다. 전체 VisBuffer를 그리는 데 약 2.5ms, 보기 + GPU 장면 => VisBuffer 완료, CPU 시간이 거의 0입니다. 약 2ms 지연된 머티리얼 채널, VisBuffer=>GBuffer, 낮은 CPU 비용, 각 머티리얼은 한 번 그려집니다.

다음으로 나나이트의 그늘에 대해 이야기해보겠습니다. 나나이트의 그림자가 레이 트레이싱되었나요? DXR은 복잡한 LOD 로직, 사용자 정의 삼각형 인코딩 및 부분 BVH 업데이트가 없기 때문에 유연성이 충분하지 않습니다. 다른 모든 작업과 함께 래스터 솔루션을 원하면 대부분의 조명은 움직이지 않으며 가능한 한 많이 캐시되어야 합니다.
가상 그림자 맵: Nanite가 가능하게 만든 새로운 기술, 어디서나 16k x 16k 그림자 맵, 스포트라이트용 1x 드롭 섀도우, 포인트 라이트용 6x 큐브, 방향성 조명용 Nx 클립맵. 1텍셀 = 1픽셀인 밉 레벨을 선택하고 LOD 요구 사항에 따라 보이는 그림자 이미지 픽셀, 나나이트 컬링 및 LOD만 렌더링합니다.

페이지 크기 = 128 x 128, 페이지 테이블 = 128 x 128, mip 포함. 필요한 페이지를 표시하고, 화면 픽셀을 그림자 공간에 투영하고, 밉 레벨(1텍셀=1픽셀)을 선택하고 해당 페이지를 표시합니다. 모든 필수 페이지에 물리적 페이지를 할당하고, 이미 존재하는 경우 캐시된 페이지를 사용하고, 캐시되지 않은 경우 무효화하고, 필수 페이지 마스크에서 제거합니다.

멀티 뷰 렌더링: 상당한 동기화 오버헤드가 있는 딥 파이프라인, NumShadowViews = NumLights x NumShadowMaps x NumMips, 다양한 뷰를 동시에 선별 및 래스터라이제이션하여 비용을 분산시킬 수 있으며 요소는 뷰 ID를 사용하여 표시됩니다.
페이지 선별 및 주소 지정: 원하는 페이지가 겹치지 않는 경우 HZB 테스트와 유사하게 선별이 수행됩니다. 소프트웨어 래스터는 겹치는 페이지당 클러스터를 내보내고, 하드웨어 래스터는 원자성 쓰기 전에 픽셀 단위로 페이지 테이블을 간접적으로 처리합니다.

Nanite 그림자 LOD: 1텍셀=1픽셀, 화면 픽셀에 비례하는 NumPages, <1픽셀의 LOD 일치 오류, 그림자 픽셀에 비례하는 numtriangle로 페이지를 렌더링합니다. 섀도우 비용은 해상도에 정비례합니다! 장면의 복잡성보다는 픽셀당 광원 수에 정비례합니다.
다음으로 스트리밍에 대해 이야기해보겠습니다. 가상 기하학, 고정된 메모리 예산 하에서 무한한 기하학. 개념적으로 가상 텍스처와 유사하게 GPU는 필요한 데이터를 요청하고 CPU는 고유한 과제를 통해 채우기를 완료합니다. 런타임 시 DAG를 로드된 형상으로만 절단하는 것은 LOD 절단과 유사하게 균열 없이 항상 전체 DAG의 유효한 절단이어야 합니다!
흐름 단위: 클러스터는 상위 클러스터와 겹칠 수 있습니다. 렌더링 클러스터 => 모든 상위는 렌더링되지 않아야 하며, 상위 노드는 렌더링되지 않습니다. => 구멍을 채우기 위해 모든 형제(또는 하위 항목)가 렌더링되어야 하며, 그룹의 클러스터를 렌더링하려면 전체 그룹이 필요합니다. 스트리밍은 그룹 단위로 수행되어야 하며, 도형 크기는 가변적이며, 메모리 조각화를 피하기 위해 고정 크기 페이지를 사용합니다. => 페이지당 다양한 도형 수입니다.
페이징: 런타임에 필요한 페이지 수를 최소화하기 위해 공간적 지역성을 기반으로 고정 크기 페이지를 그룹으로 채웁니다. 루트 페이지의 첫 번째 페이지에는 DAG의 최상위 수준이 포함되어 있으며 항상 상주하므로 항상 렌더링할 항목이 있습니다. 페이지 콘텐츠: 인덱스 데이터, 버텍스 데이터, 메타데이터(경계, LOD 정보, 재료 테이블 등), 상주 페이지는 대규모 GPU 페이지 버퍼에 저장됩니다.

그룹화된 부분의 경우 느슨합니다. 클러스터는 작고(~2KB) 그룹은 매우 클 수 있으며(8-32개의 클러스터) 전체 그룹이 할당되면 상당한 여유가 발생합니다. 그룹 분할: 그룹은 여러 연속 페이지에 걸쳐 있을 수 있으며, 메모리 사용량을 기준으로 클러스터 단위로 분할할 수 있습니다. 모든 부분이 로드되기 전에 그룹은 활성화되지 않으며 페이지는 이제 클러스터 단위(~2KB)로 채워지며 페이지당 평균 유휴 시간은 ~1KB입니다! (128KB 페이지에는 약 1%의 여유 시간이 있습니다)

무엇을 스트리밍할지 결정: UV 및 그라데이션/LOD 수준에서 직접 제공되는 가상 텍스처에 대해 쉽습니다. Nanite의 경우 그려야 할 클러스터를 찾기 위해 레이어 순회가 필요하며 스트리밍 절단이 필요합니다. 완전히 선별된 계층은 항상 클러스터 그룹에 대한 (작은) 메타데이터와 함께 상주하며 순회는 로드된 수준을 넘어설 수 있으므로 목표 품질을 달성하는 데 필요한 모든 수준이 즉시 필요합니다.
스트리밍 요청: 컬링 순회 중에 영구 셰이더는 페이지 요청을 출력하고, LOD 오류를 기반으로 우선순위가 있는 페이지 범위를 요청하고, 로드된 페이지의 우선순위를 업데이트합니다. 요청의 비동기 CPU 다시 읽기: 누락된 DAG 종속성을 추가하고, 전체 우선순위가 가장 높은 페이지에 대한 IO 페이지를 요청하고, 우선순위가 낮은 페이지를 제거합니다. 완료된 IO 요청 처리: GPU에 페이지 마운트, GPU 측 포인터 수정, 새로 로드/언로드된 페이지의 그룹에 대한 포인터 수정, 완료되었거나 더 이상 완료되지 않은 분할 그룹에 대한 포인터 수정, 클러스터를 리프로 표시/표시 해제합니다.
다음으로 압축에 대해 알아보겠습니다. 메모리 표현과 디스크 표현이라는 두 가지 표현이 있습니다. 메모리 내 표현: 렌더링을 위한 직접, 거의 즉각적인 디코딩 시간, 가시성 버퍼, 양자화 및 비트 압축에서 임의 액세스를 지원해야 하며 목표는 메모리 및/또는 대역폭을 절약하는 것입니다. 디스크 표현: 데이터가 유입되면 더 높은 디코딩 비용을 견딜 수 있고 임의 액세스가 필요하지 않은 메모리 내 표현으로 트랜스코딩합니다. 단, 데이터가 (하드웨어) 바이트 기반 LZ에 의해 압축된다고 가정하면 압축된 디스크 크기를 줄일 수 있습니다.
버텍스 양자화 및 인코딩: 최소/최대 범위를 기준으로 로컬 좌표에 값을 저장하는 전역 양자화, 아티스트 제어 및 영감을 받은 클러스터의 조합입니다. 구성 요소당 최소 비트 수(ceil(log2(range)))를 사용하는 클러스터당 사용자 정의 버텍스 형식은 버텍스 비트스트림이 버텍스 선언을 디코딩해야 합니다. 버텍스 선언은 바이트 정렬이 아닌 비트 문자열일 뿐입니다. GPU 비트스트림 리더로 디코딩: 다양한 형식 => 읽을 때마다 다시 채워지나요? 누적 컴파일 시간 읽기 크기가 오버플로되는 경우에만 다시 채워지는 지정된 읽기 크기에 대한 컴파일 시간 범위를 읽습니다.
버텍스 위치: 일관되지 않은 양자화로 인해 균열이 발생합니다! 단일 물체를 피하기 쉬운데, 물체 사이의 균열을 피하는 방법은 무엇입니까? 모듈을 사용하여 고도 지오메트리를 구축하는 일반적인 방법입니다. 객체 공간 그리드로 양자화: 객체당 2N의 거듭제곱에 대한 절대 지수(예: 1/16cm), 객체 원점을 중심으로 경계로 정규화되지 않습니다. 다음과 같은 경우 정점이 동일한 메시에 속합니다. 양자화 수준이 동일하고 객체 간 변환도 단계 크기의 배수입니다. 리프 수준만 완전히 정렬되고, 단순화 결정이 개체 간에 일관되지 않으며, 런타임 LOD 결정이 동기화되지 않습니다.

암시적 탄젠트 공간: 0비트! 탄젠트/부접선은 뷰 공간 노멀 평면의 U/V 방향입니다. 이를 파생시키세요! 스크린 파생 탄젠트 공간(Mikkelsen)과 유사하며 스크린 ddx/ddy를 사용하는 대신 삼각형 좌표에서 직접 계산되며 재질 채널의 무게 중심 및 텍스처 LOD 계산을 위해 이미 계산된 로컬 삼각형 uv/위치 삼각형을 재사용합니다. 기존의 명시적 탄젠트 좌표는 이웃 평균으로 계산되며 높은 다각형 메시의 경우 덜 중요합니다.
재료 테이블: 각 클러스터는 재료에 의해 지정된 삼각형 범위, 동일한 32비트의 인코딩 별칭 2개, 3개 범위 인코딩의 빠른 경로, 메모리를 가리키는 느린 경로, 최대 64개의 재료를 지정하는 재료 테이블을 저장합니다.
디스크 표현: 하드웨어 LZ 압축 해제, DirectStorage, 문자열 중복 제거 및 엔트로피 인코딩을 사용하는 콘솔과 PC에서 놀라울 정도로 빠르고 다재다능합니다. 더 나은 압축을 위해: 데이터가 LZ에 의해 압축된다고 가정하고 아직 LZ에 의해 캡처되지 않은 중복성에 중점을 두고 보다 압축 가능한 형식으로 도메인별 변환을 수행합니다.
GPU 트랜스코딩: GPU에서의 트랜스코딩, 병렬 변환의 높은 처리량, 병렬인 한 바이트당 많은 (비동기) 계산이 있으며 현재 약 50GB/s로 실행되고 있으며 PS5의 코드는 상당히 최적화되지 않았으며 궁극적으로 데이터가 GPU 메모리로 직접 전송됩니다. 직렬 엔트로피 인코딩 및 문자열 일치를 처리하는 하드웨어 LZ의 성능과 결합하면 이 세대의 일반적인 패턴이 될 수 있습니다. Nanite: GPU에는 컨텍스트가 있으며 페이지는 CPU 복사본 없이도 상위 페이지의 데이터를 참조할 수 있습니다.
Lumen in the Land of Nanite에 대한 결과: 4억 3300만 개의 입력 삼각형, 8억 8200만 개의 Nanite 삼각형, 원시 데이터: 25.90GB, 전체 부동 소수점, 바이트 인덱스, 암시적 탄젠트, 메모리 형식: 7.67GB, 압축: 6.77GB, 압축 디스크 형식: 4.61GB, EA 버전보다 ~20% 개선, Nanite 삼각형당 5.6바이트, 입력 삼각형당 11.4바이트, 백만 개의 삼각형 = 디스크에서 ~10.9MB.
Nanite 소스 코드 분석은 언리얼 렌더링 시스템 분석(06) - UE5 특별 1부(기능 및 Nanite)를 참조하세요.
14.5.4.9 래디언스 캐싱
[실시간 전역 조명을 위한 복사 캐싱]( https://dl.acm.org/doi/abs/10.1145/3450626.3459812#:~:text=Abstract 실시간 신경 복사 캐싱을 제시합니다. ,no%20assumptions%20about%20the%20lighting%2C%20geometry%2C%20and%20materials.) Epic Games의 Daniel Wright가 발표한 이 글에서는 UE5 Lumen의 실시간 전역 조명 구현 기술인 Radiance Caching에 대해 설명합니다. Radiance Caching은 Lumen에서 사용되는 최고의 수집 기술로, 차세대 콘솔 게임을 대상으로 하며 고급 PC에서 품질 우선으로 끌어올립니다. Ray Tracing은 매우 느리고 보조 BVH, 일관성 없는 트리 순회 및 인스턴스 중첩과 같은 문제가 있습니다.

픽셀당 1/2 광선만 제공되지만 고품질 GI에는 수백 개가 필요합니다!

이전의 실시간 연구에는 Irradiance Fields 및 Screen Space Denoiser와 같은 방법이 포함되었습니다. Lumen은 스크린 공간 래디언스 캐싱을 사용합니다.

입사광은 일관성이 있지만 기하학적 법선은 그렇지 않은 입사 방사선을 다운샘플링하면 전체 해상도에서 BRDF에 입력 조명을 통합합니다.

화면 공간이 아닌 래디언스 캐시 공간에서 필터링합니다(왼쪽 아래). 첫 번째 일은 더 나은 샘플링을 수행하는 것입니다. 중요한 것은 들어오는 빛을 샘플링하는 것입니다(아래 이미지 참조). 안정적인 장거리 조명 및 월드 공간 방사선 캐시(아래, 오른쪽).

최종 수집 파이프라인:

화면 공간 방사조도 캐시는 다음 단계로 세분화될 수 있습니다.

스크린 프로브 구조: 경계가 있는 팔면체 아틀라스(일반적으로 프로브당 8x8), 월드 공간 방향이 고르게 분포되어 있고 2D 아틀라스에서 방향, 광도 및 교차 거리가 동일한 이웃입니다.

스크린 프로브 배치: 계층적 개선을 통한 적응형 레이아웃 [Křivánek et al. 2007], 반복 보간법이 실패하는 경우 최종 수준 홍수 채우기.

적응형 샘플링: 실시간 성능을 위한 상한이 필요하고 적응형 프로브를 처리할 때 추가 장애물에 직면하지 않으려면 적응형 프로브를 아틀라스 하단에 배치합니다.

스크린 프로브 디더링: 시간 디더링은 누출 없이 픽셀에 그리드와 방향을 직접 배치하므로 스크린 셀 내의 폐색 차이는 시간 필터링을 통해 숨겨야 합니다.

보간: 전경 누락이 배경으로 누출되는 것을 방지하기 위한 평면 거리 가중치, 보간 시 지터 오프셋, 동일한 평면에 있는 한 프로브 간의 차이를 공간적으로 분산하고 최종 조명을 위해 TAA 3x3 이웃을 확장하여 시간적 안정성을 달성합니다.
중요도 샘플링: 입사 광도
구조화된 중요도 샘플링: 확률 밀도 함수(PDF)의 계층적 영역에 소수의 샘플을 할당합니다. [Agarwal et al. 2003] 좋은 글로벌 계층화를 달성하기 위해. 샘플 배치에는 오프라인 알고리즘이 필요합니다.

팔면체 밉 쿼드트리에 완벽하게 매핑되었습니다!

파이프라인에 통합: 추적 스레드에 간접 경로를 추가하고, RayCoord, MipLevel을 저장하고, 추적 후 최종 통합을 위해 TraceRadiance를 균일한 프로브 레이아웃으로 결합합니다.

광선 생성 알고리즘: 추적 스레드를 포화 상태로 유지하기 위해 균일하게 분포된 프로브 광선 방향에서 시작하여 BRDF의 PDF x 각 팔면체 텍스처에 대한 빛의 PDF를 계산합니다. 고정된 출력 광선 개수가 필요합니다. PDF별로 광선을 정렬하고, PDF가 컬링 임계값보다 낮은 3개 광선마다 높은 PDF 광선과 일치하도록 슈퍼샘플링합니다.

개선 사항: 조명 PDF는 광선을 컬링할 수 없으며, 조명 PDF는 대략적이며, BRDF는 정확합니다. 컬링은 공간 필터링을 통해 보다 적극적으로 수행될 수 있으며, 더 높은 BRDF 임계값으로 컬링, 공간 필터링 중 컬링된 광선의 무게가 감소하고, 모서리가 어두워지는 문제를 수정합니다.

중요도 샘플링 검토: 마지막 프레임의 조명과 원거리 조명을 사용하여 이 프레임의 광선을 안내하면 광선을 프로브에 묶으면 더 스마트한 샘플링을 제공할 수 있습니다.
다음으로 공간 필터링 기술에 대해 이야기해보겠습니다.
방사선 캐시 공간 필터링: 저렴한 대규모 공간 필터링, 프로브 공간은

평평한 표면에는 효과가 좋지만 형상이 접촉하는 장소에서는 빛샘 문제가 있습니다.

접촉 그림자 유지: 원거리 조명 쪽으로 편향된 각도 오류 = 누출, 원거리 조명에는 시차가 없으며 결코 거부되지 않습니다. 해결 방법: 재투영하기 전에 이웃의 적중 거리를 자신의 거리에 맞춰 고정하세요.

다음으로 월드 공간의 방사선 캐시에 대해 이야기해 보겠습니다.
원거리 조명에 문제가 있고, 약간 밝은 특징에서 발생하는 노이즈가 거리에 따라 증가하고, 길고 고르지 못한 트레이스가 느리고, 원거리 조명이 천천히 변합니다. 캐싱 기회가 있고 근처 화면 프로브의 중복 작업이 가능합니다. 해결책: 원거리 방사선을 별도로 샘플링합니다. 원거리 조명을 위한 월드 공간 래디언스 캐시(The Tomorrow Children [McLaren 2015]의 기술), 월드 공간 이후 안정적인 오류 - 체적 라이트맵처럼 숨기기 쉽습니다.

파이프라인 통합: 화면 주위에 프로브를 배치한 다음 방사선을 추적하고 계산하여 화면 프로브 광선의 장거리 조명을 설명하기 위해 보간합니다.

자체 조명 방지: 월드 프로브 광선은 보간된 발자국을 건너뛰어야 합니다.

연결된 광선: 스크린 프로브 광선은 보간된 공간 + 건너뛰기 거리를 커버해야 합니다.

빛샘 문제도 있다. 월드 프로브의 방사선은 차단되어야 하지만 시차가 잘못되어서는 안됩니다.

해결책: 단순한 구형 시차. 월드 프로브 구와 교차하도록 스크린 프로브 광선을 재투영합니다.

희박한 적용 범위: 카메라 중심의 3D 클립맵 그리드는 프로브 인덱스를 아틀라스에 저장하고 클립맵 배포는 화면 크기로 제한됩니다.

아틀라스(Atlas): 팔면체 프로브 아틀라스는 방사선 및 추적 거리(보통 각 프로브에 대해 32x32 방사선)를 저장합니다.

배치 및 캐싱: 마커는 클립맵 간접 참조에서 나중에 어디에든 삽입됩니다. 표시된 각 월드 프로브에 대해 이전 프레임의 추적을 재사용하거나 새 프로브 인덱스를 할당하고 캐시 히트의 하위 집합을 다시 추적하여 조명 변경을 전파합니다.

문제: 매우 가변적인 비용, 빠른 카메라 이동 및 캐시되지 않은 많은 프로브를 추적해야 하는 불연속적인 필요성. 솔루션: 전체 해상도 프로브를 위한 고정 예산, 캐시 누락을 위한 저해상도 기타 프로브 추적, 기타 프로브 추적을 위한 조명 업데이트 건너뛰기.
중요도 샘플링. BRDF의 중요한 샘플링: 스크린 프로브, 주사위 프로브 추적 타일에서 BRDF를 축적하고 BRDF를 기반으로 추적 타일 해상도를 생성합니다. 슈퍼샘플링된 근접 카메라, 최대 64x64의 유효 해상도, 4096트랙! 매우 안정적인 장거리 조명.
프로브 간 공간 필터링: 다시 이웃 교차점을 거부하면 문제는 상호 가시성을 가정할 수 없다는 것입니다. 이상적으로는 단일 폐색 시도가 잘 작동하며 프로브 깊이를 재사용하여 프로브 깊이를 통해 인접한 광선 경로를 재추적함으로써 거의 무료입니다.


월드 공간 방사선 캐시는 스크린 프로브 중요도 샘플링, 머리카락, 반투명도, 다중 바운스를 안내하는 데에도 사용됩니다.
통합으로 돌아가서 이제 입사 방사선이 화면 공간의 방사선 캐시에서 더 낮은 해상도로 계산되었으므로 모든 기하학적 세부 사항을 얻으려면 전체 해상도로 통합해야 합니다.

중요도 샘플링 BRDF는 일관성 없는 획득, 8spp*4 인접 프로브 방향 조회로 이어지며 밉(필터링된 중요도 샘플링)을 사용할 수 있지만 자체 조명으로 이어질 수 있습니다[Colbert et al. 2007], 특히 직접 조명을 받는 영역 주변. 프로브 방사선을 3차 구면 고조파로 변환: SH는 스크린 프로브별로 계산되고, 전체 해상도 픽셀은 SH로 균일하게 로드되며, SH는 저비용 및 고품질 통합입니다[Ramamoorthi 2001].

Rough Specular: 디퓨즈에 초점을 맞춘 높은 거칠기의 레이 트레이싱 반사입니다. 스크린 프로브 재사용: GGX에서 방향을 생성하고, 프로브 방사선을 샘플링하고, 완료된 프로브 샘플링 및 필터링을 자동으로 활용합니다! 다운샘플링된 추적에서는 접촉 그림자가 손실됩니다. 전체 해상도 곡선 노멀: 빠른 화면 추적을 사용하여 계산되며, 화면 프로브 사이의 거리에 결합된 추적 거리: ~16픽셀. 스크린 공간 방사선 캐시와의 통합: 스크린 프로브 GI를 원거리 방사조도로 취급하고, 전체 해상도 곡선 법선은 근거리의 양을 나타내며, 수평 기반 간접 조명[Mayaux 2018], 다중 바운스 근사는 근거리 방사조도를 제공합니다.


시간 필터링: 지터 프로브 위치에는 깊이 컬링을 사용하는 안정적인 시간 필터링이 필요합니다. 이를 통해 안정적인 결과를 얻을 수 있지만 빛 변화에 대한 응답 속도도 느려집니다. 추적 과정에서 빠르게 움직이는 물체의 투영 영역에 속하는 히트 속도와 히트 깊이가 추적됩니다. 빠르게 움직이는 개체를 추적하면 빠른 업데이트 모드로 전환하고 시간 필터링을 낮추고 공간 필터링을 높입니다.

최종 컬렉션 성능:



향후 작업은 폐색 제거 품질, 매우 동적인 장면의 시간적 안정성, 다중 바운스 GI를 위한 Lumen의 표면 캐시에 화면 공간 방사선 캐싱 적용에 관한 것입니다. Radiance Cache는 Lumen 기술의 일부일 뿐입니다. Lumen에는 표면 캐싱, 소프트웨어 레이 트레이싱, 하드웨어 레이 트레이싱, 반사, 투명 GI 등도 포함됩니다. Lumen의 소스 코드 분석은 Unreal Rendering System 분석(06) - UE5 Special Part 2(Lumen 및 기타)를 참조하세요.
14.5.4.10 서펠 GI
Surfels를 기반으로 한 전역 조명은 실시간 전역 조명을 구현하기 위해 표면 요소를 사용하는 EA 내부 엔진의 기술을 설명합니다. GIB(Global Illumination Based on Surfaces)는 간접 확산 조명을 실시간으로 계산하는 솔루션입니다. 이 솔루션은 하드웨어 레이 트레이싱과 장면 형상의 이산화를 결합하여 시간과 공간에 걸쳐 조명 계산을 캐시하고 상각합니다. 사전 계산, 특수 메시, 특수 UV 세트가 필요하지 않습니다. GIBS는 어떤 규모의 콘텐츠도 수용하면서 충실도가 높은 조명을 지원합니다. "

Surfel 전역 조명을 기반으로 한 표면 시각화입니다.
이번 강연의 내용은 Surfel 이산화, 비선형 가속도 구조, 조도 통합 기술, 색상 오버플로 완화, 다중 광원 샘플링, 투명도 등을 포함합니다. 먼저 표면 요소의 개념을 이해해야 합니다. Surfel=표면 요소. 서핑은 위치, 반경 및 법선으로 정의되며 주어진 위치 근처 표면의 작은 이웃에 가깝습니다.

장면 표면화: GBuffer에서 서펠을 생성하고, 형상이 시야에 들어올 때 화면을 채우고, 월드 공간에서 지속되며 방사조도를 축적하고 캐싱합니다. 화면 공간 채우기를 반복하고, 화면을 16x16 블록으로 분할하고, 적용 범위가 가장 낮은 타일을 찾고, 빈 적용 범위와 추적 가중치를 적용하고, 타일이 임의 임계값을 초과하는 경우 서핑을 생성합니다.

강체를 지원하는 것 외에도 스킨 뼈의 비닝도 지원합니다. 모든 것이 동적이라고 가정하기 때문에 스킨 처리된 형상과 이동된 형상 모두 정적 형상처럼 솔루션의 나머지 부분과 상호 작용합니다.

빈은 화면 공간 투영에 따라 크기가 조정되며 생성 알고리즘은 비선형 가속 구조를 통해 모든 거리에서 적용 범위를 보장합니다.

빈 관리: 모든 것에 대한 고정 크기 버퍼, 예측 가능한 예산, 고정된 빈 수, 고정된 가속 구조, 사용하지 않는 빈 재활용.

재활용 휴리스틱: 관련 저장소를 활성 상태로 유지하고, 마지막으로 확인했을 때 추적하고, 간격 감지 중에 표시되면 재설정하고, 위치 업데이트 중에 증가합니다. 휴리스틱은 활성화된 저장소의 총 수, 본 이후의 시간, 거리 및 적용 범위를 기반으로 합니다. 다음 그림은 거리 휴리스틱입니다.

조명 적용: 각 픽셀에 대해: 표면 그리드 셀을 찾고, 셀에서 N개의 빈을 가져오고, 표면 방사조도를 축적하고, 거리 및 법선에 따라 가중치를 부여하고, 방사 가중치 < 1인 경우 가중 평균 셀 방사조도를 추가합니다. 방사형 가우스 깊이를 사용하여 해결되는 빛 오버플로 문제가 있습니다.

수리 전후 비교:

통합 방사조도 다이어그램:

적분기: 수정된 지수 이동 평균 추정기[Barré Brisebois 2019]. 단기 평균 및 분산 추정치를 추적하고 단기 추정기를 사용하여 혼합 요인을 조정하므로 저잡음 지점으로 수렴하면서 변화에 신속하게 대응할 수 있습니다. 단기 분산을 기반으로 한 편향된 광선 계산, 광선 수를 사용하여 상대적인 신뢰도를 알려주는 다중 규모 평균 추정기, 변화와 변형에 신속하게 반응하여 광선 수를 작게 유지하면서 안정적으로 유지하는 피드백 루프입니다.

BRDF의 중요도 샘플링: Lambert BRDF로 가정되는 누적 확산 방사조도는 코사인 로브의 중요도 샘플링을 통해 광선을 생성합니다.

레이 안내:

각 서펠은 반구에 대해 이동 평균 6x6 휘도 맵을 생성하며, 단일 4K 텍스처(모든 서펠을 지원하려면 7x7), 텍스처당 8비트 + 텍스처당 단일 16비트 스케일링, 프레임 기능별로 정규화되어 저장됩니다.

중요도 샘플링 변수를 사용하면 함수의 각 개별 부분이 해당 위치의 함수 값인 확률 밀도 함수와 함께 해당 값에 비례하여 선택됩니다.


방사조도 공유: 인근 서핑 데이터를 활용하여 서핑이 인접한 서핑의 광도, 구조적 가속도를 찾을 수 있도록 하며, 서핑 VPL, Mahalanobis 거리, 깊이 함수와 동일한 가중치를 사용합니다.

조도 공유 전후 비교:

또한 BF5 방법을 사용하여 광선, 위치 및 방향별로 정렬된 상자 광선, 공간용 12비트, 방향용 4비트, 공간 해시의 셀 위치 지정, 광선 방향 방향, 총 상자 수 및 오프셋 계산, 광선 인덱스 및 이전에 계산된 빈 오프셋을 기반으로 광선 재정렬을 정렬할 수 있습니다.

다중 조명 샘플링은 중요도 샘플링(무작위 광원 분할, 예비 샘플링)을 사용합니다. 무작위 광원 절단은 작은 샘플로 빠르게 수렴되며 사전 구축된 데이터 구조가 필요하고 샘플링 비용이 많이 들 수 있습니다.

저장소 샘플링의 개략도:

레이 트레이싱 프로브 다이어그램:

RT 프로브 볼륨 구조: 투명 개체에는 불투명 개체와 같은 대형 화면 지원이 필요하며, Clipmap은 클로즈업 세부 정보 유지, 대규모 장면 지원, 메모리 비용이 낮은 희소 프로브 배치, LOD의 가변 속도 업데이트 등의 요구 사항을 충족하는 최선의 선택입니다.

클립맵 업데이트 알고리즘: 업데이트 방향과 거리를 계산하고, 이동 후 유효한 프로브 데이터를 복사하고, 더 높은 수준의 프로브로 새로 생성된 프로브를 초기화합니다.

레벨 4 클립맵 배치의 개략도:

Clipmap 샘플링 프로세스는 다음과 같습니다.

의 샘플링최적화 : color 노이즈 titude지터링 샘플링.

프레임 개요:
진행중입니다. 위치 업데이트, 재활용, 그리드 할당, 광선 정렬, 레이 트레이싱, 클립맵 업데이트, 프로브 추적.
만들다. 형상 일반 재구성, 간격 채우기, 광선 정렬, 레이 트레이싱, 영구 저장소에 쓰기, 프로브 볼륨에 쓰기.
필터. 공간적 소음 감소, 시간적 소음 감소.
애플리케이션. 새로운 생성물 주입, 조명 적용(1/4 영역 해상도로 실행), 조명 업샘플링, 클립맵 샘플링.
14.5.5 결과 기간 요약
CPU와 GPU의 전체 컴퓨팅 성능과 병렬성이 크게 향상되었으며 멀티 코어, TBDR, HSR, FPK, RT Core 등과 같은 다양한 절전, 고성능 아키텍처, 구성 요소 및 파이프라인이 탄생했습니다.
게임 엔진은 더욱 현실적이고, 믿을 수 있으며, 영화 수준의 효과를 향해 발전하고 있습니다. 다양한 유형의 실시간 전역 조명 계산이 끝없이 나타나고 있습니다. 가장 눈에 띄는 것은 하드웨어 기반 레이 트레이싱과 UE5의 Nanite 및 Lumen입니다. 최신 그래픽 API의 탄생과 개발은 게임 엔진에 새로운 기회를 가져왔고 게임 엔진에 더 많은 플레이 공간을 제공했습니다. 이는 또한 렌더링 이미지를 기반으로 하는 중간 계층 렌더링 계산을 발생시켰으며 렌더링 품질을 새로운 차원으로 끌어올렸습니다.
다양한 렌더링 기술(예: AA, 지형, 물리, 풍경 시뮬레이션, 특수 재료 등)의 출현은 게임 엔진과 게임 개발팀에 확실한 동기를 부여해 왔습니다.
모바일, XR, 클라우드 렌더링, 웹 등의 분야도 완전히 개발되어 업계의 풍부한 생태계의 중요한 부분이 되었습니다.
14.6 이 기사 요약
14.6.1 게임 엔진의 미래
향후에는 씬당 1개의 드로우콜을 구현하여 대중화할 예정입니다. GPU 파이프라인 명령의 순서는 프레임마다 거의 일정하고 명령은 장면 구조에 따라 변경되지 않으며 그리기 호출 수는 예측 가능하고 합리적으로 낮으며 관리 가능한 최대 인덱스 버퍼 크기, 최악의 경우 메모리 오버헤드는 약 6%, 잠재적으로 손상을 줄 수 있는 모든 GPU 파이프라인 명령은 중첩된 명령 목록에 기록됩니다.

장치 생성 명령. GPU 파이프라인 명령을 조건부로 작성할 수 있는 가능성, GPU에서 PSO 선택의 유연성 향상, 컴파일 타임 최적화를 통해 런타임 조건에 따라 PSO를 전환할 수 있는 가능성, 빈 풀 체인 방지, 예약된 메모리 크기 감소.

또한, 하드웨어와 엔진의 아키텍처는 더욱 완전하고 포괄적이며, 도구 체인은 더욱 인간적이고 자동화되고 지능적이며, 레이 트레이싱은 점차 대중화되고 있으며, 시각 효과는 더욱 현실적이고 화려해졌습니다. PBR은 더욱 철저하며 간섭, 분산, 회절, 중첩, 커스틱스 등과 같은 나노 규모의 조명 모델을 도입합니다. AI의 통합은 더욱 광범위하고 일반적이며 병렬화, 다중 GPU 및 다중 장치가 점차 대중화되고 있습니다. GPU 기반 오프라인 기술은 실시간이며 다른 분기는 완전히 개발되었으며 렌더링 및 디버깅 도구는 더욱 완벽하고 지능적이며 시각적입니다.
면책조항: 위의 예측은 순전히 경험에 근거한 것이며 권위가 없습니다.
14.6.2 결론
이 글은 저자가 쓴 전체 글 중 참고문헌이 540개 이상으로 가장 많은 참고문헌을 갖고 있다. 참고자료를 정리하기 전에 1,000여 개가 넘는 다양한 문서를 참고했습니다. 그럼에도 불구하고 저자는 이것이 그래픽 렌더링 기술과 게임 엔진 기술의 빙산의 일각에 불과하다고 생각했다.
많은 기술이 시대에 깊이 각인되어 있지만, 시대의 족쇄를 돌파한 기술도 많습니다. 지난 수십 년 동안에도 이러한 기술은 시대를 초월해 오늘날의 주류 엔진에 널리 퍼져 있습니다. 역사와 마찬가지로 기술 진화의 순환은 중단 없이 진행되어 왔습니다.
이 글은 기획부터 완성까지 거의 반년이 걸렸고, 총 단어 수는 43만 개가 넘고, 참고 문헌은 540개 이상이고, 사진은 3,400여 장에 이른다. 최근 수십 년간 실시간 렌더링 분야의 주요 연구 및 응용 결과를 담고 있습니다. 정보 밀도가 높고 총량이 크다. 그럼 아동화, 페이는 배워보셨나요? O_O? 헤어볼륨은 아직 건강한가요? (그나저나 블로거에 대한 존경심으로 먼저 떨어뜨린건 얘들아 안심~)
특별 지침
모든 참고문헌의 저자에게 감사드립니다. 일부 사진은 참고 자료와 인터넷에서 가져온 것이므로 삭제되었습니다.
이 시리즈의 기사는 저자가 직접 작성한 것이며 블로그에만 게시됩니다. 이 글의 링크를 공유하셔도 좋지만 무단 전재는 허용되지 않습니다!
계속되는 일련의 기사. 전체 목록을 보려면 콘텐츠 개요를 클릭하세요.
계속되는 일련의 기사. 전체 목록을 보려면 콘텐츠 개요를 클릭하세요.
계속되는 일련의 기사. 전체 목록을 보려면 콘텐츠 개요를 클릭하세요.
📚 참고 자료 및 공식 링크 (References)
- Unreal Engine Source
- Rendering and Graphics
- Materials
- Graphics Programming
- Unreal Engine 2 Documentation
- Unreal Engine 3 Documentation
- Game engine
- List of game engines
- Game Engine Architecture
- Game Engine Architecture Third Edition
- Game Engine Architecture Course
- Welcome to CS1950u!
- Game Engine Fundamentals
- Designing the Framework of a Parallel Game Engine
- 📖 GPU 하드웨어 아키텍처 및 작동 메커니즘에 대한 심층적인 이해
- 📖 얕은 것부터 깊은 것까지 PBR의 원리와 구현을 배워보세요.
- 📖 언리얼 엔진의 초현실적 휴먼 렌더링 기술 분석 1부 - 개요 및 피부 렌더링
- 📖 언리얼 엔진의 초현실적인 휴먼 렌더링 기술 분석 2부 - 안구 렌더링
- 📖 언리얼 엔진의 초현실적 휴먼 렌더링 기술 분석 3부 - 헤어 렌더링 등
- Playstation 2 Architecture
- Procedural Rendering on Playstation® 2
- Independent Game Development
- CryEngine Sandbox Far Cry Edition
- Information Visualisation utilising 3D Computer Game Engines
- Using Commonsense Reasoning in Video Games
- GeForce 6 series
- List of game engines
- 3D Game Engine Architecture
- 『:』12UE5
- Unreal Engine
- 언리얼 엔진(Unreal Engine)
- FROM ABSTRACT DATA MAPPING TO 3D PHOTOREALISM: UNDERSTANDING EMERGING INTERSECTIONS IN VISUALISATION PRACTICES AND TECHNIQUES
- Game Developer - October 2005
- Torque Tutorial #2
- Game Engine Tutorials:Chapter 1 - Introduction
- Unreal Engine 3 Technology
- Using the Source Engine for Serious Games
- Designing a Modern Rendering Engine
- Finding Next Gen – CryEngine 2
- CryENGINE 3 Game Development Beginner's Guide
- GPU overview Graphics and Game Engines
- 3dfx Interactive
- RIVA TNT
- DirectX
- Direct3D feature levels
- Feature levels in Direct3D
- High-Level Shader Language
- DirectX 3.0
- Microsoft Ships DirectX Version 3.0
- Microsoft Ships DirectX 5.0
- DirectX 5.0
- Microsoft's Official DirectX 6.0
- Multitexturing in DirectX 6
- Microsoft® DirectX® 7: What's New for Graphics
- GLFW
- OpenGL Related toolkits and APIs
- Nurien Mstar Online - (4minute - Huh) Bubble Item Mode
- GDM_April_2008(Game Developer)
- How To Go From PC to Cross Platform Development Without Killing Your Studio
- “A bit more Deferred” - CryEngine 3
- CryEngine
- Far Cry®
- CryENGINE 2
- Crysis 1 XBOX/PS3
- CryENGINE 3
- CryEngine Features
- The Matrix Awakens: An Unreal Engine 5 Experience
- Hitting 60Hz with the Unreal Engine: Inside the Tech of Mortal Kombat vs DC Universe
- Parallel Graphics in Frostbite – Current & Future
- Frostbite (game engine)
- EA Tech Blog
- irrlicht
- Practical techniques for managing Code and Assets in multiple cross platform titles
- Next-Gen Asset Streaming Using Runtime Statistics
- Light Pre-Pass Deferred Lighting: Latest Development
- The Next Mainstream Programming Language: A Game Developer’s Perspective
- An explanation of Doom 3’s repository-style architecture
- TerraForm3D Plasma Works 3D Engine & USGS Terrain Modeler
- Entity component system
- Entity Component Systems in Unity
- Entity Component System VS Entity Component
- Entities, components and systems
- Redefining Game Engine Architecture through Concurrency
- Tim Sweeney on the first version of the Unreal Editor
- Integrating Architecture Soar Workshop
- Ray Tracing for Games
- Modern Graphics Engine Design
- Ogre Golf
- Selecting the Best Open Source 3D Games Engines
- Theory, Design, and Preparation
- The Benefits of Multiple CPU Cores in Mobile Devices
- GAME ENGINES
- Development of a 3D Game Engine - OpenCommons
- Physically Based Shading Models for Film and Game Production
- Physically Based Shading at Disney
- Real Shading in Unreal Engine 4
- The Game Engine Space for Virtual Cultural Training
- Game Engines
- Quake III Arena Game Structures
- iOS and Android development with Unity3D
- The use cases that drive XNAT development
- Exploiting Game Engines For Fun & Profit
- GAME ENGINES: A 0-DAY’S TALE
- Comparison and evaluation of 3D mobile game engines
- Barotrauma
- Microsoft XNA
- Game Engines
- Game Engines-The Overview
- Multithreading for Gamedev Students
- A History of the Unity Game Engine
- A brief insight into BRTECH1
- CRYENGINE 5.3 - Getting Started Guide
- The architecture and evolution of computer game engines
- Designing a Modern GPU Interface
- Game Engine Programming
- DX12 & Vulkan Dawn of a New Generation of Graphics APIs
- GPU-Driven Rendering Pipelines
- Limitation to Innovation in the North American Console Video Game Industry 2001-2013: A Critical Analysis
- The 4+1 View Model of Architecture
- Architectural Blueprints—The “4+1” View Model of Software Architecture
- Serious Games Architectures and Engines
- Game Engine Solutions
- Remote exploitation of the Valve Source game engine
- Game Engines - Computer Science
- High quality mobile VR with Unreal Engine and Oculus
- The Report by the written by Amanda Wong funded by the July 2017
- Entity Component Systems & Data Oriented Design
- A Taxonomy of Game Engines and the Tools that Drive the Industry
- Torque 3D Documentation
- Comparative Study on Game Engines
- MOBILE GAME DEVELOPMENT
- Evaluation of CPU and Memory performance between Object-oriented Design and Data-oriented Design in Mobile games
- Efficient generation and rendering of tube geometry in Unreal Engine
- Global Illumination Based on Surfels
- Radiance Caching for real-time Global Illumination
- BigWorld
- Ubisoft Anvil
- Destiny Game Engine: Tiger
- Multithreading the Entire Destiny Engine
- Lessons from the Core Engine Architecture of Destiny
- Destiny 2: Tiger Engine Changes
- Destiny
- Destiny 2
- RE Engine
- Rockstar Advanced Game Engine
- NVIDIA DLSS
- OpenGL
- OpenGL ES
- Tone Reproduction and Physically Based Spectral Rendering
- A Framework for an R to OpenGL Interface for Interactive 3D graphics
- Beyond Finite State Machines Managing Complex, Intermixing Behavior Hierarchies
- Game Mobility Requires Code Portability
- Challenges in programming multiprocessor platforms
- Adding Spherical Harmonic Lighting to the Sushi Engine
- Real World Multithreading in PC Games Case Studies
- Speed up the 3D Application Production Pipeline
- New 3D Graphics Rendering Engine Architecture for Direct Tessellation of Spline Surfaces
- A realtime immersive application with realistic lighting: The Parthenon
- The Parthenon Demo: Preprocessing and Rea-Time Rendering Techniques for Large Datasets
- Rendering Gooey Materials with Multiple Layers
- Practical Parallax Occlusion Mapping For Highly Detailed Surface Rendering
- Real-time Atmospheric Effects in Games
- Shading in Valve’s Source Engine slide
- Shading in Valve’s Source Engine
- Ambient Aperture Lighting
- Fast Approximations for lighting of Dynamic Scenes
- An Analysis of Game Loop Architectures
- Exploiting Scalable Multi-Core Performance in Large Systems
- Ritual™ Entertainment: Next-Gen Effects on Direct3D® 10
- Feeding the Monster: Advanced Data Packaging for Consoles
- Best Practices in Game Development
- High-Performance Physics Solver Design for Next Generation Consoles
- Collaborative Soft Object Manipulation for Game Engine-Based Virtual Reality Surgery Simulators
- Introduction to Direct3D 10 Course
- Practical Global Illumination with Irradiance Caching
- General-Purpose Computation on Graphics Hardware
- GPUBench
- The Mobile 3D Ecosystem
- Advanced Real-Time Rendering in 3D Graphics and Games
- Frostbite Rendering Architecture and Real-time Procedural Shading & Texturing Techniques
- Saints Row Scheduler
- PCI Express
- The Delta3D Gaming and Simulation Engine: An Open Source Approach to Serious Games
- Software Requirement Specification Common Infrastructure Team
- Dragged Kicking and Screaming: Source Multicore
- OpenGL ES 2.0 : Start Developing Now
- Interactive Relighting with Dynamic BRDFs
- Advances in Real-Time Rendering in 3D Graphics and Games (SIGGRAPH 2008 Course)
- Advanced Virtual Texture Topics
- March of the Froblins: Simulation and rendering massive crowds of intelligent and detailed creatures on GPU
- Using wavelets with current and future hardware
- StarCraft II: Effects & Techniques
- The Intersection of Game Engines & GPUs: Current & Future
- Software Instrumentation of Computer and Video Games
- John Carmack Archive - Interviews
- UnrealScript: A Domain-Specific Language
- GPU evolution: Will Graphics Morph Into Compute?
- Introduction to the Direct3D 11 Graphics Pipeline
- Lighting and Material of HALO 3
- Snakes! On a seamless living world
- Threading Successes of Popular PC Games and Engines
- THQ/Gas Powered Games Supreme Commander and Supreme Commander: Forged Alliance
- Emergent Game Technologies: Gamebryo Element Engine
- Namco Bandai, EA Partner For Hellgate: London
- Project “Smoke” N-core engine experiment
- New Dog, Old Tricks: Running Halo 3 Without a Hard Drive
- Creating believable crowds in ASSASSIN'S CREED
- id Tech 5 Challenges - From Texture Virtualization to Massive Parallelization
- Building a Dynamic Lighting Engine for Velvet Assassin
- Techniques for Improving Large World and Terrain Streaming
- A Novel Multithreaded Rendering System based on a Deferred Approach
- Regressions in RT Rendering: LittleBigPlanet Post Mortem
- Meshless Deformations Based on Shape Matching
- sphere ambient occlusion - 2006
- Insomniac Physics
- State-Based Scripting in Uncharted 2: Among Thieves
- Zen of Multicore Rendering
- Star Ocean 4 - Flexible Shader Managment and Post-processing
- Light Propagation Volumes in CryEngine 3
- https://advances.realtimerendering.com/s2009/SIGGRAPH
- Precomputed Atmospheric Scattering
- Theory and Practice of Game Object Component Architecture
- Rendering Technology at Black Rock Studio
- NVIDIA Developer Tools for Graphics and PhysX
- Animated Wrinkle Maps
- Terrain Rendering in Frostbite Using Procedural Shader Splatting
- Spherical Harmonic Lighting: The Gritty Details
- Precomputed Radiance Transfer for Real-Time Rendering in Dynamic, Low-Frequency Lighting Environments
- A Gentle Introduction to Precomputed Radiance Transfer
- Spherical harmonics
- Tetris packing [Levy 02]
- Multi-Chart Geometry Images
- Direct3D 11.1 Features
- Direct3D 11.2 Features
- Vulkan
- Metal (API)
- Mantle (API)
- ADVANCED GRAPHICS ENGINE BASED ON THE NEW OPENGL FEATURES
- A High Dynamic Range Rendering Pipeline
- A Real Time Radiosity Architecture for Video Games
- Advanced Screenspace Antialiasing
- The Benefits of Multiple CPU Cores in Mobile Devices
- Direct3D 11 In-Depth Tutorial: Tessellation
- Real-time Diffuse Global Illumination in CryENGINE 3
- Future graphics in games
- Physically-Based Shading Models in Film and Game Production
- Crafting Physically Motivated Shading Models for Game Development
- Pre-computing Lighting in Games
- Direct3D 11 Performance Tips & Tricks
- Oit And Indirect Illumination Using Dx11 Linked Lists
- http://advances.realtimerendering.com/s2010/Hable-Uncharted2
- UFO Invasion: DX11 and Multicore to the Rescue
- CryENGINE 3: reaching the speed of light
- 레이 트레이싱(Ray Tracing):Regular Grid 및 3DDDA
- Destruction Masking in Frostbite 2 using Volume Distance Fields
- Sample Distribution Shadow Maps
- Shears - Squeeze the Juice Out of the CPUs: Post Mortem of a Data-Driven Scheduler
- Advanced Material Rendering
- Water and lightin underwater photography
- http://advances.realtimerendering.com/s2010/Ownby
- http://advances.realtimerendering.com/s2010/Salvi-AVSM
- DiRT2 DirectX 11 Technology
- What Is Ambient Occlusion? (SSAO, HBAO, HDAO And VXAO)
- HORIZON-BASED AMBIENT OCCLUSION PLUS (HBAO+)
- R-Trees -- Adapting out-of-core techniques to modern memory architectures
- Streaming Massive Environments from 0 to 200 MPH
- A Dynamic Component Architecture for High Performance Gameplay
- The Game Engine Space for Virtual Cultural Training: Requirements, Devices, Engines, Porting Strategies and a Future Outlook
- DirectCompute Performance on DX11 Hardware
- DirectCompute Optimizations and Best Practices
- Per-Pixel Linked Lists with Direct3D 11
- Texture Compression in Real-Time Using the GPU
- Reflection for Tools Development
- The Asset pipeline for Just Cause 2: Lessons learned
- Real-Time Order Independent Transparency and Indirect Illumination Using Direct3D 11
- Multi-Core Memory Management Technology in Mortal Kombat
- Mega Meshes - Modeling, Rendering and Lighting a World Made of 100 Billion Polygons
- Game Worlds from Polygon Soup: Visibility, Spatial Connectivity and Rendering
- Building a Multithreaded Web Based Game Engine Using HTML5, CSS3 and JavaScript
- Culling the Battlefield: Data Oriented Design in Practice
- Dynamic lighting in GOW3
- Firaxis LORE And other uses of D3D11
- DirectX 11 Rendering in Battlefield 3
- Secrets of CryENGINE 3 Graphics Technology
- Rendering in Cars 2
- http://www.klayge.org/material/4_2/DoF/An
- DX11 Performance Gems
- Lighting the Apocalypse: Rendering Techniques for RED FACTION: ARMAGEDDON
- Five Rendering Ideas from Battlefield 3 & Need For Speed
- 📖 UE Part 1에서 PBR 머티리얼 제작 가이드 - 색상 지식
- High Performance Post-Processing
- Separating Semantics from Rendering:A Scene Graph based Architecture for Graphics Applications
- Pre-Integrated Skin Shading
- Scaling the Pipeline
- Practical Occlusion Culling on PS3
- Putting the Plane Together Midair
- 『』기술
- Accelerating Rendering Pipelines Using Bidirectional Iterative Reprojection
- CSM Scrolling: An acceleration technique for the rendering of cascaded shadow maps
- Analytic Anti-Aliasing of Linear Functions on Polytopes
- iOS and Android Development with Unity3D
- http://twvideo01.ubm-us.net/o1/vault/gdc2012/slides/Programming
- Effects Techniques Used in Uncharted 3: Drake's Deception
- Cutting the Pipe: Achieving Sub-Second Iteration Times
- Mastering DirectX 11 with Unity
- Practical Physically Based Rendering in Real-time
- GPU Task-Parallelism: Primitives and Applications
- Beyond a simple physically based Blinn-Phong model in real-time
- Water Technology of Uncharted
- Geometry Clipmaps: Terrain Rendering Using Nested Regular Grids
- Graphics Gems for Games - Findings from Avalanche Studios
- New particle trimming tool
- Particle trimmer
- LEAN Mapping
- Forward Rendering Pipeline for Modern GPUs
- Using GPUView to Understand your DirectX 11
- Realtime global illumination and reflections in Dust 514
- Advanced Procedural Rendering with DirectX 11
- Survey of Physics Engines for Games
- http://advances.realtimerendering.com/s2012/Ubisoft/Rock-Solid
- Linear Efficient Anti-aliased Normal Mapping
- Sand Rendering in Journey
- Scalable High-Quality Motion Blur and Ambient Occlusion
- 📖 언리얼 엔진의 초현실적 휴먼 렌더링 기술 분석 1부 - 개요 및 피부 렌더링
- 📖 언리얼 엔진의 초현실적인 휴먼 렌더링 기술 분석 2부 - 안구 렌더링
- Bringing AAA Graphics to Mobile Platforms
- Deferred Radiance Transfer Volumes: Global Illumination in Far Cry 3
- The Technology Behind the “Unreal Engine 4 Elemental demo”
- Interactive Indirect Illumination Using Voxel-Based Cone Tracing
- Terrain in Battlefield 3: A Modern, Complete and Scalable System
- Practical Implementation of Light Scattering Effects Using Epipolar Sampling and 1D Min/Max Binary Trees
- Accelerate your Mobile Apps and Games for Android™ on ARM
- OpenGL ES 3.0 - Challenges and Opportunities
- An Architecture Approach for 3D Render Distribution using Mobile Devices in Real Time
- Destiny: From Mythic Science Fiction to Rendering in Real-Time
- Graphics Gems from CryENGINE 3
- Oceans on a Shoestring: Shape Representation, Meshing and Shading
- Practical Clustered Shading
- Clustered Deferred and Forward Shading
- Pixel Synchronization: Solving Old Graphics Problems with New Data Structures
- REDengine 3 Character Pipeline
- Virtual Reality Capabilities of Graphics Engines
- Efficient Usage of Compute Shaders on Xbox One and PS4
- Killzone Shadow Fall: Threading the Entity Update on PS4
- Developing Virtual Reality Experiences with the Oculus Rift
- Virtual Reality and Getting the Best from Your Next-Gen Engine
- Diving into VR World with Oculus
- Solving Visibility and Streaming in The Witcher 3: Wild Hunt with Umbra 3
- Volumetric Fog: Unified compute shader based solution to atmospheric scattering
- SCRIPTING PARTICLES
- Compute-Based GPU Particle Systems
- Multithreading for Gamedev Students
- Moving Frostbite to Physically Based Rendering 3.0
- 『』개발
- Landscape creation and rendering in REDengine 3
- Next-Gen Characters From Facial Scans to Facial Animation
- PCA
- Hybrid Reconstruction Anti Aliasing
- OpenGL ES 3.0 and Beyond: How To Deliver Desktop Graphics on Mobile Platforms
- Rendering in Codemasters’ GRID2 and beyond Achieving the ultimate graphics on both PC and tablet
- Real-time lighting via Light Linked List
- Authoring Tools Framework: Open Source from Sony's Worldwide Studios
- Introduction to PowerVR Ray Tracing
- Practical Techniques for Ray Tracing in Games
- Next Generation Post Processing in Call of Duty
- Concurrent Interactions in The Sims 4
- Crafting a Next-Gen Material Pipeline for The Order: 1886
- Reflection System in Thief
- Rendering Techniques in Ryse
- Tessellation in Call of Duty: Ghosts
- Achieving the Best Performance with Intel Graphics Tips, Tricks, and Clever Bits
- High Quality Temporal Supersampling
- Realistic Cloud Rendering Using Pixel Sync
- Calibrating Lighting and Materials in Far Cry 3
- Adaptive Clothing System in Kingdom Come: Deliverance
- Sound Propagation in Hitman
- Visual Effects in Star Citizen
- Adaptive Virtual Texture Rendering in Far Cry 4
- Rendering the World of Far Cry 4
- Assassin's Creed Identity: Create a Benchmark Mobile Game!
- D3D12 A new meaning for efficiency and performance
- PowerVR Graphics - Latest Developments and Future Plans
- Unified Telemetry, Building an Infrastructure for Big Data in Games Development
- Quick and Dirty: 2 Lightweight AI Architectures
- Dynamic Occlusion With Signed Distance Fields
- Fast Approximations for Global Illumination on Dynamic Scenes
- SIMD at Insomniac Games
- Frostbite on Mobile
- Destiny's Multi-threaded Renderer Architecture
- Lessons from the Core Engine Architecture of Destiny
- Parallelizing the Naughty Dog Engine Using Fibers
- Strategies for efficient authoring of content in Shadow of Mordor
- Multi-Scale Global Illumination in Quantum Break
- Physically-based & Unified Volumetric Rendering in Frostbite
- Piko: A Framework for Authoring Programmable Graphics Pipelines
- Rendering the Alternate History of The Order: 1886
- MSAA Resolve Filters
- Far Cry 4 and Assassin’s Creed Unity: Spicing Up PC Graphics with GameWorks
- The Real-Time Volumetric Cloudscapes of Horizon Zero Dawn
- Sampling Methods for Real-time Volume Rendering
- Stochastic Screen-Space Reflections
- Hybrid Ray-Traced Shadows
- Advancements in Tiled-Based Compute Rendering
- Advanced VR Rendering
- Authoring Realtime Volumetric Cloudscapes with the Decima Engine
- Towards Cinematic Quality, Anti-aliasing in Quantum Break
- Math for Game Programmers: Voxel Surfing
- The Transvoxel Algorithm
- Aggregate G-Buffer Anti-Aliasing in Unreal Engine 4
- D3D12 & Vulkan: Lessons Learned
- Deferred Lighting in Uncharted 4
- Bent Normals and Cones in Screen-Space
- Rendering 'Rainbow Six | Siege'
- 4K Rendering Breakthrough: The Filtered and Culled Visibility Buffer
- Filmic SMAA: Sharp Morphological and Temporal Antialiasing
- Architecting Archean: Simultaneously Building for Room-Scale and Mobile VR, AR, and All Input Devices
- Optimizing the Graphics Pipeline With Compute
- The Rendering of INSIDE: Low Complexity, High Fidelity
- Mixed Resolution Rendering in 'Skylanders: SuperChargers'
- High Dynamic Range Imaging
- How we rethought driver abstraction
- From Pixels to Reality – Thoughts on Next Game Engine
- Explicit Multi GPU Programming with DirectX 12
- Building a Low-Fragmentation Memory System for 64-bit Games
- Real-time BC6H Compression on GPU
- Temporal Reprojection Anti-Aliasing in INSIDE
- Rendering Antialiased Shadows with Moment Shadow Mapping
- Real-Time Area Lighting: a Journey from Research to Production
- Rendering Rapids in Uncharted 4
- Temporal Antialiasing In Uncharted 4
- The devil is in the details: idTech 666
- Practical DirectX 12 - Programming Model and Hardware Capabilities
- Developing The Northlight Engine: Lessons Learned
- Advanced VR Rendering Performance
- Volumetric Global Illumination At Treyarch
- Top five technologies to watch: 2017 to 2021
- Tiled shading: light culling – reaching the speed of light
- Efficient Texture Streaming in 'Titanfall 2'
- GDC2017: D3D12 & Vulkan: Lessons learned
- Crest: Novel ocean rendering techniques in an open source framework
- Decima Engine: Advances in Lighting and AA
- Data Binding Architectures for Rapid UI Creation in Unity
- DirectX 12 Case Studies
- FrameGraph: Extensible Rendering Architecture in Frostbite
- Parallelism and Concurrent Programming
- Advanced Graphics Tech: Moving to DirectX 12: Lessons Learned
- Higher Res Without Sacrificing Quality, plus Other Lessons from 'PlayStation VR Worlds'
- PBR Diffuse Lighting for GGX+Smith Microsurfaces
- High quality mobile VR with Unreal Engine and Oculus
- Improved Culling for Tiled and Clustered Rendering
- Precomputed lighting in Call Of Duty: Infinite Warfare
- SIGGRAPH: The Destiny Particle Architecture
- 3D Repo 4 Unity Dynamic Loading of Version Controlled 3D Assets into the Unity Game Engine
- 4K Checkerboard in Battlefield 1 and Mass Effect Andromeda
- A Life of a Bokeh
- The Latest Graphics Technology in Remedy's Northlight Engine
- Advanced Graphics Techniques Tutorial: GPU-Based Clay Simulation and Ray-Tracing Tech in 'Claybook'
- Entity-Component Systems & Data Oriented Design In Unity
- Data-Oriented Design blog post & links
- Typical C++ Bullshit slide gallery
- Data-Oriented Design and C++ video
- Data-Oriented Design (Or Why You Might Be Shooting Yourself in The Foot With OOP) blog post
- Practical Examples in Data Oriented Design slides
- The Lighting Technology of 'Detroit: Become Human'
- Efficient Screen-Space Subsurface Scattering Using Burley’s Normalized Diffusion in Real-Time
- Precomputed Global Illumination in Frostbite
- Rendering Technology in 'Agents of Mayhem'
- Rebuilding Your Engine During Development: Lessons from 'Mafia III'
- HDR Image Based Lighting: From Acquisition to Render
- The Elusive Frame Timing: A Case Study for Smoothness Over Speed
- By Grabthar's Hammer, What a Savings: Making the Most of Texture Memory with Sprite Dicing
- Cluster Forward Rendering and Anti-Aliasing in 'Detroit: Become Human'
- Filtering Distributions of Normals for Shading Antialiasing
- https://yusuketokuyoshi.com/papers/2017/Error
- Material Advances in Call of Duty: WWII
- Performance and Memory Post Mortem for Middle earth: Shadow
- Bungie's Asset Pipeline: 'Destiny 2' and Beyond
- Real-Time Ray Tracing of Correct* Soft Shadows
- Adopting lessons from offline ray tracing to real-time ray tracing for practical pipelines
- Real-Time Reflections in 'Mafia III' and Beyond
- Shading of 'Spellsouls': Achieving AAA Quality on Mobile
- Terrain Rendering in 'Far Cry 5'
- The Challenges of Rendering an Open World in Far Cry 5
- The Road toward Unified Rendering with Unity’s High Definition Render Pipeline
- A Journey Through Implementing Multiscattering BRDFs and Area Lights
- Leveraging Real-Time Ray Tracing to build a Hybrid Game Engine
- Content Fueled Gameplay Programming in 'Frostpunk'
- It Just Works: Ray-Traced Reflections in "Battlefield V"
- GPU Driven Rendering and Virtual Texturing in 'Trials Rising'
- Efficient Rendering in 'The Division 2'
- Interactive Wind and Vegetation in 'God of War'
- "Interactive Wind and Vegetation in 'God of War'" in Unreal Engine 4
- Strand-based Hair Rendering in Frostbite
- High Zombie Throughput in Modern Graphics
- The Indirect Lighting Pipeline of 'God of War'
- Controller to Display Latency in 'Call of Duty'
- Physically-Based Calibration: Accurate Material Production in 'Forza Horizon 4'
- Mesh Shading: Towards Greater Efficiency of Geometry Processing
- Procedurally Crafting Manhattan for Marvel’s Spider-Man
- Creating the Atmospheric World of Red Dead Redemption 2: A Complete and Integrated Solution
- Not-So-Little Light: Bringing 'Destiny 2' to HDR Displays
- Halcyon Architecture - "Director's Cut"
- Scalable Real time Global Illumination for Large Scenes
- 6 Years of Optimizing World of Tanks: Making the Game a Great Experience on All Systems from Laptops to High End PCs
- Bringing Replays to World of Tanks: Mercenaries
- Software-based Variable Rate Shading in Call of Duty: Modern Warfare
- For the Alliance! World of Warcraft and Intel Discuss an Optimized Azeroth
- Rendering Roblox Vulkan Optimisations on PowerVR
- Imagination Tech Doc
- Intel® ISPC in Unreal Engine 4: A Peek Behind the Curtain
- MOBILE GAME DEVELOPMENT
- Multi Adapter Integrated + Discrete GPUs
- Optimizing Roblox: Vulkan Best Practices forMobile Developers
- volk loader
- Quad mesh simplification in Frostbite
- Lima Oscar Delta!: Scaling Content in 'Call of Duty: Modern Warfare'
- idTech 7: Rendering the Hellscape of Doom Eternal
- Precomputed Lighting Advances in Call of Duty: Modern Warfare
- From Ray to Path Tracing: Navigating through Dimensions
- VRS Tier 1 with DirectX 12 From Theory To Practice
- https://ericrxw.github.io/xiaoweiren/docs/HPCA2021/CHOPIN-HPCA2021.pdf#:~:text=In this paper%2C we propose CHOPIN%2C a novel
- Evaluation of CPU and Memory performance between Object-oriented Design and Data-oriented Design in Mobile games
- Creating Cooperative Character Behaviors using Deep Reinforcement LearningVincent
- Real-Time Samurai Cinema: Lighting, Atmosphere, and Tonemapping in Ghost of Tsushima
- A Deep Dive into Nanite Virtualized Geometry
- Adaptive TetraPuzzles
- Quick-VDR
- Batched Multi-Triangulation
- https://dl.acm.org/doi/abs/10.1145/3450626.3459812#:~:text=Abstract We present a real-time neural radiance caching
- Blowing from the West: Simulating Wind in 'Ghost of Tsushima'
- Global Illumination Based on Surfels
- Experimenting with Concurrent Binary Trees for Large Scale Terrain Rendering
- Large-Scale Global Illumination in Call of Duty
- FidelityFX Super Resolution (FSR)
- What's new in Direct3D 12
- History of OpenGL
- LunarG Releases New Vulkan 1.3.204.0 SDKs with Profiles Toolset and New Extensions
- Khronos Group Releases Vulkan 1.2
- Khronos Group Releases Vulkan 1.1
- Metal (API)