Unity/Study
유니티 Spline의 정규 값을 통해 World Position값 얻어내기 #다른 Spline으로 자연스럽게 이동시키고 싶을 때
VR하는소년
2024. 9. 27. 08:00
Spline이란?
Spline은 곡선을 나타내기 위한 수학적 표현으로, 객체를 경로를 따라 이동시킬 때 사용됩니다.
스플라인의 기본 개념은 여러 제어점(Control Points)을 이용해 곡선을 만들어 내고, 곡선을 따라 객체가 움직이도록 하는 것입니다. 곡선은 정규화 값(normalized value), 즉 0에서 1까지의 값을 사용해 스플라인 상의 특정 위치를 계산할 수 있습니다.
정규화 값이 0이면 스플라인의 시작점, 1이면 끝점을 나타냅니다.
Spline의 특정 위치를 계산하기
public Vector3 GetPositionOnSpline(int splineIndex, float normalizedPosition)
{
//spline Index : 얻고자 하는 Spline
if (splineIndex >= 0 && splineIndex < splineContainers.Count)
{
SplineContainer splineContainer = splineContainers[splineIndex];
Spline spline = splineContainer.Spline;
Vector3 localPosition = spline.EvaluatePosition(normalizedPosition);
Vector3 worldPosition = splineContainer.transform.TransformPoint(localPosition);
return worldPosition;
}
else
{
Debug.LogError("Spline index out of range.");
return Vector3.zero;
}
}
핵심함수는 EvaluatePosition입니다.
EvaluatePosition 함수는 Spline 시스템에서 제공하는 함수로, 스플라인의 특정 정규화된 위치(0에서 1 사이의 값)에 해당하는 로컬 좌표(Local Position)를 반환하는 역할을 합니다.
다른 스플라인으로 자연스럽게 이동해보기
using Cysharp.Threading.Tasks;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Splines;
public class SplineHandler : MonoBehaviour
{
public SplineAnimate splineAnimator;
public List<SplineContainer> splineContainers;
[Header("Start lane")]
[SerializeField, Tooltip("Index + 1이 Lane Num에 속함(Ex.Index : 1-> Lane 2)")]
private int currentSplineIndex = 1;
private void Start()
{
splineAnimator.Container = splineContainers[currentSplineIndex];
Play();
}
public void SetSplineContainer(int index, float startOffset = 0f)
{
if (index >= 0 && index < splineContainers.Count)
{
splineAnimator.Container = splineContainers[index];
splineAnimator.StartOffset = startOffset;
}
else
{
Debug.LogError("Spline index out of range.");
}
}
public void Play()
{
splineAnimator.Play();
}
public void Restart(bool isFromStart = true)
{
splineAnimator.Restart(isFromStart);
}
public void Pause()
{
splineAnimator.Pause();
}
public async UniTask SmoothTransition(int targetSplineIndex, float normalizedPosition, float duration)
{
Pause();
var targetPosition = GetPositionOnSpline(targetSplineIndex, normalizedPosition);
if (targetSplineIndex < 0 || targetSplineIndex >= splineContainers.Count)
{
Debug.LogError("Spline index out of range.");
return;
}
SplineContainer currentSpline = splineAnimator.Container;
SplineContainer targetSpline = splineContainers[targetSplineIndex];
float elapsedTime = 0f;
Vector3 initialPosition = transform.position;
while (elapsedTime < duration)
{
elapsedTime += Time.deltaTime;
float t = Mathf.Clamp01(elapsedTime / duration);
transform.position = Vector3.Lerp(initialPosition, targetPosition, t);
await UniTask.Yield();
}
transform.position = targetPosition;
SetSplineContainer(targetSplineIndex, normalizedPosition);
Restart();
}
public Vector3 GetPositionOnSpline(int splineIndex, float normalizedPosition)
{
if (splineIndex >= 0 && splineIndex < splineContainers.Count)
{
SplineContainer splineContainer = splineContainers[splineIndex];
Spline spline = splineContainer.Spline;
Vector3 localPosition = spline.EvaluatePosition(normalizedPosition);
Vector3 worldPosition = splineContainer.transform.TransformPoint(localPosition);
return worldPosition;
}
else
{
Debug.LogError("Spline index out of range.");
return Vector3.zero;
}
}
}
이 코드는 UniTask를 활용합니다.
위 포스팅을 참고해주세요.