CylinderMesh GenerateCylinder(TelescopeParameters tParams, float slope, bool innerGroove = false, bool outerGroove = false, bool overhang = true, int extraRings = 0) { // We basically need to sweep a circular cross-section along a circular path. List <List <IndexedVertex> > circles = new List <List <IndexedVertex> >(); float lengthStep = 1f / (Constants.CUTS_PER_CYLINDER - 1); float radiusLoss = 0; int numCircles = Constants.CUTS_PER_CYLINDER + (overhang ? Constants.OVERHANG_CUTS : 0) + extraRings; // Generate vertices for (int i = 0; i < numCircles; i++) { radiusLoss = i * lengthStep * slope * tParams.length; Vector3 centerPoint = getLocalLocationAlongPath(i * lengthStep, tParams.curvature, tParams.torsion); Vector3 facingDirection = getDirectionAlongPath(i * lengthStep, tParams.curvature, tParams.torsion); Vector3 normalDirection = getNormalAlongPath(i * lengthStep, tParams.curvature, tParams.torsion); bool doInner = (innerGroove && i < Constants.CUTS_PER_CYLINDER + Constants.FIN_CUTS); bool doOuter = (outerGroove && i <= Constants.FIN_CUTS); List <IndexedVertex> circle = GenerateCircle(i, centerPoint, facingDirection, normalDirection, tParams.radius - radiusLoss, addInnerGrooves: doInner, addOuterGroove: doOuter); circles.Add(circle); } // Now generate faces List <IndexTriangle> allIndices = new List <IndexTriangle>(); for (int i = 0; i < numCircles - 1; i++) { List <IndexTriangle> tris = StitchCircles(circles[i], circles[i + 1]); allIndices.AddRange(tris); } CylinderMesh cm = new CylinderMesh(circles, allIndices); return(cm); }
public Mesh GenerateInnerVolume(TelescopeParameters nextParams, float arcOffset, int extraRings = 0) { currentIndex = 0; Mesh mesh = new Mesh(); // Get the inner cylinder of the shell CylinderMesh inner = GenerateInnerCylinder(nextParams, HasOverhang, arcOffset, extraRings: extraRings); // Get the vertices List <IndexedVertex> verticesList = flattenList(inner.circleCuts); // Create the triangles for the two ends of the cylinder; this also // adds 2 vertices to the list. List <IndexTriangle> capTris = CloseCylinderCaps(inner, verticesList); // Get the positions out of the list List <Vector3> vertices = verticesList.ConvertAll(new System.Converter <IndexedVertex, Vector3>(IndexedVertex.toVector3)); List <int> indicesList = new List <int>(); // Add triangles for the cylinder itself foreach (IndexTriangle tri in inner.triangles) { tri.addFrontFace(indicesList); } // Add triangles for the two ends foreach (IndexTriangle tri in capTris) { tri.addFrontFace(indicesList); } mesh.vertices = vertices.ToArray(); mesh.triangles = indicesList.ToArray(); mesh.RecalculateNormals(); mesh.RecalculateBounds(); return(mesh); }
public void GenerateGeometry(TelescopeParameters theParams, TelescopeParameters nextParams, bool doOverhang = true, bool outerGroove = true) { HasOverhang = doOverhang; this.thickness = theParams.thickness; this.length = theParams.length; this.radius = theParams.radius; this.curvature = theParams.curvature; this.torsion = theParams.torsion; this.twistAngle = theParams.twistFromParent; this.nextTwistAngle = (nextParams != null) ? nextParams.twistFromParent : 0; // Reset the mesh. currentIndex = 0; mFilter.mesh.Clear(); float slopeCosmetic = thickness * Constants.COSMETIC_TAPER_RATIO; TelescopeParameters outerParams = new TelescopeParameters(length, radius - Constants.SHELL_GAP, thickness, curvature, torsion, 0); CylinderMesh outerCyl = GenerateCylinder(outerParams, slopeCosmetic + Constants.TAPER_SLOPE, outerGroove: outerGroove, overhang: doOverhang); CylinderMesh innerCyl = GenerateInnerCylinder(nextParams, doOverhang, 0); // Flatten vertex list List <IndexedVertex> outerVerts = flattenList(outerCyl.circleCuts); List <IndexedVertex> innerVerts = flattenList(innerCyl.circleCuts); outerVerts.AddRange(innerVerts); // Get the triangles that join the inner and outer surfaces. List <IndexTriangle> edgeTriangles = stitchCylinderEnds(outerCyl, innerCyl); // Sort the vertices just to be safe outerVerts.Sort(); // Make vertex buffer List <Vector3> vecs = outerVerts.ConvertAll(new System.Converter <IndexedVertex, Vector3>(IndexedVertex.toVector3)); Vector3[] vertices = vecs.ToArray(); // Make index buffer List <int> indicesList = new List <int>(); foreach (IndexTriangle tri in outerCyl.triangles) { tri.addFrontFace(indicesList); } foreach (IndexTriangle tri in innerCyl.triangles) { tri.addBackFace(indicesList); } foreach (IndexTriangle tri in edgeTriangles) { tri.addFrontFace(indicesList); } mFilter.mesh.vertices = vertices; mFilter.mesh.triangles = indicesList.ToArray(); mFilter.mesh.RecalculateBounds(); mFilter.mesh.RecalculateNormals(); }
List <IndexTriangle> CloseCylinderCaps(CylinderMesh cylinder, List <IndexedVertex> verts) { List <IndexTriangle> triangles = new List <IndexTriangle>(); List <IndexedVertex> bottomCircle = cylinder.circleCuts[0]; List <IndexedVertex> topCircle = cylinder.circleCuts[cylinder.circleCuts.Count - 1]; // Compute center point of bottom circle. Vector3 bottomCenter = Vector3.zero; foreach (IndexedVertex v in bottomCircle) { bottomCenter += v.vertex; } bottomCenter /= bottomCircle.Count; // Compute center point of top circle. Vector3 topCenter = Vector3.zero; foreach (IndexedVertex v in topCircle) { topCenter += v.vertex; } topCenter /= topCircle.Count; // Add the two points to the mesh. IndexedVertex bottomCenterVert = new IndexedVertex(bottomCenter, currentIndex); currentIndex++; IndexedVertex topCenterVert = new IndexedVertex(topCenter, currentIndex); currentIndex++; verts.Add(bottomCenterVert); verts.Add(topCenterVert); // Add triangle fans. for (int i = 0; i < bottomCircle.Count; i++) { // Bottom circle gets CCW order int iPlus = (i + 1) % bottomCircle.Count; IndexedVertex i1 = bottomCenterVert; IndexedVertex i2 = bottomCircle[i]; IndexedVertex i3 = bottomCircle[iPlus]; IndexTriangle tri = new IndexTriangle(i1, i2, i3); triangles.Add(tri); } for (int i = 0; i < topCircle.Count; i++) { // Top circle gets CW order int iPlus = (i + 1) % topCircle.Count; IndexedVertex i1 = topCenterVert; IndexedVertex i2 = topCircle[iPlus]; IndexedVertex i3 = topCircle[i]; IndexTriangle tri = new IndexTriangle(i1, i2, i3); triangles.Add(tri); } return(triangles); }
List <IndexTriangle> stitchCylinderEnds(CylinderMesh outer, CylinderMesh inner) { if (outer.circleCuts.Count != inner.circleCuts.Count) { throw new System.Exception("Cylinders do not have same number of cuts."); } int numCuts = outer.circleCuts.Count; List <IndexTriangle> triangles = new List <IndexTriangle>(); List <IndexedVertex> topOuter = outer.circleCuts[numCuts - 1]; List <IndexedVertex> topInner = inner.circleCuts[numCuts - 1]; topVerts = topOuter.ConvertAll <Vector3>(new Converter <IndexedVertex, Vector3>(IndexedVertex.toVector3)); if (topOuter.Count != topInner.Count) { throw new System.Exception("Circles do not have same number of vertices."); } // Since the cuts are not necessarily aligned (in the case of curvature // or torsion changes), we want to stitch using the closest pairs of vertices. // Since we start with outer vertex i = 0, find the index of the inner vertex // closest to outer 0. Vector3 outer0top = topOuter[0].vertex; int topInnerOffset = 0; float closestDistance = Vector3.Distance(outer0top, topInner[0].vertex); for (int i = 0; i < topInner.Count; i++) { float dist = Vector3.Distance(topInner[i].vertex, outer0top); if (dist < closestDistance) { closestDistance = dist; topInnerOffset = i; } } // To join the top rim, we need to add the triangles with // counterclockwise ordering, since the vertices are clockwise // when viewed from below (not above). for (int outerI = 0; outerI < topOuter.Count; outerI++) { int outerIPlus = (outerI + 1) % topOuter.Count; int innerI = (outerI + topInnerOffset) % topInner.Count; int innerIPlus = (innerI + 1) % topInner.Count; // The triangles with two vertices in the outer circle have // the order outer[i], inner[i], outer[i+1]. IndexedVertex iv1 = topOuter[outerI]; IndexedVertex iv2 = topInner[innerI]; IndexedVertex iv3 = topOuter[outerIPlus]; IndexTriangle tri = new IndexTriangle(iv1, iv2, iv3); triangles.Add(tri); // The triangles with two vertices in the inner circle have // the order inner[i], inner[i+1], outer[i+1]. iv1 = topInner[innerI]; iv2 = topInner[innerIPlus]; iv3 = topOuter[outerIPlus]; tri = new IndexTriangle(iv1, iv2, iv3); triangles.Add(tri); } List <IndexedVertex> bottomOuter = outer.circleCuts[0]; List <IndexedVertex> bottomInner = inner.circleCuts[0]; bottomVerts = bottomOuter.ConvertAll <Vector3>(new Converter <IndexedVertex, Vector3>(IndexedVertex.toVector3)); if (bottomOuter.Count != bottomInner.Count) { throw new System.Exception("Circles do not have same number of vertices."); } // Same procedure as top ring: find starting vertex closest to // vertex 0 of outer ring. Vector3 outer0bottom = bottomOuter[0].vertex; int bottomInnerOffset = 0; closestDistance = Vector3.Distance(outer0bottom, bottomInner[0].vertex); for (int i = 0; i < bottomInner.Count; i++) { float dist = Vector3.Distance(bottomInner[i].vertex, outer0bottom); if (dist < closestDistance) { closestDistance = dist; bottomInnerOffset = i; } } // To join the bottom faces, we add triangles with vertices in clockwise order. for (int outerI = 0; outerI < bottomOuter.Count; outerI++) { int outerIPlus = (outerI + 1) % bottomOuter.Count; int innerI = (outerI + bottomInnerOffset) % bottomInner.Count; int innerIPlus = (innerI + 1) % bottomInner.Count; // The triangles with two vertices in the outer circle have // the order outer[i], outer[i+1], inner[i]. IndexedVertex iv1 = bottomOuter[outerI]; IndexedVertex iv2 = bottomOuter[outerIPlus]; IndexedVertex iv3 = bottomInner[innerI]; IndexTriangle tri = new IndexTriangle(iv1, iv2, iv3); triangles.Add(tri); // The triangles with two vertices in the inner circle have // the order inner[i], outer[i+1], inner[i+1]. iv1 = bottomInner[innerI]; iv2 = bottomOuter[outerIPlus]; iv3 = bottomInner[innerIPlus]; tri = new IndexTriangle(iv1, iv2, iv3); triangles.Add(tri); } return(triangles); }