6일차 요약(회전, Collider, RigidBody)
회전
- 회전은 크게 오일러, 쿼터니언으로 구분된다. (오일러: (x, y, z), 쿼터니언: (x, y, z, w))
- 오일러 방식으로 회전을 적용하면 짐벌락이라는 문제가 생긴다.
- 짐벌락: 하나의 축이 다른 축과 겹쳐져 구분이 되지 않는 상태
- 오일러 → 쿼터니언: Quaternion.Euler(Vector3)
- 쿼터니언 → 오일러: Quaternion(변수).eulerAngles;
- 회전시키는 함수
- Rotate(Axis * Degree) : Axis(축)을 기준으로 Dgree만큼 회전
- RotateAround(TargetPos, Axis, Degree): TargetPos의 Axis를 기준으로 Speed만큼 회전
- LookAt(Transform, Axis): Transform을 바라보며 Axis를 축으로 회전
- 이외에도 많은 오버로딩 버전이 존재
Collider
- 물체의 충돌 및 감지를 담당하는 Component
- 두 물체의 충돌이 이벤트로 처리되기 위해서는 양쪽 모두 Collider가 존재해야 함
- IsTrigger라는 변수로 충돌, 감지 이벤트를 설정
- IsTrigger = false: 충돌
- OnCollisionEnter: 충돌 시작
- OnCollisionStay: 충돌 중
- OnCollisionExit: 충돌 종료
- IsTrigger = ture: 감지(Overlap)
- OnTriggerEnter: 감지 시작
- OnTriggerStay: 감지 중
- OnTriggerExit: 감지 종료
- IsTrigger = false: 충돌
RigidBody
- 물체의 물리 작용(중력, 속도, 가속도 등)을 담당하는 Component
- 충돌 처리를 위해서는 충돌한 두 물체중 적어도 하나에는 해당 Component가 존재해야 한다.
회전
회전은 크게 오일러, 쿼터니언 방식으로 나뉜다.
- 오일러: 0º ~ 360º로 표시 (x, y, z)
- 쿼터니언: 사원수를 이용한 회전 표현 (x, y, z, w)
오일러 회전은 이해가 가능한 수치로 표시가 되기 때문에 편리하지만 짐벌락과 같은 문제가 발생할 수 있다.
짐벌락: 임의의 축을 90º 회전하면 다른 축과 겹쳐져 병합된 상태
출처 | https://hub1234.tistory.com/21 |
이를 해결하는 방법이 쿼터니언을 사용하는 것이다.
쿼터니언은 가상의 축을 기반으로 x, y, z 세 축이 동시에 회전하는 것이다.
쿼터니언은 복잡한 계산 과정을 행렬 연산을 통해 결과를 내므로 수치를 보고 사람이 판단하기는 쉽지 않다.
즉, 짐벌락을 방직하기 위해서는 쿼터니언을 사용해야 하지만 알아볼 수 없는 값이기 때문에 불편한 부분이 있다.
이를 Quaternion이라는 struct를 사용하면 편리하게 사용할 수 있다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ExampleClass : MonoBehaviour
{
void Start()
{
//월드상 원점(0, 0, 0)으로 회전
transform.rotation = Quaternion.identity;
transform.rotation = Quaternion.Euler(new Vector3(0f, 130f, 0));
Vector3 targetRotation = new Vector3(0f, 130f, 0f);
transform.rotation = Quaternion.Euler(targetRotation);
}
}
Vector3를 통해 회전값(Degree)을 설정하고 Quaternion.Euler()를 통해 쿼터니언으로 변환한 후 rotation에 대입한다.
반대로 현재의 rotation을 Vector3로 변환하는 방법은 다음과 같다.
var currentRot = transform.rotation.eulerAngles;
이를 활용하여 키입력을 통해 90º씩 회전하게 만들어 보았다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
var currentRot = transform.rotation.eulerAngles;
transform.rotation = Quaternion.Euler(currentRot + new Vector3(0f, 90f, 0f));
}
}
}
현재 rotation을 받아와 직접 더해줘도 동작하지만, 함수를 사용하면 더욱 쉽게 회전시킬 수 있다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
transform.Rotate(new Vector3(0f, 90f, 0f));
}
}
}
또한, 특정 대상의 특정 축을 기준으로 회전하는 함수도 있다.
transform.RotateAround(target.transform.position, Vector3.up, rotSpeed * Time.deltaTime);
그리고 특정 대상을 바라보게 강제하는 함수도 있다.
transform.LookAt(Target.transform, Vector3.up);
Asset Import
Asset을 Import하는 방법은 다음과 같다.
- Services를 눌러 Explore를 누르면 PackageManger를 연다.
- Import하고 싶은 Asset을 선택한다.
- My Assets에서는 자신의 계정에서 다운로드한 Asset들을 확인할 수 있다.
- Download를 누른 뒤 Import를 통해 현재 프로젝트에 추가할 수 있다.
만약, Import했을 때 다음과 같이 이상하게 표시된다면 Material이 깨져서 그런 것이다.
Import한 Resource는 URP이고 현재 프로젝트는 Built-in이라 Material이 호환되지 않아 제대로 적용되지 않은 것이다.
그렇다면, 깨진 Material의 Shader를 알맞은 형식으로 변경해 주면 된다.
Collider
Collider란 충돌이나 감지에 대한 이벤트를 처리하는 Component이다.
Collider의 종류에는 Box, Capsule, Sphere, Mesh 등으로 다양한 모양을 갖는다.
Mesh Collider는 Mesh를 Collider로 설정하는 것이다.
하지만, 아무리 RowPoly라고 해도 많은 primitive를 갖는다.
따라서, 부하가 심해질 수 있다.
만약, 형태에 맞는 많은 디테일이 요구되는 충돌 및 감지 이벤트를 처리할 때만 사용한다고 생각할 수 있다.
Colldier는 기본 형태를 변형하여 적용할 수 있다.
해당 버튼을 누르면 다음과 같이 Collider를 수정할 수 있다.
Wireframe View를 켜주고 초록색 점이 각 면에 생긴 것을 볼 수 있다.
점을 잡고 늘리거나 줄이는 등으로 크기를 조절할 수 있으며 Inspector에서도 수치값을 조정할 수 있다.
Collider는 기본적으로 충돌(Collision) 이벤트를 감지한다.
IsTrigger를 활성화한다면 충돌이 아닌 Trigger를 감지하도록 설정할 수 있다.
단, 두 물체가 충돌하기 위해서는 두 물체 모두에 Collider가 있어야 하며 하나의 물체에는 RigidBody가 있어야 한다.
또한, 하나의 물체라도 IsTrigger가 켜져 있지 않아야 한다.
이외의 경우에는 모두 충돌하지 않고 Trigger 이벤트만 처리하게 된다.
빨간색 큐브는 IsTrigger가 false이고, 파란색 큐브는 IsTrigger가 true이다.
Collider의 충돌, 감지 이벤트를 처리하는 script는 다음과 같다.
- CollisionEvent(IsTrigger = false)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ColliderEvent : MonoBehaviour
{
public void OnCollisionEnter(Collision collision)
{
Debug.Log("Collision Enter");
}
public void OnCollisionStay(Collision collision)
{
Debug.Log("Collision Stay");
}
public void OnCollisionExit(Collision collision)
{
Debug.Log("Collision Exit");
}
}
Event에 대한 Callback으로 Collision이라는 매개변수를 전달받는다.
Collision이라는 클래스에는 다음과 같은 값들이 포함되어 있다.
//총 충격량
public Vector3 impulse => m_Pair.ImpulseSum;
//두 물체의 상대 속도
public Vector3 relativeVelocity => m_Flipped ? m_Header.m_RelativeVelocity : (-m_Header.m_RelativeVelocity);
//충돌한 rigidbody(없으면 null)
public Rigidbody rigidbody => body as Rigidbody;
//충돌한 ArticulationBody(관절)
public ArticulationBody articulationBody => body as ArticulationBody;
//충돌한 body
public Component body => m_Flipped ? m_Header.Body : m_Header.OtherBody;
//충돌한 Collider
public Collider collider => m_Flipped ? m_Pair.Collider : m_Pair.OtherCollider;
//충돌위치
public Transform transform => (rigidbody != null) ? rigidbody.transform : collider.transform;
//충돌한 gameObject
public GameObject gameObject => (body != null) ? body.gameObject : collider.gameObject;
//충돌수
public int contactCount => (int)m_Pair.m_NbPoints;
//접촉점들
public ContactPoint[] contacts
{
get
{
if (m_LegacyContacts == null)
{
m_LegacyContacts = new ContactPoint[m_Pair.m_NbPoints];
m_Pair.ExtractContactsArray(m_LegacyContacts, m_Flipped);
}
return m_LegacyContacts;
}
}
충돌한 위치나 상대 속도 등 유용한 값들이 있다.
- TriggerEvent(IsTrigger = false)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TriggerEvent : MonoBehaviour
{
public void OnTriggerEnter(Collider other)
{
Debug.Log("Trigger Enter");
}
public void OnTriggerStay(Collider other)
{
Debug.Log("Trigger Stay");
}
public void OnTriggerExit(Collider other)
{
Debug.Log("Trigger Exit");
}
}
TriggerEvent는 Collider를 매개변수로 전달받는다.
전달받은 Collider로 gameObject를 받아오거나 하는 등의 처리가 가능해 보인다.
Collision은 충격량이나 속도 등 물리적인 작용이 추가로 필요하기 때문에 그와 관련된 다른 값들을 포함한 Collision 클래스를 매개변수로 전달받는 듯 하다.
하지만, TriggerEvent의 경우 추가적인 물리 작용이 일어나지 않고 Overlap된 물체만 감지하면 되기 때문에 Collider를 매개변수로 전달 받는 것 같다.
RigidBody
RigidBody는 Collider의 이벤트를 처리하는 계산기와 같은 Component이다.
만약, 두 물체가 충돌했을 때, 두 물체 모두 RigidBody를 소유하지 않았다면 두 물체의 충돌은 무시된다.
즉, 어떠한 이벤트도 일어나지 않는다.
RigidBody는 중력, 속도, 가속도, 저항 등 물리 연산을 담당하는 역할을 한다.
그렇기 때문에 일반적으로 움직이는 물체에 RigidBody를 부착한다.