/// <summary> /// This method calculates and caches rotation, distance, curveLeft, and curveRight. /// </summary> /// <param name="shouldRipple">Whether or not to tell neighbors to also recalc and cache. Rippling does not recurse, and so it only affects left and right.</param> void CacheData(bool shouldRipple) { cameraDataNode = GetComponent <CameraDataNode>(); angleCurveIn = angleCurveOut = percentCurveIn = percentCurveOut = length = 0; curveCenter = curveIn = curveOut = transform.position; if (shouldRipple) { if (left) { left.CacheData(false); // ripple outwards } if (right) { right.CacheData(false); // ripple outwards } } if (right) { // if there's a node to the right, use it to calculate and cache values for length & rotationYaw Vector3 diff = right.transform.position - transform.position; length = diff.magnitude; float angle = Mathf.Atan2(-diff.z, diff.x) * Mathf.Rad2Deg; rotationYaw = Quaternion.Euler(0, angle, 0); } if (left && right) { clampedCurveRadius = curveRadius; Vector3 p1 = left.transform.position; Vector3 p2 = transform.position; Vector3 p3 = right.transform.position; Vector3 leftDiff = OverwriteY(p1 - p2); // get the FLAT vector to left Vector3 rightDiff = OverwriteY(p3 - p2); // get the FLAT vector to right Vector3 leftAxis = leftDiff.normalized; // direction to left Vector3 rightAxis = rightDiff.normalized; // direction to right // the YAW to angle1 and angle2 float angleToP3 = Mathf.Atan2(rightDiff.z, rightDiff.x); // YAW from this to right float angleToP1 = Mathf.Atan2(leftDiff.z, leftDiff.x); // YAW from this to left angleToP3 = AngleWrapFromTo(angleToP3, angleToP1); // wrap the values into the same 180-degree arc if (Mathf.Abs(angleToP1 - angleToP3) >= Mathf.PI) // if in a straight line... don't try to curve. { clampedCurveRadius = 0; return; } float angleBetween = Mathf.Abs(angleToP3 - angleToP1) / 2; // save a step, and half the difference float angleToCenter = (angleToP3 + angleToP1) / 2; // angle from p2 to center... use the average of our previous two angles float maxAdjacent = Mathf.Min(leftDiff.magnitude, rightDiff.magnitude) * 0.5f; float cos = Mathf.Cos(angleBetween); float maxDistance = maxAdjacent / cos; float disToCenter = curveRadius / Mathf.Sin(angleBetween); if (maxDistance < disToCenter) { clampedCurveRadius *= maxDistance / disToCenter; disToCenter = maxDistance; } Vector3 axisToCenter = new Vector3(Mathf.Cos(angleToCenter), 0, Mathf.Sin(angleToCenter)); curveCenter = transform.position + axisToCenter * disToCenter; float disToInOut = cos * disToCenter; // use trig to find FLAT distance to curveIn and curveOut percentCurveIn = disToInOut / leftDiff.magnitude; // percent of the way from p2 to p1 percentCurveOut = disToInOut / rightDiff.magnitude; // percent of the way from p2 to p3 curveIn = Vector3.Lerp(p2, p1, percentCurveIn); curveOut = Vector3.Lerp(p2, p3, percentCurveOut); angleCurveIn = CurveAngleTo(curveIn); angleCurveOut = CurveAngleTo(curveOut); angleCurveOut = AngleWrapFromTo(angleCurveOut, angleCurveIn); } }