/// <summary> /// Generate a mesh for a spline according to the parallel transport algorithm. /// </summary> /// <param name="points">Points of the spline.</param> /// <param name="crossSectionShape">Vertices of the mesh cross section to be placed at each point.</param> /// <param name="crossSectionNormals">Normals of the cross section.</param> /// <param name="crossSectionScale">Vector to scale the cross section by. Can be used to control the diameter of the tube mesh.</param> /// <param name="generateCaps">Should the ends of the mesh be closed with planar meshes?</param> /// <returns></returns> public static Mesh GetMesh(List <Vector3> points, List <Vector3> crossSectionShape, List <Vector3> crossSectionNormals, Vector3 crossSectionScale, bool generateCaps) { List <Vector3> tangents = GetTangents(points); Vector3 initialNormal = Vector3.Cross(tangents[0], Vector3.right); if (initialNormal.magnitude == 0) { initialNormal = Vector3.Cross(tangents[0], Vector3.forward); } List <Vector3> normals = GetSplineNormals(initialNormal, tangents); List <Vector3> meshVertices = new List <Vector3>(); List <Vector3> meshNormals = new List <Vector3>(); for (int i = 0; i < points.Count; i++) { List <Vector3> transformedCrossSection = TransformPoints(crossSectionShape, points[i], tangents[i], normals[i], crossSectionScale); List <Vector3> transformedCrossSectionNormals = TransformNormals(crossSectionNormals, tangents[i], normals[i]); meshVertices.AddRange(transformedCrossSection); meshNormals.AddRange(transformedCrossSectionNormals); } //update triangles List <int> meshTriangles = new List <int>(Triangles.GenerateTrianglesCounterclockwise((meshVertices.Count / crossSectionShape.Count), crossSectionShape.Count)); //mesh is empty or there is just a single cross section left because second to last control point or last control point was removed if (meshVertices.Count <= crossSectionShape.Count && meshNormals.Count <= crossSectionShape.Count) { return(new Mesh()); } Mesh mesh; if (generateCaps) { (List <Vector3> capVertices, List <Vector3> capNormals, List <int> capTriangles) = TubeMesh.GenerateCapsMesh(meshVertices.GetRange(0, crossSectionShape.Count), meshVertices.GetRange(meshVertices.Count - crossSectionShape.Count, crossSectionShape.Count), meshVertices.Count); mesh = TubeMesh.GetMeshWithCaps(meshVertices, meshNormals, meshTriangles, capVertices, capNormals, capTriangles, crossSectionShape.Count); } else { mesh = new Mesh(); mesh.SetVertices(meshVertices); mesh.SetNormals(meshNormals); mesh.subMeshCount = 1; mesh.SetTriangles(meshTriangles.ToArray(), 0); mesh.SetUVs(0, TextureCoordinates.GenerateQuadrilateralUVsStretchU(meshVertices.Count, crossSectionShape.Count)); } mesh.RecalculateTangents(); return(mesh); }
/// <summary> /// Generates a patch surface mesh from a grid of control points. /// </summary> /// <param name="controlPoints">Flattened list of control points grid.</param> /// <param name="width">Number of control points horizontally.</param> /// <param name="height">Number of control points vertically.</param> /// <param name="resolutionWidth">Vertices between two control points horizontally.</param> /// <param name="resolutionHeight">Vertices between two control points vertically.</param> /// <returns></returns> public static Mesh GeneratePatchMesh(List <Vector3> controlPoints, int width, int height, int resolutionWidth, int resolutionHeight) { Vector3[] vertices = GenerateVerticesOfPatch(controlPoints, width, height, resolutionWidth, resolutionHeight); int[] trianglesArray = Triangles.GenerateTrianglesClockwise((width - 1) * resolutionWidth, (height - 1) * resolutionHeight); Mesh patchMesh = new Mesh(); patchMesh.SetVertices(vertices); patchMesh.SetTriangles(trianglesArray, 0); patchMesh.SetUVs(0, TextureCoordinates.GenerateQuadrilateralUVs(vertices.Length, (height - 1) * (resolutionHeight))); patchMesh.RecalculateNormals(); patchMesh.RecalculateTangents(); return(patchMesh); }