RTX란 무엇인가 시리즈


my_rtx 내 컴퓨터에 장착되어 있는 RTX 그래픽카드. 너무 이뽀….

자랑 맞습니다만, 얼마전에 RTX 2060을 장착한 컴퓨터를 새로 장만했습니다. ㅎㅎ 그 동안 팀포2도 50 fps로 간신히 돌리는 노트북을 5년 정도 썼습니다만. 갑자기 성능이 엄청 좋은 컴퓨터를 쓰기 시작하니 정신을 못 차리겠더군요. 컴퓨터 바꾼 날 이후로 과하다 싶을 정도로 게임만 하고 있습니다. 게다가 초갓겜 원신 임팩트가 출시한 덕분에 제 인생은 머나먼 곳으로….

이렇게 놀고만 있을 수는 없죠! 이제부턴 게임 좀 줄이고 좀 더 생산적인 일에 집중해 볼까 합니다. 그 첫 타자로, 저에게 크나큰 기쁨을 안겨준 이 RTX란 녀석에 대해 자세히 알아 보기로 했습니다. 저는 게임 엔진 개발 경험이 있기 때문에 분명 그것과 연계하면 좋은 공부가 될 것이라 생각합니다.

Ⅰ. RTX On

RTX On은 게임 커뮤니티에서 꽤나 유명한 문구이지요. RTX 기술을 적용하기 전과 후의 사진을 비교해 보여주며 RTX의 아름다움을 뽐내는 마케팅 전략입니다. 저도 그 마케팅에 뿅가 RTX를 지르고 말았습니다.

여기서 RT는 레이트레이싱 Ray Tracing의 약자인 것으로 보입니다. 뒤에 X가 붙은 이유는, 글쎄요, 그동한 사용하던 GTX라는 이름과의 연관성을 위해서일까요? TX자 돌림 가족이네요.

RTX 그래픽카드는 레이트레이싱을 할 줄 아는 그래픽 하드웨어입니다. 기존의 그래픽카드로 레이트레이싱을 수행하면 너무 느려서 실시간으로 변하는 게임 화면을 그릴 수는 없습니다. Nvidia는 이 문제를 해결하기 위해 다양한 방법을 강구했으며 그 결과가 바로 RTX On입니다.

배틀필드 5, 셰도우 오브 더 툼레이더, 마인크래프트 등 몇몇 게임에 RTX가 적용되어 우리의 눈을 즐겁게 해주었습니다. 주로 바닥에 고인 물에 반사가 멋지다던가, 유리창의 반사가 멋지다던가, 총기 표면에 주변 사물이 실시간으로 반사된다던가. 주로 반사 분야가 눈에 많이 띄지요?

minecraft_rtx_on

battlefield5_mine

도대체 RTX 그래픽카드는 뭐 하는 놈이길래 이런 혁신이 가능한 것일까요? 이전에 있었던 다른 그래픽카드와 무슨 차이가 있을까요? 여러분들은 모두 그 이유를 알고 싶어 이 글을 클릭하셨을 텐데요.

저는 꽤 깊은 내용까지 다룰 예정입니다. 우선 레이트레이싱이 무엇인가에 대해 공부할 것입니다. 고등학교 수준의 기하학 내용이 필요합니다. 그리고 RTX 2060에 사용된 튜링 아키텍처의 구조, RT코어와 텐서코어 등 각 부속품이 구체적으로 무슨 일을 하는지도 배울 겁니다. 그리고 RTX를 사용해 게임을 만들려는 프로그래머가 사용할 수 있는 API에 대해서도 알아볼 예정입니다.

내용이 꽤나 많으며 수학 얘기, 프로그래밍 얘기가 나오는 등 쉽지는 않을 거라고 생각합니다. 그렇지만 이해가 안 되는 부분이 많다고 해서 좌절하지 마세요! 방대한 내용을 한 번에 다 이해할 필요는 없습니다. 잘 모르겠는 부분은 그냥 넘어가세요. 처음 읽을 때는 전체 내용의 반도 이해 못 하는 것이 당연합니다. 하지만 며칠 뒤 한번 더 읽고, 한 달 뒤 한번 더 읽고, 이런 식으로 반복해서 읽다 보면 100% 이해에 점점 수렴해갈 것입니다. 본인의 판단에 따라 70% 정도만 이해하고 그만 읽어도 되고요.

그럼 시작해 보겠습니다.

Ⅱ. 레이트레이싱 Ray Tracing

이런 글까지 찾아 흘러들어온 분들이라면 RTX 그래픽카드가 어떤 기술을 사용하는지 그 이름 정도는 들어 보셨을 거예요. 네, 레이트레이싱 (Ray Tracing) 말입니다. RTX가 무엇인지, 어떤 능력을 가졌는지 이해하기 위해서는 당연히 레이트레이싱이 뭔지 이해하고 넘어가야겠죠?

