참고
- 쿼터니언으로 구현한 단진자의 운동
- 쿼터니언으로 구현한 단진자의 운동 확장
- 독립된 단진자의 운동
- 런타임에 단진자 운동 설정하기
쿼터니언으로 구현한 단진자의 운동의 경우 pivot을 회전시키고, pivot의 자식으로 단진자를 설정해야 한다.
이러한 제약 조건은 나중에 개발을 확장할 때 불편할 수 있다.
LerpAngle 메서드를 이용하면 부모 - 자식 관계가 아닌 독립된 상태에서 단진자 운동을 구현할 수 있다.
Mathf.LerpAngle도 Quaternion.Lerp와 원리가 같으므로, 시작 각도, 도착 각도가 필요하다.
그리고 최초 세 점을 지나는 평면(pivot, pivot 바로 아래, 단진자)을 저장한다.
pivot → oscillator 벡터의 최초 상태는 startPO에 저장하고 두 오브젝트의 사이도 distance에 저장해둔다.
float startAngle, endAngle;
Vector3 startPlaneNormal;
Vector3 startPO;
float distance;
angle은 처음 0º에서 2Θ를 움직이게 된다.
normal은 이전에 만들어 둔 getNormal로 구한다.
void Start()
{
float angle = Vector3.Angle(this.transform.position - pivot.position, Vector3.down);
startAngle = 0.0f; endAngle = angle * 2;
Vector3 normal
= getNormal(pivot.position + Vector3.down, pivot.transform.position, this.transform.position);
startPlaneNormal = normal;
setPlane(pivot.position + Vector3.down, pivot.transform.position, this.transform.position);
startPO = (this.transform.position - pivot.position).normalized;
distance = Vector3.Distance(this.transform.position, pivot.position);
}
시간에 따라 angle이 변화하게 될 것이고, 이 angle을 평면에 대한 노멀 벡터에 대해 회전시킨다.
pivot → oscillator 벡터가 AngleAxis에 의해 회전될 것이고,
pivot의 위치에서 변화한 벡터에 distance만큼 곱해서 더해주면 현재의 진자의 위치가 될 것이다.
void FixedUpdate()
{
startRot += (Time.fixedDeltaTime * speed);
float angle
= Mathf.LerpAngle(startAngle, endAngle, (Mathf.Sin(startRot - Mathf.PI / 2) + 1.0f) / 2.0f);
Vector3 vPO
= Quaternion.AngleAxis(angle, startPlaneNormal) * startPO;
this.transform.position
= pivot.transform.position + (vPO).normalized * distance;
}
즉, pivot을 회전시키는 것이 아니라, 단진자의 위치 자체를 직접 수정하므로 부모-자식 관계를 맺을 필요가 없다.
게임을 실행하면 pivot은 회전하지 않고 단진자만 움직인다.
전체 코드는 다음과 같다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ExpandedSimpleHarmonicOscillator : MonoBehaviour
{
public Transform pivot;
public float speed = 2.0f;
public GameObject plane;
float startAngle, endAngle;
Vector3 startPlaneNormal;
Vector3 startPO;
float distance;
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;
}
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);
startAngle = 0.0f; endAngle = angle * 2;
Vector3 normal
= getNormal(pivot.position + Vector3.down, pivot.transform.position, this.transform.position);
startPlaneNormal = normal;
setPlane(pivot.position + Vector3.down, pivot.transform.position, this.transform.position);
startPO = (this.transform.position - pivot.position).normalized;
distance = Vector3.Distance(this.transform.position, pivot.position);
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);
float angle
= Mathf.LerpAngle(startAngle, endAngle, (Mathf.Sin(startRot - Mathf.PI / 2) + 1.0f) / 2.0f);
Vector3 vPO
= Quaternion.AngleAxis(angle, startPlaneNormal) * startPO;
this.transform.position
= pivot.transform.position + (vPO).normalized * distance;
}
}
위의 실행결과는 아래의 unitypackage에서 확인 가능하다.
Unity Plus:
Unity Pro:
Unity 프리미엄 학습:
'개발 > Unity' 카테고리의 다른 글
유니티 - 라인 렌더러를 이용한 단진자 속도의 시각화 (0) | 2023.04.03 |
---|---|
유니티 - 런타임에 단진자 운동 설정하기 (Runtime Independent Simple Pendulum) (0) | 2023.03.29 |
유니티 - 쿼터니언으로 구현한 단진자의 운동 확장 (Expanded Simple Pendulum with Unity Quaternion) (0) | 2023.03.29 |
유니티 - 쿼터니언으로 구현한 단진자의 운동 (Simple Pendulum with Unity Quaternion) (0) | 2023.03.29 |
유니티 - 세 점을 지나는 평면 구하기 (Creating a Plane from 3 Dots) (0) | 2023.03.27 |
댓글