내적과 외적
서론
우리는 수학시간 때 내적과 외적에 대해서 배웠었다. 물론 단지 수학문제를 풀기 위해 배우고 썼었는데 게임을 제작하거나 그래픽스 데모를 제작할 때 등 여러 분야에서 실제로 쓰인다. 어떻게 쓰이는지 알아보자
본론
내적이란?
영어로는 dot product이다. 두 벡터 사이에 dot을 적으면 내적을 나타내는 말이다 예를 들어 a벡터와 b벡터를 내적한다 라고하면
A○B로 나타낼 수 있고 , 결과를 보면
A○B = ||A|| ||B|| cos θ이다.
만약 각각의 벡터 성분을 알고 있다면 다음과 같이 나타낼 수 도 있다.
A = (a1, a2), B=(b1, b2)
A○B = a1*b1 + a2*b2;
또는 sqrt(a1^2+a2^2) * sqrt(b1^2+b2^2) * cos θ 로 나타낼 수 있다.
즉 θ 를 알고 있다면 cos θ 로 나타낼 수 있는 수식을 써서 계산하면 된다.
하지만 게임개발 및 그래픽스에서 쓰이는 내적은 두 벡터 사이의 각도 즉 θ를 알아내기 위해 많이 쓰인다. 따라서 각각의 벡터의 성분을 알고 있을 때 각도를 구하고 싶다면 두 가지 계산법을 모두 이용해서 알아낼 수 있는 방법이다. 위에서
A○B = a1*b1 + a2*b2; ----------------------------------------- (1)
A○B = sqrt(a1^2+a2^2) * sqrt(b1^2+b2^2) * cos θ --------- (2)
위 (1) 번과 (2) 번의 값은 서로 같은 것을 이용하여 cos θ 만 우변에 남기고 나머지를 좌변으로 넘긴다. 이때 우리는 벡터의 크기와 상관없이 두 벡터가 이루는 각만 구하면 되기 때문에 두 벡터를 normalized(정규화) 시킨 후에 계산을 하면 편리하다. 이때 normalized는 벡터의 길이를 1로 통일하는 것을 의미한다. 즉 방향성만 남기고 길이를 1로 만들어 방향에 대한 값만 계산하기 편리하게 만드는 것이다. 간단하게 벡터를 벡터자신의 크기로 나눠 주면 normalized 할 수 있다.
normalized(A) == A/||A||
normalized(A) = (a1/( sqrt(a1^2+a2^2) ), a2/( sqrt(a1^2+a2^2) ))
A = normalized(A), B= normalized(B);
(a)
a1*b1 + a2*b2 = sqrt(a1^2+a2^2) * sqrt(b1^2+b2^2) * cos θ
(b)
( a1*b1 + a2*b2 ) / ( sqrt(a1^2+a2^2) * sqrt(b1^2+b2^2) ) = cos θ
(b)
arccos( a1*b1 + a2*b2 ) / ( sqrt(a1^2+a2^2) * sqrt(b1^2+b2^2) ) = θ
a와 b의 성분을 알고 있으니 좌변은 하나의 상수로 나오게 된다. 이후, 양변에 arccos을 취하게 되면 온전한 θ를 구할 수 있게 된다.
위에서 알아낸 각도를 우리는 어떻게 사용할까? 간단한 예시로는 오브젝트를 렌더 할 때 오브젝트와 광원이 이루는 각에 따라 조명의 양을 계산할 때 쓰일 수 있다.
또는 카메라의 시선에서 오브젝트를 바라보았을 때, 즉, 카메라 벡터와 오브젝트의 노말 벡터가 이루는 각이 둔각이면(90도 이상) 카메라의 입장에서는 보이지 않기 때문에 렌더 하지 않는 backface culling을 사용할 때에도 쓰일 수 있다.
외각이란?
AxB(cross product)로 쓴다.
외적은 두 벡터의 수직 된 벡터이다. 즉 3D공간에서 설명해야 한다. 두 벡터가 있는 평면의 법선벡터라고 볼 수 있겠다. 여기서 사실 두 가지 방향이 있다. 평면을 xy평면이라고 했을 때 +z 축으로의 법 선벡터, 또는 -z 축으로의 법선벡터가 그것들이다.
이때 우리는 오른손 법칙을 이용하여 정한다.
위 그림에서 A 쪽 벡터에서 B벡터 쪽으로 오른손을 감싼다고 생각하면 엄지가 위를 가리키기 때문에 수직 위로 가는 방향이 외적의 결과로 볼 수 있다.
반대로 B와 A의 외적은 오른손으로 B방향으로 시작해서 A벡터 쪽으로 감싸면 엄지가 아래로 향하기 때문에 결과는 아래로 수직 하는 벡터이다.
다음으로 각각의 성분을 알고 있다면 수식으로도 표현 가능하다.
a = (a1, a2, a3), b = (b1, b2, b3) 일 때 다음고 같이 계산할 수 있으며
위처럼 계산이 가능하다.
그렇다면 외적은 어디에 사용될까?
위에서 언급하였듯이 외적은 a벡터와 b벡터가 이루는 평면의 법선벡터이기 때문에 그래픽스에서는 각각의 폴리곤의 normal벡터를 구할 수 있다. 정확히 말하자면 하나의 폴리곤에서 두 개의 벡터가 이루는 꼭짓점, 즉 vertex normal을 구할 수 있다. 따라서 두 벡터의 외적값은 face normal을 뜻하고 한 꼭짓점의 normal을 구하려면 이 꼭짓점을 둘러싸는 face들의 normal을 더해서 그 개수만큼 나눈 값이 되겠다. 즉 평균을 구하면 되기 때문에 모든 vertex들을 traverse 하면서 해당 꼭짓점에 해당되는 face들의 개수와 normal을 잘 계산하면 된다.
다음으로는 회전축을 제공한다. 쉽게 예를 들면 게임 내에서 사람의 시선이 앞을 향하고 들고 있는 총구의 방향은 땅과 수평되며 살짝 옆으로 돌아가있다고 했을 때 진행방향과 총구의 외적을 구해서 회전축으로 정한 뒤 캐릭터의 시선방향을 회전시키는 기준으로 만들 수 있다.
또는 물리 엔진에서 토크를 계산할 수 도 있다.
결론
내적과 외적으로 수학 문제만 풀 수 있는 것이 아니고 실제 게임 개발이나 그래픽스 개발에도 아주 많이 쓰인다.
마무리
위의 내용을 바탕으로 개발자 면접 간
1. 내적과 외적은 무엇인가요?
2. 이들을 사용해서 프로그래밍한 적이 있나요?
3. 어떤 곳에서 쓰이나요?
등에 대한 질문을 생각해 볼 수 있겠다. 스스로에게 질문을 해보고 답해보자.
헷갈리는 부분은 보완하기! 찡긋 O.<
틀린 부분이나 보완해줬으면 하는 내용이 있으면 댓글로 알려주세요! 추가 설명이 필요하신 부분도 댓글로 알려주세요.
어떠한 피드백도 환영입니다. 긴 글 읽어주셔서 감사합니다.