[게임 수학] 백페이스 컬링과 로드리게스 회전

ounols·2021년 11월 11일
3

게임 수학

목록 보기
3/9
post-thumbnail

🧐 해당 파트는 게임 개발 환경을 구성하는 컴퓨터 그래픽스(Computer Graphics)를 이해하기 위한 기초 수학의 간단한 개념에 대해 설명하고 있습니다!

혹여나 이해가 잘 안되거나 잘못된 정보를 발견하시게 되었다면 관련해서 피드백 해주시면 정말 감사하겠습니다!

백페이스 컬링

들어가기 전, 컬링이란?

절두체 컬링과 오클루전 컬링이 적용되는 단계를 설명한 이미지

컴퓨터가 렌더링하는 것은 사실 화면에 보여지는 부분만 렌더링을 해도 전부를 렌더링하는 것과 보이는 것의 차이가 없습니다.

이렇게 화면에 보여지는 부분만 보여주는 기법 중 하나가 바로 컬링입니다.
화면에서 봤을 때 보여지는 부분만 렌더링하고 나머지 부분은 렌더링을 생략하죠!

혹시 모릅니다... 어쩌면 우리가 사는 실제 세계에서도 우리 눈에 보이지 않는 부분은 공허로 되어있을 수도 있습니다...!

이런, 댕소리가 너무 길어졌네요.
아무튼 본론으로 돌아가서 이번엔 매쉬의 앞부분만 렌더링하는 백페이스 컬링에 대해 알아보고자 합니다.

1-1. 백페이스 컬링의 원리와 구현 방법

백페이스 컬링은 뒷면의 렌더링을 생략한다고 했으니 면이 앞을 향했는지 뒤를 향했는지 알아내기만 하면 쉽게 진행할 수 있을 것 같습니다.

그래서 이걸 판별할 방법이 바로 하나의 면을 구성하는 3개의 버텍스를 렌더링하는 회전 방향에 따라 앞면과 뒷면을 구별할 수 있게 됩니다!

근데 뭔가 익숙한 전제조건입니다...!
이전 2편에서 배웠던 두 점을 이용해 노멀 벡터를 얻어내는 방식과 정말 비슷합니다!

따라서 백페이스 컬링의 구현 단계는 아래처럼 정리할 수 있겠습니다.

  1. 한 면의 노멀 벡터를 얻기 위해 최소 두 점을 이용하여 외적을 진행합니다.

  2. 카메라의 시선 벡터와 노멀벡터를 내적합니다.
    카메라의 시선 기준으로 앞면인지 뒷면인지 판별하기 위해 내적을 사용하고, 결과값은 스칼라입니다. 이를 식으로 표현하면 zlocalnz_{local}\cdot \vec{n} 으로 표현할 수 있습니다.

  3. 결과값의 범위를 통해 앞면과 뒷면을 구별합니다.
    내적을 통해 z>0z > 0 인 경우엔 앞면을 향한다고 볼 수 있습니다!

1-2. 삼각형 면의 노멀, 정점의 노멀 데이터, 노멀 맵의 노멀 데이터는 각각 어떻게 쓰이나요?

면의 노멀정점의 노멀노멀맵의 노멀

생각해보면 앞서 봤던 백페이스 컬링은 결정적으로 노멀백터를 사용합니다.

이렇게 여러 용도로 사용되는 노멀벡터! 그런데 데이터에 따라 사용처가 다 다릅니다!
각 노멀벡터는 어디에 사용되는지 한번 알아봅시다!

1. 면의 노멀

면의 노멀은 앞서 배운 것 처럼 백페이스 컬링에 주로 쓰입니다.
자세한 방식은 위에서 설명했으니 생략하도록 하겠습니다!

혹시 반대로 뒷면만 남기고 앞면을 컬링하는 경우도 있나요?
네! 스카이 박스같은 예시도 존재하지만 스카이 박스는 매쉬 단계에서 아예 인덱스 방향을 바꿀 수 있으므로 렌더링 단계에서 프론트페이스 컬링을 진행하는 대표적인 예시를 든다면 쉐도우 맵핑이라고 할 수 있겠습니다.

부동 소수점은 온전한 소수점을 가지지 않기 때문에 쉐도우 맵핑을 구현하는 단계에서 몇가지 처리를 진행해야합니다. 이러한 단계를 진행하다보면 그림자가 붕 떠있는 현상을 확인하실 수 있습니다.

이를 피터 패닝 현상이라고 합니다.
이러한 현상을 해결하기 위해 앞면만 컬링하여 위 그림처럼 잡다한 영역의 불필요한 그림자 판정을 막을 수 있습니다.

2. 정점의 노멀

일반적인 정점 노멀(왼쪽)과 선형 보간 된 정점 노멀(오른쪽)입니다. 보간된 정점 노멀이 빛을 더 자연스럽게 표현하고 있습니다.

