본문 바로가기
개발/Unity

유니티 - 쿼터니언으로 구현한 단진자의 운동 (Simple Pendulum with Unity Quaternion)

by 피로물든딸기 2023. 3. 29.
반응형

Unity 전체 링크

 

참고

- 쿼터니언과 회전의 덧셈

- 쿼터니언으로 구현한 단진자의 운동
- 쿼터니언으로 구현한 단진자의 운동 확장
- 독립된 단진자의 운동
- 런타임에 단진자 운동 설정하기

 

빨간색 Sphere를 pivot으로 하는 단진자를 Quaternion.Lerp를 이용해서 구현해보자.


쿼터니언의 Lerp 메서드

 

Quaternion.Lerp(start, end, float t = [0 ~ 1])은 0에 가까우면 start의 각도가, 1에 가까우면 end의 각도가 된다.

값이 0.5라면 start와 end의 중심이 된다.

 

단진자는 가운데로 갈수록 속도가 커지고 양 옆에서는 속도가 0이 된다.

그리고 이것이 계속 반복된다.

 

이러한 조건을 잘 만족하는 함수는 삼각함수이다.

그런데 sinΘ 함수는 -1 ~ 1사이의 값을 가지므로, 전체 값에서 1을 증가시킨다.

그러면 sinΘ + 1 = 0  ~ 2가 되는데, 쿼터니언의 Lerp는 [0 ~ 1] 사이의 값을 넣어줘야 하므로 2로 나눈다.

 

위치가 일정하게 제대로 호출되기 위해서 FixedUpdate에 위의 내용을 구현하면 다음과 같다.

    void FixedUpdate()
    {
        startRot += (Time.fixedDeltaTime * speed);
        pivot.rotation 
            = Quaternion.Lerp(startQt, endQt, (Mathf.Sin(startRot - Mathf.PI / 2) + 1.0f) / 2.0f);
    }

Mathf.PI / 2 (= 90º)를 빼는 이유는 최초의 startRot이 0일 때, (sin(0) + 1) / 2 = 0.5가 되기 때문이다.

따라서 -90º만큼 빼줘야 startQt부터 시작하게 된다.

 

이제 각도 Θ에 대해 알아보자.

위 식에서 Θ는 pivot의 중심 아래로 내려오는 벡터와 (pivot → 오브젝트) 벡터가 만드는 각도다.

 

식으로 나타내면 다음과 같다.

float angle = Vector3.Angle(this.transform.position - pivot.position, Vector3.down);

 

그리고 시작점에서 최대 2Θ 만큼 각이 변하게 될 것이다.

 

쿼터니언의 곱셈으로 오브젝트의 각을 변화할 수 있으므로, 시작점과 끝점의 쿼터니언을 구할 수 있다.

여기서 pivot의 Rotation은 모두 0이라고 가정한다.

    Quaternion getRotateQuaternion(float angle)
    {
        Quaternion current = Quaternion.Euler(new Vector3(0, 0, 0));
        Quaternion quaternion = Quaternion.Euler(new Vector3(angle, 0, 0));

        return current * quaternion;
    }

    void Start()
    {
        float angle = Vector3.Angle(this.transform.position - pivot.position, Vector3.down);

        startQt = getRotateQuaternion(pivot, 0);
        endQt = getRotateQuaternion(pivot, 2 * angle * dir);
    }

 

그런데 위의 경우는 오브젝트가 왼쪽에 있다고 가정한 경우이다.

오른쪽인 경우도 보완하면 아래와 같은 식이 만들어진다. (오른쪽에 있다면 -2Θ 만큼 변화)

    void Start()
    {
        float angle = Vector3.Angle(this.transform.position - pivot.position, Vector3.down);
        float dir = (pivot.position.z < this.transform.position.z) ? 1.0f : -1.0f;

        startQt = getRotateQuaternion(pivot, 0);
        endQt = getRotateQuaternion(pivot, 2 * angle * dir);
    }

 

FixedUpdate에서 pivot이 회전하도록 하였으므로, 오브젝트를 pivot의 자식으로 만든다.

 

게임을 실행하면 오브젝트가 왼쪽이든 오른쪽이든 잘 이동하는 것을 알 수 있다.

 

라인 렌더러 관련된 코드는 전체 코드를 참고하자.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SimpleHarmonicOscillator : MonoBehaviour
{
    public Transform pivot;
    public float speed = 2.0f;

    Quaternion startQt, endQt;

    public GameObject lineRenderer;
    LineRenderer[] lrs;

    float startRot = 0.0f;   

    void setLineRenderer(LineRenderer lr, Color color)
    {
        lr.startWidth = lr.endWidth = .1f;
        lr.material.color = color;

        lr.positionCount = 2;
    }

    Quaternion getRotateQuaternion(float angle)
    {
        Quaternion current = Quaternion.Euler(new Vector3(0, 0, 0));
        Quaternion quaternion = Quaternion.Euler(new Vector3(angle, 0, 0));

        return current * quaternion;
    }

    void Start()
    {
        float angle = Vector3.Angle(this.transform.position - pivot.position, Vector3.down);
        float dir = (pivot.position.z < this.transform.position.z) ? 1.0f : -1.0f;

        startQt = getRotateQuaternion(0);
        endQt = getRotateQuaternion(2 * angle * dir);
   
        lrs = lineRenderer.GetComponentsInChildren<LineRenderer>();
        setLineRenderer(lrs[0], Color.blue);
        lrs[0].SetPosition(0, pivot.position);
    }

    void Update()
    {
        lrs[0].SetPosition(1, this.transform.position);
    }

    void FixedUpdate()
    {
        startRot += (Time.fixedDeltaTime * speed);
        pivot.rotation 
            = Quaternion.Lerp(startQt, endQt, (Mathf.Sin(startRot - Mathf.PI / 2) + 1.0f) / 2.0f);
    }
}

 

위의 실행결과는 아래의 unitypackage에서 확인 가능하다.

SimpleHarmonicOscillator.unitypackage
0.02MB

 

Unity Plus:

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Unity Pro:

 

Unity Pro

The complete solutions for professionals to create and operate.

unity.com

 

Unity 프리미엄 학습:

 

Unity Learn

Advance your Unity skills with live sessions and over 750 hours of on-demand learning content designed for creators at every skill level.

unity.com

반응형

댓글