/// <summary> /// Gets the previous point in the path. If this is the first point and /// and the path is closed, this method will return the last point. /// </summary> /// <returns>The previous point.</returns> /// <param name="point">Point.</param> public BezierPointAttribute GetPreviousPoint(BezierPointAttribute point) { int index = m_Points.IndexOf(point); return GetPreviousPoint(index); }
/// <summary> /// Creates a bezier circle path. /// </summary> /// <param name="radius">Radius.</param> public static BezierPath Circle(float radius) { BezierPath path = CreateInstance<BezierPath>(null); path.closed = true; float controlDistance = radius * 4.0f * (s_Root2 - 1.0f) / 3.0f; Quaternion offset = Quaternion.identity; Quaternion increment = Quaternion.Euler(0.0f, 0.0f, 90.0f); BezierPointAttribute[] points = new BezierPointAttribute[4]; for (int index = 0; index < 4; index++) { Vector3 position = Vector3.up * radius; Vector3 inTangent = Vector3.right * controlDistance; Vector3 outTangent = Vector3.left * controlDistance; BezierPointAttribute point = BezierPointAttribute.CreateInstance<BezierPointAttribute>(); point.tangentMode = TangentMode.Smooth; point.position = offset * position; point.inTangent = offset * inTangent; point.outTangent = offset * outTangent; points[index] = point; offset *= increment; } path.points = points; return path; }
/// <summary> /// Provides the patch and patch delta for the given path delta. /// </summary> /// <param name="pointA">Point a.</param> /// <param name="pointB">Point b.</param> /// <param name="patchDelta">Patch delta.</param> /// <param name="delta">Delta.</param> private void PatchForDelta(out BezierPointAttribute pointA, out BezierPointAttribute pointB, out float patchDelta, float delta) { int patches = m_Points.Length - 1; if (m_Closed) patches++; if (patches < 1) throw new Exception("No patches in the path!"); delta = Mathf.Repeat(delta, 1.0f); int patchIndex = HydraMathUtils.FloorToInt(delta * patches); pointA = m_Points[patchIndex]; pointB = GetNextPoint(patchIndex); float singlePatchDelta = 1.0f / patches; patchDelta = delta - (patchIndex * singlePatchDelta); patchDelta *= patches; }
/// <summary> /// Returns the normal at the given non-linear delta. /// </summary> /// <returns>The normal vector.</returns> /// <param name="pointA">Point a.</param> /// <param name="pointB">Point b.</param> /// <param name="delta">Delta.</param> public Vector3 Normal(BezierPointAttribute pointA, BezierPointAttribute pointB, float delta) { Vector3 position = Interpolate(pointA, pointB, delta); Vector3 tangent = Tangent(pointA, pointB, delta).normalized; // Cheat to get the next point along the curve float nextDelta = delta + NORMAL_INTERVAL; Vector3 position2 = Interpolate(pointA, pointB, nextDelta); Vector3 tangent2 = Tangent(pointA, pointB, nextDelta); tangent2 -= (position2 - position); tangent2 = tangent2.normalized; Vector3 c = new Vector3(tangent2.y * tangent.z - tangent2.z * tangent.y, tangent2.z * tangent.x - tangent2.x * tangent.z, tangent2.x * tangent.y - tangent2.y * tangent.x).normalized; Matrix4x4 r = Matrix4x4.identity; r.SetRow(0, new Vector4(c.x * c.x, c.x * c.y - c.z, c.x * c.z + c.y)); r.SetRow(1, new Vector4(c.x * c.y + c.z, c.y * c.y, c.y * c.z - c.x)); r.SetRow(2, new Vector4(c.x * c.z - c.y, c.y * c.z + c.x, c.z * c.z)); return r.MultiplyVector(tangent); }
/// <summary> /// Returns the tangent at the given non-linear delta. /// </summary> /// <returns>The tangent vector.</returns> /// <param name="pointA">Point a.</param> /// <param name="pointB">Point b.</param> /// <param name="delta">Delta.</param> public Vector3 Tangent(BezierPointAttribute pointA, BezierPointAttribute pointB, float delta) { BezierPointAttribute previousPoint = GetPreviousPoint(pointA); BezierPointAttribute nextPoint = GetNextPoint(pointB); Vector3 outTangent = GetOutTangent(previousPoint, pointA, pointB); Vector3 inTangent = GetInTangent(pointA, pointB, nextPoint); float x = ComputeBezierDerivative(pointA.position.x, outTangent.x, inTangent.x, pointB.position.x, delta); float y = ComputeBezierDerivative(pointA.position.y, outTangent.y, inTangent.y, pointB.position.y, delta); float z = ComputeBezierDerivative(pointA.position.z, outTangent.z, inTangent.z, pointB.position.z, delta); return new Vector3(x, y, z); }
/// <summary> /// Returns the positions on the curve between the two points at the given deltas. /// /// This method is faster than calling Interpolate multiple times for the same patch. /// </summary> /// <returns>The interpolated positions.</returns> /// <param name="output">Output.</param> /// <param name="pointA">Point a.</param> /// <param name="pointB">Point b.</param> /// <param name="deltas">Deltas.</param> public void Interpolate(ref Vector3[] output, BezierPointAttribute pointA, BezierPointAttribute pointB, float[] deltas) { BezierPointAttribute previousPoint = GetPreviousPoint(pointA); BezierPointAttribute nextPoint = GetNextPoint(pointB); Interpolate(ref output, previousPoint, pointA, pointB, nextPoint, deltas); }