참고
- 쿼터니언으로 구현한 단진자의 운동
- 쿼터니언으로 구현한 단진자의 운동 확장
- 독립된 단진자의 운동
- 런타임에 단진자 운동 설정하기
투명한 Plane을 추가해서 그림으로 보면 아래와 같은 상황이다. (x = 0으로 고정)
Plane의 설정은 현재 아래와 같다.
마찬가지로 pivot과 object의 좌표도 x = 0이다.
이제 object의 x 좌표를 변경해보자.
현재의 코드대로라면 아래와 같이 x 축이 고정된 채로 부자연스럽게 단진자 운동을 하게 된다.
x = 0이라고 가정한 코드이기 때문에 수정이 필요하다
오브젝트가 어디에 있던지 간에 자연스럽게 움직일 수 있도록 해보자.
평면 추가
먼저 원할한 디버깅을 위해 Pivot 아래에 UnderPivot이라는 임의의 오브젝트를 추가한다.
UnderPivot은 Pivot과 (x, z) 좌표는 같고, y 좌표만 다르다.
Oscillator가 어디에 있던, 단진자는 Pivot, UnderPivot, Oscillator 세 점을 지나는 평면에서 움직이게 된다.
세 점을 지나는 평면 구하기를 참고하여 아래의 코드를 추가해보자.
Vector3 getNormal(Vector3 a, Vector3 b, Vector3 c)
{
Plane p = new Plane(a, b, c);
return p.normal;
}
void setPlane(Vector3 a, Vector3 b, Vector3 c)
{
plane.transform.position = a;
plane.transform.up = getNormal(a, b, c);
}
void Start()
{
...
setPlane(pivot.position + Vector3.down, pivot.transform.position, this.transform.position);
}
처음에는 세 오브젝트가 모두 평면에 존재한다.
하지만, 단진자는 평면에서 움직이지 않는다.
코드 확장
문제가 되는 코드는 getRotateQuaternion 함수다.
angle을 보면 new Vector3에서 x축에만 값이 들어간다.
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;
}
이것을 노멀 벡터를 기준으로 회전하도록 변경하면 된다.
AngleAxis를 이용하면 노멀 벡터를 기준으로 angle만큼 회전할 수 있다.
Quaternion getRotateQuaternion(float angle, Vector3 normal)
{
Quaternion current = Quaternion.Euler(new Vector3(0, 0, 0));
Quaternion quaternion = Quaternion.AngleAxis(angle, normal);
return current * quaternion;
}
normal은 pivot의 아래, pivot, 진자를 기준으로 만들었다.
반대로 만들 경우, start/endQt의 normal에 -를 곱해야한다.
Vector3 normal
= getNormal(pivot.position + Vector3.down, pivot.transform.position, this.transform.position);
setPlane(pivot.position + Vector3.down, pivot.transform.position, this.transform.position);
startQt = getRotateQuaternion(0, normal);
endQt = getRotateQuaternion(2 * angle, normal);
전체 코드는 다음과 같다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ExpandedSimpleHarmonicOscillator : MonoBehaviour
{
public Transform pivot;
public float speed = 2.0f;
public GameObject plane;
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, Vector3 normal)
{
Quaternion current = Quaternion.Euler(new Vector3(0, 0, 0));
Quaternion quaternion = Quaternion.AngleAxis(angle, normal);
return current * quaternion;
}
Vector3 getNormal(Vector3 a, Vector3 b, Vector3 c)
{
Plane p = new Plane(a, b, c);
return p.normal;
}
void setPlane(Vector3 a, Vector3 b, Vector3 c)
{
plane.transform.position = a;
plane.transform.up = getNormal(a, b, c);
}
void Start()
{
float angle = Vector3.Angle(this.transform.position - pivot.position, Vector3.down);
Vector3 normal
= getNormal(pivot.position + Vector3.down, pivot.transform.position, this.transform.position);
setPlane(pivot.position + Vector3.down, pivot.transform.position, this.transform.position);
startQt = getRotateQuaternion(0, normal);
endQt = getRotateQuaternion(2 * angle, normal);
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에서 확인 가능하다.
Unity Plus:
Unity Pro:
Unity 프리미엄 학습:
'개발 > Unity' 카테고리의 다른 글
유니티 - 런타임에 단진자 운동 설정하기 (Runtime Independent Simple Pendulum) (0) | 2023.03.29 |
---|---|
유니티 - 독립된 단진자의 운동 (Independent Simple Pendulum with Unity LerpAngle) (0) | 2023.03.29 |
유니티 - 쿼터니언으로 구현한 단진자의 운동 (Simple Pendulum with Unity Quaternion) (0) | 2023.03.29 |
유니티 - 세 점을 지나는 평면 구하기 (Creating a Plane from 3 Dots) (0) | 2023.03.27 |
유니티 - 스트로보 효과 (Stroboscopic Effect with Unity) (0) | 2023.03.26 |
댓글