정점의 노멀은 주로 빛계산이 필요한 쉐이더에서 자주 쓰입니다.
GPU에 계산을 시키기 위해 우리는 GPU에 여러 데이터들을 보내는데 그 중 Attribute 타입이 존재합니다.
Attribute는 정점 쉐이딩 단계에서만 쓰이며, 주로 많은 데이터를 가지는 정점의 데이터를 얻어옵니다.
정점의 데이터를 위주로 받다보니 Attribute로 전달받는 데이터들은 대부분 정점 기준으로 받습니다.

면의 노멀로 받아오기엔 면 기준으로도 전달받을 데이터가 너무 많고, 이걸 또 정점 기준으로 사용하기 위한 절차가 길어집니다. 따라서 관련 노멀값은 정점을 기준으로 받아옵니다.

정점 데이터를 쉐이더에서 선형 보간을 통해 부드러운 표면의 처리를 진행하는게 정석이지만
실사용은 매쉬 단계에서 자체적으로 선형 보간 처리된 노멀값을 입력하고 GPU는 이 노멀값을 기준으로 픽셀단위로 보간하여 사용합니다.

3. 노멀맵의 노멀

노멀맵 역시 쉐이더에서 주로 쓰입니다.

정점의 노멀 데이터는 정점 쉐이딩에서 데이터를 받고 픽셀 쉐이딩에서 이 데이터를 선형 보간처리하기 때문에 픽셀 쉐이딩 단계에서 상세한 노멀의 표현이 어렵습니다.

이를 보완하기 위해 노멀맵을 사용합니다! (뭔가 노멀의 최종보스 느낌입니다)
노멀맵은 다른 노멀과 달리 픽셀 쉐이딩 단계에서 처리하는 텍스쳐 형태입니다.

그런데 노멀맵을 처리하다보면 위와 같이 면의 방향과 빛계산이 틀어지는 현상이 일어납니다.
이는 기존 노멀값을 기준으로 노멀맵 처리를 해줘야 우리가 알고있는 노멀맵의 형태로 보여집니다. 이러한 방식은 탄젠트 스페이스라는 개념을 통해 TBN 행렬을 만들어 적용을 해야합니다.

이에 대한 간략한 설명은 TBN행렬로 보간한 노멀 맵핑 원리를 설명하는 해당 링크를 통해 확인해보시는 것을 추천드립니다!

2. 로드리게스 회전공식

이 회전 공식은 외적과 내적을 응용하는 대표적인 예시 중 하나입니다.

어.....사실 개인적으로 이런 회전 공식이 존재하는줄도 몰랐습니다...!

애초에 그래픽스를 배우면서 이런 부분의 설명은 하나도 없이
'아~ 오일러각의 문제는 사원수가 다 해결해줘요!!! 근데 사원수를 이해하는건 힘들어요!~~' 이런식으로 넘어갔었다고 핑계를 대고 싶습니다..하핫...;

그래서 저도 이런 개념을 처음 배우는데 많은 부분들에 있어 놀란 부분이 한두가지가 아니였습니다. 그래서 저는 따로 이 회전공식을 배우면서 인상깊었던 특징들도 간단하게 정리해보려고 합니다.

로드리게스 회전공식의 특징

  • 짐벌락으로부터 자유로워진다.
  • 여러 방향의 회전 보간이 가능해진다.
  • 사원수와 같은 공식이 적용된다!

오..사원수랑 같은 공식이 적용된다에서 정말 크게 놀랐습니다.
나중에 사원수 파트로 넘어가면서 이 놀랍고도 신기한 수학의 일치를 다뤄보도록 하겠습니다.
서로 같은 공식을 증명할 날을 생각하면 정말 신납니다.

2-1. 로드리게스 회전공식을 단계별로 유도해 정리해봅시다.

간단하게 회전 공식의 로직을 위 그림처럼 작성하였고, 각 단계별로 간략한 설명은 다음과 같습니다.

1. 원점 OO 에서 OO'을 향하는 벡터를 u\vec{u}n\vec{n}을 내적한 투영공식을 통해 구합니다.
2. OPO'P 선분에서 OPO'P'xx축의 기저벡터를 담당하기 위해 cosθ\cos\theta를 곱해줍니다.
3. 외적을 통해 OPO'Pn\vec n에 직교하는 OQO'Q 선분을 이용하여 OPO'P'yy축의 기저벡터를 담당하기 위해 sinθ\sin\theta를 곱해줍니다.
4. 서로 직교하는 두 기저벡터를 더하여 최종적으로 OP{O'P'}를 구합니다.

이제 각 단계별로 식을 표현해보도록 하겠습니다.

1단계

위 이미지에서 구해야하는 1번에 해당되는 투영벡터를 v\vec v 라고 선언하고 식을 작성해보겠습니다.

v=(un)n\vec{v}=(\vec{u}\cdot \vec{n})\vec{n}

투영 공식에 의해 u\vec{u}n\vec{n}을 내적하여 투영벡터 v\vec v를 구했습니다.

2단계

OPO'P 를 구하기 위해선 이전에 구했던 u\vec u에서 v\vec v를 빼주면 구할 수 있습니다.

