Get it on Google Play


Wm뮤 :: 유니티 각도계산 모음

블로그 이미지
가끔 그림그리거나 3D모델링하거나
취미로 로봇만드는
퇴직한 전자과 게임프로그래머
2020.3.48f1 , 2022.3.6f1 주로 사용
모카쨩
@Ahzkwid

Recent Comment

Archive


2017. 11. 6. 14:54 Unity/C#

좌표계산

https://wmmu.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EC%A2%8C%ED%91%9C%EA%B3%84%EC%82%B0-%EB%AA%A8%EC%9D%8C

 

결과값이 좌표일 경우에는 위 링크로

결과값이 각도일 경우에는 이 글을 이용

 

 

 

pos1에서 pos2에대한 각도

Vector3 relativePos = pos2-pos1; 
Quaternion rotation = Quaternion.LookRotation (relativePos, Vector3.up );

 

 

상대 회전각

dir_speed=target.transform.rotation*Quaternion.Inverse(dir_previous);

 

상대 회전각2

a에서 b에대한 각도(위와 같음)

var a = Quaternion.Euler(0, 15, 0);
var b = Quaternion.Euler(0, 20, 0);
Debug.DrawLine(Vector3.zero, a * Vector3.forward, Color.red);
Debug.DrawLine(Vector3.zero, b * Vector3.forward, Color.blue);
Debug.DrawLine(Vector3.zero, (Quaternion.Inverse(a) * b) * Vector3.forward, Color.green);

 

상대회전각3

테스트는 안 해봄

var rotRel=Quaternion.FromToRotation(fromDir,ToDir);

 

각도 반전

var rotInverse=Quaternion.Inverse(transform.rotation);

 

 

 

 

speed = Quaternion.euler (0,0,0) * new vector3(0,0,0);  //len_vec과 동일

 

 

pDir(pointDirection)

2D계산용
수학계산을 이용한다. 일반적으로는 아래의 SignedAngle사용

    float PointDirection(Vector2 vec2)
    {
        vec2 = vec2.normalized;
        float offset;
        if (vec2.x > 0)
        {
            if (vec2.y > 0)
            {
                offset = 0;
            }
            else
            {
                var t = vec2.x;
                vec2.x = -vec2.y;
                vec2.y = t;

                offset = 270;
            }
        }
        else
        {
            if (vec2.y > 0)
            {
                var t = vec2.x;
                vec2.x = vec2.y;
                vec2.y = -t;

                offset = 90;
            }
            else
            {
                vec2.x = -vec2.x;
                vec2.y = -vec2.y;

                offset = 180;
            }
        }
        if (vec2.x == 0)
        {
            return 0;
        }
        return (Mathf.Atan(vec2.y / vec2.x) * Mathf.Rad2Deg) + offset;
    }

 

 

 

 

PDir

3D계산

var direction = Quaternion.LookRotation(pos2- pos1, Vector3.up);

 

 

PDir2D

좌현이 기준각도라서

Vector2.right를 좌현에 두고 쓰면 겜메랑 똑같이 나온다

Debug.Log(Vector2.SignedAngle(Vector2.zero, Vector2.up)); //0
Debug.Log(Vector2.SignedAngle(Vector2.zero, Vector2.down)); //0
Debug.Log(Vector2.SignedAngle(Vector2.zero, Vector2.left)); //0
Debug.Log(Vector2.SignedAngle(Vector2.zero, Vector2.right)); //0

Debug.Log(Vector2.SignedAngle(Vector2.right, Vector2.up)); //90
Debug.Log(Vector2.SignedAngle(Vector2.right, Vector2.down)); //-90
Debug.Log(Vector2.SignedAngle(Vector2.right, Vector2.left)); //180
Debug.Log(Vector2.SignedAngle(Vector2.right, Vector2.right)); //0

