백터를 이용한 계산
백터의 내적과 외적을 이용하면 어렵게 수식을 작성하지 않고, 물체의 앞뒤좌우를 쉽게 파악할 수 있습니다.
1. 내적 (Dot Product, A·B)
두 개의 백터의 곱으로 스칼라값을 가져올 수 있습니다. 스칼라값을 역cosθ에 반영하면 사이각을 가져올 수 있습니다.
공식과 이해
스크립트
using UnityEditor;
using UnityEngine;
/// <summary>
/// 백터 내적 테스트
/// 설명: 두 개의 백터의 사이각을 가져올 수 있다. 해당 사이각을 통해서 스칼라를 가져올 수 있고, 스칼라는 cosθ에 해당, 스칼라 값을 통해서 앞뒤를 구분하는데 사용할 수 있다.
/// 예시: 내적을 통해 Onwer가 바라보는 방향(forward)을 기준으로 Target이 앞에 있는지 뒤에 있는지 구분을 할 수가 있다.
/// Target이 앞에 있을 경우 경우 양수(+), 뒤에 있을 경우 음수(-)를 출력한다.
/// 키워드: Vector의 forward, Vector.Dot(내적), 앞뒤 구분 가능(좌우 구분에 대해서는 명확하지 않다)
/// </summary>
public class VectorDotProduct : MonoBehaviour
{
private const float DISTANCE = 1.5f;
#region Inspector
public Transform owner;
public Transform target;
#endregion
private float _duration = 0f;
private void OnDrawGizmos()
{
if (!owner || !target) return;
Gizmos.color = Color.white;
Gizmos.DrawWireSphere(owner.position, 0.1f);
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(target.position, 0.1f);
Gizmos.DrawLine(owner.position, target.position);
Gizmos.color = Color.white;
// 내적
float dot = Vector3.Dot(owner.forward, target.position);
Handles.color = Color.white;
Handles.Label(transform.position + Vector3.up * 0.5f, $"Dot: {dot}");
Handles.Label(owner.position + Vector3.down * 0.5f, "내적, 2개 백터의 사잇각을 구할 수 있다.\n" +
"이를 cosθ을 통해 스칼라 값을 구할 수 있고, 스칼라 값이 양수냐 음수냐에 따라 앞뒤 구분하는데 주로 사용한다.");
Handles.DrawLines(new Vector3[] { owner.position, owner.position + owner.forward });
Handles.Label(owner.position + owner.forward + Vector3.up * 0.2f, $"Forward");
}
private void Update()
{
// Target 시계 방향으로 로테이트 애니메이션
_duration += Time.deltaTime * 0.5f;
if (_duration > 1f) _duration = 0f;
Quaternion quaternion = Quaternion.AngleAxis(360f * _duration, owner.up);
target.position = this.transform.position + quaternion * owner.forward * DISTANCE;
}
}
참고로
float dot = Vector3.Dot(A, B)를 통해서 구한 값(dot)으로
1. 라디안 = Mathf.Acos(dot)
2. 디그리(각도) = Mathf.Acos(dot) * Mathf.Rad2Deg
위와 같이 사이각을 사용할 수 있습니다.
2. 외적 (Cross product, A×B)
두 개의 백터 간 90도로 직교되는 백터를 가져올 수 있습니다. 외적은 2개의 점에서 90도로 직교되는 점을 가져와야하기 때문에 3D에서만 사용할 수 있습니다.
공식과 이해
스크립트
using UnityEditor;
using UnityEngine;
/// <summary>
/// 백터 외적 테스트
/// 설명: 두 개의 백터가 90도로 직교되는 백터를 가져올 수 있다. 외적은 2개의 점에서 90도로 직교되는 점을 가져와야하기 때문에 3D에서만 사용할 수 있다.
/// 예시: 외적을 통해 Onwer가 바라보는 방향(forward)을 기준으로 Target이 왼쪽에 있는지 오른쪽에 있는지 구분을 할 수가 있다.
/// 2개의 백터가 90도로 직교되는 위 또는 아래의 축을 가져옵니다. 좌표계에 따라 왼손좌표계는 아래 축을, 오른손좌표계는 위를 향하는 축을 가져온다. (좌표계에 따라 시작 값이 다르다.)
/// 이를 통해 가져오는 축의 값이 양수(+)인지 음수(-)인지에 따라 좌우를 구분할 수 있다.
/// 일반적인 3D게임에서 x,z축으로 움직이는 경우, 외적을 통한 직교되는 y축의 값으로 좌우를 구분할 수 있다.
/// 키워드: Vector의 forward, Vector.Cross(외적), 좌우 구분 가능
/// </summary>
public class VectorCrossProduct : MonoBehaviour
{
private const float DISTANCE = 1.5f;
#region Inspector
public Transform owner;
public Transform target;
#endregion
private float _duration = 0f;
private void OnDrawGizmos()
{
if (!owner || !target) return;
Gizmos.color = Color.white;
Gizmos.DrawWireSphere(owner.position, 0.1f);
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(target.position, 0.1f);
Gizmos.DrawLine(owner.position, target.position);
Gizmos.color = Color.white;
Vector3 cross = Vector3.Cross(owner.forward, target.localPosition);
Handles.color = Color.yellow;
Handles.DrawLine(owner.position, owner.position + cross);
Handles.color = Color.white;
Handles.Label(owner.position + Vector3.up * 0.5f, $"x: {cross.x}, y: {cross.y}, z: {cross.z}");
Handles.Label(owner.position + Vector3.down * 0.5f, "외적, 2개 백터가 직교하는 90도 축을 가져온다.\n" +
"이를 통해 축의 값이 양수냐 음수냐에 따라 좌우 구분하는데 주로 사용된다.");
Handles.DrawLines(new Vector3[] { owner.position, owner.position + owner.forward });
Handles.Label(owner.position + owner.forward + Vector3.up * 0.2f, $"Forward");
}
private void Update()
{
// Target 시계 방향으로 로테이트 애니메이션
_duration += Time.deltaTime * 0.5f;
if (_duration > 1f) _duration = 0f;
Quaternion quaternion = Quaternion.AngleAxis(360f * _duration, owner.up);
target.position = this.transform.position + quaternion * owner.forward * DISTANCE;
}
}
마무리
게임을 제작하게되면 가장 많이 접하게 되는 백터 연산입니다. 캐릭터의 앞뒤좌우를 구분하거나, 타겟의 방향에 따라 행동 방식 결정하기 또는 유도 미사일등 다양하게 사용되고 있습니다. 저 역시 공부 중에 기록을 남기고자 작성하였으며, 많은 분들께 도움되길 바랍니다. :)
참고(내적) : https://velog.io/@nacfson/%EC%88%98%ED%95%99Unity-%EB%82%B4%EC%A0%81
참고(외적) : https://velog.io/@nacfson/%EC%88%98%ED%95%99Unity-%EC%99%B8%EC%A0%81
참고(유니티 공식 문서) : https://docs.unity3d.com/kr/530/Manual/UnderstandingVectorArithmetic.html
참고(유투브 참고 영상) : https://www.youtube.com/watch?v=BHhndhjcTsw
'Study' 카테고리의 다른 글
Unity, IK를 이용한 거미 다리 이동 (0) | 2024.02.14 |
---|---|
C#, 포인터의 크기 (Pointer size) (0) | 2023.12.29 |
Unity, Coroutine과 Invoke 차이 (0) | 2023.11.10 |
자료구조, Array와 List 차이 (0) | 2023.10.31 |
Unity, 베지에 곡선으로 포물선 만들기 (Bezier Curve) (0) | 2023.03.01 |
댓글