OP=uv\vec{O'P} = \vec u - \vec v

이제 OPO'P'를 구하기 위해 OPO'P'xx방향의 기저벡터를 구합니다. 이 때 우리는 θ\theta를 이용해서 기저벡터를 다음과 같은 식으로 유추할 수 있습니다.
여기서 xx방향의 기저벡터를 xx'이라 선언하겠습니다.

x=OPcosθ=(uv)cosθx' = \vec{O'P} \cdot cos\theta \\ = (\vec u - \vec v) \cdot cos\theta

이제 yy방향의 기저벡터를 구하면 끝납니다!

3단계

이제 xx'n\vec n을 직교하는 OQ\vec {O'Q}를 구해야합니다. 여기서 xx'n\vec n의 값을 모두 가지고 있기 때문에 이 둘을 외적시켜줍니다.

OQ=n×OP=n×(uv)\vec {O'Q} = \vec n \times \vec{O'P} \\ = \vec n \times (\vec u - \vec v)

여기서도 yy방향의 기저벡터를 구하기 위해 2단계처럼 θ\theta를 이용해서 기저벡터를 구합니다.
여기서 yy방향의 기저벡터를 yy'이라 선언하겠습니다.

y=OQsinθ=n×(uv)sinθy' = \vec{O'Q} \cdot \sin\theta \\ = \vec n \times (\vec u - \vec v) \cdot \sin\theta

와! 기저벡터를 모두 모았습니다! 이제 흩어진 드래곤볼을 모으듯이 합쳐봅시다!

잠깐! 식을 더 간단하게 만들 수 있을 것 같은데요?
여기서 식을 간단하게 만들 수 있습니다! 먼저 외적에 대해 분배법칙을 적용해보겠습니다.

n×(uv)sinθ=(n×un×v)sinθ=(n×u)sinθ\vec{n}\times (\vec{u}-\vec{v})\cdot \sin\theta\\ =(\vec{n}\times \vec{u}-\vec{n}\times \vec{v})\cdot \sin\theta\\ =(\vec{n}\times \vec{u})\cdot \sin\theta

n×v-\vec{n}\times \vec{v}는 서로 평행하기 때문에 영벡터로 나옵니다. 따라서 해당 부분은 생략할 수 있습니다.

4단계

서로 직교하는 두 기저벡터를 더하면 하나의 벡터가 나옵니다. 바로 OP\vec {O'P'}입니다!
이제 다 합쳐봅시다.

OP=x+y=OPcosθ+OQsinθ=(uv)cosθ+n×(uv)sinθ=(uv)cosθ+n×usinθO'P' = x' + y' \\ = \vec{O'P} \cdot \cos\theta + \vec{O'Q} \cdot \sin\theta \\ = (\vec u-\vec v)\cos\theta + \vec n \times (\vec u -\vec v )\cdot \sin\theta \\ = (\vec u-\vec v)\cos\theta + \vec n \times \vec u \cdot \sin\theta

이로써 최종적인 식은 (uv)cosθ+n×usinθ(\vec u-\vec v)\cos\theta + \vec n \times \vec u \cdot \sin\theta 로 나타납니다!

2-2. 막상 응용과정에서 로드리게스 회전 공식을 사용하지 않는 이유?

이렇게 엄청난 공식을 그래픽스에서 쓰지 않는 이유가 무엇일까요?
이러한 문제로 아마 저도 해당 공식을 배우는걸 넘기지 않았을까 싶긴 합니다...

어쨌든 다시 본론으로 돌아가서 사용하지 않는 이유를 정리해보았습니다.

  • 사용되는 값이 너무 알아보기 힘듭니다.
    위의 공식에서 봤다시피 값을 구하기 위해선 여러 벡터들이 필요합니다.
    심지어 θ\theta값도 필요합니다.. 이걸 쓰게 된다면 회전 행렬이랑 또 다른 맛의 어지러움을 느낄 것 같습니다!

    그래도 오일러 각의 문제를 대체할 수 있으니 알아보기 힘든점을 감안하고 쓸만하지 않을까 생각이 들지도 모릅니다. 그러나...

  • 사원수라는 대체제가 있습니다.
    앗! 사원수라는 훌륭한 대체제가 존재합니다! 이 친구에 대해선 잘 모르지만 대충 알아본 바로는 일단 로드리게스 공식보다 필요한 값이 적습니다!

    그래도 여전히 로드리게스 공식을 마음에 두고 계시다면...

  • 결과 값에 대해 행렬과 오일러 각으로의 변환이 어렵습니다.
    이와 같은 문제가 있습니다... 하지만 사원수는 행렬과 오일러각의 변환이 자유로운 편이라 사원수를 채택하는 게임 엔진이 절대적으로 많다고 할 수 있겠습니다.


지금까지 로드리게스 회전 공식을 알아봤습니다. 저 역시 오랜만의 수학이라 그런지 수학의 변태성(?)을 다시 깨닫게 하는 그런 시간이 아니였나 싶습니다. 많이 아찔했지만 덕분에 뭔가 발견하는 재미를 확실하게 느낄 수 있으니 결국 무언가를 배웠다는 성취감만큼은 잘 전달되었으면 좋겠습니다!
profile
(게임 엔진 프로그래머가 되고싶은) 게임 클라이언트 프로그래머

0개의 댓글