반응형
참고
- 쿼터니언으로 구현한 단진자의 운동
- 쿼터니언으로 구현한 단진자의 운동 확장
- 독립된 단진자의 운동
- 라인 렌더러로 간단한 화살표 만들기
라인 렌더러를 이용해 간단한 화살표를 만들어보자.
이전 글에서 라인 렌더러로 선을 그었으니 그 반대의 방향으로 선을 만들 수 있다.
이 벡터를 양 옆으로 정해진 각도만큼 움직인다.
그러면 3개의 점으로 삼각형을 추가하면 화살표가 만들어진다.
코드로 보면 다음과 같다.
여기서 기준이 되는 normal은 startPlaneVector가 된다.
void makeArrow(LineRenderer lr, Vector3 start, Vector3 end, Vector3 normal)
{
Vector3 vES = (start - end) * ratio;
Vector3 dot1 = end + Quaternion.AngleAxis(theta, normal) * vES;
Vector3 dot2 = end + Quaternion.AngleAxis(360 - theta, normal) * vES;
lr.positionCount = 5;
lr.SetPosition(0, start);
lr.SetPosition(1, end);
lr.SetPosition(2, dot1);
lr.SetPosition(3, dot2);
lr.SetPosition(4, end);
}
속도의 방향에 알맞게 화살표가 생성된 것을 알 수 있다.
그리고 ratio와 theta를 조절해서 화살표의 크기를 적절히 조절할 수 있다.
전체 코드는 다음과 같다.
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 gravity = 1.0f;
float startAngle, endAngle;
Vector3 startPlaneNormal;
Vector3 startPO;
float distance;
public GameObject lineRenderer;
LineRenderer[] lrs;
float startRot = 0.0f;
bool isDragging;
[Range(0.0f, 45.0f)]
public float theta = 30.0f;
[Range(0.0f, 1.0f)]
public float ratio = 0.1f;
float totalEnergy;
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 OnMouseDown()
{
isDragging = true;
}
void OnMouseDrag()
{
float distance = Camera.main.WorldToScreenPoint(transform.position).z;
Vector3 mousePos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance);
Vector3 objPos = Camera.main.ScreenToWorldPoint(mousePos);
objPos.x = 0;
this.transform.position = objPos;
}
void OnMouseUp()
{
initSettings();
isDragging = false;
}
void initSettings()
{
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);
startRot = 0.0f;
totalEnergy = this.transform.position.y; // Potential Energy = mgh
}
void Start()
{
initSettings();
lrs = lineRenderer.GetComponentsInChildren<LineRenderer>();
setLineRenderer(lrs[0], Color.blue);
lrs[0].SetPosition(0, pivot.position);
setLineRenderer(lrs[1], Color.red);
}
int getCurrentState()
{
float hPi = Mathf.PI / 2.0f;
return (int)(startRot / hPi) % 4;
}
float getNormalDirection()
{
return getCurrentState() < 2 ? 1.0f : -1.0f;
}
void Update()
{
lrs[0].SetPosition(1, this.transform.position);
}
void makeArrow(LineRenderer lr, Vector3 start, Vector3 end, Vector3 normal)
{
Vector3 vES = (start - end) * ratio;
Vector3 dot1 = end + Quaternion.AngleAxis(theta, normal) * vES;
Vector3 dot2 = end + Quaternion.AngleAxis(360 - theta, normal) * vES;
lr.positionCount = 5;
lr.SetPosition(0, start);
lr.SetPosition(1, end);
lr.SetPosition(2, dot1);
lr.SetPosition(3, dot2);
lr.SetPosition(4, end);
}
void FixedUpdate()
{
if (isDragging) return;
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;
float kinetic = gravity * (totalEnergy - this.transform.position.y);
float v = Mathf.Sqrt(2 * kinetic); // k = 1/2 m v^2 -> v = sqrt(2k/m)
Vector3 verocity
= (Quaternion.AngleAxis(90, startPlaneNormal) * vPO).normalized * getNormalDirection();
makeArrow(lrs[1], this.transform.position, this.transform.position + verocity * v, startPlaneNormal);
}
}
위의 실행결과는 아래의 unitypackage에서 확인 가능하다.
Unity Plus:
Unity Pro:
Unity 프리미엄 학습:
반응형
'개발 > Unity' 카테고리의 다른 글
유니티 AR - 이미지 타겟팅으로 오브젝트 띄우기 From Image (Vuforia Image Targeting From Image) (1) | 2023.06.06 |
---|---|
유니티 - 운동하는 단진자의 로프를 끊기 (Cut the Rope) (0) | 2023.04.03 |
유니티 - 라인 렌더러를 이용한 단진자 속도의 시각화 (0) | 2023.04.03 |
유니티 - 런타임에 단진자 운동 설정하기 (Runtime Independent Simple Pendulum) (0) | 2023.03.29 |
유니티 - 독립된 단진자의 운동 (Independent Simple Pendulum with Unity LerpAngle) (0) | 2023.03.29 |
댓글