꽃미남 프로그래머 김포프가 창립한 탑 프로그래머 양성 교육 기관 POCU 아카데미 오픈!
절찬리에 수강생 모집 중!
프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.
Posted by 알 수 없는 사용자

안녕하세요. 자그마치 2달 정도를 연재를 쉬었던 rihwan (유인환)입니다.


음 오늘 쓰고 싶은 것은 실시간으로 진짜 Ambient Occlusion을 처리하는 것입니다. 근데 여기서 제가 보여드리는 방법은 사실은 실제로 적용 가능한 것은 아니며, 단지 가능하다는 것을 보여주며, 또 눈요기 정도는 가능하겠네요. 시작하기 전에 우선 CUDA와 Ambient Occlusion에 대해서 좀 설명을 드려야 겠습니다.


CUDA란?

그래픽 카드의 성능이 점점 발전하면서 그래픽 카드가 어느샌가 CPU의 연산 능력을 훌쩍 넘어버린 시대가 되어 버렸고, 그럼으로 인해서 CPU의 연산을 GPU에서 처리하고자 하는 시도가 2000년 넘어서부터 계속 되었죠. 그걸 그 당시에는 GPGPU (General Purpose Graphical Processing Units)라고 불렀고 그 당시 Shader를 사용해서 RenderTarget 텍스처에 계산 결과를 기록하는 방식으로 GPU의 연산 능력을 CPU가 사용하고 있었습니다.

사실 그래픽 카드 내의 GPU 연산 능력은 CPU에 비하면 상당히 떨어집니다. 한 1 Ghz 정도인데다가, 캐쉬 메모리는 1 KB도 안되는 정도로 약한 능력을 가졌습니다. 하지만 그래픽 카드는 어마어마한 장점을 가졌는데, 바로 GPU가 1개가 아니라는 점입니다. 그래픽 카드 내에는 요새는 512개 정도의 GPU (1 Ghz짜리)가 들어가고 있으며 곧 1024개 이상으로 증가할 예정입니다. 이렇게 엄청난 양의 병렬 GPU가 존재할 수 있는 이유는 어차피 그래픽 카드에서 처리하는 데이터는 주로 정점(삼각형)과 픽셀 단위이며, 이 데이터는 사실 모조리 완전히 병렬적으로 처리할 수 있었기 때문입니다. 그에 반해서 CPU의 경우는 GPU처럼 만들 수가 없었죠. 많아봐야 요새 16개의 CPU를 가질 수 있으려나요... 그 이유는 엄청나게 많은 명령어의 개수, L1 - L3 캐쉬 메모리,  메인 메모리, 컨트롤 명령, 동기화 등등을 가지고 있고 기존 시스템과의 호환성을 만족시켜야 하기 때문에 쉽게 병렬화 시킬 수가 없었습니다.

그리고 쉐이더 버전 1 - 3 당시였을 때, 사실 GPU는 매우 제한된 수의 명령어 집합(어셈블리 명령어)을 가지고 있었습니다. 그리고 캐쉬 메모리도 KB도 안될 정도로 작았던 것 등등 매우 GPGPU로의 변신은 매우 제한적이었죠. 하지만 2007년인가 2008년인가 상황이 급변합니다. NVIDIA에서 GPGPU가 발전 가능성이 있다는 사실을 깨닫고 아주 일반적으로 GPU의 연산 능력을 활용하는 프로젝트를 시작했고, 그렇게 해서 탄생한 것이 CUDA입니다.

CUDA는 C++등의 언어를 지원하고, C++과 거의 비슷하고 아주 약간의 변화를 주면 GPU 내의 임의의 메모리에 GPU를 이용해서 계산해서 계산 결과를 기록할 수 있습니다. 또한 CPU와 그래픽 카드 메모리 사이의 send & receive 함수 셋등을 지원하지요. 생각해보면 3 Ghz 짜리 CPU 4개 보다 1 Ghz 짜리 512개로 연산시키면 사실 연산 능력은 거의 수백배 차이가 날 것은 분명하겠죠. 심지어 GPU의 실수 계산 능력은 CPU와 비교했을 때 더 낳거나 거의 동급에 가까우니까요. 이 문서에서는 CUDA에 대해서 이렇게까지만 얘기드리고 궁금하신 분들을 위해서 책을 소개시켜드리겠습니다. "예제로 배우는 CUDA 프로그래밍" 이란 책이 매우 CUDA에 대해서 설명을 쉽게 잘해주고 있습니다 (왠지 책 장사하는 것 같군요...)