Debug.Log(Vector2.SignedAngle(Vector2.up, Vector2.up)); //0
Debug.Log(Vector2.SignedAngle(Vector2.up, Vector2.down)); //180
Debug.Log(Vector2.SignedAngle(Vector2.up, Vector2.left)); //90
Debug.Log(Vector2.SignedAngle(Vector2.up, Vector2.right)); //-90

 

 

Vector2.Angle 예제

Debug.Log(Vector2.Angle(Vector2.zero, Vector2.up)); //0
Debug.Log(Vector2.Angle(Vector2.zero, Vector2.down)); //0
Debug.Log(Vector2.Angle(Vector2.zero, Vector2.left)); //0
Debug.Log(Vector2.Angle(Vector2.zero, Vector2.right)); //0

Debug.Log(Vector2.Angle(Vector2.right, Vector2.up)); //90
Debug.Log(Vector2.Angle(Vector2.right, Vector2.down)); //90
Debug.Log(Vector2.Angle(Vector2.right, Vector2.left)); //180
Debug.Log(Vector2.Angle(Vector2.right, Vector2.right)); //0

Debug.Log(Vector2.Angle(Vector2.up, Vector2.up)); //0
Debug.Log(Vector2.Angle(Vector2.up, Vector2.down)); //180
Debug.Log(Vector2.Angle(Vector2.up, Vector2.left)); //90
Debug.Log(Vector2.Angle(Vector2.up, Vector2.right)); //90

 

DeltaAngle예제

-179.9~180각도 Normalize용 (정규화)

일반적으론 좌현을 0으로 두고 쓰면 된다

Debug.Log(Mathf.DeltaAngle(0, -270)); //90
Debug.Log(Mathf.DeltaAngle(0, -180)); //180
Debug.Log(Mathf.DeltaAngle(0, -90)); //-90
Debug.Log(Mathf.DeltaAngle(0, 0)); //0
Debug.Log(Mathf.DeltaAngle(0, 90)); //90
Debug.Log(Mathf.DeltaAngle(0, 180)); //180
Debug.Log(Mathf.DeltaAngle(0, 270)); //-90

Debug.Log(Mathf.DeltaAngle(90, -270)); //0
Debug.Log(Mathf.DeltaAngle(90, -180)); //90
Debug.Log(Mathf.DeltaAngle(90, -90)); //180
Debug.Log(Mathf.DeltaAngle(90, 0)); //-90
Debug.Log(Mathf.DeltaAngle(90, 90)); //0
Debug.Log(Mathf.DeltaAngle(90, 180)); //90
Debug.Log(Mathf.DeltaAngle(90, 270)); //180

 

 

각도정규화 

v1

더보기

 겜메 시절에 썼던거

public double d_set(double _Dir)
{
    if(_Dir<0d)
    {
        _Dir=360d-((-_Dir)%360d);
    }
    if(_Dir>=360d)
    {
        return _Dir%360d;
    }
    return _Dir;
}

 

v2

dir = (dir % 360f + 360f) % 360f;

 

v3

dir = Mathf.Repeat(dir, 360f);

 

 

각도정규화 (쉐이더용)

0~1로 정규화 한다

dir = frac(dir);

 

 

 

 

 

 

Dot예제

각도 연산을 바로 인풋으로 받아들일때 쓰면 편하다

Debug.Log(Vector2.Dot(Vector2.zero, Vector2.up)); //0
Debug.Log(Vector2.Dot(Vector2.zero, Vector2.down)); //0
Debug.Log(Vector2.Dot(Vector2.zero, Vector2.left)); //0
Debug.Log(Vector2.Dot(Vector2.zero, Vector2.right)); //0

Debug.Log(Vector2.Dot(Vector2.right, Vector2.up)); //0
Debug.Log(Vector2.Dot(Vector2.right, Vector2.down)); //0
Debug.Log(Vector2.Dot(Vector2.right, Vector2.left)); //-1
Debug.Log(Vector2.Dot(Vector2.right, Vector2.right)); //1

