/// <summary> /// Evaluate the splien at the given time and write the result to the "result" object /// </summary> /// <param name="result">The result output</param> /// <param name="percent">Percent of evaluation [0-1]</param> public void Evaluate(SplineResult result, double percent) { if (points.Length == 0) { result = new SplineResult(); return; } percent = DMath.Clamp01(percent); if (closed && points.Length <= 2) { closed = false; } if (points.Length == 1) { result.position = points[0].position; result.normal = points[0].normal; result.direction = Vector3.forward; result.size = points[0].size; result.color = points[0].color; result.percent = percent; return; } double doubleIndex = (points.Length - 1) * percent; int pointIndex = Mathf.Clamp(DMath.FloorInt(doubleIndex), 0, points.Length - 2); double getPercent = doubleIndex - pointIndex; Vector3 point = EvaluatePosition(percent); result.position = point; result.percent = percent; if (pointIndex <= points.Length - 2) { SplinePoint nextPoint = points[pointIndex + 1]; if (pointIndex == points.Length - 2 && closed) { nextPoint = points[0]; } float valueInterpolation = (float)getPercent; if (customValueInterpolation != null) { if (customValueInterpolation.length > 0) { valueInterpolation = customValueInterpolation.Evaluate(valueInterpolation); } } float normalInterpolation = (float)getPercent; if (customNormalInterpolation != null) { if (customNormalInterpolation.length > 0) { normalInterpolation = customNormalInterpolation.Evaluate(normalInterpolation); } } result.size = Mathf.Lerp(points[pointIndex].size, nextPoint.size, valueInterpolation); result.color = Color.Lerp(points[pointIndex].color, nextPoint.color, valueInterpolation); result.normal = Vector3.Slerp(points[pointIndex].normal, nextPoint.normal, normalInterpolation); } else { if (closed) { result.size = points[0].size; result.color = points[0].color; result.normal = points[0].normal; } else { result.size = points[pointIndex].size; result.color = points[pointIndex].color; result.normal = points[pointIndex].normal; } } if (type == Type.BSpline) { double step = (1.0 - precision) / points.Length; if (percent <= 1.0 - step && percent >= step) { result.direction = EvaluatePosition(percent + step) - EvaluatePosition(percent - step); } else { Vector3 back = Vector3.zero, front = Vector3.zero; if (closed) { if (percent < step) { back = EvaluatePosition(1.0 - (step - percent)); } else { back = EvaluatePosition(percent - step); } if (percent > 1.0 - step) { front = EvaluatePosition(step - (1.0 - percent)); } else { front = EvaluatePosition(percent + step); } result.direction = front - back; } else { back = result.position - EvaluatePosition(percent - step); front = EvaluatePosition(percent + step) - result.position; result.direction = Vector3.Slerp(front, back, back.magnitude / front.magnitude); } } } else { EvaluateTangent(ref result.direction, percent); } result.direction.Normalize(); }
public void Evaluate(SplineResult result, double percent) { if (points.Length == 0) { result = new SplineResult(); return; } percent = DMath.Clamp01(percent); if (closed && points.Length <= 2) { closed = false; } if (points.Length == 1) { result.position = points[0].position; result.normal = points[0].normal; result.direction = Vector3.forward; result.size = points[0].size; result.color = points[0].color; result.percent = percent; return; } double doubleIndex = (points.Length - 1) * percent; int pointIndex = Mathf.Clamp(DMath.FloorInt(doubleIndex), 0, points.Length - 2); double getPercent = doubleIndex - pointIndex; Vector3 point = EvaluatePosition(percent); result.position = point; result.percent = percent; if (pointIndex <= points.Length - 2) { SplinePoint nextPoint = points[pointIndex + 1]; if (pointIndex == points.Length - 2 && closed) { nextPoint = points[0]; } float valueInterpolation = (float)getPercent; if (customValueInterpolation != null) { if (customValueInterpolation.keys.Length > 0f) { valueInterpolation = customValueInterpolation.Evaluate(valueInterpolation); } } float normalInterpolation = (float)getPercent; if (customNormalInterpolation != null) { if (customNormalInterpolation.keys.Length > 0) { normalInterpolation = customNormalInterpolation.Evaluate(normalInterpolation); } } result.size = Mathf.Lerp(points[pointIndex].size, nextPoint.size, valueInterpolation); result.color = Color.Lerp(points[pointIndex].color, nextPoint.color, valueInterpolation); result.normal = Vector3.Slerp(points[pointIndex].normal, nextPoint.normal, normalInterpolation); } else { if (closed) { result.size = points[0].size; result.color = points[0].color; result.normal = points[0].normal; } else { result.size = points[pointIndex].size; result.color = points[pointIndex].color; result.normal = points[pointIndex].normal; } } double step = (1.0 - precision) / points.Length; if (percent < 1.0 - step) { result.direction = EvaluatePosition(percent + step) - result.position; } else { if (closed) { result.direction = EvaluatePosition(percent + step) - result.position; result.direction += EvaluatePosition(percent + step - 1f) - EvaluatePosition(0f); } else { result.direction = EvaluatePosition(DMath.Clamp01(percent + step)) - result.position; if (Mathf.Max(result.direction.x, result.direction.y, result.direction.z) <= 0.009f) //If the direction vector is too small, calculate the direction backwards { double backPercent = DMath.Clamp01(percent - step); result.direction = result.position - EvaluatePosition(backPercent); } } } result.direction.Normalize(); }
internal Connection(SplineComputer comp, int index, SplinePoint inputPoint) { _pointIndex = index; _computer = comp; point = inputPoint; }
public void BendObject(BendProperty p) { if (!p.enabled) { return; } GetevalResult(p.positionPercent); p.transform.position = evalResult.position; if (p.applyRotation) { //p.transform.rotation = evalResult.rotation * axisRotation * p.originalRotation; p.transform.rotation = bendRotation * (Quaternion.Inverse(p.parentRotation) * p.originalRotation); } else { p.transform.rotation = p.originalRotation; } if (p.applyScale) { p.transform.scale = p.originalScale * evalResult.size; } Matrix4x4 toLocalMatrix = Matrix4x4.TRS(p.transform.position, p.transform.rotation, p.transform.scale).inverse; if (p.editMesh != null) { BendMesh(p.vertexPercents, p.normals, p.editMesh, toLocalMatrix); p.editMesh.hasUpdate = true; } if (p._editColliderMesh != null) { BendMesh(p.colliderVertexPercents, p.colliderNormals, p.editColliderMesh, toLocalMatrix); p.editColliderMesh.hasUpdate = true; } if (p.originalSpline != null) { for (int n = 0; n < p.splinePointPercents.Length; n++) { SplinePoint point = p.originalSpline.points[n]; GetevalResult(p.splinePointPercents[n]); point.position = evalResult.position; GetevalResult(p.primaryTangentPercents[n]); point.tangent = evalResult.position; GetevalResult(p.secondaryTangentPercents[n]); point.tangent2 = evalResult.position; switch (axis) { case Axis.X: point.normal = Quaternion.LookRotation(evalResult.forward, evalResult.up) * Quaternion.FromToRotation(Vector3.up, evalResult.up) * point.normal; break; case Axis.Y: point.normal = Quaternion.LookRotation(evalResult.forward, evalResult.up) * Quaternion.FromToRotation(Vector3.up, evalResult.up) * point.normal; break; case Axis.Z: point.normal = Quaternion.LookRotation(evalResult.forward, evalResult.up) * point.normal; break; } p.destinationSpline.points[n] = point; } } }
public override bool SceneEdit(ref SplinePoint[] points, ref List <int> selected) { bool change = false; if (originalPoints.Length == 0) { originalPoints = points; center = computer.transform.position; } center = Handles.PositionHandle(center, computer.transform.rotation); DrawMirror(); if (lastCenter != center || lastAxis != axis || lastFlip || mirrored.Length != originalPoints.Length * 2) { List <int> half = GetHalf(ref originalPoints); int welded = -1; if (half.Count > 0) { if (flip) { if (IsWeldable(originalPoints[half[0]])) { welded = half[0]; half.RemoveAt(0); } } else { if (IsWeldable(originalPoints[half[half.Count - 1]])) { welded = half[half.Count - 1]; half.RemoveAt(half.Count - 1); } } int offset = welded >= 0 ? 1 : 0; int additionalSlot = computer.isClosed && half.Count > 0 ? 1 : 0; if (additionalSlot > 0) { if (flip) { if (IsWeldable(originalPoints[half[half.Count - 1]])) { additionalSlot = 0; } } else { if (IsWeldable(originalPoints[half[0]])) { additionalSlot = 0; } } } mirrored = new SplinePoint[half.Count * 2 + offset + additionalSlot]; for (int i = 0; i < half.Count; i++) { if (flip) { mirrored[i] = new SplinePoint(originalPoints[half[(half.Count - 1) - i]]); mirrored[i + half.Count + offset] = GetMirrored(originalPoints[half[i]]); SwapTangents(ref mirrored[i]); SwapTangents(ref mirrored[i + half.Count + offset]); } else { mirrored[i] = new SplinePoint(originalPoints[half[i]]); mirrored[i + half.Count + offset] = GetMirrored(originalPoints[half[(half.Count - 1) - i]]); } } if (welded >= 0) { mirrored[half.Count] = new SplinePoint(originalPoints[welded]); if (flip) { SwapTangents(ref mirrored[half.Count]); } MakeMiddlePoint(ref mirrored[half.Count]); } if (computer.isClosed && mirrored.Length > 0) { if (additionalSlot == 0) { MakeMiddlePoint(ref mirrored[0]); } mirrored[mirrored.Length - 1] = new SplinePoint(mirrored[0]); } } else { mirrored = new SplinePoint[0]; } lastCenter = center; lastAxis = axis; change = true; } points = mirrored; selected.Clear(); return(change); }
void MakeMiddlePoint(ref SplinePoint point) { point.type = SplinePoint.Type.Broken; point.position = computer.transform.InverseTransformPoint(point.position); point.tangent = computer.transform.InverseTransformPoint(point.tangent); point.tangent2 = computer.transform.InverseTransformPoint(point.tangent2); Vector3 newPos = point.position; Vector3 localCenter = computer.transform.InverseTransformPoint(center); switch (axis) { case Axis.X: newPos.x = localCenter.x; point.SetPosition(newPos); if ((point.tangent.x >= localCenter.x && flip) || (point.tangent.x <= localCenter.x && !flip)) { point.tangent2 = point.tangent; point.tangent2.x = point.position.x + (point.position.x - point.tangent.x); } else { point.tangent = point.tangent2; point.tangent.x = point.position.x + (point.position.x - point.tangent2.x); } break; case Axis.Y: newPos.y = localCenter.y; point.SetPosition(newPos); if ((point.tangent.y >= localCenter.y && flip) || (point.tangent.y <= localCenter.y && !flip)) { point.tangent2 = point.tangent; point.tangent2.y = point.position.y + (point.position.y - point.tangent.y); } else { point.tangent = point.tangent2; point.tangent.y = point.position.y + (point.position.y - point.tangent2.y); } break; case Axis.Z: newPos.z = localCenter.z; point.SetPosition(newPos); if ((point.tangent.z >= localCenter.z && flip) || (point.tangent.z <= localCenter.z && !flip)) { point.tangent2 = point.tangent; point.tangent2.z = point.position.z + (point.position.z - point.tangent.z); } else { point.tangent = point.tangent2; point.tangent.z = point.position.z + (point.position.z - point.tangent2.z); } break; } point.position = computer.transform.TransformPoint(point.position); point.tangent = computer.transform.TransformPoint(point.tangent); point.tangent2 = computer.transform.TransformPoint(point.tangent2); }
public void BendObject(BendProperty p) { if (!p.enabled) { return; } Quaternion axisRotation = Quaternion.identity; switch (axis) { case Axis.X: axisRotation = Quaternion.AngleAxis(-90f, Vector3.up); break; case Axis.Y: axisRotation = Quaternion.AngleAxis(90f, Vector3.right); break; } GetBendResult(p.positionPercent); if (this.transform == computer.transform && p.transform.transform == this.transform) { } else { p.transform.position = bendResult.position; if (p.applyRotation) { p.transform.rotation = bendResult.rotation * axisRotation * p.originalRotation; } else { p.transform.rotation = p.originalRotation; } if (p.applyScale) { p.transform.scale = p.originalScale * bendResult.size; } } if (p.editMesh != null) { for (int n = 0; n < p.vertexPercents.Length; n++) { GetBendResult(p.vertexPercents[n]); p.editMesh.vertices[n] = bendResult.position; switch (axis) { case Axis.X: p.editMesh.normals[n] = Quaternion.LookRotation(bendResult.direction, bendResult.normal) * axisRotation * Quaternion.FromToRotation(Vector3.up, bendResult.normal) * p.normals[n]; break; case Axis.Y: p.editMesh.normals[n] = Quaternion.LookRotation(bendResult.direction, bendResult.normal) * axisRotation * Quaternion.FromToRotation(Vector3.up, bendResult.normal) * p.normals[n]; break; case Axis.Z: p.editMesh.normals[n] = Quaternion.LookRotation(bendResult.direction, bendResult.normal) * p.normals[n]; break; } } p.editMesh.hasUpdate = true; } if (p.editColliderMesh != null) { for (int n = 0; n < p.colliderVertexPercents.Length; n++) { GetBendResult(p.colliderVertexPercents[n]); p.editColliderMesh.vertices[n] = bendResult.position; switch (axis) { case Axis.X: p.editColliderMesh.normals[n] = Quaternion.LookRotation(bendResult.direction, bendResult.normal) * axisRotation * Quaternion.FromToRotation(Vector3.up, bendResult.normal) * p.colliderNormals[n]; break; case Axis.Y: p.editColliderMesh.normals[n] = Quaternion.LookRotation(bendResult.direction, bendResult.normal) * axisRotation * Quaternion.FromToRotation(Vector3.up, bendResult.normal) * p.colliderNormals[n]; break; case Axis.Z: p.editColliderMesh.normals[n] = Quaternion.LookRotation(bendResult.direction, bendResult.normal) * p.colliderNormals[n]; break; } } p.editColliderMesh.hasUpdate = true; } if (p.originalSpline != null) { for (int n = 0; n < p.splinePointPercents.Length; n++) { SplinePoint point = p.originalSpline.points[n]; GetBendResult(p.splinePointPercents[n]); point.position = bendResult.position; GetBendResult(p.primaryTangentPercents[n]); point.tangent = bendResult.position; GetBendResult(p.secondaryTangentPercents[n]); point.tangent2 = bendResult.position; switch (axis) { case Axis.X: point.normal = Quaternion.LookRotation(bendResult.direction, bendResult.normal) * axisRotation * Quaternion.FromToRotation(Vector3.up, bendResult.normal) * point.normal; break; case Axis.Y: point.normal = Quaternion.LookRotation(bendResult.direction, bendResult.normal) * axisRotation * Quaternion.FromToRotation(Vector3.up, bendResult.normal) * point.normal; break; case Axis.Z: point.normal = Quaternion.LookRotation(bendResult.direction, bendResult.normal) * point.normal; break; } p.destinationSpline.points[n] = point; } } }
void Merge(int index, MergeSide currentSide, MergeSide otherSide, ref SplinePoint[] points) { SplinePoint[] mergedPoints = availableMergeComputers[index].GetPoints(); SplinePoint[] original = new SplinePoint[points.Length]; points.CopyTo(original, 0); List <SplinePoint> pointsList = new List <SplinePoint>(); if (!mergeEndpoints) { points = new SplinePoint[mergedPoints.Length + original.Length]; } else { points = new SplinePoint[mergedPoints.Length + original.Length - 1]; } if (currentSide == MergeSide.End) { if (otherSide == MergeSide.Start) { for (int i = 0; i < original.Length; i++) { pointsList.Add(original[i]); } for (int i = mergeEndpoints ? 1 : 0; i < mergedPoints.Length; i++) { pointsList.Add(mergedPoints[i]); } } else { for (int i = 0; i < original.Length; i++) { pointsList.Add(original[i]); } for (int i = 0; i < mergedPoints.Length - (mergeEndpoints ? 1 : 0); i++) { pointsList.Add(mergedPoints[(mergedPoints.Length - 1) - i]); } } } else { if (otherSide == MergeSide.Start) { for (int i = mergeEndpoints ? 1 : 0; i < mergedPoints.Length; i++) { pointsList.Add(mergedPoints[i]); } for (int i = 0; i < original.Length; i++) { pointsList.Add(original[i]); } } else { for (int i = 0; i < mergedPoints.Length - (mergeEndpoints ? 1 : 0); i++) { pointsList.Add(mergedPoints[(mergedPoints.Length - 1) - i]); } for (int i = 0; i < original.Length; i++) { pointsList.Add(original[i]); } } } points = pointsList.ToArray(); double mergedPercent = (double)(mergedPoints.Length - 1) / (points.Length - 1); double from = 0.0; double to = 1.0; if (currentSide == MergeSide.End) { from = 1.0 - mergedPercent; to = 1.0; } else { from = 0.0; to = mergedPercent; } MergeComputer(availableMergeComputers[index], from, to); Init(); }