using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Threading; namespace Dreamteck.Splines { [RequireComponent(typeof(MeshFilter))] [RequireComponent(typeof(MeshRenderer))] [AddComponentMenu("Dreamteck/Splines/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 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; } } [SerializeField] [HideInInspector] private int _slices = 1; [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 Awake() { base.Awake(); mesh.name = "path"; } protected override void Reset() { base.Reset(); } protected override void BuildMesh() { if (sampleCount == 0) return; 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++) { GetSample(i, 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; if (hasOffset) center += offset.x * right + offset.y * evalResult.up + offset.z * evalResult.forward; float fullSize = size * evalResult.size; Vector3 lastVertPos = Vector3.zero; Quaternion rot = Quaternion.AngleAxis(rotation, evalResult.forward); if (uvMode == UVMode.UniformClamp || uvMode == UVMode.UniformClip) AddUVDistance(i); Color vertexColor = evalResult.color * 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, 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++; } } } } }