Debug.Log(Vector2.Dot(Vector2.up, Vector2.up)); //1
Debug.Log(Vector2.Dot(Vector2.up, Vector2.down)); //-1
Debug.Log(Vector2.Dot(Vector2.up, Vector2.left)); //0
Debug.Log(Vector2.Dot(Vector2.up, Vector2.right)); //0

 

 

두 벡터간 각도차이

Vector3.Angle(ray.direction, Camera.main.transform.forward)

 

특정 시야각 안에 들어왔는지 검사


bool IsInFOV(Vector3 position, float fovRatio)
{
    var cam = Camera.main;
    if (cam == null)
    {
        return false;
    }
    var direction = position - cam.transform.position;
    var angle = Vector3.Angle(cam.transform.forward, direction);
    var fov = cam.fieldOfView * fovRatio;
    if (angle > fov)
    {
        return false;
    }
    return true;
}

 

특정 시야각 안에 들어왔는지 검사2

targetingCircle.GetComponent<Image>().color = Color.white;
targetingCircle.GetComponent<FovToRectsize>().fov = GetWeapon().GetComponent<Gun>().spread * 2;
var fov = targetingCircle.GetComponent<FovToRectsize>().fov;
var targets = GameSystem.GetInGameOtherCharacters();
var cam = Camera.main;
var targeting = false;
foreach (var target in targets)
{
    Debug.DrawLine(transform.position, target.transform.position, Color.cyan);
    var directionToTarget = target.transform.position - cam.transform.position;
    var angle = Vector3.Angle(cam.transform.forward, directionToTarget);
    if (angle > fov)
    {
        continue;
    }

    var humanoidAnimatorController = target.GetComponentInChildren<HumanoidAnimatorController>();


    //디버깅이 원활하도록 배열로 한번에 안 만들고 하나씩 추가함
    var targetPoses = new List<Vector3>();
    targetPoses.Add(target.transform.position);
    targetPoses.Add(humanoidAnimatorController.GetBoneTransform(HumanBodyBones.Hips).position);
    targetPoses.Add(humanoidAnimatorController.GetBoneTransform(HumanBodyBones.Head).position);

    foreach (var targetPos in targetPoses)
    {
        if (Physics.Raycast(cam.transform.position, targetPos - cam.transform.position, out RaycastHit hit, maxDistance: 100))
        {
            Debug.DrawRay(cam.transform.position, targetPos - cam.transform.position, Color.red);
            if (hit.transform.tag == "Player")
            {
                Debug.DrawLine(targetPos, targetPos + Vector3.up, Color.red);
                targeting = true;
                break;
            }
        }
    }
    if (targeting)
    {
        break;
    }
}
{
    //정중앙에 보고 있는게 닿았는지 검사
    if (Physics.Raycast(cam.transform.position, cam.transform.forward, out RaycastHit hit))
    {
        Debug.DrawRay(cam.transform.position, cam.transform.forward, Color.red);
        if (hit.transform.tag == "Player")
        {
            targeting = true;
        }
    }
}
if (targeting)
{
    targetingCircle.GetComponent<Image>().color = new Color(1, 0.5f, 0.5f);
}

 

 

 

맞은 각도 표시

firePosition은 발사지점

var relativePosition = Quaternion.Inverse(transform.rotation) * (firePosition - transform.position);
var relativePosition2D = new Vector2(relativePosition.x, -relativePosition.z);

var rot = Quaternion.Euler(0, 0, Vector2.SignedAngle(relativePosition2D, Vector2.right));
damageUI.transform.rotation = rot;

'Unity > C#' 카테고리의 다른 글

충돌 계산 스크립트  (0) 2017.12.17
유니티 함수 정리  (0) 2017.07.02
c# list(리스트) 관련  (0) 2017.03.23
posted by 모카쨩

  • total
  • today
  • yesterday

Recent Post

저사양 유저용 블로그 진입