하지만, 포물선 운동의 경우 x축에 대해선 등속운동을 진행하지만 y축의 경우엔 중력의 존재떄문에 등속운동을 진행할 수가 없다. 동일한 방향으로 직선 운동을 하되, 가속도의 영향을 계속 받기 때문에 y축의 경우엔 등가속도 직선 운동을 한다고 할 수 있다. 그러므로, 위의 수식의 x값은 맞다고 할 수 있지만, y값에 대해선 틀력다고 할 수 있다.
y축은 등가속도 직선 운동을 하기 때문에, 등가속도 직선 운동의 공식을 사용해야 한다.
등가속도 직선 운동에서 변위를 구하는 공식은 아래와 같다.
$$s = v * t \; + \frac{1}{2} * a * t^{2}$$
벡터의 속력은 벡터가 최초에 가지고 있던 원소의 값이라고 할 수 있다. (처음에 가한 힘)
가속도는 -9.8이며, 시간은 t가 될 것이다.
공식에 대입하면, t초 후의 변위는 아래와 같다.
$$s = \left | v \right | * sin(\theta) * t \; - \frac{1}{2} * 9.8 * t^{2}$$
즉, 포물선 운동을 (0, 0)에서 시작했다고 한다면, t초 후의 물체의 좌표는 아래와 같아지는 것이다.
$$(x, y) =(\left | v \right | * cos(\theta) * t ,\ \left | v \right | * sin(\theta) * t \; - \frac{1}{2} * 9.8 * t^{2})$$
아래 사진처럼 왼쪽을 바라보며 서있다면, 몹은 나의 뒤에 존재하게 되고, 나의 오른쪽에 존재하게 된다.
즉, 몹과 나의 방향 관계를 정확히 파악하려면 먼저 바라보고 있는 방향에 대한 벡터가 필요하다.
방향 벡터를 구하는 것은 어렵지 않다.
먼저, 플레이어의 위치, 회전관계를 전혀 건드리지 않았을 때 최초에 바라보는 방향이 필요하다.
아마 일반적인 상태에선 최초에 바라보는 방향에 대한 벡터는 (0, 0, 1)일 것이다.
(매쉬에 따라 다를 수 있고, 엔진 환경에 따라 다를 수 있다. 다만, 최초에 바라보고 있는 방향 벡터라는 것만 알면 된다.)
이런 상황에서 플레이어가 x축으로 60도만큼 회전했다면?
바라보는 방향에 대한 벡터 또한 x축으로 60도만큼 같이 회전할 것이다.
즉, 플레이어의 현재 회전값만큼 항상 함께 회전하기 때문에 (0,0,1)벡터를 플레이어의 회전 값만큼 회전시키면
그게 현재 플레이어의 정면 벡터인 것이다.
정면에 대한 벡터는 이렇게 구해보았다. 그렇다면 다음은 무엇을 해야 할 까.
아래 사진을 보자. 보라색 벡터는 플레이어로부터 몹을 향하는 벡터이다.
정면을 향하는 벡터와 몹을 향하는 벡터 사이의 각 (Theta)가 90도보다 크다면, 몹은 뒤에 있다고 할 수 있지 않을까?
반대로, Theta가 90도 보다 작다면, 몹이 내 앞에 있다고 할 수 있지 않을까?
그렇다. 노란색 벡터(정면에 대한 벡터)와 보라색 벡터(몹을 향한 벡터) 사이의 각도를 구하면 몹이 앞에 있는지 뒤에 있는 지를 판별할 수 있다.
일단, 각도를 구하기 전에 보라색 벡터(몹을 향한 벡터)를 구해보자.
이건 간단하게 구할 수 있다.
(몹의 위치 좌표 - 나의 위치 좌표)가 보라색 벡터이다.
벡터의 뺄셈 연산을 알고있다면 이해하는 것에 무리는 없을 것이다.
이렇게, 정면 벡터와 몹을 향한 벡터를 구했다면 두 벡터 사이의 각을 구하면 된다.
그런데, 그 전에 한가지 알고 넘어가야 하는 사실이 있다.
바로 몹과 나의 y축 좌표(위, 아래)를 고려해야 하는가? 에 대한 문제이다.
나의 정면 벡터는 정상적으로 서있다면, 항상 지면에 수평이다.
하지만, 나와 몹의 높이 차이가 존재한다면 몹을 향한 벡터는 지면에 수평이지 않을 수 있다.
즉 두 벡터 사이의 각도가 우리가 의도하는 것과는 다르게 나올 수 있다는 것이다.
단순히 몹이 내 앞에 있는가? 뒤에 있는가? 만을 고려한다면 y값의 차이는 계산에 영향을 미쳐선 안된다.
그렇기 때문에, 정면 벡터의 y값을 0으로, 몹을 향한 벡터의 y값을 0으로 하여 x와 z만을 가지고 계산하는 것이 일반적으로 옳다.
그렇게 y값을 제거한 뒤, 두 벡터를 구했다면 이제 각도만 구하면 된다.
각도는 벡터의 내적을 이용하여 구하면 된다.
A · B = 벡터A의 길이 * 벡터B의 길이 * Cos(Theta)이다.
여기서 길이의 곱만 제거한다면 Cos(Theta)만 남을 것이다.
그렇기 때문에, 두 벡터를 내적하기 이전에 먼저 정규화(노말라이즈)를 해주어야 한다.
정규화란 벡터의 길이를 1으로 맞추는 작업이며 벡터의 크기의 영향을 제거하고 방향만을 가지고 계산을 하기 위한 연산이다.
정규화는 어렵지 않다.
벡터의 x,y,z 성분을 벡터의 크기로 나누어 주면 끝이다.
벡터의 크기가 L이라면, (x/L, y/L, z/L)이 정규화된 벡터이다.
이렇게, 정면 벡터와 몹을 바라보는 두 벡터를 정규화 하였다면, 두 벡터를 내적해주자.
내적은 각 성분을 모두 곱해주면 된다.
(X1, Y1, Z1), (X2, Y2, Z2) 두 벡터가 있다면, (X1 * X2 + Y1 * Y2 + Z1 * Z2)가 두 벡터의 내적 값이다.
이렇게, 정면 벡터와 몹을 바라보는 두 벡터를 내적하였다면, 그 값은 Cos(Theta)일 것이다.
A · B = (X1 * X2 + Y1 * Y2 + Z1 * Z2) = 벡터A의 길이 * 벡터B의 길이 * Cos(Theta) 이고, 두 벡터의 길이는 1이므로
A · B = (X1 * X2 + Y1 * Y2 + Z1 * Z2) = Cos(Theta)
여기서, acos함수를 이용하여 Theta를 정확히 구할 수도 있지만 사실 불필요한 연산이다.
Cos함수의 경우 각도에 따른 값의 범위가 명확히 정해져 있다.
0 <= Theta < 90 이라면, 0 < Cos(Theta) <= 1 이고
90 <= Theta < 180 이라면, -1 < Cos(Theta) <= 0 이 될 것이다.
즉, 두 벡터를 내적한 값이 0과 1 사이라면, 몹은 내 앞에 있는 것이며
-1과 0 사이라면 나의 뒤에 있는 것이라고 판별할 수 있다.
하지만, 이렇게 내적으로 몹과 나의 위치관계를 구하게 되면 한 가지 문제가 있다.
내적은 0~180도 범위에서만 작동한다.
저렇게 몹이 반대편에 위치한다고 하더라도 값은 똑같이 나온다.
즉, 앞 뒤는 구별할 수 있어도 왼쪽 오른쪽은 구별할 수 없다는 뜻이다.
그렇다면 왼쪽 오른쪽은 어떻게 구할까?
간단하다. 정면벡터와 몹을 향하는 방향 두 벡터를 외적해보면 된다.
두 벡터의 y값을 제거하고 지면에 수평인 벡터로 만들어 준다.
그리고 두 벡터를 외적하면 지면에 수직힌 벡터가 나올 것이다.
두 벡터의 위치 관계에 따라, 지면 위로 솟아나는 방향일 수도 있도, 지면 안쪽으로 들어가는 방향일 수도 있다.
무조건, 정면 벡터를 앞에 두고 ( 정면 벡터 x 몹을 향한 벡터 ) 이렇게 외적을 해보자.
오른손 법칙에 의해, 몹을 향한 벡터가 정면 벡터보다 왼쪽을 향하고 있다면 위로 솟아나는 벡터가 나올 것이고
몹을 향한 벡터가 정면 벡터보다 오른쪽을 향하고 있다면 아래로 들어가는 벡터가 나올 것이다.
즉, 두 벡터를 외적한 벡터의 y값이 양수이면 왼쪽, 음수이면 오른쪽 이라고 판별할 수 있다.
https://snowfleur.tistory.com/98 에서 퍼온 사진
그림에도 나와 있듯이, 정면 벡터(u) 를 기준으로 했을 때, 몹을 향한 벡터(v)가 왼쪽에 위치한다면 외적한 벡터는 위를 향할 것이다.
당연히, 오른쪽에 있다면 외적한 벡터는 아래를 향할 것이다.
다만 아주 중요한 점이 있다
위에선 오른손을 기준으로 외적의 뱡향을 설명했지만, 항상 이 기준이 오른손이 되는 것이 아니다. 좌표계를 어떻게 정의하느냐에 따라 달라질 수 있다. DirectX, Unreal Enigne, Unity에선 왼손을 기준으로 계산 해야한다!반면, OpenGL, Vulkan 등에선 오른손을 기준으로 계산 해야한다!