프로젝트를 하면서 Mathf.Sin()과 Quaternion.Lerp() 를 사용할 일이 생겨 사용하는 김에 어떤것이고 어떨때 필요한지를 정리하기 위해 작성하는 포스트이다.
Mathf.Sin(), Math.Cos()
Sin, Cos함수 Mathf 구조체 안에 있다.
Sin Cos 는 각각 각도에 따라 Sin은 높이를, Cos는 밑변을 나타내는 함수이다.
빗변의 길이는 1로 유니티에서 정해줬으며 이에 따른 함수 내에 매개변수로 각도를 정해줄 수 있다.
그렇다면 이를 주기적으로 변하게 하려면 어떤식으로 할 수 있는가? 그건 현재 게임 시간을 특정 수와 곱해주면 된다.
특정 수는 해당 물체의 속도가 될것이다. 왜냐하면 시간마다 각도가 변하는데 시간은 일정하게 흐르지만 이를 높은 수를 곱할수록 더 빠르게 각이 변하기 때문에 속도가 올라가는 것이다.
코드 적용
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
public class SwingObject : MonoBehaviour
{
public float swingSpeed = 2.0f; // 판자의 흔들리는 속도
public float swingAngle = 30.0f; // 판자의 최대 흔들리는 각도
void Update()
{
// swing
float angle = Mathf.Sin(Time.time * swingSpeed) * swingAngle;
Debug.Log(angle);
// 판자 rotation값 변화
transform.rotation = Quaternion.Euler(angle, transform.rotation.eulerAngles.y, transform.rotation.eulerAngles.z);
}
}
위 코드는 판자가 그네처럼 움직이는 코드이다.
보면 float angle에 Sin값에 특정 각도를 곱해주고있다.
천천히 살펴보면 위에서 말했듯이 게임 시간에 특정 값(속도) 를 곱해주므로써 주기적으로 각을 높여주고 있고, 이 최대치를 정해주기 위해 swingAngle이라는 최댓값을 임의로 정해서 곱해주고 있다.
이를 현재 오브젝트의 rotation값에 Quaternion.Euler의 값을 각각 넣어주고있다.
그렇다면 Quaternion.Euler() 는 또 대체 무엇인가?
Quaternion
Quaternion이라고 하면 3D 컴퓨터 그래픽스에서 회전을 나타내는 수학적 개체를 말한다. 보통 3D 에서 회전을 표현하는데 사용된다.
Quaternion은 세 개의 표준 축(x, y, z)를 기준으로 회전을 표현하며 각 축을 따라 얼마나 회전되었는지를 나타내는데 사용된다.
Euler각 즉, 각 축을 따라 얼마나 회전되었는지를 나타내는 값으로 Quaternion.Euler를 사용한다.
Quaternion.Euler()
위에서 말했듯 Euler 각도는 특정 축을 중심으로 회전된 각도를 나타내는 방식이다.
Quaternion.Euler(float x, float y, float z); 이렇게 나타내며
x는 x축을 중심으로 하는 회전 각도, y는 y축을 중심으로 하는 회전 각도, z는 z축을 중심으로 하는 회전각도를 의미한다.
예를들어 Quaternion.Euler(0f, 45f, 0f); 가 있다고 치면 y축을 중심으로 회전하는 Quaternion을 말하는 것이다.
그렇다면 위 코드에서 이부분이 어느정도는 해소될것이다.
transform.rotation = Quaternion.Euler(angle, transform.rotation.eulerAngles.y, transform.rotation.eulerAngles.z);
현재 물체의 rotation값을 아까 Sin값으로 특정 값까지 각도를 올려주거나 내려주는 것을 반복하는 값을 x축으로 하여 x축을 중심으로 돌면서 나머지값은 transform.eulerAngles 을 통해 현재 값을 유지해주는 역할을한다.
그래서 해당 코드를 정리하자면 특정 1 ~ -1 사이를 반복하면서 일정한 속도로 특정 값만큼 각도가 변화하는 값을 x축을 중심으로 물체를 회전시키는 코드라고 볼 수 있다.
Quaternion.Lerp()
Quaternion.Lerp 쿼터니언의 중간의 값을 반환하여 부드러운 효과를 준다. Quaternion.Lerp(시작 쿼터니언, 타겟 쿼터니언, 0~1까지 있는 시간)
그래서 코루틴을 통해 시작 시간과 도착 시간을 정해 시작시간을 deltatime을 더해주면서 시작 시간이 도착 시간보다 작을 때 현재 쿼터니언에서 목표 쿼터니언까지 부드럽게 변화되게 된다.
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Rendering;
using UnityEngine;
public class DoorObjectInteraction : MonoBehaviour
{
[SerializeField] private float rotY = 0.5f;
private Rigidbody _rigidBody;
private GameObject _gameObject;
private Quaternion _objectRotation;
private bool _isInteracting = false;
private void Start()
{
_rigidBody = GetComponent<Rigidbody>();
_gameObject = _rigidBody.gameObject;
_objectRotation = gameObject.transform.rotation;
Debug.Log(_objectRotation.y);
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Player"))
{
Debug.Log("???");
//InteractDoor();
StartCoroutine(InteractDoor());
}
}
/// <summary>
/// 코루틴을 이용해 문을 회전
/// </summary>
/// <returns></returns>
private IEnumerator InteractDoor()
{
_isInteracting = true;
Quaternion currentRotation = _gameObject.transform.rotation; // 오브젝트의 현재 rotaion값
Quaternion targetRotation = Quaternion.Euler(currentRotation.eulerAngles + new Vector3(0f, -90f, 0f)); // 내가 원하는 rotation값
float elapsedTime = 0f;
float duration = 0.3f; // 회전에 걸리는 시간
// 회전 시간
while (elapsedTime < duration)
{
// Quaternion.Lerp 쿼터니언의 중간의 값을 반환하여 부드러운 효과를 줌, Quaternion.Lerp(시작 쿼터니언, 타겟 쿼터니언, 0~1까지 있는 시간)
_gameObject.transform.rotation = Quaternion.Lerp(currentRotation, targetRotation, elapsedTime / duration);
elapsedTime += Time.deltaTime;
yield return null;
}
_gameObject.transform.rotation = targetRotation;
}
}
해당 코드는 충돌시에 코루틴이 발동하며 현재 오브젝트의 rotation값과 내가 원하는 rotation값을 정해 이를 필요한 시간으로 부드럽게 변화시켜주는 역할을 한다.
실행하면 아래와 같다.
'Unity' 카테고리의 다른 글
유니티 SkyBox로 배경 꾸미기 (0) | 2024.01.04 |
---|---|
AddForce() (0) | 2024.01.03 |
로딩 구현하기 (0) | 2023.12.28 |
[FSM] 플레이어 상태머신 (2) (0) | 2023.12.27 |
[FSM] 플레이어 StateMachine 만들어보기 (1) | 2023.12.26 |