묻공러
[게임 수학] 벡터의 외적(2)
묻공러
묻지마공부
묻공러
전체
오늘
어제
  • 분류 전체보기 (530) N
    • C (54)
      • [코드조선] C 핵심 (35)
      • [언어본색] C 기초 (19)
    • C++ (72)
      • [루키스] C++ (9)
      • [루키스] 콜백함수 (6)
      • [루키스] STL (8)
      • [루키스] Modern C++ (11)
      • [노코프] C++ (10)
      • [노코프] Tips (16)
      • [일지] C++ (12)
    • C# (20)
      • [루키스] C# (9)
      • [루키스] 자료구조 (3)
      • [루키스] 실전 문법 (8)
    • 자료구조 & 알고리즘 (50)
      • [코드조선] C 자료구조 & 알고리즘 (6)
      • [합격자되기] C++ 코딩테스트 (12)
      • [루키스] C++ 자료구조 & 알고리즘 (32)
    • CS (69)
      • [널널한 개발자] CS 개론 (19)
      • [혼자 공부하는] 컴퓨터 구조 (16)
      • [혼자 공부하는] 운영체제 (18)
      • [널널한 개발자] 네트워크 (16)
    • 게임 그래픽스 (46)
      • [전북대] OpenGL (25)
      • [일지] DirectX (21)
    • 게임 엔진 - 언리얼 (123)
      • [코드조선] 언리얼 (53)
      • [코드조선] 언리얼 데디서버 (8)
      • [일지] 언리얼 (59)
      • [일지] 언리얼 (2) (3)
    • 게임 엔진 - 유니티 (23) N
      • [최적화] 유니티 (4)
      • [루키스] 유니티 (19) N
    • 게임 서버 (17)
    • 게임 수학 & 물리 (19)
      • 게임 수학 (12)
      • 게임 물리 (7)
    • GIT & GITHUB (4)
    • 영어 (18)
      • [The Outfit] 대본 공부 (11)
      • the others (7)
    • 그 외 (14)
      • In (5)
      • Out (5)
      • Review (4)

인기 글

최근 글

hELLO · Designed By 정상우.
게임 수학 & 물리/게임 수학

[게임 수학] 벡터의 외적(2)

2024. 2. 26. 11:32

벡터의 외적 유니티

벡터의 외적은 유니티에서 Vector3.Cross를 이용해 쉽게 구할 수 있다

 

법선벡터


면(두 벡터)의 수직인 벡터를 노멀라이즈 한 것을 법선벡터라고 한다
셰이더에서는 빛이 들어오는 방향과 비치는 부분 등을 계산하는데 활용되고
카메라에서는 보이는 부분인지 안 보이는 부분인지 컬링 하는데 활용된다


벡터의 외적 예시 1

위는 Vec1과 Vec2를 외적 한 벡터를 노란 공(cVec)을 통해 출력하는 예시이며

아래와 같이 구현 가능하다

    void Update()
    {
        CrossVector();

        Vector3 dir = cVec - Vec3.position;
        if (dir.magnitude >= 0.1f) 
        Vec3.position += dir.normalized * Time.deltaTime;
    }

    void CrossVector()
    {
        cVec = Vector3.Cross(Vec1.position, Vec2.position);
       //cVec = Vector3.Cross(Vec2.position, Vec1.position); //교환번칙 성립하지 않는다

        Debug.Log(nameof(cVec) + ":  " + cVec);
        Debug.Log(nameof(Util.MyCross) + ":  " + Util.MyCross(Vec1.position, Vec2.position));

        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        {
            sb.Append("Vec1: " + Vec1.position);
            sb.Append("\n");
            sb.Append("Vec2: " + Vec2.position);
            sb.Append("\n");
            sb.Append("cVec: " + cVec);

            textMesh.text = sb.ToString();
        }
    }

 

 

벡터의 외적 예시 2

위는 목표 벡터를 향해 상하좌우 각도를 조절하는 모습이다

