반사 벡터(Reflect Vector) 유도하기

레페·2023년 5월 9일

DirectX_3D

목록 보기
1/2
post-thumbnail

어떤 정점을 향해 비추는 빛 벡터(vLight)와, 해당 정점의 노멀 벡터(vNormal : 정점에 수직 방향을 가리키는 벡터)가 있을 때, 해당 정점의 반사 벡터를 구해보자.

수포자인 내가 한참 뒤에 보더라도 이해할 수 있게, 유치원생의 눈높이에 맞춰 매우 자세히 설명해볼 것이다.

0. 개요

어떤 정점을 비추는 빛 벡터 (vL),
어떤 정점에 수직인 벡터(vN),
우리가 구해야 할 반사 벡터(vR)가 있다.

[주어진 정보에서 알 수 있는 사실]
1. vN, vL 벡터들은 방향벡터이므로, Normalize(정규화) 되어있어 길이가 1이다.
2. 입사각 = 반사각이므로, vN 벡터에 대해 vL이 이루는 각도(a)와 vN 벡터에 대해 vR이 이루는 각도(b)는 동일하다.
당연히 저 아래 각도도 90 - a(=b)이기 때문에, c각도와 d각도 역시 동일할 것이다.

1. 접근

우리가 구하고자 하는 vR을 포함, vL과 vN은 방향벡터이기 때문에 방향값이 중요하지 시작점은 어디에 있든 상관이 없다. 따라서 vL 벡터가 원점에서 시작한다고 가정해보겠다.

vL벡터를 그대로 원점 아래로 내려보니, vR은 vL벡터와 x벡터의 합인 것처럼 보인다!

1-1. 벡터의 합

다음과 같이 두 벡터 A와 B가 있을 때, 두 벡터의 합은 어떻게 구할까?
물론 두 좌표를 더하면 되지만, 그래프적으로는 두 번째 그림처럼 두 벡터를 각각 대변으로 가지는 평행사변형의 대각선을 이은 벡터로 표현할 수 있다.

또한, A벡터만큼 간 다음 그 자리에서 다시 B벡터만큼 간 결과와도 같다는 것을 알 수 있다. (혹은 반대로 B벡터만큼 간 다음, 그 자리에서 A벡터만큼 이동한 것과 같음)

다시 vL을 내린 그래프를 보면, vR은 시작점을 원점으로 하는 vL벡터(말이 이렇지 사실 방향은 동일하므로 그냥 vL벡터 그자체이다) 와 vL벡터의 끝에서 vR방향으로 향하는 x벡터의 합이라는 것을 알 수 있다.

한번에 이해하기가 어렵다면, 해당 x벡터를 vL벡터와 시작점을 맞춰주면 이해하기 쉬울 수도 있다.

다음과 같이 x벡터의 시작점을 원점으로 옮기면, 아까 벡터의 합에서 봤던 것처럼 x벡터와 vL벡터를 대변으로 하는 평행사변형꼴이 만들어지고, 그 대각선의 길이가 vR이 되는 것을 확인할 수 있다!

즉, vR = vL + X이다.

2. X 벡터 구하기

그렇다면 x벡터는 어떻게 구할 수 있을까?

  1. x 벡터의 방향
    x 벡터는 vN벡터의 방향과 동일하다. (그러나 길이는 vN의 길이와 같지 않다. 입사각도가 어떻게 들어오느냐에 따라 다를 것이다.)
    벡터는 방향값과 길이값을 동시에 가지는데, 방향값이 vN과 같다는 것을 알았으니,

x벡터는 vN x (x벡터의 길이) 라고 정리할 수 있겠다.

  1. x 벡터의 길이
    우리는 개요에서 입사각은 반사각과 같다는 사실로 그림의 θ값이 모두 동일하다는 것을 알았다. 또한, vR과 vL은 모두 노멀라이즈된 방향 벡터이기에 길이가 1이라는 것도 알았다. 그렇다면 그림에서 보는 것처럼 x축을 기준으로 동일한 각도(θ), 동일한 길이의 빗변, 동일한 길이의 높이를 가진 y를 밑변으로 가진 삼각형 두 개로 표현할 수 있겠다. 둘은 똑같은 삼각형이며, 그러므로 x의 길이는 2y로 표현할 수 있다.

x벡터는 vN x (2y) 라고 정리할 수 있겠다.

3. 길이 y 구하기

그렇다면 저 y값만 구한다면 최종적으로 반사 벡터를 구할 수 있을 것이다. y값은 어떻게 구할 수 있을까?

y값은 vR의 y값이므로, 이를 y축까지 끌고 와도 y값의 길이는 동일할 것이다. 이 y값을 y축으로 끌고 오니 또다시 직각삼각형이 보인다.
삼각함수를 이용하니 cos θ = 밑변(y) / 빗변(vR) 임을 알 수 있는데, 우리가 구하려는 vR은 노멀라이즈되어 길이가 1이다. 즉, 우리가 구하고자 하는 y는 바로 vL과 vN 사이의 각도 θ의 코사인값이다.

y = cos θ;

cos θ는 어떻게 구할까? 우리는 노멀라이즈된 두 벡터를 내적하면 cos θ가 된다는 것을 배웠다.(두 벡터의 길이가 각각 1이기 때문에 cos θ만 남는다) 즉, cos θ = vL벡터와 vN벡터의 내적값이다.

단, 이때 빠뜨리기 쉬운 부분이 바로 vL값에 음수 부호를 붙여 방향을 반대로 만든 뒤 내적을 해야한다는 것이다.
내적을 하려면 두 벡터는 시작점이 같아야하는데, vL의 경우 태양에서 해당 정점으로 향하는 빛이고, vN은 정점에서 수직 방향이기 때문에, vL을 뒤집어(정점에서 태양(광원)을 향하는 벡터로 만든 뒤) 계산해야 정확한 값이 나오게 된다.

vR = vL + 2 * ( - vL • vN) * vN;

총 3번의 유도과정을 통해 vL 벡터, vN 벡터만을 이용해 반사벡터 vR벡터를 유도해냈다.

profile
게임 개발자를 꿈꾸는 취준생입니다

0개의 댓글