public void PrependShell() { Vector3 loc = shells[0].getLocalLocationAlongPath(-1); Quaternion rot = shells[0].getLocalRotationAlongPath(-1); TelescopeParameters p = new TelescopeParameters(shells[0].getParameters()); p.radius += p.thickness; // Create the new shell object GameObject newShell = new GameObject(); TelescopeShell shell = newShell.AddComponent <TelescopeShell>(); shell.GenerateGeometry(p, null); shell.setMaterial(material); Vector3 shellLoc = shells[0].transform.position; Quaternion shellRot = shells[0].transform.rotation; // Move the new shell to be in position to receive the old one shell.transform.parent = shells[0].transform.parent; shell.transform.position = shellLoc + shellRot * loc; shell.transform.rotation = shellRot * rot; // Reparent the old starting shell so it becomes the child of the new one shells[0].baseTranslation = Vector3.zero; shells[0].baseRotation = Quaternion.identity; shells[0].transform.parent = shell.transform; shell.extensionRatio = shells[0].extensionRatio; shells.Insert(0, shell); }
public void MakeShellsFromDiffs(List <TelescopeParameters> diffs) { initNumShells = diffs.Count; parameters = diffs; shells = new List <TelescopeShell>(); initialDirection.Normalize(); // Compute the absolute parameter values from the list of diffs we are given. List <TelescopeParameters> concreteParams = new List <TelescopeParameters>(); TelescopeParameters theParams = diffs[0]; concreteParams.Add(new TelescopeParameters(diffs[0])); for (int i = 1; i < initNumShells; i++) { if (diffs[i].radius > -wallThickness) { diffs[i].radius = -wallThickness; } theParams = theParams + diffs[i]; theParams.length -= 0; // wallThickness; //theParams.radius -= wallThickness; concreteParams.Add(theParams); } // Make sure the final shell is greater than the minimum possible width. if (concreteParams[concreteParams.Count - 1].radius < wallThickness) { concreteParams[concreteParams.Count - 1].radius = wallThickness; } // Make sure that all the shells fit inside each other. TelescopeUtils.growChainToFit(concreteParams); MakeShellsFromFinalList(concreteParams); }
public TelescopeShell addChildShell(TelescopeShell parent, TelescopeParameters parentParams, TelescopeParameters childParams, TelescopeParameters nextParams, bool isNotLast) { int i = shells.Count; // Make the new shell, and set the previous shell as its parent GameObject shellObj = new GameObject(); shellObj.transform.parent = parent.transform; shellObj.name = name + "-shell" + i; // Make the geometry, etc. TelescopeShell newShell = shellObj.AddComponent <TelescopeShell>(); newShell.GenerateGeometry(childParams, nextParams, doOverhang: true); newShell.setMaterial(material); // Set the shell's rest transformation relative to its parent. // When the shell's current extension ratio is 0, this is where // it is located relative to its parent. // newShell.baseRadians = newShell.radiansOfLength(wallThickness); newShell.baseTranslation = TelescopeUtils.childBasePosition(parentParams, childParams); newShell.baseRotation = TelescopeUtils.childBaseRotation(parentParams, childParams); shells.Add(newShell); shellObj.layer = 8; newShell.containingSegment = this; return(newShell); }
public TelescopeParameters(TelescopeParameters baseParams, TelescopeParameters diff) { length = baseParams.length + diff.length; radius = baseParams.radius + diff.radius; thickness = baseParams.thickness; curvature = baseParams.curvature + diff.curvature; torsion = baseParams.torsion + diff.torsion; twistFromParent = diff.twistFromParent; }
public TelescopeParameters(TelescopeParameters toCopy) { length = toCopy.length; radius = toCopy.radius; thickness = toCopy.thickness; curvature = toCopy.curvature; torsion = toCopy.torsion; twistFromParent = toCopy.twistFromParent; }
CylinderMesh GenerateInnerCylinder(TelescopeParameters nextParams, bool overhang, float arcOffset, int extraRings = 0) { TelescopeParameters ourParams = getParameters(); CylinderMesh innerCyl; // If there is a change in profile from this shell to the next... if (nextParams != null && (nextParams.curvature != curvature || nextParams.torsion != torsion || nextParams.radius < radius - Constants.WALL_THICKNESS * 1.01f)) { // Generate the outer profile of the child shell; this will become // the inner profile of this shell. TelescopeParameters innerParams = new TelescopeParameters(nextParams.length, nextParams.radius, nextParams.thickness, nextParams.curvature, nextParams.torsion, nextParams.twistFromParent); innerCyl = GenerateCylinder(innerParams, Constants.TAPER_SLOPE, innerGroove: true, overhang: overhang, extraRings: extraRings); // Move and rotate the inner profile so that the end circles align. Quaternion alignRotation = TelescopeUtils.childBaseRotation(ourParams, nextParams); Vector3 alignTranslation = TelescopeUtils.childBasePosition(ourParams, nextParams); Quaternion backRotation = TelescopeUtils.RotateAlongHelix(nextParams.curvature, nextParams.torsion, arcOffset); Vector3 backTranslation = TelescopeUtils.TranslateAlongHelix(nextParams.curvature, nextParams.torsion, arcOffset); innerCyl.ApplyRotation(backRotation); innerCyl.ApplyTranslation(backTranslation); innerCyl.ApplyRotation(alignRotation); innerCyl.ApplyTranslation(alignTranslation); } else { TelescopeParameters innerParams = new TelescopeParameters(length, radius - thickness, thickness, curvature, torsion, 0); innerCyl = GenerateCylinder(innerParams, Constants.TAPER_SLOPE, innerGroove: (nextParams != null), overhang: overhang, extraRings: extraRings); if (nextParams != null) { Quaternion backRotation = TelescopeUtils.RotateAlongHelix(nextParams.curvature, nextParams.torsion, arcOffset); Vector3 backTranslation = TelescopeUtils.TranslateAlongHelix(nextParams.curvature, nextParams.torsion, arcOffset); innerCyl.ApplyRotation(backRotation); innerCyl.ApplyTranslation(backTranslation); } } return(innerCyl); }
public static void growParentToChildHelix(TelescopeParameters parent, TelescopeParameters child, bool shrinkFit = false) { float maxRequiredRadius = 0; // Find the largest radius necessary at every point along the parent arc for (int i = 0; i <= Constants.CUTS_PER_CYLINDER; i++) { float arcPos = parent.length / Constants.CUTS_PER_CYLINDER * i; Vector3 parentPos = TranslateAlongHelix(parent.curvature, parent.torsion, arcPos); Vector3 parentT = FrameAlongHelix(parent.curvature, parent.torsion, arcPos).T; float minDot = 1; Vector3 closestPoint = parentPos; float closestArc = 0; // Find the point on the second arc nearest to the normal of the first one. for (int j = 0; j <= Constants.CUTS_PER_CYLINDER; j++) { float childArc = child.length / Constants.CUTS_PER_CYLINDER * j; Vector3 childPos = TranslateAlongHelix(child.curvature, child.torsion, childArc); Vector3 childOffset = childPos - parentPos; // Want the point to be in the orthogonal plane of the tangent, since // the cross-sections of the shell are circular in that plane float dot = Vector3.Dot(childOffset.normalized, parentT.normalized); if (Mathf.Abs(dot) < minDot) { minDot = Mathf.Abs(dot); closestPoint = childPos; closestArc = childArc; } } // Don't count the change if the dot product is too large, because this probably means // we went past the end of the arc segment. if (minDot > 0.3f) { continue; } // Write out the parameters for the circle in the child shell Vector3 closestTangent = FrameAlongHelix(child.curvature, child.torsion, closestArc).T; // Get the farthest point on the outside of the child shell Vector3 farthest = FarthestPointOnCircle(closestPoint, closestTangent, child.radius, parentPos); float requiredRadius = Vector3.Distance(farthest, parentPos); maxRequiredRadius = Mathf.Max(requiredRadius, maxRequiredRadius); } // Account for wall thickness maxRequiredRadius += Constants.WALL_THICKNESS; // Widen the parent so it contains the child shell. // However, don't ever decrease the thickness. parent.radius = Mathf.Max(parent.radius, maxRequiredRadius); }
/// <summary> /// Returns the local rotation of a child shell with the given parameters, /// such that, when used with the local position from childBasePosition, /// the end cross-section of the child will be perfectly aligned /// with the end cross-section of the parent with its parameters. /// </summary> /// <param name="parent"></param> /// <param name="child"></param> /// <param name="useTorsion"></param> /// <returns></returns> public static Quaternion childBaseRotation(TelescopeParameters parent, TelescopeParameters child, bool useTorsion = true) { float parentTorsion = (useTorsion) ? parent.torsion : 0; float childTorsion = (useTorsion) ? child.torsion : 0; Quaternion rotationToBase = RotateAlongHelix(parent.curvature, parentTorsion, parent.length); Quaternion rotationBack = RotateAlongHelix(child.curvature, childTorsion, -child.length); return(rotationToBase * rotationBack); }
/// <summary> /// Returns the local position of a child shell with the given parameters, /// such that (when combined with the local rotation from childBaseRotation) /// the end cross-section of the child will be perfectly aligned /// with the end cross-section of the parent with its parameters. /// </summary> /// <param name="parent"></param> /// <param name="child"></param> /// <param name="useTorsion"></param> /// <returns></returns> public static Vector3 childBasePosition(TelescopeParameters parent, TelescopeParameters child, bool useTorsion = true) { float parentTorsion = (useTorsion) ? parent.torsion : 0; float childTorsion = (useTorsion) ? child.torsion : 0; Vector3 translationToBase = TranslateAlongHelix(parent.curvature, parentTorsion, parent.length); Quaternion rotationToBase = RotateAlongHelix(parent.curvature, parentTorsion, parent.length); Vector3 translationBackwards = TranslateAlongHelix(child.curvature, childTorsion, -child.length); translationToBase = translationToBase + (rotationToBase * translationBackwards); return(translationToBase); }
public static void growParentToChild(TelescopeParameters parent, TelescopeParameters child, bool shrinkFit = false) { // Compute the coordinates of the child's starting position, // in the parent's coordinate frame. Vector3 childBasePos = childBasePosition(parent, child); Quaternion childBaseRot = childBaseRotation(parent, child); Vector3 childOutward = childBaseRot * Vector3.down; // Compute the two inner corners of the child, when nested inside its // parent; these are the corners we want to bounds check. Vector3 retractedInner = childBasePos - (child.radius * childOutward); Vector3 retractedOuter = childBasePos + (child.radius * childOutward); // If the parent has no curvature, then the required width is just the // max absolute y value of the child. float finalRadius; if (parent.curvature < 1e-6) { finalRadius = Mathf.Max(Mathf.Abs(retractedInner.y), Mathf.Abs(retractedOuter.y)) + parent.thickness; if (!shrinkFit) { finalRadius = Mathf.Max(finalRadius, parent.radius); } } // Otherwise we need to compute the distance from the center line to the // corners, and take their max distance. else { // Fact: The centers of rotation for the parent and the extended child both lie // on the line (in the ZY plane) defined by the parent's center and its far face. float parentRadius = 1f / parent.curvature; Vector3 centerOfRotation = new Vector3(0, parentRadius, 0); // Now we can determine what width we need to 'fatten' the parent by. float innerDistance = Vector3.Distance(retractedInner, centerOfRotation); float outerDistance = Vector3.Distance(retractedOuter, centerOfRotation); float innerDiff = Mathf.Abs(innerDistance - parentRadius); float outerDiff = Mathf.Abs(outerDistance - parentRadius); finalRadius = Mathf.Max(innerDiff, outerDiff) + parent.thickness; if (!shrinkFit) { finalRadius = Mathf.Max(finalRadius, parent.radius); } } parent.radius = finalRadius; // parent.thickness += widthChange; }
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 void SelectShell(TelescopeShell selection) { if (!selection) { return; } if (selected) { selected.setMaterial(defaultTelescopeMaterial); } selected = selection; selected.setMaterial(selectedTelescopeMaterial); TelescopeParameters tp = selected.getParameters(); lengthField.text = tp.length.ToString(); radiusField.text = tp.radius.ToString(); curvatureField.text = tp.curvature.ToString(); twistField.text = tp.twistFromParent.ToString(); }
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); }
TelescopeSegment CreateStraightSegment(float length, float radius) { GameObject segObj = new GameObject(); TelescopeSegment seg = segObj.AddComponent <TelescopeSegment>(); List <TelescopeParameters> paramList = new List <TelescopeParameters>(); float thickness = Constants.WALL_THICKNESS; float startRadius = radius + 3 * thickness + 3 * length * Constants.TAPER_SLOPE; TelescopeParameters firstParam = new TelescopeParameters(length, startRadius, thickness, 0, 0, 0); paramList.Add(firstParam); paramList.Add(new TelescopeParameters(0, 0, 0, 0, 0, 0)); paramList.Add(new TelescopeParameters(0, 0, 0, 0, 0, 0)); seg.material = segment1.material; seg.MakeShellsFromDiffs(paramList); seg.transform.parent = transform; return(seg); }
public TelescopeParameters getParameters() { TelescopeParameters tp = new TelescopeParameters(length, radius, thickness, curvature, torsion, twistAngle); return(tp); }
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(); }
public static TelescopeParameters operator +(TelescopeParameters t1, TelescopeParameters t2) { TelescopeParameters sum = new TelescopeParameters(t1, t2); return(sum); }
public static TelescopeSegment telescopeOfCone(Vector3 startPos, float startRadius, Vector3 endPos, float endRadius, Vector3 curvatureCenter, float wallThickness = Constants.WALL_THICKNESS, bool useCurvature = false) { float curvature; Vector3 segmentDirection; if (useCurvature) { float radius = Vector3.Distance(curvatureCenter, startPos); curvature = 1f / radius; if (curvature < 1e-6) { curvature = 0; segmentDirection = endPos - startPos; segmentDirection.Normalize(); } else { segmentDirection = CurveDirectionFromParent(startPos, endPos, curvatureCenter); } } else { curvature = 0; segmentDirection = endPos - startPos; segmentDirection.Normalize(); } float distance = ArcLengthFromChord(startPos, endPos, curvature); int numShells = Mathf.CeilToInt((Mathf.Max(startRadius, endRadius) - Mathf.Min(startRadius, endRadius)) / wallThickness); if (numShells < 2) { numShells = 2; } // int numShells = Mathf.CeilToInt(distance / Mathf.Min(startRadius, endRadius)); // Length is just the distance we need to cover divided by the number of shells. float lengthPerShell = distance / numShells; // We attempt to choose the radii such that the telescope tapers from the start // radius to the end radius over the given number of shells. float radiusStep = (startRadius - endRadius) / numShells; float twist = 0; if (curvature >= 1e-6) { // Compute twist angles Quaternion rotationToOrigin = Quaternion.FromToRotation(Vector3.forward, segmentDirection); // The "up" direction we would like to have -- orthogonal direction from circle center. Vector3 startEnd = endPos - startPos; Vector3 desiredUp = startEnd - Vector3.Dot(segmentDirection, startEnd) * segmentDirection; desiredUp.Normalize(); Vector3 inverseDesired = Quaternion.Inverse(rotationToOrigin) * desiredUp; // The angle computation doesn't work right in 3rd and 4th quadrants, // so work around it by doing everything in 1st and 2nd. if (inverseDesired.x < 0) { inverseDesired *= -1; twist = 180; } float angleBetween = Mathf.Atan2(Vector3.Cross(Vector3.up, inverseDesired).magnitude, Vector3.Dot(Vector3.up, inverseDesired)); twist += -angleBetween * Mathf.Rad2Deg; } List <TelescopeParameters> diffList = new List <TelescopeParameters>(); // Create the initial shell parameters. TelescopeParameters initialParams = new TelescopeParameters(lengthPerShell, startRadius, wallThickness, curvature, 0, twist); diffList.Add(initialParams); // Create all the diffs. for (int i = 1; i < numShells; i++) { TelescopeParameters tp = new TelescopeParameters(0, -radiusStep, wallThickness, 0, 0, 0); diffList.Add(tp); } // Create a game object that will be the new segment. GameObject obj = new GameObject(); obj.name = "segment" + segmentCount; segmentCount++; obj.transform.position = startPos; TelescopeSegment seg = obj.AddComponent <TelescopeSegment>(); seg.material = DesignerController.instance.defaultTelescopeMaterial; seg.initialDirection = segmentDirection; seg.MakeShellsFromDiffs(diffList); seg.transform.position = startPos; return(seg); }
public static TelescopeParameters shrinkChildToParent(TelescopeParameters parent, TelescopeParameters child) { Debug.Log("Unimplemented"); return(child); }
public TelescopeSegment MakeTelescope(float startRadius, bool reverse = false) { List <TelescopeParameters> tParams = new List <TelescopeParameters>(); CurveSegment initialSeg = (reverse) ? segments[segments.Count - 1] : segments[0]; float wallThickness = Constants.WALL_THICKNESS; float currRadius = startRadius * BulbShrinkRatio; TelescopeParameters initial = new TelescopeParameters(initialSeg.arcLength, currRadius, Constants.WALL_THICKNESS, initialSeg.curvature, initialSeg.torsion, 0); tParams.Add(initial); for (int i = 1; i < segments.Count; i++) { int index = (reverse) ? segments.Count - 1 - i : i; /* * if (i == 2 && StartJuncture && StartJuncture.childCurves.Count == 5) * { * Debug.Log("Hack to create lizard toenails, please delete once done"); * currRadius -= 1.5f * wallThickness; * }*/ // Subtract the wall thickness of the previous piece currRadius -= wallThickness; float curvature = (reverse) ? segments[index].curvature : segments[index].curvature; float torsion = (reverse) ? segments[index].torsion : segments[index].torsion; float impulse = (reverse) ? -segments[index + 1].impulse : -segments[index].impulse; impulse *= Mathf.Rad2Deg; TelescopeParameters p = new TelescopeParameters(segments[index].arcLength, currRadius, wallThickness, curvature, torsion, impulse); tParams.Add(p); } GameObject obj = new GameObject(); obj.name = "telescope" + (numScopes++); TelescopeSegment segment = obj.AddComponent <TelescopeSegment>(); segment.paramMode = SegmentParametersMode.Concrete; segment.material = DesignerController.instance.defaultTelescopeMaterial; if (reverse) { CurveSegment lastSeg = segments[segments.Count - 1]; obj.transform.position = TransformedHelixPoint(lastSeg, lastSeg.arcLength); OrthonormalFrame initFrame = TransformedHelixFrame(lastSeg, lastSeg.arcLength); segment.initialDirection = -initFrame.T; segment.initialUp = initFrame.N; } else { obj.transform.position = segments[0].startPosition; segment.initialDirection = segments[0].frame.T; segment.initialUp = segments[0].frame.N; } segment.MakeShellsFromConcrete(tParams); if (reverse) { segment.ReverseTelescope(); } return(segment); }
public void MakeAllShells(List <TelescopeParameters> paramList, bool reversed = false) { DeleteTelescope(); // Create an object for the first shell GameObject rootShellObj = new GameObject(); rootShellObj.name = name + "-shell0"; rootShellObj.transform.parent = this.transform; rootShellObj.transform.localPosition = Vector3.zero; telescopeRootShell = rootShellObj; // Make the shell geometry TelescopeShell shell = rootShellObj.AddComponent <TelescopeShell>(); // Get the twist impulse of the shell after, since we need to cut the // grooves in this shell to enable it TelescopeParameters params1 = (paramList.Count > 1) ? paramList[1] : null; shell.GenerateGeometry(paramList[0], params1, outerGroove: false); shell.setMaterial(material); // Shells don't know anything about their position/rotation, // so we set that here. Quaternion initialFacing = Quaternion.LookRotation(initialDirection, initialUp); rootShellObj.transform.rotation = initialFacing; rootShellObj.layer = 8; shell.containingSegment = this; // shell.baseRadians = 0; shell.baseTranslation = Vector3.zero; shell.baseRotation = Quaternion.identity; shells.Add(shell); shell.isRoot = true; // Make all of the child shells here. TelescopeShell prevShell = shell; TelescopeParameters previousParams = paramList[0]; TelescopeParameters currentParams = paramList[0]; float accumulatedTaper = shell.getTaperLoss(); for (int i = 1; i < paramList.Count; i++) { // Get the computed parameters for this and the previous shell. currentParams = paramList[i]; previousParams = paramList[i - 1]; // Shrink the radius by the accumulated taper so far. currentParams.radius -= accumulatedTaper; // Get the twist impulse for the next shell, so that we can cut the grooves. TelescopeParameters nextParams = (i < paramList.Count - 1) ? paramList[i + 1] : null; TelescopeParameters taperedParams = (nextParams != null) ? new TelescopeParameters(nextParams) : null; if (taperedParams != null) { taperedParams.radius -= accumulatedTaper; } // Add it. bool isNotLast = (i < paramList.Count - 1); prevShell = addChildShell(prevShell, previousParams, currentParams, taperedParams, isNotLast); accumulatedTaper += prevShell.getTaperLoss(); } if (fountainPrefab) { GameObject fountain = Instantiate <GameObject>(fountainPrefab); fountain.transform.parent = prevShell.transform; } }