아래와 같이 구현 가능하다

    void Update()
    {
        // 두 벡터의 방향 벡터
        Vector3 dir = Player.position - Target.position;

        // 외적
        Vector3 cross = Vector3.Cross(Player.forward, dir);

        // 좌우
        float dotUP = Vector3.Dot(cross.normalized, Vector3.up);

        // 상하
        float dotRight = Vector3.Dot(crossFor.normalized, Vector3.right);

        Debug.Log("cross: " + cross);
        Debug.Log("dot:  " + dotUP);
        Debug.Log("dotFor: " + dotRight);

        Util.DrawLine(LineDir, dir, Color.yellow, 50f);
        //Util.DrawFowardLine(LineDir, crossFor, Color.yellow, 5f);

        if (Input.GetKey(KeyCode.Space))
        {
            float angleY = dotUP > 0 ? -rotateSpeed : rotateSpeed;
            float y = (angleY * Time.deltaTime) + Player.rotation.eulerAngles.y;

            float angleX = dotRight > 0 ? -rotateSpeed : rotateSpeed;
            float x = (angleX * Time.deltaTime) + Player.rotation.eulerAngles.x;

            Player.rotation = Quaternion.Euler(x, y, 0);
        }

        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        {
            sb.Append("cross: " + cross);
            sb.Append("\n");
            sb.Append("dot: " + dotUP);
            sb.Append("\n");
            sb.Append("dotFor: " + dotRight);

            textMesh.text = sb.ToString();
        }
    }


Player.forward랑 dir을 외적 하는데 
이 외적 한 값이 수평이 되면 0이 된다

두 벡터를 외적한 벡터와 Up벡터를 내적 해서 나오는 값이 음수, 양수, 0이냐 에따라 좌우 판단을 하고
두 벡터를 외적한 벡터와 Right벡터를 내적해서 나오는 값이 음수, 양수, 0이냐 에따라 상하 판단을 할 수 있다

 


벡터의 외적 예시 3

직사각형은 arcTan를 통해 각도를 알아내서 바로 적용한 것이고

원은 외적을 통해 수평이 될 때까지 각도를 조절하도록 작성한 것이다

아래와 같이 구현 가능하다

void Update()
{
    if (target != null)
    {
        Vector3 dirVec = (target.position - transform.position);
        float length = dirVec.magnitude;
        if (length <= 0.01f)
        {
            index++;
            index = (index >= Points.Length) ? 0 : index;

            target = Points[index];
        }

        transform.position += transform.up * moveSpeed * Time.deltaTime;

        Vector3 cross = Vector3.Cross(transform.up, dirVec);

        float dotForward = Vector3.Dot(cross, Vector3.forward);

        float angleZ = dotForward > 0 ? rotateSpeed : -rotateSpeed;
        float z = (angleZ * Time.deltaTime) + transform.rotation.eulerAngles.z;

        transform.rotation = Quaternion.Euler(0, 0, z);
    }
    
// tanget를 통해 알아낸 직사각형의 코드
// float rot = Mathf.Atan(dirVec.y / dirVec.x);
// float degree = rot * Mathf.Rad2Deg;

// if (dirVec.x < 0)
//     degree = 180 + degree;

// transform.rotation = Quaternion.Euler(0, 0, degree);

}

 


벡터의 외적 예시 4

회전된 RotateVecTF를 기준으로 Vec(빨간 공)의 위아래 방향을 알아내는 예시이다

노란 선은 RotateVecTF의 Right를 의미하고

마젠타 선이 Vec(빨간 공)의 방향벡터이고

보라색 선이 외적 한 벡터를 의미한다

그리고 cVec(노란 공)은 외적한 벡터의 z 값을 나타내고 있다

 

이처럼 외적을 통해,

RotateVecTF 아래에 있을 때와 위에 있을 때를 확실히 구분할 수 있다

 

void Update()
{
    CrossVector();

    Vector3 dir = cVec - Vec3.position;
    if (dir.magnitude >= 0.1f) Vec3.position += dir * Time.deltaTime * 5.0f;

    Util.DrawLine(lineRenderer, RotateVecTF.right, Color.yellow, 10.0f);
}