1. 광선이 너무 많아

공간 속에서 빛은 직선으로 이동합니다. 그러다가 물체에 부딪치면 튕겨져서(반사돼서) 반대쪽 방향으로 계속 나아가죠. 혹은 물체에 흡수되어 사라지기도 합니다. 빛이 이리저리 날아다니다가 우리 눈의 망막에 부딪치는 순간, 우리는 색깔을 인식합니다.

레이트레이싱은 이런 빛의 움직임을 흉내냅니다. 3차원 공간의 선분(벡터)을 빛이라 생각하고, 이 선분이 공간 안에서 물체와 부딪치다 카메라 안으로 들어오기까지의 과정을 추적합니다.

그림을 보면 화살표가 카메라 안에서 밖으로 나가가지요? 빛이 카메라에 도달하지 못 하면 어짜피 그 빛은 화면에 나타나지 않습니다. 그래서 보통은 빛의 이동 경로를 카메라로부터 광원까지 역순으로 찾아갑니다. 뉴턴역학을 배우신 분이라면 아시겠지만, 물리이론은 시간을 정방향으로 하나 역방향으로 하나 성립하지요.

우선 여러분 모니터의 한 픽셀마다 하나의 광선을 발사해야 합니다. 위 그림을 보시면 카메라에서 세 개의 광선을 발사한 모습을 볼 수 있는데요. 화면 전체를 체우는 이미지를 만들려면 모든 사각형(픽셀)에서 광선을 하나씩 발사해야 합니다. 가장 일반적으로 사용되는 Full HD 모니터를 사용한다면 $1920 \times 1080 = 2073600$개나 되는 광선을 발사해야 합니다.

하지만 2073600개는 한 픽셀당 광선을 하나만 사용할 때 얘기입니다. 위 그림에서 그림자 중앙에 꽂힌 광선을 봐주세요. 광선이 도달한 바닥의 저 지점이 그림자 안에 있는지 없는지 알아내려면? 그 지점에서 광선 하나를 전구를 향해 발사하여 그 사이에 어떤 물체가 있는가 확인해야 합니다. 보면 그림자 지점에서 출발한 광선은 전구로 가다가 공과 만납니다. 전구에 도달하지 못 했으므로 그림자가 드리워졌음을 알 수 있습니다.

보통 렌더링을 할 때, 모든 픽셀에서 그림자 여부를 확인합니다. 한 픽셀에서 그림자 여부를 확인하기 위해선 광선 하나를 추가적으로 발사해야 하는데요. 이러면 광선의 개수는 총 $1920 \times 1080 \times 2 = 4147200$가 되는군요. 만약 전구가 하나 더 있다면 $1920 \times 1080 \times 3 = 6220800$이 될 것입니다. 전구가 n개 있다면 광선의 수는 $1920 \times 1080 \times (1+n) = 6220800 \times (1+n)$개나 되겠군요.

vector_reflection

공 표면에 반사 효과를 넣고 싶다면, 공 표면에서 출발하는 광선 하나를 더 발사해야 합니다. 이때 공 표면에서 반사된 광선은 위 그림처럼 만듭니다. 그 광선이 어떤 물체와 만난다면 그 물체가 공 표면에 그려집니다.

그런데 공에 반사된 반사상을 잘 보면, 거기에도 그림자가 있고 반사상이 있겠죠? 자동차 표면에 내 얼굴이 반사되어 보이는데, 거기 보이는 내 얼굴에도 그림자가 있잖아요? 그래서 반사상을 만들 때 또 광선을 몇 개 더 발사해야 할 필요가 있습니다. 이런 식으로 꼬리에 꼬리를 물고 광선을 계속계속 추적하면 현실과 매우 비슷한 그림을 얻을 수 있습니다. 하지만 그만큼 픽셀당 광선의 수도 늘어나 컴퓨터에 큰 부담이 되지요.

자 그럼 이제 우리는 레이트레이싱 기술에서 광선이 얼마나 많이 필요한지 알 수 있게 되었습니다.

ma-th(필요한 \ 광선의 \ 개수) = (화면 \ 너비) \times (화면 \ 높이) \times (광원 \ 개수) \times (반사 \ 샘플링 \ 횟수)ma-th

물론 이것은 단순한 렌더링에서나 그렇단 것입니다. 실제로는 글로벌 일루미네이션, 반사상을 흐리게 만들기, 그림자 가장자리를 흐리게 만들기 등 구현해야 할 효과들이 있습니다. 좀 더 현실적인 이미지를 만들기 위해서는 픽셀당 훨씬 더 많은 광선이 필요합니다.

2. 삼각형도 너무 많아 T_T

