You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
287 lines
8.5 KiB
287 lines
8.5 KiB
using System; |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
using UnityEngine; |
|
using Random = UnityEngine.Random; |
|
|
|
public class ME_TrailRendererNoise : MonoBehaviour |
|
{ |
|
|
|
[Range(0.01f, 10)] |
|
public float MinVertexDistance = 0.1f; |
|
public float VertexTime = 1; |
|
public float TotalLifeTime = 3; |
|
public bool SmoothCurves = false; |
|
public bool IsRibbon; |
|
|
|
[Range(0.001f, 10)] public float Frequency = 1f; |
|
|
|
[Range(0.001f, 10)] public float TimeScale = 0.1f; |
|
|
|
[Range(0.001f, 10)] public float Amplitude = 1; |
|
|
|
public float Gravity = 1; |
|
|
|
public float TurbulenceStrength = 1; |
|
|
|
public bool Autodestruct; |
|
LineRenderer lineRenderer; |
|
Transform t; |
|
Vector3 prevPos; |
|
|
|
List<Vector3> points = new List<Vector3>(500); |
|
List<float> lifeTimes = new List<float>(500); |
|
List<Vector3> velocities = new List<Vector3>(500); |
|
|
|
|
|
|
|
private float randomOffset; |
|
|
|
void Start() |
|
{ |
|
lineRenderer = GetComponent<LineRenderer>(); |
|
lineRenderer.useWorldSpace = true; |
|
t = transform; |
|
prevPos = t.position; |
|
|
|
points.Insert(0, t.position); |
|
lifeTimes.Insert(0, VertexTime); |
|
velocities.Insert(0, Vector3.zero); |
|
randomOffset = Random.Range(0, 10000000) / 1000000f; |
|
} |
|
|
|
private void OnEnable() |
|
{ |
|
points.Clear(); |
|
lifeTimes.Clear(); |
|
velocities.Clear(); |
|
if (Autodestruct) Destroy(gameObject, TotalLifeTime); |
|
} |
|
|
|
void Update() |
|
{ |
|
AddNewPoints(); |
|
UpdatetPoints(); |
|
|
|
if (SmoothCurves && points.Count > 2) |
|
{ |
|
UpdateLineRendererBezier(); |
|
} |
|
else |
|
{ |
|
UpdateLineRenderer(); |
|
} |
|
} |
|
|
|
void AddNewPoints() |
|
{ |
|
if ((t.position - prevPos).magnitude > MinVertexDistance || |
|
IsRibbon && points.Count == 0 || |
|
IsRibbon && points.Count > 0 && (t.position - points[0]).magnitude > MinVertexDistance) |
|
{ |
|
prevPos = t.position; |
|
points.Insert(0, t.position); |
|
lifeTimes.Insert(0, VertexTime); |
|
velocities.Insert(0, Vector3.zero); |
|
} |
|
} |
|
|
|
void UpdatetPoints() |
|
{ |
|
for (var i = 0; i < lifeTimes.Count; i++) |
|
{ |
|
lifeTimes[i] -= Time.deltaTime; |
|
if (lifeTimes[i] <= 0) |
|
{ |
|
var removedRange = lifeTimes.Count - i; |
|
lifeTimes.RemoveRange(i, removedRange); |
|
points.RemoveRange(i, removedRange); |
|
velocities.RemoveRange(i, removedRange); |
|
return; |
|
} |
|
else |
|
{ |
|
CalculateTurbuelence(points[i], TimeScale, Frequency, Amplitude, Gravity, i); |
|
|
|
} |
|
} |
|
} |
|
|
|
void UpdateLineRendererBezier() |
|
{ |
|
if (SmoothCurves && points.Count > 2) |
|
{ |
|
InterpolateBezier(points, SmoothCurvesScale); |
|
var bezierPositions = GetDrawingPoints(); |
|
lineRenderer.positionCount = bezierPositions.Count - 1; |
|
lineRenderer.SetPositions(bezierPositions.ToArray()); |
|
} |
|
} |
|
|
|
void UpdateLineRenderer() |
|
{ |
|
lineRenderer.positionCount = Mathf.Clamp(points.Count - 1, 0, Int32.MaxValue); |
|
lineRenderer.SetPositions(points.ToArray()); |
|
} |
|
|
|
void CalculateTurbuelence(Vector3 position, float speed, float scale, float height, float gravity, int index) |
|
{ |
|
float sTime = Time.timeSinceLevelLoad * speed + randomOffset; |
|
float xCoord = position.x * scale + sTime; |
|
float yCoord = position.y * scale + sTime + 10; |
|
float zCoord = position.z * scale + sTime + 25; |
|
position.x = (Mathf.PerlinNoise(yCoord, zCoord) - 0.5f) * height * Time.deltaTime; |
|
position.y = (Mathf.PerlinNoise(xCoord, zCoord) - 0.5f) * height * Time.deltaTime - gravity * Time.deltaTime; |
|
position.z = (Mathf.PerlinNoise(xCoord, yCoord) - 0.5f) * height * Time.deltaTime; |
|
points[index] += position * TurbulenceStrength; |
|
} |
|
|
|
private List<Vector3> controlPoints = new List<Vector3>(); |
|
private int curveCount; |
|
private const float MinimumSqrDistance = 0.01f; |
|
private const float DivisionThreshold = -0.99f; |
|
private const float SmoothCurvesScale = 0.5f; |
|
|
|
#region Bezier |
|
|
|
public void InterpolateBezier(List<Vector3> segmentPoints, float scale) |
|
{ |
|
controlPoints.Clear(); |
|
|
|
if (segmentPoints.Count < 2) |
|
return; |
|
|
|
for (int i = 0; i < segmentPoints.Count; i++) |
|
{ |
|
if (i == 0) // is first |
|
{ |
|
Vector3 p1 = segmentPoints[i]; |
|
Vector3 p2 = segmentPoints[i + 1]; |
|
|
|
Vector3 tangent = (p2 - p1); |
|
Vector3 q1 = p1 + scale * tangent; |
|
|
|
controlPoints.Add(p1); |
|
controlPoints.Add(q1); |
|
} |
|
else if (i == segmentPoints.Count - 1) //last |
|
{ |
|
Vector3 p0 = segmentPoints[i - 1]; |
|
Vector3 p1 = segmentPoints[i]; |
|
Vector3 tangent = (p1 - p0); |
|
Vector3 q0 = p1 - scale * tangent; |
|
|
|
controlPoints.Add(q0); |
|
controlPoints.Add(p1); |
|
} |
|
else |
|
{ |
|
Vector3 p0 = segmentPoints[i - 1]; |
|
Vector3 p1 = segmentPoints[i]; |
|
Vector3 p2 = segmentPoints[i + 1]; |
|
Vector3 tangent = (p2 - p0).normalized; |
|
Vector3 q0 = p1 - scale * tangent * (p1 - p0).magnitude; |
|
Vector3 q1 = p1 + scale * tangent * (p2 - p1).magnitude; |
|
|
|
controlPoints.Add(q0); |
|
controlPoints.Add(p1); |
|
controlPoints.Add(q1); |
|
} |
|
} |
|
|
|
curveCount = (controlPoints.Count - 1) / 3; |
|
} |
|
|
|
public List<Vector3> GetDrawingPoints() |
|
{ |
|
List<Vector3> drawingPoints = new List<Vector3>(); |
|
|
|
for (int curveIndex = 0; curveIndex < curveCount; curveIndex++) |
|
{ |
|
List<Vector3> bezierCurveDrawingPoints = FindDrawingPoints(curveIndex); |
|
|
|
if (curveIndex != 0) |
|
//remove the fist point, as it coincides with the last point of the previous Bezier curve. |
|
bezierCurveDrawingPoints.RemoveAt(0); |
|
|
|
drawingPoints.AddRange(bezierCurveDrawingPoints); |
|
} |
|
|
|
return drawingPoints; |
|
} |
|
|
|
private List<Vector3> FindDrawingPoints(int curveIndex) |
|
{ |
|
List<Vector3> pointList = new List<Vector3>(); |
|
|
|
Vector3 left = CalculateBezierPoint(curveIndex, 0); |
|
Vector3 right = CalculateBezierPoint(curveIndex, 1); |
|
|
|
pointList.Add(left); |
|
pointList.Add(right); |
|
|
|
FindDrawingPoints(curveIndex, 0, 1, pointList, 1); |
|
|
|
return pointList; |
|
} |
|
|
|
private int FindDrawingPoints(int curveIndex, float t0, float t1, |
|
List<Vector3> pointList, int insertionIndex) |
|
{ |
|
Vector3 left = CalculateBezierPoint(curveIndex, t0); |
|
Vector3 right = CalculateBezierPoint(curveIndex, t1); |
|
|
|
if ((left - right).sqrMagnitude < MinimumSqrDistance) |
|
return 0; |
|
|
|
float tMid = (t0 + t1) / 2; |
|
Vector3 mid = CalculateBezierPoint(curveIndex, tMid); |
|
|
|
Vector3 leftDirection = (left - mid).normalized; |
|
Vector3 rightDirection = (right - mid).normalized; |
|
|
|
if (Vector3.Dot(leftDirection, rightDirection) > DivisionThreshold || Mathf.Abs(tMid - 0.5f) < 0.0001f) |
|
{ |
|
int pointsAddedCount = 0; |
|
|
|
pointsAddedCount += FindDrawingPoints(curveIndex, t0, tMid, pointList, insertionIndex); |
|
pointList.Insert(insertionIndex + pointsAddedCount, mid); |
|
pointsAddedCount++; |
|
pointsAddedCount += FindDrawingPoints(curveIndex, tMid, t1, pointList, insertionIndex + pointsAddedCount); |
|
|
|
return pointsAddedCount; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
public Vector3 CalculateBezierPoint(int curveIndex, float t) |
|
{ |
|
int nodeIndex = curveIndex * 3; |
|
Vector3 p0 = controlPoints[nodeIndex]; |
|
Vector3 p1 = controlPoints[nodeIndex + 1]; |
|
Vector3 p2 = controlPoints[nodeIndex + 2]; |
|
Vector3 p3 = controlPoints[nodeIndex + 3]; |
|
|
|
return CalculateBezierPoint(t, p0, p1, p2, p3); |
|
} |
|
|
|
private Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) |
|
{ |
|
float u = 1 - t; |
|
float tt = t * t; |
|
float uu = u * u; |
|
float uuu = uu * u; |
|
float ttt = tt * t; |
|
|
|
Vector3 p = uuu * p0; //first term |
|
|
|
p += 3 * uu * t * p1; //second term |
|
p += 3 * u * tt * p2; //third term |
|
p += ttt * p3; //fourth term |
|
|
|
return p; |
|
} |
|
|
|
#endregion |
|
}
|
|
|