두벡터 사이의 각도 구하기

두 벡터가 이루는 각도는 내적에 의해서 구할 수 있다.

내적

1.       U   dot   V = |U| * |V| * cos Θ

2.       U   dot   V =  (Ux * Vx) + (Uy * Vy) + (Uz * Vz)

( U dot V   =  0  )결과가 0이면 두벡터간의 두벡터간의 각도는 90도이다.
( U dot V   <  0  ) 결과가 0보다 작으면 두벡터간의 각도는 90도보다 크다.
( U dot V   >  0  ) 결과가 0보다 크다면 두벡터간의 각도는 90보다  작다.

U, V  벡터를 단위 벡터로 만들면 |U|, |V| 값은  1이 되므로 내적의 공식은 단순화 된다.

지금 부터의 U, V 벡터는 단위 벡터라 가정한다.

U   dot   V = cos  Θ  =  (Ux * Vx) + (Uy * Vy) + (Uz * Vz)

cos  Θ  =  (Ux * Vx) + (Uy * Vy) + (Uz * Vz)

      theta  =  acos [ (Ux * Vx) + (Uy * Vy) + (Uz * Vz) ]

theta를 라디안에서 도  단위로 바꿀려면   theta = theta  * 180 / 3.141592654

U , V 벡터가 단위 벡터가 아니라면 내적의 공식에 의해  계산하면 된다.

acos(-1) ~ acos(1)을 라디안으로 표시하면 0 ~ 파이를 의미한다.
acos(-1)  = 0  ---> 0도
acos(0) = 파이 / 2  ---> 90도
acos(1) = 파이 ---> 180도

이렇게 하면 각도는 구할 수 있지만 각도는 0~180도밖에 나오지 않는다. 0~360도 범위를 구할려면 외적의 Z성분을 이용한다. 두벡터의 각도가 180~360 또는 -180~0이면 외적의 Z값은 0보다 작다.

외적은 Z성분은   (ax*by) - (ay*bx) 로 구할 수 있다.

#include "stdafx.h"

#include <d3dx9.h>

#include <iostream>

 

using namespace std;

 

float GetAngle( const D3DXVECTOR3& a, const D3DXVECTOR3& b )

{

    float cosAngle  = acosf( D3DXVec3Dot(&a, &b) / (D3DXVec3Length(&a) * D3DXVec3Length(&b)) );

    cosAngle = D3DXToDegree( cosAngle );

 

    //외적의 z성분으로 방향이 결정된다.

    float angle =  (a.x * b.y - a.y * b.x > 0.0f) ? cosAngle : -cosAngle;

    return angle;

}

 

int _tmain( int argc, _TCHAR* argv[])

{

    D3DXVECTOR3 a(1.0f, 1.0f, 0.0f);

    D3DXVECTOR3 b(1.0f, 0.0f, 0.0f);

 

    float angle = GetAngle( a, b );

    cout << angle << endl;  //결과값은 -45가 나온다.

 

    return 0;

}


아래 코드는 유니티용 코드이다.

    public float ContAngle(Vector3 fwd, Vector3 targetDir)
    {
        float angle = Vector3.Angle(fwd, targetDir);

        if (AngleDir(fwd, targetDir, Vector3.up) == -1)
        {
            angle = 360.0f - angle;
            if (angle > 359.9999f)
                angle -= 360.0f;
            return angle;
        }
        else
            return angle;
    }

    public int AngleDir(Vector3 fwd, Vector3 targetDir, Vector3 up)
    {
        Vector3 perp = Vector3.Cross(fwd, targetDir);
        float dir = Vector3.Dot(perp, up);

        if (dir > 0.0)
            return 1;
        else if (dir < 0.0)
            return -1;
        else
            return 0;
    }

        //테스트
        Vector3[] A = new Vector3[5];
        Vector3[] B = new Vector3[5];
        A[0] = new Vector3(3, 0, 0); B[0] = new Vector3(5, 5, 0);  //45
        A[1] = new Vector3(3, 4, 0); B[1] = new Vector3(-8, 6, 0); //90
        A[2] = new Vector3(5, 6, 0); B[2] = new Vector3(-1, 4, 0); //53
        A[3] = new Vector3(5, 6, 0); B[3] = new Vector3(-1, 4, 0); //53
        A[4] = new Vector3(3, 5, 0); B[4] = new Vector3(-1, 6, 0); //40

        for (int n = 0; n < A.Length; ++n)
        {
            float a = ContAngle(A[n], B[n]);
            Debug.Log("Angle " + a + "   VectorA: " + A + "   VectorB: " + B);
        }


참조 :

http://djmilk.nazoa.net/

http://beeswing.net/

http://sekainonaka.tistory.com/164