안 그래도 광선 개수가 너무 많아서 컴퓨터 입장에서는 죽을 맛인데…. 이건 빙산의 일각에 불과합니다. 우리는 아직 광선 하나를 갖고 구체적으로 뭘 하는지 배우지 않았죠? 사실 광선 단 하나만 따져도 계산해야 할 게 엄청나게 많습니다. 지금부터 ‘광선을 추적한다’는 것이 구체적으로 무슨 계산을 의미하는 것인지 함께 알아보도록 해요.

광선을 발사하면 그 광선이 어떤 물체와 충돌하겠죠? 그러니 광선을 추적한다는 것은 광선이 어떤 물체랑 부딪치는가, 어느 지점에서 충돌이 일어나는지 알아내는 과정입니다.

직관적으로 생각해 보면 물체와 광선이 부딪치는 모습이 머릿속에 너무나 명백하게 그려집니다. 하지만 컴퓨터는 고양이와 강아지를 구분하는 것도 힘들어하는 기계입니다. 숫자밖에 모르는 컴퓨터가 빛과 물체를 다루기 위해서는 광선과 물체를 숫자로 표현해야 합니다.

광선과 물체는 컴퓨터에서 어떻게 표현될까요? 그 해답은 기하와 벡터 책 속에 있습니다. 네, 이과생 여러분들이 고등학교 수학시간에 공부한 바로 그 과목 말입니다. (너무 깊에 들어가진 않을 테니 걱정 마세요!)

image

우선 광선은 2개의 3차원 벡터로 이루어져 있습니다. 광선이 시작하는 점을 $S$, 끝나는 점을 $E$로 정하겠습니다. 하나의 3차원 벡터는 $(2.3, 6.12, 4.55)$처럼 숫자 세 개로 이루어져 있습니다.

삼각형은 3개의 벡터로 만들어집니다. 위 그림에서는 각 꼭짓점을 $A$, $B$, $C$라고 이름을 붙였습니다. 광선과 삼각형은 모두 3차원 공간에 있습니다. 점선으로 표시된 부분은 삼각형 뒤에 숨어 안 보이는 영역을 말합니다.

위 그림은 광선이 삼각형과 충돌한 모습이죠. 광선과 삼각형의 교점, 즉 빛이 물체에 부딪치는 지점은 $P$입니다. 점 $P$가 존재하면 광선과 물체가 충돌하기 때문에, 그 지점의 색깔을 알아내서 여러분의 모니터에 그려줍니다. 점 $P$를 시작점 $S$로 삼아 몇 개의 광선을 발사하여 그림자, 반사상을 추가로 알아낼 수도 있죠.

여기서 점 $P$의 위치는 우리가 고등학교에서 배운 기하학을 사용하여 계산할 수 있습니다. 말로만 간단히 설명 드릴게요. 이해가 안 된다면 그냥 넘어가도 좋아요.

우선은 삼각형의 세 점을 사용해 평면 방정식을 만듭니다. $Ax + By + Cz + d = 0$ 이렇게 생긴 놈 말이에요. 그리고 그 평면과 광선의 교점을 구합니다. 이 교점이 바로 $P$인데요. $P$는 평면상에 존재하지만 삼각형 내부에 있을 수도 있고 외부에 있을 수도 있죠. Barycentric 테스트란 신기한 방법을 사용하면 $P$가 삼각형 내부에 있는지 알 수 있습니다. 만약 $P$가 삼각형 내부에 있다면 충돌을 한 것입니다. 외부에 있다면 충돌하지 않은 것이므로 무시하고 넘어갑니다.

수학적인 얘기라 복잡하고 재미없죠? 그런데도 굳이 설명하고 넘어간 이유가 있습니다. 이후의 글에서 얘기하겠지만, RTX 그래픽카드가 하는 일이 정확하게 이거라서요.

3. 장면 복잡도

암튼! 삼각형 하나와 광선 하나가 출동을 하냐 안 하냐를 판별하는 법은 알았습니다. 왜 삼각형이냐? 여러분도 잘 아시겠지만, 3D 물체들은 폴리곤으로 이루어져 있는데요. 대부분의 경우 삼각형만을 폴리곤으로 사용합니다. 그 어떤 복잡한 물체라도 많은 수의 삼각형을 모아모아 표현할 수 있습니다.

wireframe_three

삼각형이 엄청나게 많죠? 사각형이 보인다고요? 쟤네들도 게임에서 사용될 땐 삼각형으로 쪼개서 쓴답니다. 이렇듯 삼각형이 엄청나게 많은데, 광선 하나를 발사하면 위에 보이는 모든 삼각형과 하나하나 충돌 검사를 해야 합니다. 위 그림에서 좌측에 있는 한복 디바 모델은 삼각형이 1만 5394개 있습니다. ㄷㄷ 한 픽셀당 광선을 3개씩만 쓴다고 가정해도 $1920 \times 1080 \times 3 \times 15394 = 95762995200$번이나 광선-삼각형 충돌 테스트를 해야 합니다. 오버워치에서는 이런 캐릭터가 12명이 있으니 대충 12를 곱해야겠네요. 게다가 맵을 그리기 위한 삼각형까지 포함하면….

