들어가는 말


Bokeh II: The Sequel (Bokeh II: 속편)

bokeh 샘플을 마친 후, 나는 “완전히 멋지다”고 말하고 내 인생을 계속 살기 전에 해결하고 싶었던 몇 가지 남은 문제들이 있었습니다.

좋은 블러 (Good blur)

지난 샘플에서 나는 전체 해상도에서 수행되는 포아송 디스크(poisson disc)에 대한 2-pass 블러, 또는 1/4 해상도에서 수행되는 bilateral Gaussian 블러(둘 다 픽셀 셰이더에서 수행됨) 중 하나를 사용했습니다. 전자는 픽셀당 가변적인 필터 폭을 제공하기 때문에 좋지만, 불충분한 샘플링으로 인해 노이즈와 같은 못생긴 아티팩트가 발생합니다. 특히 필터 반경이 매우 클 경우 너무 많은 샘플로 인해 성능이 실제로 급락할 수 있습니다. 두 번의 패스를 수행하면 많은 도움이 되지만, 아래 그림과 같은 아티팩트가 발생합니다:

[이미지: 아티팩트가 있는 2-pass blur]

전통적인 “1/4 해상도의 가우시안 블러” 접근 방식은 훨씬 더 나쁩니다. 이는 낮은 해상도가 bilateral 필터링을 망치기 때문이며, 필요한 텍스처 샘플의 양이 많기 때문에 픽셀 셰이더에서의 성능도 그다지 좋지 않습니다. 그러나 최악의 경우는, “in-focus”와 “out-of-focus”를 시뮬레이션하기 위해 블러 처리된 픽셀과 블러 처리되지 않은 픽셀 사이를 lerp를 사용하여 혼합하기 때문에 보기에 좋지 않다는 것입니다. 그것은 점진적으로 초점이 맞거나 벗어나는 이미지라기보다는 소프트 포커스처럼 보입니다. 게다가 낮은 해상도에서 작업하여 얻는 앨리어싱 아티팩트가 있어 깜박임과 떠다니는 현상이 발생합니다.

이 문제에 대한 나의 해결책은 compute shader에서 엄청난 21-tap separable bilateral blur를 구현하는 것이었습니다. 넓은 separable blur 커널은 compute shader에 꽤 잘 맞습니다. 왜냐하면 텍스처 샘플을 shared memory에 저장할 수 있기 때문에 각 스레드가 N개가 아닌 단일 텍스처 샘플을 가져올 수 있기 때문입니다. Shared memory는 그렇게 빠르지 않지만, 더 큰 커널(약 10픽셀 정도)의 경우 절약 효과가 픽셀 셰이더 구현보다 우세하기 시작합니다. 이렇게 넓은 블러 커널을 사용하여, 전경이 초점이 맞고 배경이 초점이 맞지 않을 때 멋진 선명한 가장자리를 제공하기 위해 전체 해상도에서 블러링을 수행할 수 있었습니다. 다음은 위의 이미지와 유사한 이미지이지만, 이번에는 아티팩트가 없습니다:

[이미지: 아티팩트 없는 결과]

나는 결국 Gaussian 대신 박스 필터(box filter)를 사용하게 되었는데, 이는 일반적으로 밝은 지점에 못생긴 상자 모양의 하이라이트를 제공합니다. 다행히도 bokeh는 이러한 점들을 추출하고 bokeh 모양으로 교체하는 데 훌륭한 역할을 합니다. 블러 처리된 이미지와 블러 처리되지 않은 이미지 사이를 lerp할 필요를 피하기 위해, 나는 필터 커널이 작동 중인 픽셀의 CoC 크기를 벗어나는 샘플을 거부하도록 했습니다. 이것은 효과적으로 픽셀당 가변 크기의 블러 커널을 제공하며, 이는 초점이 맞거나 벗어나는 객체에 대해 훨씬 더 나은 전환을 제공합니다. 디스크 기반 블러의 전환만큼 좋아 보이지는 않지만, 공정한 절충안이라고 생각합니다. 아래 이미지는 초점이 맞는 상태에서 초점이 벗어나는 상태로 전환될 때 커널이 어떻게 보이는지 보여줍니다:

[이미지: 가변 크기 커널 전환]

초점이 맞지 않는 전경 객체 (Out-of-focus foreground objects)

대부분의 DOF 구현과 마찬가지로, 초점이 맞지 않는 전경 객체는 블러 처리되었지만 여전히 날카로운 가장자리를 가지고 있었습니다. 이것은 배경으로 블러되는 객체가 모습을 시뮬레이션하는 핵심 부분이기 때문에 꽤 나쁘게 보일 수 있습니다. 이 문제를 해결하는 간단한 방법은 CoC 크기 또는 흐릿함 계수(blurriness factor)를 텍스처에 저장한 다음 화면 공간에서 블러 처리하는 것입니다. 이것은 본질적으로 Infinity Ward가 그들이 제작한 지난 몇 개의 Call of Duty 게임에 사용한 접근 방식입니다. 나는 유사한 것을 사용했지만, DOF 블러와 마찬가지로 CoC 텍스처의 21-tap separable blur를 수행하기 위해 compute shader를 사용했습니다. 이것을 잘 보이게 하려면 더 낮은 깊이에서 오는 샘플만 수집하고, 해당 스레드가 작동 중인 픽셀보다 큰 CoC를 가진 샘플만 수집해야 합니다. 다음은 CoC spreading이 있을 때와 없을 때 초점이 맞지 않는 전경 객체입니다:

CoC Blur Off: [이미지: CoC 블러 끄기]