void CrossVector()
{
    Vector3 dir = Vec1.position - RotateVecTF.position;
    cVec = Vector3.Cross(RotateVecTF.right, dir);

    Util.DrawLine(lineRendererDir, dir, Color.magenta, 3.0f);
    Util.DrawLine(lineRendererCross, cVec, Color.blue, 3.0f);

    System.Text.StringBuilder sb = new System.Text.StringBuilder();
    {
        sb.Append("dir: " + dir);
        sb.Append("\n");
        sb.Append("cVec: " + cVec);
        sb.Append("\n");
        string str = cVec.z < 0 ? "아래에 위치" : " 위에 위치";// 굳이 내적하지 않고 cVec.z만 이용
        sb.Append(str);

        textMesh.text = sb.ToString();
    }
}

 

특정 기준을 두고 상하 및 좌우 여부를 판단할 때,

특정 기준의 transform 만을 이용해 그 여부를 판단을 할 때는 문제가 발생한다

 

특히,
transform은 고정되어 있지만 회전을 해서 기울기가 생긴다면
단순히 transform을 통해 판단은 불가능하다

그래서 위 코드처럼 외적을 이용해서 판단을 한다


또한, RotateVecTF.right가 기준이 되어 dir을 외적 한 다음
굳이 Dot(내적)을 통해 스칼라 값으로 변경하지 않고 cVec.z값으로만 판단을 했다

 

 

정리

// 위에 나온 예시 코드들 중 일부
Vector3 dir = Player.position - Target.position;

Vector3 cross = Vector3.Cross(Player.forward, dir);
float dotUP = Vector3.Dot(cross.normalized, Vector3.up);

 

앞선 예시들을 통해 코드들을 분석하면

1) dir과 기준 오브젝트(ex. 플레이어)의 특정 방향을 외적을 하고

2) 그 외적한 벡터를 스칼라(값)로 변경하기 위해서

특정한 기준(ex. Vector3.forward)과 함께 내적 했다는 사실을 알 수 있다

 

다시 정리하면,

아래와 같은 형태로 작성이 된다

cross = Cross(dir, A)
dot = Dot(cross, B)
// dot의 부호를 통해 각도를 확인할 수 있다


그리고 A와 B에 들어오는 종류는 아래와 같다


A:
1) 기준 오브젝트(플레이어)의 forward:

주로 3D 백뷰 게임에서 사용된다

주로 캐릭터나 객체가 바라보는 방향을 나타낸다

 

2) 기준 오브젝트(플레이어)의 up:

주로 2D 탑뷰 게임에서 사용된다

주로 캐릭터나 객체의 상단 방향을 나타낸다

B:
A가 기준 오브젝트(플레이어) 의 Forward인 경우에,
1) Vector3.Up: 좌우 방향을 측정한다
2) Vector3.Right: 상하 방향을 측정한다

A가 기준 오브젝트(플레이어)의 Up인 경우에,
1) Vector3.Forward: 좌우 방향을 측정한다
2) Vector3.Right: 상하 방향을 측정한다

 

결국 핵심은

플레이어의 Up(2D) 혹은 Forward(3D) 벡터와 dir벡터의 외적 한 벡터를

우리가 원하는 기준 축과 내적 해서

그 값을 통해 각도 및 방향을 알아내는 것이다

저작자표시 비영리 변경금지 (새창열림)

'게임 수학 & 물리 > 게임 수학' 카테고리의 다른 글

[게임 수학] 행렬(2)  (0) 2024.02.28
[게임 수학] 행렬(1)  (0) 2024.02.27
[게임 수학] 벡터의 외적 (1)  (0) 2024.02.25
[게임 수학] 벡터의 내적 (2)  (1) 2023.10.28
[게임 수학] 벡터의 내적 (1)  (0) 2023.10.28
'게임 수학 & 물리/게임 수학' 카테고리의 다른 글
  • [게임 수학] 행렬(2)
  • [게임 수학] 행렬(1)
  • [게임 수학] 벡터의 외적 (1)
  • [게임 수학] 벡터의 내적 (2)
묻공러
묻공러
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.