public OrthonormalFrame PropagateBishop(Vector3 prevPos, Vector3 nextPos, OrthonormalFrame prevFrame) { Vector3 tangent = (nextPos - position).normalized; Vector3 prevTangent = (position - prevPos).normalized; Vector3 binormal = Vector3.Cross(prevTangent, tangent).normalized; float angle = TelescopeUtils.AngleBetween(prevTangent, tangent, binormal); Quaternion rotation = Quaternion.AngleAxis(angle, binormal); OrthonormalFrame rotated = prevFrame.RotatedBy(rotation); bishopFrame = rotated; return(rotated); }
/// <summary> /// Create a set of vertices arranged evenly spaced in a circle, with the specified radius, /// centered at centerPoint, and with the specified normal direction. The number of vertices /// is given by verticesPerCircle. /// </summary> /// <param name="centerPoint"></param> /// <param name="direction"></param> /// <param name="radius"></param> /// <returns></returns> List <IndexedVertex> GenerateCircle(int circNum, Vector3 centerPoint, Vector3 direction, Vector3 normal, float radius, bool addInnerGrooves = false, bool addOuterGroove = false) { float angleStep = (2 * Mathf.PI) / Constants.VERTS_PER_CIRCLE; float degreeStep = angleStep * Mathf.Rad2Deg; int twistCuts = Mathf.CeilToInt(Mathf.Abs(nextTwistAngle) / degreeStep); twistCuts *= Mathf.RoundToInt(Mathf.Sign(nextTwistAngle)); List <IndexedVertex> verts = new List <IndexedVertex>(); int grooveRange = Constants.GROOVE_CUT_RADIUS; // First create points in a circle in the XY plane, facing the forward direction. // Then apply the rotation that will rotate the normal onto the desired direction. // Finally, offset it in space to the desired location. Quaternion circleRotation = Quaternion.FromToRotation(Vector3.forward, direction); Vector3 initNormal = Vector3.up; Vector3 rotatedNormal = circleRotation * initNormal; float angle = TelescopeUtils.AngleBetween(rotatedNormal, normal, direction); Quaternion normalRotation = Quaternion.AngleAxis(angle, direction); for (int i = 0; i < Constants.VERTS_PER_CIRCLE; i++) { float currentAngle = i * angleStep; float radiusOffset = 0; if (i < grooveRange || Mathf.Abs(i - Constants.VERTS_PER_CIRCLE / 2) < grooveRange || Mathf.Abs(i - Constants.VERTS_PER_CIRCLE) < grooveRange) { if (addInnerGrooves) { radiusOffset = (thickness - Constants.SHELL_GAP) * Constants.INDENT_RATIO; } else if (addOuterGroove) { radiusOffset = (thickness - Constants.SHELL_GAP / 2) * Constants.INDENT_RATIO; } } else if (circNum >= Constants.CUTS_PER_CYLINDER - 1 && circNum < Constants.CUTS_PER_CYLINDER + Constants.FIN_CUTS) { if (addInnerGrooves && (IsInRadius(i, 0, twistCuts, grooveRange) || IsInRadius(i, Constants.VERTS_PER_CIRCLE, Constants.VERTS_PER_CIRCLE + twistCuts, grooveRange) || IsInRadius(i, Constants.VERTS_PER_CIRCLE / 2, Constants.VERTS_PER_CIRCLE / 2 + twistCuts, grooveRange))) { radiusOffset = (thickness - Constants.SHELL_GAP) * Constants.INDENT_RATIO; } } // Make the vertices in clockwise order Vector3 vert = new Vector3(Mathf.Cos(currentAngle), -Mathf.Sin(currentAngle)); // Scale by radius. vert *= (radius + radiusOffset); // Rotate it to orbit the desired direction. vert = circleRotation * vert; // Rotate it again so that the curvature normal is aligned. vert = normalRotation * vert; // Offset in space to the center point. vert += centerPoint; IndexedVertex iv = new IndexedVertex(vert, currentIndex); currentIndex++; verts.Add(iv); } return(verts); }
// Compute all internal bending axes/angles from a list of points. public void InitFromPoints(List <Vector3> points, float segLength) { segmentLength = segLength; StartingPoint = points[0]; startingTangent = points[1] - points[0]; startingTangent.Normalize(); discretizedPoints = new List <DCurvePoint>(); Vector3 prevBinormal = Vector3.zero; // We need to store bending angles / directions of all the interior // vertices of the curve (but not the endpoints). for (int i = 1; i < points.Count - 1; i++) { Vector3 previousVec = points[i] - points[i - 1]; Vector3 nextVec = points[i + 1] - points[i]; previousVec.Normalize(); nextVec.Normalize(); // If zero, then treat it as a straight segment if (nextVec.magnitude < 0.5f) { DCurvePoint d = new DCurvePoint(prevBinormal, 0, 0); discretizedPoints.Add(d); continue; } Vector3 curvatureBinormal = Vector3.Cross(previousVec, nextVec).normalized; if (i == 1) { startingBinormal = curvatureBinormal; } // Compute bending angles (discrete curvature). float dot = Vector3.Dot(previousVec, nextVec); float bendAngle = (dot >= 1) ? 0 : Mathf.Rad2Deg * Mathf.Acos(dot); // Compute twisting angles (discrete torsion). float twistAngle; // Compute twist angles as we go along. // The first vertex is considered to have no twist. if (i == 1) { twistAngle = 0; } else { twistAngle = TelescopeUtils.AngleBetween(prevBinormal, curvatureBinormal, previousVec); // If the bend angle is tiny, then the curve is basically straight, so // just set twist values to 0 to avoid unnecessary twisting. /*if (Mathf.Abs(bendAngle) <= 0.1) * { * bendAngle = 0; * twistAngle = 0; * }*/ } if (float.IsNaN(bendAngle)) { throw new System.Exception("Bend angle is nan, dot = " + dot); } if (float.IsNaN(twistAngle)) { throw new System.Exception("Twist angle is nan"); } prevBinormal = curvatureBinormal; DCurvePoint dcp = new DCurvePoint(curvatureBinormal.normalized, bendAngle, twistAngle); discretizedPoints.Add(dcp); } if (startingBinormal.magnitude < 0.001f) { if (startingTangent == Vector3.up) { startingBinormal = Vector3.right; } else { startingBinormal = Vector3.up; Vector3 orthogonal = Vector3.Dot(startingBinormal, startingTangent) * startingTangent; startingBinormal = startingBinormal - orthogonal; startingBinormal.Normalize(); } } targetEndPoint = ReconstructFromAngles(); ComputeFrenetFrames(); ComputeBishopFrames(); }