'3D 기초 수학 강좌'에 해당되는 글 1건
- 2019.09.24
http://lab.gamecodi.com/board/zboard.php?id=GAMECODILAB_Lecture_series&no=121&z=21
3D 게임 프로그래밍을 위한 기초 수학
3D 게임 프로그래밍을 위한 기초 수학에 대한 연재 강좌를 시작합니다.
저도 수학에 대해서 잘 모르지만 공부하면서 알게된 지식을 공유하기 위한 목적으로 올립니다.
벡터와 삼각함수 부분을 연재해 나갈 계획이며,
수학에 기초가 약한 분들을 대상으로 쉽게 쓰려고 합니다.
따라서 이미 베테랑이신 분들은 다 아는 내용일지도 모릅니다.
혹시 내용중 잘못된 부분에 대한 지적이나 의견을 주시면 너무 감사하겠습니다.
적극적인 피드백 부탁드립니다.^^
3D 게임 프로그래밍을 위한 기초 수학 - 1. 시작
저같이 수학에 약한 게임 프로그래머들에게 이런 말씀을 드리고 싶습니다.
게임 프로그래밍, 특히 3D 게임 프로그래밍을 하는데 필요한 수학은 아주 재미있을 뿐 아니라
결과가 컴퓨터를 통해서 즉시 출력되기 때문에 학교 수업처럼 지루하게 느껴지지 않을 겁니다.
단, 여기서 말하는 수학은 단순히 시험 점수를 얻기 위한 수학이 아님을 말씀드립니다.
수학과 물리가 일상 생활의 문제점들을 해결하기 위해서 발전해 왔듯이 게임 프로그래밍에서의 수학도 분명한 쓰임새가 있기 때문에 필요한 것입니다.
수학을 사용하지 않고 게임을 만들고 있다면 아직 그러한 쓰임이 필요하지 않은 게임을 만들어 왔거나,
이미 수학을 사용하고 있지만 단지 “수학”이라고 인지 하지 않고 있을 뿐이라고 말씀드릴 수 있습니다.
또한 프로그래밍 언어를 배울 정도의 논리력을 갖고 있는 사람이라면
아주 쉽고 재미있게 3D 게임 프로그래밍을 위한 수학을 배워나갈 수 있다고 확신합니다.
여기에 나무 두 그루가 있습니다.
왼쪽 나무는 1m 오른쪽 나무는 2m의 높이를 갖고 있지요. 어느 쪽 나무가 더 높은가요?
“그야 당연히 오른쪽 나무가 더 높죠.”
그럼 왼쪽 나무에 비해 오른쪽 나무는 얼마나 더 높은가요?
“왼쪽 나무가 1m이고, 오른쪽 나무가 2m이니까 두배 더 높군요.”
이번에는 이렇게 질문 드리겠습니다. 오른쪽 나무에 비해 왼쪽 나무는 얼마나 더 높은가요?(혹은 작은가요?)
“오른쪽 나무가 2m이고, 왼쪽 나무가 1m이니 딱 절반만큼 작습니다.”
여기 까지 읽는데 머릿속에 별다른 막힘이 없었다면 앞으로 나올 3D 게임 프로그래밍을 위한 수학도
충분히 이해할 수 있는 두뇌를 갖고 계신 겁니다.
왜냐하면 수학적 내용들이 언뜻 보기에 복잡한 수식으로 무장되어 있는 것 같지만
하나하나 따져가다 보면 자연스럽게 이해될 수 있는 얘기를 수와 문자를 통한 논리로 표현했을 뿐이기 때문이지요.
방금 설명해 드린 내용은 분수의 개념을 그림을 통해서 나타낸 것입니다.
답변한 내용 중에 왼쪽 나무에 비해 오른쪽 나무가 두배 더 높다 라고 한 부분이 있죠?
또한 오른쪽 나무에 비해 왼쪽 나무가 절반만큼 작다 라고 답변한 부분도 있습니다.
바로 이렇게 서로를 비교하는데 사용할 수 있는 것이 분수입니다.
(물론 분수를 정의하는 데에는 다른 뜻도 있습니다.)
(참고 : http://terms.naver.com/entry.nhn?docId=957717&cid=47308&categoryId=47308)
그런데 흔히 알고 있는 분수는 몇 분의 몇 이런 식으로 부르는데 그것과 이 내용이 무슨 관계가 있는 걸까요?
다시 한번 그림을 보면서 차근차근 설명해 드리겠습니다. 아까 봤던 그림이니 어려울 것 없겠죠?
우선 왼쪽 나무에 비해 오른쪽 나무는 두 배 더 높다고 하셨죠? 이것을 수학적으로 나타내면
오른쪽 나무의 높이
---------------------
왼쪽 나무의 높이
이렇게 표시할 수 있습니다. 수학적으로 말이죠.
반대로 오른쪽 나무에 비해 왼쪽 나무는 절반만큼 작다 라고 말씀하셨는데 이것도 수학적으로 표현해 보면
왼쪽 나무의 높이
---------------------
오른쪽 나무의 높이
이렇게 나타낼 수 있습니다. 초등학교때 봤던 분수의 형태와 똑같죠?
오른쪽 나무와 왼쪽 나무의 글자 위치에 나무의 높이를 넣어보면 각각 이렇게 표현 됩니다.
오른쪽 나무의 높이 2
--------------------- ---- = 2 (두배)
왼쪽 나무의 높이 1
왼쪽 나무의 높이 1
--------------------- ---- = 0.5 (절반)
오른쪽 나무의 높이 2
결국 분수 라는 것은 어느 한쪽에 비해서 어느 한쪽이 얼마나 더 크냐를 나타낼 때 사용할 수 있다는 것을 알 수 있죠.
그것을 수학적으로 표현하면 분수의 형태로 나타낼 수 있고
그 분수의 형태는 결국 실생활에서 크기를 비교하고 계산하는데 사용할 수 있는 도구가 되는 셈입니다.
그리고 그런 도구들의 사용법을 배우는 것이 3D 게임 프로그래밍을 위한 수학을 배우는 것과 같다고 말할 수 있는 것이죠.
간단하게 분수의 개념에 대해서 알아봤습니다.
물론 분수를 모르시는 분들은 거의 없을테지만 수학적 개념이란게 이처럼 쉽게 이해될 수 있다는 것을 알려드리고 싶었습니다.
다음 강좌 부터는 벡터를 시작으로 본격적인 3D 게임 프로그래밍을 위한 수학에 대해 학습해 보겠습니다.
3D 게임 프로그래밍을 위한 기초 수학 - 2. 벡터(덧셈)
벡터의 정의
크기와 방향을 동시에 나타내는 물리량을 말한다.
(네이버 백과사전. http://terms.naver.com/entry.nhn?docId=940915&cid=47338&categoryId=47338)
벡터라는 단어를 처음 접한다면 위 내용이 무슨 뜻인지 알 수가 없습니다.
벡터의 사전적 정의는 잠시 잊어 버리고 그림을 보면서 알아보도록 하죠.
집과 나무, 사람이 있는 그림입니다.
여기서 한 가지 질문을 드리겠습니다. 저 그림에서 사람이 어디에 위치해 있죠?
단순히 그림만 본다면 이렇게 대답할 것입니다.
“집에서 조금 떨어져 있고 나무 아래에 있는데요?”
그렇다면 이번에는 조금 더 수학적으로 접근해 보도록 합시다.
아래 그림을 보고 다시 얘기해 주세요.
사람이 집에서 얼마만큼 떨어져 있나요?
이제는 이렇게 대답할 수 있겠죠.
“집에서부터 5m 떨어져 있네요.”
네. 맞습니다. 그럼 방금 답하신 내용을 문장이 아닌 벡터로 표현해 보도록 하겠습니다.
위 그림은 사람의 위치를 문장이 아닌 벡터로 나타낸 것입니다.
벡터는 크기와 방향을 갖는다고 백과사전에 나와 있었죠?
저 그림에서 사람을 가리키는 벡터는 크기가 5이며, 방향은 화살표가 가리키는 오른쪽 방향이다 라고 이해하시면 됩니다.
여기서 크기라는 것은 화살표의 길이를 의미 합니다.
그렇다면 도대체 왜 벡터라는 것을 쓰는 건가요?
위치를 나타내려면 x,y처럼 점으로 표현할 수 도 있지 않나요?
맞습니다. 점으로도 위치를 표현할 수 있죠.
하지만 벡터를 사용하는 이유는 벡터의 특성들을 게임에 활용하기 위해서입니다.
점으로만 사용했을 때 보다 훨씬 더 다양한 모습들을 쉽게 계산할 수 있거든요.
앞으로 그 특성들을 하나하나 알려드릴 텐데요,
그 전에 벡터 하나를 더 추가해보도록 하겠습니다.
그림에서 사과가 보이시나요? 사과를 가리키는 벡터를 그려볼까요?
사람의 위치를 나타내는 벡터와 마찬가지로
집에서부터 사과의 위치까지 화살표를 그리면 사과를 가리키는 벡터가 되죠.
크기는 화살표의 길이, 방향은 집에서부터 사과를 향하고 있습니다.
게임 안에 존재하는 어떤 물체라도 벡터를 통해서 그 위치를 표현할 수 있습니다.
심지어 눈에 보이지 않는 속도, 힘 등을 표현하는 데에도 벡터가 사용됩니다.
그럼 이제 벡터의 특성에 대해서 알아보도록 하겠습니다.
위 그림에서 벡터의 화살표가 가리키는 위치는 점으로 표현했을 때의 위치와 동일하죠.
따라서 벡터와 점이 무슨 차이가 있는지 모를 겁니다.
하지만 벡터는 크기와 방향으로 구성된다고 말했습니다.
즉, 크기와 방향이 같다면 어디에 있는 벡터든지 모두 같은 벡터로 취급할 수 있다는 뜻입니다.
위 그림에서 네 개의 벡터는 각각 위치가 다르지만 모두 다 같은 벡터입니다.
“시작 위치가 다르고 화살표의 끝이 가리키는 곳이 다른데 어떻게 같은 벡터가 될 수 있나요?”
벡터의 뜻을 찾아봤을 때 크기와 방향으로 이루어져 있다고 말씀드렸습니다.
시작 위치나 끝 위치 등의 개념은 갖고 있지 않죠.
다만 게임 내에서는 원점(0,0)을 시작으로 각각의 객체의 위치까지 벡터로 이은다고 생각하면
벡터를 이용하여 좌표를 나타낼 수 있으므로 여러 가지 편리한 점이 많습니다.
크기와 방향이 같으면 모두 같은 벡터이다.
그렇다면 벡터는 시작점에 고정되어 있는 것이 아니다 라고 이해하면 되는 건가요?
그렇습니다. 벡터는 어느 한 점에 고정되어 있지 않습니다.
따라서 크기와 방향이 같다면 이리저리 옮겨 다녀도 모두 같은 벡터라는 것이죠.
같은 벡터이기 때문에 결국 벡터 연산에 있어서 크기와 방향만 같다면
어디에 붙여놔도 동일한 계산 결과가 나온다는 뜻입니다.
벡터를 이해하려면 약간의 상상력을 더해야 합니다.
눈에 보이지는 않지만 우리 주변에 무수히 많은 벡터가 있다고 생각해 봅시다.
내 오른쪽 1m 옆에 누군가가 서 있다면 나로부터 오른쪽으로 1m 길이를 갖는
화살표(벡터)가 존재한다고 상상해볼 수 있습니다.
또한 땅으로부터 내 머리 끝까지 화살표로 잇는다면 내 키를 표현하는 벡터가 생기게 됩니다.
내가 자리에 앉거나 바닥에 눕는다면 그 벡터의 길이와 방향도 같이 변하게 되겠죠.
대부분의 게임 프로그래밍에서는 캐릭터를 이동시킬 때 벡터의 연산을 이용합니다.
따라서 벡터의 덧셈, 뺄셈 등의 연산 방법을 배우는 것은
게임 프로그래밍을 하는데 가장 기초적인 수학적 기반을 쌓는 셈이죠.
혹, 벡터라는 것을 모르고 게임 프로그래밍을 하고 있더라도 걱정할 필요는 없습니다.
용어의 차이만 있을 뿐이지 코드 속에서는 이미 벡터의 개념을 활용하고 있을 것이기 때문이지요.
만약 유니티 엔진을 사용하여 게임을 개발하고 있다면 씬에 빈 오브젝트를 하나 올려 놓는 것 만으로도
벡터를 사용하게 되는 셈입니다.(Transform의 position값이 벡터로 되어있기 때문입니다.)
이런 내용을 머릿속에 담고 이제부터 벡터끼리 계산하는 방법을 알아보도록 하겠습니다.
벡터의 덧셈
그림속의 사람이 게임 캐릭터라고 생각해 봅시다.
현재 집으로부터 5m 위치에 서 있는데 떨어지는 사과를 받기 위해 6m 지점으로 이동시키려고 합니다.
벡터를 사용한다면 이걸 어떻게 표현할 수 있을까요?
현재 5m 지점에 서 있고, 사과는 그보다 1m 오른쪽에 있는 6m 지점으로 떨어질 테니까 현재 위치에서 오른쪽으로 1m 이동하면 되겠네요.
이것을 벡터로 표현한다면 a = [5,0] 이 되겠군요. [x좌표, y좌표] 순서로 씁니다.
그리고 사과가 떨어질 위치는 집으로부터 오른쪽으로 6m 지점에 위치해 있으니
c = [6,0] 이라고 표현할 수 있습니다.
(캐릭터를 A, 사과가 떨어질 위치를 C라고 두겠습니다)
또한 현재 위치에서 오른쪽으로 1m 이동하면 사과가 떨어질 위치까지 갈 수 있으니
이것도 벡터로 표현한다면 b = [1,0] 이 되겠네요.
이렇게 세 개의 벡터가 생겨났습니다.
이걸 그림으로 그려 볼까요?
우선 벡터 a와 벡터 b를 그려봤습니다.
앗, 그런데 벡터 b는 왜 저 위에 있지요?
b = [1,0] 이라면 집의 위치에서부터 시작해서 오른쪽으로 1m 지점에 위치한 벡터로 그려야 맞지 않나요?
벡터는 크기와 방향이 같다면 어디에 있든지 같은 벡터라고 말씀 드렸었죠?
어떠한 특정한 지점에 고정되어 있지 않다는 것을 기억해 두세요.
이 특성은 벡터의 덧셈을 할 때 아주 유용하게 사용됩니다.
벡터의 덧셈은 아주 간단한데요 꼬리에서 머리로 이어주면 됩니다.
꼬리는 벡터가 시작되는 부분을 말하고요,
머리는 벡터의 화살표 부분을 말합니다.
두 벡터의 덧셈은 한 벡터의 꼬리에서부터 다른 벡터의 머리까지 쭉 이어줬을 때 생기는 새로운 벡터를 의미합니다.
먼저 벡터 b를 움직여서 벡터 a와 서로 붙도록 만들어 봅시다.
이제 이렇게 만든 벡터를 아까 말씀드린 덧셈 방법에 따라 더해 봅시다.
덧셈은 꼬리에서 머리로 이어주면 된다고 했습니다.
벡터 a의 꼬리가 가리키는 지점에서 벡터 b의 머리가 가리키는 지점 까지 이어주면
다음과 같이 새로운 벡터를 얻을 수 있습니다.
새로 생긴 벡터 c는 결국 벡터 a + b로 계산된 결과입니다.
수학적으로 표현하면 아래와 같은 식이 나오죠.
a + b = [5,0] + [1,0] = [6,0]
벡터의 덧셈을 그림으로 나타내면 꼬리에서 머리로 이어주는 벡터가 되며,
수식으로 나타내면 벡터의 각 요소[x,y] 끼리 더해준 결과입니다.
같은 선 위에 있지 않은 벡터도 물론 더할 수 있습니다.
위 그림에서 사람을 가리키고 있는 벡터와 사과를 가리키고 있는 벡터를 더하면 아래 그림과 같은 벡터가 생깁니다.
벡터 a를 벡터 b의 머리 부분에 이어지도록 위치 시킵니다.
벡터는 크기와 방향만 같으면 어디에 옮겨도 상관 없기 때문에
벡터 a를 b의 머리 부분으로 이동시켜도 이전에 사람을 가리키고 있던 벡터와 동일한 벡터로 취급할 수 있습니다.
이 상태에서 꼬리에서 머리로 이어주면 두 벡터를 더한 새로운 벡터(a+b)가 생깁니다.
물론 게임 프로그래밍에서 두 벡터를 더할 때 위와 같은 풀이 과정을 거칠 필요는 없습니다.
두 벡터의 각 요소[x,y]를 서로 더해주면 이 풀이 과정과 동일한 결과를 나타내기 때문에
산술적으로 계산만 해주면 됩니다.
참 쉽죠?
여기에는 단순히 두 수를 더해주는 계산만 필요하기 때문에 수학적으로 어려운 개념은 전혀 없습니다.
더하기만 할 줄 안다면 누구든지 벡터의 덧셈을 할 수 있다는 뜻이기도 하죠.
게다가 계산은 컴퓨터가 해주기 때문에 게임에 활용하는 것은 더욱더 쉬워집니다.
벡터의 덧셈 정리
1. 두 벡터끼리 서로 이어지도록 만든다.
2. 한 벡터의 꼬리에서 다른 벡터의 머리까지 이어서 새로운 벡터를 만든다.
3. 새로 만들어진 벡터가 두 벡터를 더한 것이 된다.
다음 강좌에서는 벡터의 뺄셈과 곱셈에 대해서 알아보겠습니다.
감사합니다.
3D 게임 프로그래밍을 위한 기초 수학 - 3. 벡터의 뺄셈, 벡터와 스칼라의 곱셈
벡터의 뺄셈
이번에는 벡터의 뺄셈에 대해서 알아보도록 하겠습니다. 뺄셈은 덧셈으로도 표현할 수 있다는 사실을 아시나요?
1 – 1 = 0
1 + (-1) = 0
장난 같지만 위 수식처럼 뺄셈은 음수값을 더하는 형태로 나타낼 수 있죠.
이런 형태는 벡터의 뺄셈에도 똑같이 적용됩니다.
뺄셈을 덧셈처럼 생각한다면 아까 배웠던 벡터의 덧셈을 그대로 사용할 수 있으니 계산하는데 더 편할 겁니다.
a = [5,0]
b = [6,5]
b – a = b + [-a]
= [6,5] + [-[5,0] ]
= [6,5] + [-5,0]
= [6 + [-5], 5 + 0]
= [1, 5]
벡터의 뺄셈은 간단히 각 자릿수에 대해서 연산을 해주면 끝입니다만
이것만 봐서는 잘 이해가 안 되기 때문에 그림으로 벡터의 뺄셈을 알아보도록 하죠.
벡터b에서 벡터a를 뺀다는 것은 b – a라는 식으로 나타낼 수 있습니다.
위에서 뺄셈은 덧셈으로 표현할 수 있다고 말씀드렸었죠.
그렇다면 b – a = b + (-a) 로 표현할 수 있습니다.
벡터에 –를 붙인다는 것은 크기는 그대로 두면서 방향만 반대로 바꾸는 것입니다.
벡터a에 –부호를 붙이면 위 그림과 같이 길이는 그대로 유지하면서 방향만 반대로 되는 벡터가 됩니다.
-a벡터를 구했으므로 아까 배운 벡터의 덧셈을 이용하여 두 벡터를 더해봅시다.
간단하겠죠? 벡터의 덧셈은 꼬리에서 머리로 이어주면 된다고 했습니다.
a의 꼬리에서 b의 머리까지 이어주면 아래와 같은 벡터가 생깁니다.
벡터의 뺄셈도 덧셈처럼 생각한다면 특별히 어려운 개념은 없을 것입니다.
뺄셈을 통해 생겨난 벡터도 다른 벡터들과 완전히 똑같은 특성을 갖게 되죠.
아래 그림을 봅시다.
위 그림에서 빨간색으로 나타낸 두 개의 벡터는 완전히 동일한 벡터입니다.
왜냐하면 크기와 방향이 같기 때문이죠.
이처럼 벡터를 볼 때는 크기(길이)와 방향이 어떻게 생겼는지를 봐야 헷갈리지 않습니다.
그럼 벡터의 뺄셈은 어디에 활용될 수 있을까요?
위 그림에서 벡터c는 사람에서 사과를 향하는 벡터라는 것을 알 수 있죠.
이처럼 특정 위치에서 다른 위치를 향하는 벡터를 구할 때 벡터의 뺄셈을 사용한다면
아주 쉽게 해당 벡터를 구할 수 있습니다.
게임 프로그래밍에서는 캐릭터를 특정 장소로 움직이도록 만들 때 사용합니다.
예를 들어 플레이어를 추적하는 몬스터 인공지능을 구현한다고 합시다.
아주 단순하게 생각하면 몬스터가 현재 플레이어가 서 있는 위치를 향해 매 프레임 이동하는 로직을 구상할 수 있습니다.
그렇다면 몬스터의 x,y 좌표에 어떤 계산을 적용해야 플레이어를 향하여 이동하게 만들 수 있을까요?
이 때 몬스터의 이동 방향을 구하는데 벡터의 뺄셈을 활용할 수 있을 것입니다.
플레이어를 향하는 방향 = (플레이어의 위치 - 몬스터의 위치)
몬스터의 위치와 플레이어의 위치를 벡터로 간주한다면 앞서 배운 벡터의 뺄셈을 그대로 적용시킬 수 있습니다.
계산된 결과는 몬스터에서 플레이어를 잇는 벡터가 되는데, 이 벡터를 따라서 몬스터를 움직이게 하면 됩니다.
Tip.
실제 코드를 구현할 때에는 이 벡터를 단위벡터로 만든 뒤
몬스터의 이동속력을 곱하여 최종적으로 속도 벡터를 얻는 과정이 필요합니다.
이렇게 얻은 속도 벡터에 몬스터의 현재 위치를 가리키는 벡터를 매 프레임마다 더해주면
몬스터가 플레이어의 위치로 움직이는 모습이 구현되죠.
게임 내에서는 매 프레임마다 몬스터의 위치를 갱신해 주는 코드가 들어갈 테니
프레임 사이의 시간간격을 구해서 속도 벡터에 곱해준 뒤
몬스터의 위치를 가리키는 벡터에 더해야 정상적인 결과가 나오게 됩니다.
방향 벡터 = 플레이어의 현재 위치 – 몬스터의 현재 위치
방향 벡터를 단위 벡터로 만들고 이동 속력을 곱해 속도 벡터를 계산
몬스터의 새로운 위치 = 몬스터의 현재 위치 + 시간 * 속도 벡터
유니티 엔진을 사용한다면 게임 오브젝트의 위치를 나타내는 값으로 transform.position 변수가 벡터로 정의되어 있으므로 위 수식에 그대로 적용시킬 수 있습니다.
·미리보기 | 소스복사·
위 코드를 매 프레임마다 수행한다면 플레이어를 추적하는 몬스터의 모습을 구현할 수 있게 됩니다.
여기에서 몬스터의 이동 속력을 나타내는 값으로 10을 사용했습니다.
이 예제에서는 10m/s라고 정의했는데 10픽셀이라고 단정 지어서 생각하지 않기를 바랍니다.
3D 게임 프로그래밍에서는 카메라의 설정에 따라 화면에 보여지는 물체의 위치가 달라지므로 픽셀단위로 이동 한다는 말은 정확하지 않습니다.
픽셀 보다는 미터 같은 실생활의 단위를 사용하는 것이 더 좋습니다.
벡터의 뺄셈 정리
1. 뒤에 있는 벡터의 방향을 반대로 바꾼다.
b – a 라면 a벡터의 방향을 반대로 바꾼다.
방향을 바꾸는 것은 길이는 그대로 두고 화살표가 가리키는 곳만 반대로 만들어 주는 것을 의미한다.
2. 두 벡터를 덧셈 규칙에 맞게 꼬리에서 머리로 이어준다.
3. 벡터의 뺄셈은 한 위치에서 다른 위치로 향하는 벡터를 만들 때 사용할 수 있다.
벡터와 스칼라의 곱셈
일반적으로 더하기 빼기 다음에는 곱하기를 배웁니다.
벡터도 마찬가지로 곱하기가 존재합니다만 흔히 알고 있는 곱하기와는 약간 다릅니다.
심지어 곱하기의 종류는 두 가지나 있으며 계산 방법마저도 각각 다릅니다.
여기서는 일단 벡터끼리의 곱셈 이전에 벡터와 스칼라의 곱셈에 대해서 알아보겠습니다.
스칼라란 그냥 1,2,3,99,100,...과 같이 익히 알고 있는 수입니다.
벡터와 스칼라의 곱셈은 일반적인 수의 곱셈과 같은 개념입니다.
a = [5,0]
d = 2
a x d = [5,0] x 2 = [10,0]
위 수식에서 a는 벡터이며 d는 스칼라값(그냥 우리가 알고 있는 평범한 숫자라고 생각하면 됩니다) 입니다.
벡터 a [5,0]에 스칼라값 2를 곱하면 [10,0]으로 원래의 벡터보다 두배 커진 벡터가 됩니다.
5 x 2 = 10
0 x 2 = 0 이 되어서 [10,0]이라는 벡터가 됩니다.
그렇다면 음수를 곱하면 어떻게 될까요?
예상하신 대로입니다.
벡터a에 –2를 곱하면 [-10,0] 이 됩니다.
벡터와 스칼라의 곱셈은 정말 간단하며 게임 프로그래밍을 할 때도 적용하기 쉽습니다.
예를 들면 방향 벡터에 속력을 곱해서 속도 벡터로 만드는데 사용할 수 있습니다.
앞서 설명했던 플레이어를 따라가는 몬스터의 인공지능 구현 예를 보면,
몬스터에서 플레이어로 향하는 벡터를 구하고 이 벡터에 속력을 곱해서 속도를 구한다고 했습니다.
이 때 사용하는 연산이 바로 벡터와 스칼라의 곱셈입니다.
별로 특별할 것 없는 단순한 연산입니다.
여기까지 벡터의 덧셈과 뺄셈, 벡터와 스칼라의 곱셈 까지 알아봤습니다.
다음 강좌에서는 벡터끼리의 곱셈인 내적과 외적에 대해서 학습하도록 하겠습니다.
감사합니다.
3D 게임 프로그래밍을 위한 기초 수학 - 4. 벡터의 내적
내적(스칼라곱 또는 점곱, dot product, inner product)
이제 벡터의 곱셈 중 첫 번째로 내적에 대해서 알아보겠습니다.
이제부터 슬슬 어려운 용어가 나오기 시작하는데요, 전혀 걱정하실 것 없습니다.
용어가 어려운 것이지 개념이 어려운 것은 아니기 때문입니다.
내적 이라는 단어가 한자라서 괜히 어려워 보이는 것 뿐이죠.
다음은 백과사전에서 검색한 내적의 정의입니다.
(출처 : http://terms.naver.com/entry.nhn?docId=2073869&cid=47324&categoryId=47324)
내적을 처음 접하는 사람한테는 뭐라고 읽어야 할지도 모를 만큼 어려운 설명입니다.
우리는 사전적인 정의 보다도 실제 게임 프로그래밍에서 내적이 어떻게 활용되는지
그 쓰임에 대해서 알아보도록 하겠습니다.
활용하는 법을 배우고 체득하고 나면 저 공식도 자연스럽게 이해가 되기 때문이죠.
물체가 빛을 받으면 밝은 부분과 어두운 부분이 생기는데
이러한 명암을 컴퓨터 그래픽으로 모델링 할 때 벡터의 내적 연산이 사용 됩니다.
또한 위 사진에서 사과의 뒷부분(보이지 않는)을 렌더링에서 제외 하기 위한 계산에도
벡터의 내적이 사용 됩니다.
위 그림은 정육면체를 3D 그래픽으로 렌더링 한 모습입니다.
왼쪽 그림을 보면 정육면체의 면들 중 단 두 개의 면만 화면에 렌더링 되고 있는 것을 알 수 있습니다.
카메라의 입장에서 볼 때 정육면체의 뒷부분은 보이지 않는 부분이므로 렌더링 계산에서 제외할 수 있는 부분입니다.
이 때 벡터의 내적을 사용하여 어디가 뒷부분인지 선별하는 것이 가능합니다.
대략적으로 살펴본다면 다음과 같습니다.
폴리곤에서 카메라 쪽으로 향하는 벡터와 폴리곤의 법선 벡터를 내적하여
그 결과값이 0보다 작다면(음수) 뒷부분으로 판단 한다.
역시 글보다는 그림으로 이해 하는게 빠르겠죠?
아래는 위 내용을 그림으로 나타낸 것입니다.
왼쪽이 렌더링된 결과물이며 오른쪽 그림은 카메라와 물체의 관계를 옆에서 바라본 모습입니다. 파란색으로 표시된 벡터 a, b, c, d는 각 폴리곤의 법선 벡터를 표시한 것입니다.
법선 벡터(노말 벡터라고도 합니다)란 해당 표면에 수직인 벡터를 의미 합니다.
운동장 한가운데에 나무막대기를 세워놓았다고 상상해 봅시다.
나무 막대기는 넓은 운동장 표면(폴리곤)에 직각으로 세워져 있죠.
이 나무 막대기와 같은 벡터를 표면의 법선 벡터라고 부릅니다.
만약 나무 막대기가 평평한 운동장이 아닌 경사진 언덕길에 세워져 있다면 언덕길에 대해 직각일 테니 법선 벡터의 방향도 언덕길만큼 기울어져 있겠죠.
어느 표면에 붙어 있던 해당 표면에 대해 수직인 벡터라고 생각하시면 됩니다.
검은색으로 그려진 선은 각 폴리곤으로부터 카메라쪽으로 향하는 벡터를 나타낸 것입니다.
그림으로 봤을 때 이 두 벡터 사이의 각도가 90도 이하면 해당 폴리곤은 카메라쪽을
바라보고 있다고 판단할 수 있습니다(a, b).
반대로 각도가 90도 보다 크면 카메라를 등지고 있다고 판단할 수 있죠(c, d).
카메라를 등지고 있는 폴리곤은 어차피 보이지 않을 것이므로 계산에서 제외한다면 렌더링 성능이 훨씬 올라가겠죠.
그렇다면 도대체 내적이 어떻게 계산 되는 것이길래 위와 같은 구현이 가능한지 지금부터 알아보도록 하겠습니다.
내적의 계산 과정
벡터의 내적을 계산하기 위해서는 먼저 차원이 같은 두 벡터가 필요 합니다.
벡터의 각 성분들끼리 곱셈을 한 뒤 그 결과를 더해주면 내적이 계산 됩니다.
곱하기와 더하기만 할 줄 알면 되기 때문에 어려운건 없겠죠?
a = [2, 2]
b = [-1, 0]
a∙b = [2 x –1] + [2 x 0]
= -2 + 0
= -2
c = [-2,-2]
b = [-1, 0)
c∙b = [-2 x –1] + [-2 x 0]
= 2 + 0
= 2
내적의 계산은 이게 끝입니다. 간단하죠?
(∙는 내적의 기호입니다)
여기서 알 수 있는 사실은 두 벡터를 내적하면 벡터가 나오는 것이 아니라 단순한 숫자값이 나오게 된다는 것입니다.
또한 이 결과값의 부호를 통해서 폴리곤의 면이 카메라를 향하고 있는지 또는 등지고 있는지를 알아낼 수 있습니다.
내적의 결과가 양수(+)로 나온다면 두 벡터 사이의 각이 90도 보다 같거나 작다는 뜻이며
결과가 음수(-)로 나온다면 두 벡터 사이의 각이 90도 보다 크다는 뜻입니다.
이 그림을 다시 보면,
벡터 a와 카메라를 향하는 시선 사이의 각도가 90도 보다 작다는 것을 알 수 있습니다.
벡터 b도 마찬가지죠.
반면 벡터 c와 d는 카메라와의 각도가 90도 보다 크다는 것을 그림을 통해 알 수 있습니다.
즉,
벡터 a와 b를 각각 카메라를 향하는 벡터와 내적을 하면 그 결과값은 양수로 나오게 되며
두 벡터 사이의 각은 90도 보다 작다는 뜻입니다.
반면 벡터 c와 d를 각각 카메라를 향하는 벡터와 내적을 하면 그 결과값은 음수로 나오게 되며
두 벡터 사이의 각은 90도 보다 크다는 뜻입니다.
여기서 중요한 것은 각도가 몇 도 인지 까지는 계산할 필요 없이,
내적의 결과값의 부호만으로 각도의 범위를 알아낼 수 있다는 것입니다.
두 벡터 사이의 각도를 구하려면 삼각함수인 acos(아크코사인)함수를 사용해야 하는데
삼각함수를 많이 사용하면 프로그램의 성능이 하락될 수 있습니다.
따라서 몇 번의 곱셈과 덧셈만으로 끝나는 내적을 사용하는 것이 훨씬 이득이 되는 것이죠.
반사 벡터 구하기
내적을 이용하면 반사벡터도 쉽게 구할 수 있습니다.
벽에 부딪친 당구공이 어느 방향으로 튕겨 나가는지 상상해 본다면 반사벡터의 모습이 머릿속으로 그려질 것입니다.
벡터 p가 공의 속도벡터라고 한다면 반사벡터를 구하는 공식은 다음과 같습니다.
reflect = p + 2n(-p∙n)
알기 쉽게 프로그래밍 언어로 표현한다면 이렇게 됩니다.
·미리보기 | 소스복사·
더 알기 쉽게 그림을 통해서 배워보겠습니다.
n은 벽의 법선벡터를 뜻합니다.
공은 벽을 향해 대각선 방향인 p의 속도로 움직이고 있습니다. 여기서 p는 공의 속도 벡터입니다.
-p : 반사벡터를 구하기 위한 첫 번째 과정으로 p의 방향을 바꿔 줍니다.
-p∙n : -p와 벽의 법선벡터인 n을 내적 합니다. 내적의 결과로 스칼라값 하나가 나옵니다.
2n(-p∙n) : 내적의 결과값과 법선벡터 n을 두배하여 곱해줍니다. 결과적으로 법선벡터 n을
길게 늘려준 벡터가 생기게 됩니다.
p+2n(-p∙n) : 위 결과값에 p를 더해서 반사 벡터를 구합니다.
크기와 방향이 같으니 어디에 있던지 결국에는 똑같은 벡터입니다.
최종적으로 p의 반사 벡터가 구해졌습니다.
투영
반사 벡터를 구하면서 내적의 쓰임새에 대해서 알아봤습니다.
하지만 아직 첫부분에 나온 백터의 정의를 이해하기에는 무리가 있습니다.
왜냐하면 우리는 아직 삼각함수를 배우지 않았기 때문이죠.
내적의 정의에 나온 cos(코사인)은 삼각함수의 한 부분인데 내적과 cos을 연결시켜서 이해하려면
벡터뿐만 아니라 삼각함수에 대한 이해까지도 필요합니다.
이 부분은 앞으로 나올 삼각함수 챕터에서 자세히 다루도록 하겠습니다.
여기서 이해해야 할 부분은 벡터의 내적을 통해서 한 벡터가 다른 벡터에 투영된 길이를 알 수 있다는 것입니다.
투영이란 그림자라고 이해하면 쉬울 겁니다.
반사벡터를 구할 때 벡터 -p를 벽의 법선 벡터인 n과 내적 하여 계산했는데요,
이 내적의 결과로 나온 값은 벡터 -p를 법선 벡터 n에 투영한 길이가 됩니다.
단, 법선 벡터 n은 반드시 단위 벡터 상태로 되어 있어야 합니다.
(단위 벡터는 길이가 1인 벡터를 의미 합니다)
아까 반사 벡터를 구할 때 봤던 그림입니다.
벡터 n을 위로 쭉 이은다고 생각하면 가상의 선이 그려지겠죠.
이 선을 향해서 벡터 –p를 직선으로 그었을 때 만나는 점, 그 점의 길이가 바로 내적의 결과값 입니다.
위 그림에서는 점선으로 표시한 부분과 벡터 n의 연장선이 만나는 지점이 됩니다.
이 값을 수학적인 방법 없이 구하려고 한다면 머리가 좀 아플겁니다.
(물론 자로 정확하게 그어서 그 길이를 재면 되겠지만 컴퓨터 메모리상에서는 자를 사용할 수 없으니
수학적인 방법을 쓸 수 밖에 없습니다)
3D 게임 프로그래밍을 위한 기초 수학 - 5. 벡터의 외적
외적(cross product)
길고 긴 내적의 과정을 지나 또 다른 벡터의 곱셈인 외적에 대해서 알아볼 차례입니다.
벡터의 내적을 배웠을 때 생각보다 어렵지 않았었죠?
외적도 알고 보면 별거 아닙니다.
일단 부딪쳐 봐야 하니 벡터의 외적에 대한 사전적 정의를 살펴봅시다.
벡터의 외적은 두 벡터 a,b 사이의 각을 θ라 하면 a·b sin θ라는 크기, 즉 a,b를 두 변으로 하는 평행사변형의 넓이와 같은 크기를 가지고 a,b를 포함하는 평면에 수직이고...
(출처 : http://terms.naver.com/entry.nhn?docId=1186169&cid=40942&categoryId=32225)
백과사전에서 검색한 외적의 설명입니다.
사실 저 의미를 이해하려면 다음 챕터에 나오는 삼각함수에 대해 알고 있어야 합니다.
따라서 이번 외적 파트를 다 읽고도 뭔가 찝찝함이 남아 있는 분들이라면 다음 챕터에 나오는 삼각함수에 대한 내용을 이해한 뒤에 다시 돌아와 한번 더 학습하시길 권해드립니다.
일단 누구나 알 수 있도록 쉬운 부분부터 설명해 나가도록 하겠습니다.
내적의 결과값은 벡터가 아닌 스칼라값이 나온다는 사실은 다들 아시겠죠?
외적의 결과값은 또다른 벡터 하나가 생기는데 이 벡터는 두 벡터에 모두 수직인 벡터가 됩니다.
(한가지 주의해야 할 점은 벡터의 외적은 3차원 벡터에서만 적용 된다는 것입니다.)
내적을 설명할 때 법선벡터 라는 말을 잠깐 언급했는데 이 법선벡터를 구할 때 벡터의 외적을 사용하게 됩니다.
법선벡터란 어떤 평면에 수직인 벡터를 의미하므로 위에서 말씀드린 외적의 정의와 완벽히 일치하게 되는 것이죠.
어떤 두 벡터의 외적을 구하는 수식은 다음과 같습니다.
a x b = [(ay·bz – az·by), (az·bx – ax·bz), (ax·by – ay·bx)]
우리는 프로그래밍 언어가 더 친숙하므로 코드를 통해 외적을 계산해 보겠습니다.
·미리보기 | 소스복사·
위 수식을 자세히 보면 새로운 벡터의 x성분은 두 벡터의 y,z값을 각각 교차해서 곱한 뒤 서로를 뺀 값이라는 것을 알 수 있습니다.
새로운 벡터의 y,z성분도 동일한 규칙으로 계산을 한 것이죠.
수식이 중요한건 아니니 그냥 한번 읽고 넘어가시면 될 듯 합니다.
중요한건 저런 계산을 통해 나온 새로운 벡터는 두 벡터의 수직이 되는 벡터라는 것입니다.
그 벡터는 두 벡터를 통해 만들어진 평면에 수직인 벡터라고 할 수 있으며
그것을 평면의 법선벡터 또는 노말벡터 라고 부르죠.
보통 3D 제작툴에서 모델을 익스포트할 때 법선벡터도 같이 뽑아져 나오기 때문에 프로그램에서 직접 계산해줄 일은 많지 않을겁니다.
하지만 어떤 원리를 통해서 법선벡터가 생기는지 알고 있다면 활용범위가 더 넓어질 수 있겠죠.
평행사변형의 넓이
벡터의 외적을 게임 프로그래밍에서가 아닌 수학적으로 설명한 책이나 자료를 보면
아래와 같은 공식을 발견할 수 있습니다.
a x b = |a|∙|b|∙sinθ∙n
저 공식을 풀어서 설명해 드리자면,
두 벡터 a와 b의 외적은 두 벡터가 이루는 각도의 사인(sin)값에 두 벡터의 길이를 곱해서
두 벡터의 수직인 단위벡터 n을 곱한 값이라는 뜻입니다.
(|a| 이 기호는 벡터 a의 길이를 나타내는 표시입니다.)
쉽게 이해할 수 있도록 그림을 통해서 보겠습니다.
두 벡터 a와 b가 있습니다.
두 벡터 a와 b가 이루는 각도를 θ(세타)라고 했을 때
그림에서 보이는 빨간색 선(b에 수직인 선)의 길이는 sinθ에 a의 길이를 곱한 값이 됩니다.
a와 b에 모두 수직이면서 길이가 1인 벡터 n이 있다고 할 때
(벡터 n은 화면 위쪽이 아닌 모니터의 앞쪽으로 나온다고 생각하면 됩니다. 그래야 a, b에 모두 수직인 벡터가 되니까요)
sinθ에 a의 길이와 b의 길이를 곱한 값을 n에 곱해주면 최종적으로 벡터 n을 길게 늘려준 꼴이 됩니다.
왜냐하면 sinθ에 a의 길이, b의 길이를 곱하면 하나의 스칼라값이 나오는데
여기에 벡터 n을 곱하면 벡터와 스칼라를 곱하는 것이기 때문에 결국
벡터 n이 확장된 모습이 되기 때문이죠.
결국 a와 b의 외적은 |a|∙|b|∙sinθ∙n 으로도 구할 수 있습니다.
하지만 이 방법은 두 벡터 사이의 각도와 수직인 벡터 n을 알아야 하며 삼각함수까지 들어가 있기 때문에 계산 과정이 복잡해집니다.
따라서 실무에서는 벡터의 외적을 구할 때 이 방법 보다는 첫 번째로 설명 드린 방법(벡터의 각 성분들을 곱해서 빼는 방법)을 사용하게 되죠.
이러한 계산 방법을 통해서 한 가지 재미있는 사실을 알아낼 수 있는데요,
벡터의 외적을 이용하면 두 벡터가 만드는 평행사변형의 넓이를 구할 수 있다는 것입니다.
벡터 a와 b가 만드는 평행사변형은 다음과 같이 나타낼 수 있습니다.
평행사변형의 넓이를 구하는 공식을 다시 떠올려 봅시다.
평행사변형의 넓이 = 밑변 x 높이
위 그림에서 밑변은 b의 길이, 높이는 a에서 b로 수직으로 내려오는 선이라고 할 수 있죠.
높이를 구하려면 벡터 a와 b가 이루는 각도를 삼각함수 사인(sin)으로 계산한 값에 a의 길이를 곱한 것과 같습니다.
(이 부분은 삼각함수 부분을 알아야 이해할 수 있습니다.)
결국 높이 = |a|∙sinθ 가 되며, 밑변 = b의 길이 이므로
밑변(|b|) ˟ 높이(|a|∙sinθ)를 통해서 두 벡터 a와 b가 만드는 평행사변형의 넓이를 구할 수 있는 것입니다.
이 공식은 벡터의 외적을 구하는 공식 |a|∙|b|∙sinθ∙n에서 벡터 n만 제외한 것과 같죠.
결국 외적으로 구해진 벡터의 길이는 평행사변형의 넓이와 같다는 것을 알 수 있습니다.
또한 평행사변형을 둘로 나누면 삼각형 두 개가 생기기 때문에 외적을 통해 생긴 벡터의 길이를 2로 나누면 두 벡터가 만드는 삼각형의 넓이와 같게 됩니다.
두 벡터 a와 b가 만드는 삼각형의 넓이는 평행사변형의 넓이의 절반과 같다.
3D 게임 프로그래밍을 위한 기초 수학 - 6. 삼각함수(sin, cos, tan)
삼각함수
수학에서, 삼각함수(三角函數, 영어: trigonometric function)는 직각삼각형의 각을 직각삼각형의 변들의 길이의 비로 나타내는 함수이다.
(출처 : https://ko.wikipedia.org/wiki/삼각함수)
벡터 챕터에서 그래왔던 것처럼 이번 챕터에서도 삼각함수의 실제 쓰임에 대해서 알아본 뒤 수학적 정의를 이해해 나가는 형태로 배워보도록 하겠습니다.
편안한 마음으로 읽어 나가시면 됩니다.
삼각함수, 사인, 코사인, 탄젠트 이런 말 한번쯤은 다들 들어보셨겠죠?
제가 학창시절 때 삼각함수를 배웠던 때를 떠올리면 정말 머릿속이 멍했던 기억밖에는 없습니다.
교과서를 아무리 들여다 봐도 삼각함수가 무엇인지,
원과 삼각형이 무슨 관계인지 알 수가 없었기 때문입니다.
저와 같은 분들을 위해서 3D 게임 프로그래밍에서 자주 쓰이는 삼각함수에 대해 아주 쉽게 알려드리도록 하겠습니다.
탄젠트(tan)
“이야기로 아주 쉽게 배우는 삼각함수”라는 책을 보면 크리스마스 때 사용할 나무의 높이를 재기 위해 직각 삼각형의 개념을 활용한 부분이 나옵니다.
나무가 너무 높아 직접 올라가서 잴 수 없으니 태양의 고도가 45도 일 때 나무의 그림자 길이를 재서 나무의 높이를 알아냈다고 하죠.
이것을 그림으로 나타내면 다음과 같습니다.
이 그림을 자세히 보면 두 변의 길이가 같은 이등변 삼각형이 그려진다는 것을 알 수 있습니다.
이등변 삼각형은 두 변의 길이가 같으니 나무의 그림자의 길이는 곧 나무의 높이와 같다는 사실 또한 알 수 있죠.
그리고 이 삼각형은 직각 삼각형이라는 것은 말씀드리지 않아도 아실겁니다.
방금 말씀드린 내용이 삼각함수 중 탄젠트에 대한 내용입니다.
짠! 삼각함수가 이렇게 쉬운 것이었습니다!
윈도우 계산기에서 탄젠트 45도를 계산한 결과
실제로 탄젠트 45도를 계산해 보면 1이라는 결과값이 나옵니다.
이 결과값은 비율을 나타낸 것인데 어떠한 비율이 1이라는 것은 비교 대상이 서로 똑같다 라는 뜻이죠.
각도가 45도 일 때 그림자의 길이와 나무의 높이를 비교해 봤더니 둘이 똑같더라,
즉,
이라고 수학적으로 표현할 수 있습니다.
제일 첫 강좌에서 어떠한 길이를 비교할 때 사용할 수 있는 것이 분수라고 했었죠.
이것을 좀 더 삼각함수스럽게 표현한다면 이렇게 씁니다.
tan(45°) = 1
tan은 삼각함수중 하나인 탄젠트라는 함수인데 직각 삼각형에서 어떠한 각도를 넣었을 때 밑변과 먼변(수직인 변)의 비율을 구해줍니다.
이 예제에서 그림자의 길이와 나무의 높이의 비율을 구했던 것처럼 말이죠.
사인(sin)
이번에는 눈썰매장을 만든다고 상상해 봅시다.
25도 각도의 경사에 100미터 짜리 슬로프로 만들 계획입니다.
그림으로 나타내면 이런 모습이 되겠죠.
그런데 한 가지 문제가 있습니다.
슬로프의 길이와 각도는 정해졌는데 슬로프를 지지할 기둥의 높이를 몇 미터로 해야 되는지 모른다는 것이죠.
그림을 자세히 보니 이번에도 직각 삼각형이 그려졌네요.
그렇다면 삼각함수를 이용해서 뭔가 알아낼 수 있을 것 같습니다.
다만 밑변이나 높이의 길이를 모르니 아까 배웠던 탄젠트를 사용할 수는 없겠네요.
이 때 사용할 수 있는 것이 사인(sin)입니다.
sin은 제일 긴 빗변과 높이의 비율을 구해주는 함수입니다.
위 그림에서 보면 100m짜리 슬로프가 빗변을 의미 하는데 sin함수를 통해서
빗변과 먼변(높이)의 비율을 구한 뒤 빗변의 길이만큼 곱해주면 높이값이 나오게 되겠죠.
(빗변의 길이만큼 곱한다 라는 부분은 잠시 후에 설명해 드리겠습니다)
그럼 정말 sin함수를 통해서 높이를 구할 수 있는지 계산기를 두드려 봅시다.
윈도우 계산기로 sin(25°)를 계산한 결과
sin(25°)에 빗변의 길이인 100을 곱해준 결과
짠! 이렇게 해서 기둥의 높이는 42.2.... 미터가 되겠습니다.
탄젠트(tan)에 이어 사인(sin)도 직각 삼각형에 대해서 사용할 수 있다는 것,
그리고 하나의 각도가 주어져야 한다는 것을 알게 되었습니다.
우리 주변을 자세히 보면 생각보다 많은 것들이 직각 삼각형으로 표현된다는 것을 알 수 있죠.
그런데 여기서 이런 의문을 갖는 분도 계실 겁니다.
직각 삼각형에서 한 각도를 선택해 sin(25°)를 계산한 것 까지는 알겠는데,
왜 이 결과값에 슬로프의 길이인 100을 곱해서 높이를 구한 것일까?
이 의문이 풀려야 사인(sin)에 대해서 확실히 이해했다고 할 수 있겠죠.
일단 한 가지 확실히 알게 된 것은 사인(sin)은 빗변과 높이의 비율을 구해주는 함수라는 것입니다.
그렇다면 탄젠트(tan)와 마찬가지로 다음과 같이 분수의 형태로 표현할 수 있습니다.
sin(25도) = 0.422 라는 것은 슬로프의 길이(빗변)에 비해 기둥의 높이(먼변)가 0.422배 작다 라고 생각할 수 있겠죠(잘 이해가 안간다면 첫 번째 강좌에 나왔던 분수의 개념을 다시 확인해 보세요).
따라서 슬로프의 길이가 100m 라면 기둥의 높이는 100m에 비해 0.422배 작기 때문에
100 x 0.422 = 42.2
라는 식으로 이해할 수 있습니다.
닮은 삼각형
아직도 약간 알 듯 모를 듯 한 분들을 위해서 또 다른 방법을 준비했습니다.
실제로 100m 짜리 슬로프에 25도 경사를 가진 삼각형을 그리려면 학교 운동장을 다 써야 할 만큼 커다란 삼각형이 나올 겁니다.
따라서 집에서도 손쉽게 할 수 있도록 슬로프의 길이를 10cm로 축소하여 그려봅시다.
이렇게 그리면 실제로 100m의 슬로프 보다는 훨씬 작지만 생김새는 똑같은 삼각형이 됩니다.
이제 이 삼각형의 높이를 자로 재 보면...
4.2cm가 나옵니다.
그렇다면 슬로프의 길이가 10cm에서 100m로 늘어났듯이
기둥의 높이도 4.2cm에서 슬로프의 길이가 늘어난 것과 같은 비율로 늘어날 것입니다.
왜냐하면 둘은 생김새는 같지만 크기만 다른 닮은 삼각형이기 때문입니다.
직접 계산을 해 봅시다.
먼저 종이에 그린 삼각형과 실제 슬로프와의 단위를 맞춰야 합니다.
둘 다 센티미터로 바꾸면 100m는 10000cm가 됩니다(1m = 100cm이므로)
10cm에서 10000cm로 늘어났으니 정확히 1000배가 늘어난 셈이네요.
그럼 4.2cm에 1000배를 하면 4200cm가 나옵니다.
이것을 다시 미터로 환산 하면 42m가 됩니다(4200 / 100 = 42)
종이에 그린 삼각형의 높이를 잴 때 소수점 단위까지 잴 수 없었으므로 42m로 나오지만 아주 정밀한 자를 이용하여 소수점 단위까지 잰다면 42.2m까지 계산될 겁니다.
이런 방법을 통해서 알 수 있는 것은 삼각함수는 삼각형의 크기와는 관계없이 각도에만 영향이 있다는 것을 알 수 있습니다.
즉, 어떤 크기의 직각 삼각형이든 주어진 각도가 똑같다면 항상 같은 값을 돌려준다는 뜻입니다.
코사인(cos)
사인(sin), 탄젠트(tan)에 이어 3D 게임 프로그래밍에서 자주 사용하는 삼각함수는 코사인(cos)입니다.
사인(sin)함수는 기둥의 높이를 잴 때 사용했었죠.
코사인(cos)함수는 밑바닥의 길이를 잴 때 사용할 수 있습니다.
눈썰매장 그림을 다시 봅시다.
기둥의 높이는 사인(sin)함수를 통해 계산했습니다. 바닥의 길이는 어떻게 잴 수 있을까요?
여기에는 코사인(cos)함수가 사용 됩니다.
(네. 물론 피타고라스 정리를 이용해서도 구할 수 있습니다.)
사인함수는 빗변과 먼변(높이)의 비율을 계산해 준다고 했습니다.
코사인함수는 빗변과 밑변(바닥)의 비율을 계산해 주는 함수입니다.
이쯤이면 이제 바닥의 길이를 구하는 것도 식은 죽 먹기겠죠?
바로 계산기를 두드려 봅시다.
코사인(25도)의 결과값
이 값에 슬로프의 길이인 100을 곱하면...
90.6307...m가 나옵니다.
그럼 종이에 그린 작은 삼각형의 밑변의 길이도 재 봅시다.
9cm보다 조금 더 큽니다.
이제 이 값을 아까 높이를 구할 때 사용한 방법대로 계산해 보겠습니다.
9cm x 1000 = 9000cm
= 90m
소수점까지 잴 수 없으므로 정확하게 맞아 떨어지진 않지만 거의 비슷한 값이 나왔습니다.
이 과정을 통해서 코사인(cos)함수도 삼각형의 크기와는 관계없이 주어진 각도에만 영향이 있다는 사실을 알 수 있습니다.
삼각함수를 계산할 때 변의 길이를 입력하지 않고 각도를 입력한다는 것만 봐도 삼각함수가 각도와 관계가 있다는 것을 직관적으로 알 수 있죠.
삼각함수 정리
사인(sin) = 빗변과 먼변(높이)의 비율을 구한다.
코사인(cos) = 빗변과 밑변의 비율을 구한다.
탄젠트(tan) = 밑변과 먼변(높이)의 비율을 구한다.
삼각함수는 직각 삼각형에 대해서 하나의 각이 주어졌을 때 각 변에 대한 비율을 구해준다.
3D 게임 프로그래밍을 위한 기초 수학 - 7. 삼각함수(원, 라디안, 파이)
원과 삼각함수
이제 삼각함수가 어떤 것인지 감이 잡히시나요?
이번에 배울 내용은 삼각함수와 원과의 관계에 대한 것입니다.
삼각함수란 이름만 들어보면 원과는 전혀 관계가 없을 것처럼 보이죠?
여기서는 원 위의 한 점을 삼각함수를 통해 나타내는 과정을 간단히 설명하도록 하겠습니다.
(삼각함수의 단위원에 대한 정확한 정의는 다른 수학 전문 서적을 참고해 주시기 바랍니다)
위 그림은 반지름이 1인 원입니다.
1m든 1cm든 단위는 붙이기 나름이니 무엇을 사용하던 상관 없습니다.
원을 따라서 아무 곳이나 한 점을 찍어 그곳을 점 P라고 한다면
중심에서 P까지 이어지는 선의 길이도 반지름과 같습니다.
이제 점 P에서 수직으로 선을 내려 바닥과 직각이 되도록 만들면
빗변의 길이가 1인 직각 삼각형 한 개가 생깁니다.
직각 삼각형에 대해서는 삼각함수를 적용할 수 있다고 말씀드렸죠?
원 안에 생긴 직각 삼각형에 대해서 각각 사인, 코사인, 탄젠트를 적용해 봅시다.
직각 삼각형의 밑변을 x, 높이를 y, 각도를 a라고 정하도록 하겠습니다.
먼저 사인부터 적용시켜 보죠.
각각 위와 같이 나타낼 수 있습니다.
따라서 점 P의 좌표 (x,y)는 x = cos(a), y = sin(a) 라고 말할 수 있죠.
더 정확하게 말한다면 아래와 같은 공식이 나옵니다.
x = cos(a) * r
y = sin(a) * r
여기서 r은 반지름을 뜻하는데 위 그림에서는 반지름이 1이기 때문에 생략했던 것입니다.
만약 반지름이 1이 아니라면 반지름을 곱해줘야 원하는 위치가 나오겠죠.
이 과정으로 알 수 있는 사실은 삼각함수를 통해서 원의 둘레 위의 한 점의 위치를 나타낼 수 있다는 것입니다.
이것을 응용하면 원 모양으로 움직이는 캐릭터를 구현할 수 있겠죠.
파이(∏)
3.141592...
만약 자동차 바퀴의 둘레를 재려고 한다면 어떤 방법을 써야 할까요?
바퀴 둘레에 페인트칠을 해서 한 바퀴 굴린 다음 페인트가 찍힌 길이를 재면 되겠죠.
또는 줄자를 이용하여 바퀴 둘레를 감싸서 잴 수도 있을 겁니다.
또 다른 방법으로는 바퀴 둘레를 잇는 많은 직선들을 만들어 그 직선의 길이를 합친 값을 이용할 수도 있을 것 같습니다.
이 방법들은 원의 둘레를 재기 위해 아주 아주 옛날 사람들이 사용했던 방법들입니다.
이런 방법들로 원의 둘레를 구하다가 원의 지름과 둘레 사이에는 어떠한 일정한 비율이 있다는 것을 발견하게 되었죠.
원의 지름과 둘레에는 일정한 비율이 있지 않을까?
그렇다면 원의 지름과 둘레를 실제로 재 보도록 하겠습니다.
박스 테이프의 둘레 = 29.5cm
박스 테이프의 지름 = 9.4cm
주위에서 흔히 볼 수 있는 박스 테이프를 사용했습니다.
줄자를 돌려 재본 결과 약 29.5cm가 나왔습니다.
지름은 좀 더 정확하게 재기 위하여 테이프의 모양대로 종이에 똑같이 그린 뒤 잘라서
반을 접어 측정하였습니다.
약 9.4cm가 나오는군요.
이제 두 값의 비율을 계산해 보도록 하죠.
비율하면 분수가 딱 떠오르시죠?
테이프의 둘레는 지름에 비해 약 3.13829정도 크다는 값이 나왔네요.
학창시절 많이 들어본 3.14라는 값과 똑같진 않지만 상당히 비슷한 수치입니다.
(손으로 측정한 것이기 때문에 약간의 오차는 어쩔 수 없군요)
이 비율을 좀 어려운 말로 원주율 이라고 부르며 파이(∏)라고 표시합니다.
이 원주율은 원의 크기에 상관없이 항상 일정합니다(원은 모두 닮은 도형이므로).
원주율(圓周率)은 원의 지름에 대한 둘레의 비율을 나타내는 수학 상수이다. 수학과 물리학의 여러 분야에 두루 쓰인다. 그리스 문자 π로 표기하고, 파이(π)라고 읽는다.
(출처 : https://ko.wikipedia.org/wiki/원주율)
라디안
프로그래밍 언어에서 삼각함수를 사용할 때에는 도 보다는 라디안 이라는 값을 사용합니다.
그렇다면 우리에게 익숙한 각도를 라디안으로 변환하려면 어떻게 해야 하는지 알아야 겠죠.
단순히 변환만을 위한다면 아래처럼 특정한 값을 곱해주기만 하면 됩니다.
도를 라디안으로 90° x 0.01743 = 1.5696 rad(라디안 이라고 읽습니다)
라디안을 도로 2 rad x 57.2957 = 114.59°
하지만 적어도 라디안을 사용한다면 그게 무엇인지는 알아야 하지 않을까요?
아래는 국어사전에서 검색한 라디안의 뜻입니다.
<수학> 원둘레 위에서 반지름의 길이와 같은 길이를 갖는 호에 대응하는 중심각의 크기. 1라디안은 약 57도 17분 44.8초이다. 기호는 rad. [비슷한 말] 호도(弧度).
(출처 : http://krdic.naver.com/detail.nhn?docid=11447300)
역시 한번 듣고 이해할 수 있는 말이 아니죠.
한방에 이해할 수 있도록 그림으로 배워봅시다.
라디안은 바로 이런 모습입니다.
반지름이 1일 때 원을 따라 반지름의 길이 만큼 쭉 올라가서 생긴 각도의 크기를 1 라디안 이라고 부릅니다. 피자의 한 조각처럼 생겼죠.
각도로 치면 대략 57도쯤 됩니다.
그렇다면 2라디안, 3라디안은 얼마 만큼인지 예상할 수 있겠죠?
어려울 것 없이 1라디안이 세 개 모이면 3라디안이 됩니다.
마찬가지로 3라디안에서 1라디안을 더하면 4라디안이 되겠죠.
이제 180도 부분에 빨간색 선을 그어보겠습니다.
위 그림에서 보면 180도 부분은 3라디안과 4라디안 사이의 어딘가가 됩니다.
그 어딘가는 바로 3.14라디안 흔히 파이(∏)라고 불리우는 값입니다.
이전 파트에서 파이는 원주율(지름과 둘레의 비율)이라고 말씀드렸었죠.
이 말을 다시 하면 지름이 1일 때 원의 둘레가 3.14 또는 파이(∏)라고 할 수 있습니다.
지름이 1이라는 것은 반지름이 0.5라는 뜻이므로 반지름이 0.5일 때 원의 둘레가 파이(∏)다 라고 할 수도 있겠네요.
그렇다면 반지름이 1이라면 원의 둘레는 2 x ∏가 됩니다. 줄여서 2∏라고도 씁니다.
(반지름이 0.5에서 1로 두 배가 되었으니 그 둘레도 두 배가 되니까 2를 곱해줘야 겠죠?)
둘레가 2∏라면 그의 반, 즉 180도 만큼의 길이는 ∏가 됩니다.
180도를 라디안으로 표시하면 ∏ 라디안 또는 그냥 ∏ 인 셈이죠.
(라디안은 붙이기도 하고 안 붙이기도 합니다)
정리해보면,
∏(파이)는 지름이 1일 때 원의 둘레를 의미하는 문자이다.
그렇다면 반지름이 1일 때 ∏는 원의 둘레의 절반이다(180도 만큼).
결국 원의 둘레는 반지름이 두 개이므로 2 x ∏ x r (r은 반지름을 뜻한다) 즉 2∏r 이 된다.
원의 둘레를 구하는 공식 2∏r에는 이런 뜻이 있는 것입니다.
또한 ∏는 그냥 ∏ 또는 ∏ 라디안 이라고 표기합니다.
∏값이 3.14이니 3.14 또는 3.14 라디안 이라고 해도 되죠.
뒤에 라디안 이라는 글자는 붙여도 되고 안 붙여도 됩니다.
안 붙어있으면 라디안이라고 이해하면 되고, 각도(°)가 붙어 있으면 도 라고 이해하면 됩니다.
이렇게 각도를 라디안으로 표시하는 방법을 호도법 이라고 부릅니다.
이름에서도 알 수 있듯이 호도법은 호의 길이로 각도를 표시하는 체계인 것입니다.
자, 이제 도를 라디안으로 변환하고 라디안을 도로 변환할 때 사용했던 그 특정한 숫자의 의미를 이해할 수 있는 순간이 왔습니다.
방금 180도가 ∏라디안 이라고 했으니 1도는 몇 라디안일까요?
풀이) 180° => ∏ 라디안 이므로,
1° => ∏ / 180
1° => 3.141592 / 180 = 0.01743
반대로 ∏가 180도 라고 했으니 1라디안은 몇 도 일까요?
풀이) ∏ => 180° 이므로,
3.14 라디안 => 180° 와 같으니,
1 라디안 => 180 / 3.141592 = 57.2957°
∏는 소수점 이하가 끝나지 않고 계속 이어지는 수입니다. 따라서 보통 3.14라는 근사값을 사용합니다.
이번 강좌를 끝으로 3D 게임 프로그래밍을 위한 기초 수학 강좌를 마칩니다.
강좌 대부분이 이론 위주로 되어 있어 게임 프로그래밍을 하는데 당장 써먹을만한 내용은 별로 없었을 겁니다.
하지만 셰이더 프로그래밍 처럼 수학적인 이해가 필요할 때 다시한번 들춰보시면 유용하리라 생각됩니다.
다음번에 또 기회가 되면 실제 코드속에서 응용하는 부분에 대한 내용을 공유해 보도록 하겠습니다.
부족한 글 읽어주셔서 감사합니다.
- 끝 -