CoC Blur On: [이미지: CoC 블러 켜기]

bokeh sprite에 대한 깊이 차폐 없음 (No depth occlusion for bokeh sprites)

나는 샘플에서 bokeh sprite에 대한 어떤 종류의 차폐 테스트도 수행하지 않았으며, depth stencil 버퍼를 사용하고 depth testing을 활성화하는 것이 간단할 것이라고 말하며 넘어갔습니다. 그것이 사실이기는 하지만, 그렇게 하는 것이 실제로 좋은 결과를 주지 않는다는 것이 밝혀졌습니다. 문제는 bokeh sprite가 완전히 초점이 맞지 않는 영역을 덮고 있다면, 초점이 맞지 않는 픽셀이 bokeh sprite를 가리는 것을 원하지 않는다는 것입니다. 그렇지 않으면 bokeh가 DOF blur pass에 의해 블러 처리된 픽셀과 전혀 혼합되지 않습니다. 그래서 대신 나는 깊이에 따라 감쇠하지만 픽셀이 초점이 맞지 않으면 감쇠를 제거하는 자체 깊이 차폐 함수를 구현했습니다. 이를 통해 동일한 전체적인 모습을 유지하면서, 초점이 맞는 객체 위에 렌더링되는 bokeh sprite로 인해 “후광(halos)“이 생기는 경우를 제거할 수 있었습니다. 그리고 어차피 셰이더에서 수행하고 있었기 때문에, 이진 비교 대신 “소프트” 차폐 함수를 추가했습니다.

차폐 없음 (Without occlusion): [이미지: 차폐 없음]

차폐 있음 (With occlusion): [이미지: 차폐 있음]

코드 및 바이너리

코드와 바이너리는 여기에서 사용할 수 있습니다: https://github.com/TheRealMJP/DX11Samples/releases/tag/v1.4

2011년 4월 22일 - Nvidia 하드웨어에서 텍스처 샘플링 버그 수정


댓글:

Michael (jayben71@gmail.com) - 안녕하세요, 방금 업데이트를 다운로드했는데 이제 nVidia와 ATI 모두에서 잘 작동합니다. 간단한 질문이 있는데, 모션 블러 샘플을 이것과 통합하는 것이 얼마나 어려울까요? 이것이 완전한 DX11 기반 postfx 프레임워크가 될 것 같기 때문입니다!

MJP (mpettineo@gmail.com) - @Michael, 시도해 주셔서 감사하고, 멋지게 보인다고 말해 주셔서 감사합니다! 다행히 이제 직장에서 GTX 470이 있어서 Nvidia 문제를 디버그할 수 있습니다. 블록 현상이 발생한 이유는 0.5가 아닌 정수 위치에서 텍스처를 샘플링했기 때문인 것으로 밝혀졌으며, Nvidia에서는 그렇게 중심에서 벗어나 샘플링하면 문제가 발생할 수 있는 것 같습니다. @Maciej 와, 꽤 나쁘네요! 제 6950에서는 약 160fps로 실행되며, 프레임 시간의 대부분은 실제로 장면 + 섀도우 맵을 렌더링하는 데 소비됩니다.

Maciej (msawitus@gmail.com) - 매우 멋진 글과 데모입니다! 성능이 조금 더 좋으면 좋겠습니다 (ATI 5650에서 13 fps).

LieblingsAlgorithmen – Links | Echtzeitgrafiker Magdeburg - […] Bokeh II – Fake Bokeh – (소스 포함) […]

Louis Castricato (ljcrobotic@yahoo.com) - 누군가 샘플 코드를 SlimDX로 변환할 수 있나요? 나는 C++에 대해 (아직) 아무것도 모르고, 이렇게 놀라운 샘플을 놓치고 싶지 않습니다!

MJP (mpettineo@gmail.com) - 안녕하세요 Michael, 링크가 저한테는 작동하지만, Skydrive가 형편없어서 작동하지 않는 것이 놀랍지 않습니다. 제가 만든 새 Codeplex 프로젝트에 .zip을 업로드했으니 그 링크를 시도해 보세요.

Michael (jayben71@gmail.com) - 당신은 최고입니다! 멋진 업데이트입니다, 보고 싶지만 다운로드 링크가 작동하지 않는 것 같습니다…

Michael (jayben71@gmail.com) - 안녕하세요 MJP, 네 Codeplex는 괜찮습니다. 다운로드할 수 있었습니다. 저는 nvidia gtx480과 ATI 6870 windows 7을 실행하고 있습니다. ATI에서는 멋지게 보이지만 nVidia에서는 그렇지 않습니다. Computeshader가 활성화되어 있을 때 nvidia는 최종 렌더/컬러 버퍼가 매우 낮은 해상도(1/4?)로 설정된 것처럼 주요 엣지 앨리어싱과 함께 블록처럼 보입니다. 다른 변형은 괜찮아 보입니다. 전체적으로 품질이 크게 개선되었습니다. Computeshader 블러를 사용할 때 탭의 크기를 변경하는 옵션을 추가할 수 있을까요?

Draft on depth of field resources | Light is beautiful - […] Matt Pettineo의 두 번째 글을 언급하는 것을 잊었는데, 그는 더 나은 결과를 얻기 위한 기술 조합을 제안합니다. 사진에서 실제 bokeh의 예 […]

OpenGL Insights « The Danger Zone - […] 얼마 전 Charles de Rousiers가 내 Bokeh Depth of Field 샘플을 OpenGL로 적응시켰고, 우리는 최근 출시된 OpenGL Insights에 챕터로 기여했습니다. Bokeh는 […]