좌표계산
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;