Houdini

후디니 벡터 사이의 각도 구하기

Tedd_Kim 2023. 2. 18. 01:16

후디니를 하다보면 생각보다 벡터의 각도를 알아야할 때가 있다.

대표적으로 물체를 회전시킬 때나 Whitewater source노드의 vel angle파라미터 등에서도 보이지만, 삼각함수는 각도를 다룰 때 단골로 나오는 주제이다.

 

2D평면에선 기준축이 x축이 되고, 간단하게 벡터와 벡터사이의 각도가 계산되지만, 3D에서는 단계가 조금 추가된다.

하지만 간단하게 생각하면 되는데, 하나의 벡터를 다른 벡터에 투영(Projection)하고 그 과정에서 만들어진 삼각형의 사이각을 구하는 것이다.

 

두 벡터는 x좌표, y좌표, z좌표가 모두 다르지만 내적을 이용하여 B벡터를 A벡터에 투영하고 만들어진 삼각형의 세타값을 구하면 두 벡터 사이의 각도가 되는 것.

 

세타를 구하는 방법은 역삼각함수를 이용하면 되는데, 후디니에서 자주 쓰이는 역삼각함수는 acos함수과 atan2함수가 있다.

 

acos함수는 0부터 180도까지밖에 리턴하지 않는다. 즉 180도를 넘어가면 정확한 각도를 알 수 없는 것

반면 atan함수는 -90도부터 90도까지, atan2함수는 -180도부터 180도까지를 리턴한다. 

따라서, 웬만한 경우엔 atan2함수를 이용하는 것이 제일 정확한 결과값을 얻어낼 수 있음

 

여기서 acos와 atan함수의 문제가 있는데, 사분면이 겹치면서 결과값이 부정확할 때가 있다.

예를 들어 역탄젠트 함수는 [y좌표/x좌표]를 인자로 받는데

 

1사분면 +,+ 

2사분면 +,-

3사분면 -,+

4사분면 -,- 

 

y좌표/x좌표를 계산했을때 1사분면과 4사분면의 기호가 겹치게 되고, 2사분면과 3사분면의 기호가 겹치게 된다.

이러면 원래라면 230도로 계산되어야 할 것이 50도로 나오는 등 정확한 결과값이 나오지못함

 

하지만 atan2함수는 y좌표와 x좌표를 각각 따로 인자로 받게 된다. 그리하여 정확히 몇사분면에 있는지를 알아내고, 케이스를 분류하여 세타값에 적절히 부호를 달아준다.

 

tanθ = sinθ / cosθ 라는 공식을 이용하여 atan2에 들어갈 인자를 결정할 것인데,

여기서 재밌는 점!

 

두 벡터의 관계에서 cosθ = A dot B / |A| * |B|가 되고sinθ = |A cross B| / |A| * |B|가 된다.

 

결국 두 식을 정리하면 tanθ = | A cross B | / A dot B가 되고, θ = arctan(| A cross B | / A dot B)로 유도된다.그래서 atan2함수에는 후디니 vex코드로 표기했을 때

 

atan2(lenth(cross(A, B)), dot(A, B))가 된다.

 

이러면 끝? 은 아니다.

두 벡터의 각도에 따라 내적의 값은 양수와 음수를 오가며 방향에 따른 적절한 부호를 가지겠지만

외적의 크기는 항상 양수이기 때문에 +부호밖에 가지지 못한다. 즉 사분면을 결정해주기 살짝 부족함.

 

그렇게 때문에 두 벡터의 외적값을 determinat로 이용하여 양수일 때, 음수일 때를 케이스로 분류해 적절히 세타값에 부호를 붙여주어야 한다. 그럼으로써 두 벡터는 서로 각도차이에 따라서 두개 인자의 부호가 계속해서 바뀌게 된다.

 

만약 원점 비교라면 굳이 저 긴 식을 써내려갈 필요가 없지만 (애초에 atan2(@P.y, @P.z)만 넣으면 끝나니)

두 벡터를 비교할 땐 위의 과정이 필요하다.

 

acos나 atan로는 사분면을 판단할 수가 없어서 저 각도를 정확하게 구할 수 없지만 atan2함수를 이용해 구해낸 값