본문 바로가기
프로그래밍/Unreal Engine4

UE4 두백터를 이용한 방향(Direction)과 회전 Angle 구하는 코드

by 눈야옹 2016. 4. 20.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
    FVector Dest = FVector(GoalPosition.X, GoalPosition.Y, 0.0f);
    FVector Start = FVector(GetTransform().GetLocation().X, GetTransform().GetLocation().Y, 0.0f);
 
    FVector dir = Dest - Start;
 
    GoalDirection = dir.SafeNormal();
    //노말라이징한 두개의 백터를 dot한다. //여기서 축을 Z축으로 하기 위해 두백터의 Z값을 0.0f로 넣어 주었다.
    float dot = FVector::DotProduct(FVector::ForwardVector, GoalDirection);
    float AcosAngle = FMath::Acos(dot);    // dot한 값을 아크코사인 계산해 주면 0 ~ 180도 사이의 값 (0 ~ 1)의 양수 값만 나온다.
    float angle = FMath::RadiansToDegrees(AcosAngle); //그값은 degrees 값인데 이것에 1라디안을 곱해주면 60분법의 도가 나온다.
    
    //여기서 두 백터를 크로스 하여 회전할 축을 얻게 된다.
    //이 크로스 백터는 Axis회전의 회전축이 되며 , 그 양수 음수로 회전 방향 왼쪽(음수), 오른쪽(양수)를 알수 있다.
    FVector cross = FVector::CrossProduct(FVector::ForwardVector, GoalDirection); 
    FString lr = "center    //";
    if(cross.Z > 0)
    {
        lr = "Right    //";
 
        TurnAngle = angle;
    }
    else if (cross.Z < 0)
    {
        lr = "Left    //";
        //TurnAngle = 360 - angle; //360에서 뺴게되면 양수로 각을 리턴하게 된다.
        TurnAngle = -angle;
    }
 
    FString str = FString::Printf(TEXT("AcosAngle : %f, angle : %f //    "), AcosAngle, angle);
 
    //출력해보기
    GEngine->AddOnScreenDebugMessage(-1100.0f, FColor::Green, str+ lr + GoalDirection.ToString());
 
cs


*여기서 아크코사인이 사용 되었는데 그것은 물체가 왼쪽에 있을 경우 상식적으로 왼쪽으로 회전해야 하는데,

 그냥 코사인 값을 쓸 경우 오른쪽방향으로 회전하는 것이라 오래 걸린다. (행성의 자전이나 단방향 회전하는 물체 등에는 코사인으로 하면될것이다)


위코드는 forward백터를 기준으로 회전하는 것이고 

아래 코드는 내가 현재 가지고 있는 방향으로 부터 다음 방향을 구하는 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void ARollingBall::SetNewGoalDirection()
{
    //일단 기존에 가지고 있던 Direction과 Angle을 이전 값으로 해준다. 
    PrevGoalDirection = CurrentGoalDirection;
    PrevTurnAngle = GetTransform().GetRotation().Euler().Z;
 
    //먼저 현재 지점에서부터 목표지점을 향한 Direction을 구한다.
    FVector Dest = FVector(GoalPosition.X, GoalPosition.Y, 0.0f);
    FVector Start = FVector(GetTransform().GetLocation().X, GetTransform().GetLocation().Y, 0.0f);
    FVector newDir = Dest - Start;
    CurrentGoalDirection = newDir.GetSafeNormal();
 
    //노말라이징한 두개의 백터를 dot한다. //여기서 축을 Z축으로 하기 위해 두백터의 Z값을 0.0f로 넣어 주었다.
    float dot = FVector::DotProduct(PrevGoalDirection, CurrentGoalDirection);
    float AcosAngle = FMath::Acos(dot);    // dot한 값을 아크코사인 계산해 주면 0 ~ 180도 사이의 값 (0 ~ 1)의 양수 값만 나온다.
    float angle = FMath::RadiansToDegrees(AcosAngle); //그값은 degrees 값인데 이것에 1라디안을 곱해주면 60분법의 도가 나온다.
    
    //여기서 두 백터를 크로스 하여 회전할 축을 얻게 된다.
    //이 크로스 백터는 Axis회전의 회전축이 되며 , 그 양수 음수로 회전 방향 왼쪽(음수), 오른쪽(양수)를 알수 있다.
    FVector cross = FVector::CrossProduct(PrevGoalDirection, CurrentGoalDirection);
    FString lr = "center    //";
    if(cross.Z > 0)
    {
        lr = "Right    //";
 
        NextTurnAngle = angle;
    }
    else if (cross.Z < 0)
    {
        lr = "Left    //";
        //NextTurnAngle = 360 - angle; //360에서 뺴게되면 양수로 각을 리턴하게 된다.
        NextTurnAngle = -angle;
    }
}
cs