삼각형이 많을수록 그 장면을 렌더링하는 것이 오래 걸립니다. 이때 삼각형의 양을 보통 장면 복잡도라고 표현합니다.

오버워치의 사례만 생각해 봐도 계산해야 될 양이 엄청나게 많습니다. 144 fps로 게임을 즐기려면 이미지 한 장을 그리는 데 $\frac{1}{144} = 0.0069\dot4$초가 넘어가면 안 됩니다. 그런데 보통 레이트레이싱으로 렌더링을 하면 수 분, 수십 분, 심지어 몇 시간이 걸리기도 합니다. 이대로는 너무 오래 걸려서 실질적으로 사용할 수 없습니다.

다행이도 토 나올 정도로 많은 삼각형의 개수를 대폭 줄일 수 있는 기술이 존재합니다.

3. Bounding Volume Hierarchy

이것도 꽤 복잡한 개념이긴 합니다만. RTX가 하는 일이 정확이 이거라서 그냥 넘어갈 수도 없는 노릇이네요.

오버워치에서 광선을 하나 발사한 경우를 생각해 봅시다. 우선은 윈스턴 몸의 삼각형 하나하나와 검사해 봅니다. 충돌하지 않는군요. 그럼 다음은 애쉬 몸의 삼각형들과, 그 다음은 맥크리 몸의 삼각형….

그런데 여기서 한 가지 아이디어가 떠오릅니다. 광선이 애쉬 근처로도 안 가면, 애쉬 몸의 삼각형 전체를 다 무시해도 되는 거 아니냐? 근처로 가나 안 가나를 검사하기 위해 필요한 것이 bounding volume이라는 것입니다. 번역하자면 ‘감싸는 물체’ 정도가 되려나요?

애쉬의 몸 전체를 감싸는 박스를 하나 만듭니다. 그리고 박스와 광선이 충돌하나 확인해 보고, 충돌하지 않으면 애쉬 몸의 삼각형 전체를 무시합니다. 광선이 애쉬 근처로도 가지 않으면 그 많은 삼각형 근처로도 안 간다는 건 너무나 당연한 사실이죠. 애쉬 뿐만 아니라 모든 캐릭터 각각의 몸을 감싸는 박스를 만들고, 맵도 사각형으로 쪼개서 박스 안에 넣습니다. 그렇게 하면 광선-박스 검사를 통해 엄청나게 많은 수의 삼각형을 무시할 수 있습니다.

bvh_youtube 클릭하면 유튜브 영상으로 이동합니다. 꽤 좋은 자료이므로 꼭 보셔요.

Bounding Volume Hierarchy 이름도 참으로 복잡하군요. 보통 줄여서 BVH라고 부릅니다. 여기서 bounding은 무언가를 감싸고 있다는 의미입니다. Volume은 부피라는 뜻인데, 여기선 3D 물체, 혹은 맵 안에서 공간의 부분을 의미합니다. Hierarchy는 계층이란 뜻인데요. 박스 세네 개를 감싸는 하나의 박스, 그런 박스들 세네 개를 감싸는 상위 계층의 박스. 이런 식으로 계층을 만들기 때문에 붙은 단어랍니다.

Ⅲ. 레이트레이싱 관련 다루지 않은 것

현실적인 이미지를 만들어내는 과정은 매우 복잡합니다. 먼 거리에 있는 물체가 흐리게 보이도록 만들고 태양이 환하게 빛나도록 만드는 atmospheric scattering도 구현해야 하고요. 물체에 텍스처를 입히고 매테리얼을 적용하되, 물리적으로 꽤나 사실적이게 보이도록 해주는 physically based rendering도 구현해야 합니다. 레이트레이싱 기술은 책 한 권으로도 부족할 정도로 엄청나게 방대한 내용을 담고 있습니다.

하지만 우리의 목적은 RTX에 대해 이해하는 것이죠. 이를 위해서라면 이 정도 내용으로 충분하다고 생각합니다. 수학적인 얘기도 좀 있어서 이해가 잘 안 되는 부분도 있을 것입니다.

괜찮습니다! 다만 다음 네 가지만 확실히 기억해 주세요.

  • 필요한 광선의 양이 엄청 많다.
  • 엄청 많은 광선이 엄청 많은 삼각형과 만나는지 검사해야 한다.
  • 박스를 이용하면 광선-삼각형 검사 수를 확 줄일 수 있다.

재미없는 레이트레이싱 이론에 대해 읽느라 고생하셨습니다. 다음 글에서는 본격적으로 RTX가 가능케 한 변화에 대해 다뤄보겠습니다.