이번 글이 시작된 이유는 제가 한번 그럼 진짜 Ray를 활용하여 Ambient Occlusion을 CUDA에서 계산을 해봤기 때문입니다. 그리고 그 성능이 제 노트북에서 실시간으로 돌아갔기 때문이죠... 아래 링크를 한번 봐주시면 제가 작업했던 결과물이 나옵니다요.





실제로 Ray를 쏘아 진짜 Ambient Occlusion을 계산하고 있습니다. 실시간으로요!!!


Ambient Occlusion이란?

Ray Tracing등과 같이 Indirect Illumination을 계산하는 알고리즘은 사실 엄청나게 비싼 비용이 들어갑니다. 왜냐하면 Ray를 쏴서 Ray와 지형과의 충돌을 계산한 이후에 그 Ray가 어디로 반사 또는 굴절되는지, 그리고 어느 정도의 빛이 해당하는 재질에 흡수되고 반사되었는지를 계산하고, 다시 반사와 굴절 Ray를 쏴서 다시 지형과 충돌처리하고... 위와 같이 계속 재귀적으로 Ray를 쏴서 실제 해당하는 픽셀이 어떤 색상을 가지고 있는지 계산하기 때문에 엄청나게 비싼 연산입니다. 하지만 장점은 간접 조명을 표현할 수 있다는데 있죠. 빛은 다른 곳에서 팅기고 팅겨서도 눈으로 들어오게 되는데, 이런 간접 조명은 우리가 바로 느끼지는 못해도 전체 Scene에 엄청난 영향을 미치게 됩니다. 하지만 기존의 Lighting 연산들 Diffuse, Specular, Phong등등은 사실 간접 조명을 표현하지 못합니다. 단지 빛으로 부터 직접적으로 어떻게 들어오는지를 설명할 뿐이죠.

그렇다고 해서 Indirect Illumination을 진짜로 다 계산하자니 너무 비싸고 부드러운 그림자는 표현하고 싶고 해서 나온 것인 Ambient Occlusion입니다. 그리고 개념은 매우매우매우 명확하죠. "한 점이 있을 때 그 점의 주변(Ambient)에 빛을 가리는 물체가 많으면 그 점은 어두워야 하며, 주변(Ambient)에 아무런 차폐(Occlusion)이 없으면 그 점은 밝아져야 한다"가 기본 컨셉입니다.


(출처: http://www.interstation3d.com/tutorials/making_slow_decay/slow_decay_take07.htm)

위 이미지를 보시면 환경에 의해서 빛이 많이 가려지면 해당하는 점은 어두워지며, 가려지지 않으면 밝습니다. 우리 눈에 자연스럽게 느껴지지만 사실은 물리적으로는 사실이 아니며, 단지 그림자를 근사시킨 것이죠. 어쨋든 Ambient Occlusion은 매우 효과가 좋고 Indirect Illumination에 비해서 빠르게 계산할 수 있어서 자주 사용되게 됩니다. 처음에는 한 점에서 여러군데로 Ray를 다시 쏴서 어느 정도 차폐되었는지를 계산했었죠. (이 부분은 Ray Tracing과는 다릅니다. Ray Tracing은 재귀적으로 Ray를 계속 쏴야 하지만, Ambient Occlusion은 재귀적인 계산은 사용하지 않습니다.) 하지만 Ray를 쏘는 연산은 여전히 비싸기 때문에, 실시간으로 다시 Ambient Occlusion을 근사하는 방법들이 제시되었고, 요새는 그 방법이 게임에서는 널리 사용되고 있지요.


(출처: http://www.neilblevins.com/cg_education/ambient_occlusion/ambient_occlusion.htm)


그에 반해서 제가 처리한 방법은 우선 눈에서 Ray를 쏘아서 지형에 부딪치면, 해당하는 점에서 여러번 다시 한번 Ray를 쏘아서 주변에 의해서 그 부딪친 점이 얼마나 차폐(Occlusion) 되었는지를 거리의 비례해서 depth로 색상을 주었습니다. 위의 그림과 같지 진짜로 Ray를 쏘아 보내는 것이죠. 이렇게 진짜 Ambient Occlusion을 계산하는 것은 연산량이 극도로 높습니다. 하지만 CUDA로 연산을 했기 때문에 CPU 4개 코어를 모조리 사용한 것에 비해서 60배 가량 성능이 향상되었고 그로 인해서 실시간으로 처리된 것을 제가 업로드한 비디오에서 보실 수 있습니다. 사실 코드를 보는 것은 CUDA 코드로 인해서 매우 지저분하므로 실제로 정말 정말 보고 싶으시면 제게 이메일(rihawn 앳뜨 gmail 닷뜨 com)을 주시면 보내드리겠습니다.

반응형
,