213 lines
7.9 KiB
C#
213 lines
7.9 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
|
|
namespace Dreamteck.Splines
|
|
{
|
|
[RequireComponent(typeof(MeshFilter))]
|
|
[RequireComponent(typeof(MeshRenderer))]
|
|
[AddComponentMenu("Dreamteck/Splines/Users/Path Generator")]
|
|
public class PathGenerator : MeshGenerator
|
|
{
|
|
public int slices
|
|
{
|
|
get { return _slices; }
|
|
set
|
|
{
|
|
if (value != _slices)
|
|
{
|
|
if (value < 1) value = 1;
|
|
_slices = value;
|
|
Rebuild();
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool useShapeCurve
|
|
{
|
|
get { return _useShapeCurve; }
|
|
set
|
|
{
|
|
if (value != _useShapeCurve)
|
|
{
|
|
_useShapeCurve = value;
|
|
if (_useShapeCurve)
|
|
{
|
|
_shape = new AnimationCurve();
|
|
_shape.AddKey(new Keyframe(0, 0));
|
|
_shape.AddKey(new Keyframe(1, 0));
|
|
} else _shape = null;
|
|
Rebuild();
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool compensateCorners
|
|
{
|
|
get { return _compensateCorners; }
|
|
set
|
|
{
|
|
if (value != _compensateCorners)
|
|
{
|
|
_compensateCorners = value;
|
|
Rebuild();
|
|
}
|
|
}
|
|
}
|
|
|
|
public float shapeExposure
|
|
{
|
|
get { return _shapeExposure; }
|
|
set
|
|
{
|
|
if (spline != null && value != _shapeExposure)
|
|
{
|
|
_shapeExposure = value;
|
|
Rebuild();
|
|
}
|
|
}
|
|
}
|
|
|
|
public AnimationCurve shape
|
|
{
|
|
get { return _shape; }
|
|
set
|
|
{
|
|
if(_lastShape == null) _lastShape = new AnimationCurve();
|
|
bool keyChange = false;
|
|
if (value.keys.Length != _lastShape.keys.Length) keyChange = true;
|
|
else
|
|
{
|
|
for (int i = 0; i < value.keys.Length; i++)
|
|
{
|
|
if (value.keys[i].inTangent != _lastShape.keys[i].inTangent || value.keys[i].outTangent != _lastShape.keys[i].outTangent || value.keys[i].time != _lastShape.keys[i].time || value.keys[i].value != value.keys[i].value)
|
|
{
|
|
keyChange = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (keyChange) Rebuild();
|
|
_lastShape.keys = new Keyframe[value.keys.Length];
|
|
value.keys.CopyTo(_lastShape.keys, 0);
|
|
_lastShape.preWrapMode = value.preWrapMode;
|
|
_lastShape.postWrapMode = value.postWrapMode;
|
|
_shape = value;
|
|
|
|
}
|
|
}
|
|
|
|
protected override string meshName => "Path";
|
|
|
|
[SerializeField]
|
|
[HideInInspector]
|
|
private int _slices = 1;
|
|
[SerializeField]
|
|
[HideInInspector]
|
|
[Tooltip("This will inflate sample sizes based on the angle between two samples in order to preserve geometry width")]
|
|
private bool _compensateCorners = false;
|
|
[SerializeField]
|
|
[HideInInspector]
|
|
private bool _useShapeCurve = false;
|
|
[SerializeField]
|
|
[HideInInspector]
|
|
private AnimationCurve _shape;
|
|
[SerializeField]
|
|
[HideInInspector]
|
|
private AnimationCurve _lastShape;
|
|
[SerializeField]
|
|
[HideInInspector]
|
|
private float _shapeExposure = 1f;
|
|
|
|
|
|
protected override void Reset()
|
|
{
|
|
base.Reset();
|
|
}
|
|
|
|
|
|
protected override void BuildMesh()
|
|
{
|
|
base.BuildMesh();
|
|
GenerateVertices();
|
|
MeshUtility.GeneratePlaneTriangles(ref _tsMesh.triangles, _slices, sampleCount, false);
|
|
}
|
|
|
|
|
|
void GenerateVertices()
|
|
{
|
|
int vertexCount = (_slices + 1) * sampleCount;
|
|
AllocateMesh(vertexCount, _slices * (sampleCount-1) * 6);
|
|
int vertexIndex = 0;
|
|
|
|
ResetUVDistance();
|
|
|
|
bool hasOffset = offset != Vector3.zero;
|
|
for (int i = 0; i < sampleCount; i++)
|
|
{
|
|
if (_compensateCorners)
|
|
{
|
|
GetSampleWithAngleCompensation(i, ref evalResult);
|
|
}
|
|
else
|
|
{
|
|
GetSample(i, ref evalResult);
|
|
}
|
|
|
|
Vector3 center = Vector3.zero;
|
|
try
|
|
{
|
|
center = evalResult.position;
|
|
} catch (System.Exception ex) { Debug.Log(ex.Message + " for i = " + i); return; }
|
|
Vector3 right = evalResult.right;
|
|
float resultSize = GetBaseSize(evalResult);
|
|
if (hasOffset)
|
|
{
|
|
center += (offset.x * resultSize) * right + (offset.y * resultSize) * evalResult.up + (offset.z * resultSize) * evalResult.forward;
|
|
}
|
|
float fullSize = size * resultSize;
|
|
Vector3 lastVertPos = Vector3.zero;
|
|
Quaternion rot = Quaternion.AngleAxis(rotation, evalResult.forward);
|
|
if (uvMode == UVMode.UniformClamp || uvMode == UVMode.UniformClip) AddUVDistance(i);
|
|
Color vertexColor = GetBaseColor(evalResult) * color;
|
|
for (int n = 0; n < _slices + 1; n++)
|
|
{
|
|
float slicePercent = ((float)n / _slices);
|
|
float shapeEval = 0f;
|
|
if (_useShapeCurve) shapeEval = _shape.Evaluate(slicePercent);
|
|
_tsMesh.vertices[vertexIndex] = center + rot * right * (fullSize * 0.5f) - rot * right * (fullSize * slicePercent) + rot * evalResult.up * (shapeEval * _shapeExposure);
|
|
CalculateUVs(evalResult.percent, 1f - slicePercent);
|
|
_tsMesh.uv[vertexIndex] = Vector2.one * 0.5f + (Vector2)(Quaternion.AngleAxis(uvRotation + 180f, Vector3.forward) * (Vector2.one * 0.5f - __uvs));
|
|
if (_slices > 1)
|
|
{
|
|
if (n < _slices)
|
|
{
|
|
float forwardPercent = ((float)(n + 1) / _slices);
|
|
shapeEval = 0f;
|
|
if (_useShapeCurve) shapeEval = _shape.Evaluate(forwardPercent);
|
|
Vector3 nextVertPos = center + rot * right * fullSize * 0.5f - rot * right * fullSize * forwardPercent + rot * evalResult.up * shapeEval * _shapeExposure;
|
|
Vector3 cross1 = -Vector3.Cross(evalResult.forward, nextVertPos - _tsMesh.vertices[vertexIndex]).normalized;
|
|
|
|
if (n > 0)
|
|
{
|
|
Vector3 cross2 = -Vector3.Cross(evalResult.forward, _tsMesh.vertices[vertexIndex] - lastVertPos).normalized;
|
|
_tsMesh.normals[vertexIndex] = Vector3.Slerp(cross1, cross2, 0.5f);
|
|
} else _tsMesh.normals[vertexIndex] = cross1;
|
|
}
|
|
else _tsMesh.normals[vertexIndex] = -Vector3.Cross(evalResult.forward, _tsMesh.vertices[vertexIndex] - lastVertPos).normalized;
|
|
}
|
|
else
|
|
{
|
|
_tsMesh.normals[vertexIndex] = evalResult.up;
|
|
if (rotation != 0f) _tsMesh.normals[vertexIndex] = rot * _tsMesh.normals[vertexIndex];
|
|
}
|
|
_tsMesh.colors[vertexIndex] = vertexColor;
|
|
lastVertPos = _tsMesh.vertices[vertexIndex];
|
|
vertexIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|