private void GenerateSegment(Vector3 startPosition, Quaternion orientation, float segmentGrowth, List <int> startRing)
    {
        int segmentNumber = Mathf.FloorToInt(Growth - segmentGrowth);

        float startScale    = Mathf.Pow(segmentGrowth, Species.ScaleExponent);
        float endScale      = Mathf.Pow(segmentGrowth - 1, Species.ScaleExponent);
        float segmentLength = Species.SegmentLength * startScale;

        if (Species.SegmentAngleNoise > 0)
        {
            Quaternion noiseRotation = Quaternion.LookRotation(Random.insideUnitSphere, Vector3.up);
            orientation = Quaternion.Lerp(orientation, noiseRotation, Species.SegmentAngleNoise);
        }

        // build stem segment geometry

        int startVC = mg.VertexCount;

        mg.SetMaterial(0);

        float sliceAngle = 2 * Mathf.PI / Species.StemSides;

        if (startRing == null)
        {
            startRing = tempIndices.GetNext();
            startRing.Clear();

            for (int i = 0; i < Species.StemSides; i++)
            {
                startRing.Add(mg.AddVertex(RadialPoint(i * sliceAngle, Species.SegmentRadius * startScale, 0)));
            }
        }

        if (segmentGrowth >= 1)
        {
            // normal (tube) segment

            List <int> endRing = tempIndices.GetNext();
            endRing.Clear();

            for (int i = 0; i < Species.StemSides; i++)
            {
                endRing.Add(mg.AddVertex(RadialPoint(i * sliceAngle, Species.SegmentRadius * endScale, segmentLength)));
            }

            for (int i = 0; i < Species.StemSides; i++)
            {
                int j = (i + 1) % Species.StemSides;
                mg.AddFace(endRing[i], endRing[j], startRing[j], startRing[i]);
            }

            startRing = endRing;
        }
        else
        {
            // end (cone) segment

            int endPoint = mg.AddVertex(new Vector3(0, segmentLength, 0));

            for (int i = 0; i < Species.StemSides; i++)
            {
                int j = (i + 1) % Species.StemSides;
                mg.AddFace(endPoint, startRing[j], startRing[i]);
            }
        }

        // orient and position stem segment

        int endVC = mg.VertexCount;

        mg.RotateVertices(startVC, endVC, orientation);
        mg.TranslateVertices(startVC, endVC, startPosition);

        // grow leaves

        if (segmentNumber > 0 && segmentGrowth > Species.LeafThreshold && Species.LeavesPerSegment > 0)
        {
            float leafBaseRotation    = segmentNumber * 180 * (Fibonacci[Species.WhorlNumber] / (float)Fibonacci[Species.WhorlNumber + 1]);
            float leafAngleSeparation = 360f / Species.LeavesPerSegment;
            for (int i = 0; i < Species.LeavesPerSegment; i++)
            {
                Quaternion rotate = Quaternion.AngleAxis(leafBaseRotation + i * leafAngleSeparation, Vector3.up);

                if (Species.LeafAngleNoise > 0)
                {
                    Quaternion noiseRotation = Quaternion.LookRotation(Random.insideUnitSphere, Vector3.up);
                    rotate = Quaternion.Lerp(rotate, noiseRotation, Species.LeafAngleNoise);
                }

                GenerateLeaf(startPosition, rotate * orientation, segmentGrowth - Species.LeafThreshold);
            }
        }

        // grow a new segment if necessary

        if (segmentGrowth > 1)
        {
            Vector3 endOffset   = Vector3.up * segmentLength;
            Vector3 endPosition = startPosition + orientation * endOffset;
            GenerateSegment(endPosition, orientation, segmentGrowth - 1, startRing);
        }
    }