Бывалый
Регистрация: 21.12.2008
Адрес: UA
Сообщений: 878
Написано 105 полезных сообщений (для 357 пользователей)
|
Spline
Написал алгоритм CatmullRom
Основной класс
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SplineUtils {
private const int stepCount = 10;
public static Vector3[] CreateSpline(Vector3[] points) {
List<Vector3> result = new List<Vector3>();
int last = points.Length - 1;
for (int i = 0; i < points.Length-1; i++) {
int previous = Mathf.Clamp(i-1, 0, last);
int start = i;
int end = Mathf.Clamp(i+1, 0, last);
int next = Mathf.Clamp(end+1, 0, last);
for (int step = 0; step <= stepCount; step++) {
Vector3 point = SplineUtils.CatmullRom(points[previous], points[start], points[end], points[next], (float) step/stepCount);
result.Add( point );
}
}
return result.ToArray();
}
public static Vector3 GetPosition(Vector3[] points, float t) {
t = Mathf.Clamp01(t) * Length(points);
int last = points.Length - 1;
float tBegin = 0, tEnd = 0;
for (int i = 0; i < points.Length-1; i++) {
int previous = Mathf.Clamp(i-1, 0, last);
int start = i;
int end = Mathf.Clamp(i+1, 0, last);
int next = Mathf.Clamp(end+1, 0, last);
tEnd = tBegin + Length(points[previous], points[start], points[end], points[next]);
if(tBegin<=t && t<=tEnd) {
t -= tBegin;
t /= (tEnd-tBegin);
return CatmullRom(points[previous], points[start], points[end], points[next], t);
}
tBegin = tEnd;
}
return Vector3.zero;
}
public static float Length(Vector3[] points) {
float length = 0;
int last = points.Length - 1;
for (int i = 0; i < points.Length-1; i++) {
int previous = Mathf.Clamp(i-1, 0, last);
int start = i;
int end = Mathf.Clamp(i+1, 0, last);
int next = Mathf.Clamp(end+1, 0, last);
length += Length(points[previous], points[start], points[end], points[next]);
}
return length;
}
public static float Length(Vector3 previous, Vector3 start, Vector3 end, Vector3 next) {
Vector3 a = start;
float length = 0;
for (int i = 1; i <= stepCount; i++) {
Vector3 b = CatmullRom(previous, start, end, next, (float) i/stepCount);
length += Vector3.Distance( a, b );
a = b;
}
return length;
}
public static Vector3 CatmullRom(Vector3 previous, Vector3 start, Vector3 end, Vector3 next, float t) {
t = Mathf.Clamp01(t);
float t2 = t * t;
float t3 = t * t * t;
return previous * (-0.5f * t3 + t2 - 0.5f * t) +
start * ( 1.5f * t3 - 2.5f * t2 + 1.0f) +
end * (-1.5f * t3 + 2.0f * t2 + 0.5f * t) +
next * ( 0.5f * t3 - 0.5f * t2);
}
}
Скрипт для демонстрации
using UnityEngine;
using System.Collections;
public class Spline : MonoBehaviour {
public float time = 0;
void OnDrawGizmos() {
Vector3[] points = GetPoints();
Vector3[] result = SplineUtils.CreateSpline(points);
for(int i=0; i<result.Length-1; i++) {
Vector3 p1 = result[i];
Vector3 p2 = result[i+1];
Gizmos.color = Color.red;
Gizmos.DrawLine(p1, p2);
}
Gizmos.color = Color.red;
Gizmos.DrawSphere( SplineUtils.GetPosition(points, time/10), 0.2f );
}
private Vector3[] GetPoints() {
Vector3[] points = new Vector3[ transform.childCount ];
for(int i=0; i<points.Length; i++) {
points[i] = transform.GetChild(i).transform.position;
}
return points;
}
}
И маленький класс для выбора нода щелчком мыши. Использует UnityEditor и HandleUtility.GetHandleSize поэтому проект с ним не сбилдится.
using UnityEditor;
using UnityEngine;
using System.Collections;
public class SplineNode : MonoBehaviour {
void OnDrawGizmos() {
float size = HandleUtility.GetHandleSize(transform.position) * 0.1f;
Gizmos.color = Color.yellow;
Gizmos.DrawSphere(transform.position, size);
}
}
|