コード例 #1
0
        public SimpleMesh GenerateSimpleMesh(Primitive prim, DetailLevel lod)
        {
            Path    path    = GeneratePath();
            Profile profile = GenerateProfile();

            MeshmerizerMesh meshmerizer = new MeshmerizerMesh();

            meshmerizer = GenerateMeshmerizerMesh(prim);

            // Create the vertex array
            List <Vertex> vertices = new List <Vertex>(meshmerizer.primMesh.coords.Count);

            for (int i = 0; i < meshmerizer.primMesh.coords.Count; i++)
            {
                Coord  c      = meshmerizer.primMesh.coords[i];
                Vertex vertex = new Vertex();
                vertex.Position = new Vector3(c.X, c.Y, c.Z);
                vertices.Add(vertex);
            }

            // Create the index array
            List <ushort> indices = new List <ushort>(meshmerizer.primMesh.faces.Count * 3);

            for (int i = 0; i < meshmerizer.primMesh.faces.Count; i++)
            {
                MeshmerizerFace f = meshmerizer.primMesh.faces[i];
                indices.Add((ushort)f.v1);
                indices.Add((ushort)f.v2);
                indices.Add((ushort)f.v3);
            }

            SimpleMesh mesh = new SimpleMesh();

            mesh.Prim     = prim;
            mesh.Path     = path;
            mesh.Profile  = profile;
            mesh.Vertices = vertices;
            mesh.Indices  = indices;

            return(mesh);
        }
コード例 #2
0
        private List <Face> GenerateFaces(Primitive prim)
        {
            MeshmerizerMesh meshmerizer = new MeshmerizerMesh();

            meshmerizer = GenerateMeshmerizerMesh(prim);

            // Create the vertex array
            List <Vertex> vertices = new List <Vertex>(meshmerizer.primMesh.coords.Count);

            for (int i = 0; i < meshmerizer.primMesh.coords.Count; i++)
            {
                Coord  c      = meshmerizer.primMesh.coords[i];
                Vertex vertex = new Vertex();
                vertex.Position = new Vector3(c.X, c.Y, c.Z);
                vertices.Add(vertex);
            }

            // Create the index array
            List <ushort> indices = new List <ushort>(meshmerizer.primMesh.faces.Count * 3);

            for (int i = 0; i < meshmerizer.primMesh.faces.Count; i++)
            {
                MeshmerizerFace f = meshmerizer.primMesh.faces[i];
                indices.Add((ushort)f.v1);
                indices.Add((ushort)f.v2);
                indices.Add((ushort)f.v3);
            }

            Face face = new Face();

            face.Edge        = new List <int>();
            face.TextureFace = prim.Textures.DefaultTexture;
            face.Vertices    = vertices;
            face.Indices     = indices;

            List <Face> faces = new List <Face>(1);

            faces.Add(face);

            return(faces);
        }
コード例 #3
0
ファイル: PrimMesher.cs プロジェクト: Vinhold/halcyon
        public void ExtrudeCircular()
        {
            this.coords = new List<Coord>();
            this.faces = new List<MeshmerizerFace>();

            int step = 0;
            int steps = 24;

            float twistBegin = this.twistBegin / 360.0f * twoPi;
            float twistEnd = this.twistEnd / 360.0f * twoPi;
            float twistTotal = twistEnd - twistBegin;

            // if the profile has a lot of twist, add more layers otherwise the layers may overlap
            // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't
            // accurately match the viewer
            float twistTotalAbs = Math.Abs(twistTotal);
            if (twistTotalAbs > 0.01f)
            {
                if (twistTotalAbs > Math.PI * 1.5f)
                    steps *= 2;
                if (twistTotalAbs > Math.PI * 3.0f)
                    steps *= 2;
            }

            float yPathScale = this.holeSizeY * 0.5f;
            float pathLength = this.pathCutEnd - this.pathCutBegin;
            float totalSkew = this.skew * 2.0f * pathLength;
            float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew;
            float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY));
            float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f;

            // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end
            // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used
            // to calculate the sine for generating the path radius appears to approximate it's effects there
            // too, but there are some subtle differences in the radius which are noticeable as the prim size
            // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on
            // the meshes generated with this technique appear nearly identical in shape to the same prims when
            // displayed by the viewer.

            float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f;
            float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f;
            float stepSize = twoPi / this.stepsPerRevolution;

            step = (int)(startAngle / stepSize);
            int firstStep = step;
            float angle = startAngle;
            float hollow = this.hollow;

            // sanity checks
            float initialProfileRot = 0.0f;
            if (this.sides == 3)
            {
                initialProfileRot = (float)Math.PI;
                if (this.hollowSides == 4)
                {
                    if (hollow > 0.7f)
                        hollow = 0.7f;
                    hollow *= 0.707f;
                }
                else hollow *= 0.5f;
            }
            else if (this.sides == 4)
            {
                initialProfileRot = 0.25f * (float)Math.PI;
                if (this.hollowSides != 4)
                    hollow *= 0.707f;
            }
            else if (this.sides > 4)
            {
                initialProfileRot = (float)Math.PI;
                if (this.hollowSides == 4)
                {
                    if (hollow > 0.7f)
                        hollow = 0.7f;
                    hollow /= 0.7f;
                }
            }

            bool needEndFaces = false;
            if (this.pathCutBegin != 0.0 || this.pathCutEnd != 1.0)
                needEndFaces = true;
            else if (this.taperX != 0.0 || this.taperY != 0.0)
                needEndFaces = true;
            else if (this.skew != 0.0)
                needEndFaces = true;
            else if (twistTotal != 0.0)
                needEndFaces = true;

            MeshmerizerProfile profile = new MeshmerizerProfile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, needEndFaces);

            if (initialProfileRot != 0.0f)
                profile.AddRot(Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), initialProfileRot));

            bool done = false;
            while (!done) // loop through the length of the path and add the layers
            {
                bool isEndLayer = false;
                if (angle == startAngle || angle >= endAngle)
                    isEndLayer = true;

                MeshmerizerProfile newLayer = profile.Clone(isEndLayer && needEndFaces);

                float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX;
                float yProfileScale = this.holeSizeY;

                float percentOfPath = angle / (twoPi * this.revolutions);
                float percentOfAngles = (angle - startAngle) / (endAngle - startAngle);

                if (this.taperX > 0.01f)
                    xProfileScale *= 1.0f - percentOfPath * this.taperX;
                else if (this.taperX < -0.01f)
                    xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX;

                if (this.taperY > 0.01f)
                    yProfileScale *= 1.0f - percentOfPath * this.taperY;
                else if (this.taperY < -0.01f)
                    yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY;

                if (xProfileScale != 1.0f || yProfileScale != 1.0f)
                    newLayer.Scale(xProfileScale, yProfileScale);

                float radiusScale = 1.0f;
                if (this.radius > 0.001f)
                    radiusScale = 1.0f - this.radius * percentOfPath;
                else if (this.radius < 0.001f)
                    radiusScale = 1.0f + this.radius * (1.0f - percentOfPath);

                float twist = twistBegin + twistTotal * percentOfPath;

                float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles);
                xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor;

                float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale;

                float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale;

                // next apply twist rotation to the profile layer
                if (twistTotal != 0.0f || twistBegin != 0.0f)
                    newLayer.AddRot(Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), twist));

                // now orient the rotation of the profile layer relative to it's position on the path
                // adding taperY to the angle used to generate the quat appears to approximate the viewer
                //newLayer.AddRot(new Quaternion(new MeshmerizerVertex(1.0f, 0.0f, 0.0f), angle + this.topShearY * 0.9f));
                newLayer.AddRot(Quaternion.CreateFromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), angle + this.topShearY));
                newLayer.AddPos(xOffset, yOffset, zOffset);

                if (angle == startAngle)
                    newLayer.FlipNormals();

                // append the layer and fill in the sides

                int coordsLen = this.coords.Count;
                newLayer.AddValue2Faces(coordsLen);

                this.coords.AddRange(newLayer.coords);

                if (isEndLayer)
                    this.faces.AddRange(newLayer.faces);

                // fill faces between layers

                int numVerts = newLayer.coords.Count;
                MeshmerizerFace newFace = new MeshmerizerFace();
                if (step > firstStep)
                {
                    for (int i = coordsLen; i < this.coords.Count - 1; i++)
                    {
                        newFace.v1 = i;
                        newFace.v2 = i - numVerts;
                        newFace.v3 = i - numVerts + 1;
                        this.faces.Add(newFace);

                        newFace.v2 = i - numVerts + 1;
                        newFace.v3 = i + 1;
                        this.faces.Add(newFace);
                    }

                    newFace.v1 = coordsLen - 1;
                    newFace.v2 = coordsLen - numVerts;
                    newFace.v3 = coordsLen;
                    this.faces.Add(newFace);

                    newFace.v1 = coordsLen + numVerts - 1;
                    newFace.v2 = coordsLen - 1;
                    newFace.v3 = coordsLen;
                    this.faces.Add(newFace);
                }

                // calculate terms for next iteration
                // calculate the angle for the next iteration of the loop

                if (angle >= endAngle)
                    done = true;
                else
                {
                    step += 1;
                    angle = stepSize * step;
                    if (angle > endAngle)
                        angle = endAngle;
                }
            }
        }
コード例 #4
0
ファイル: PrimMesher.cs プロジェクト: Vinhold/halcyon
        public void ExtrudeLinear()
        {
            this.coords = new List<Coord>();
            this.faces = new List<MeshmerizerFace>();

            int step = 0;
            int steps = 1;

            float length = this.pathCutEnd - this.pathCutBegin;
            float twistBegin = this.twistBegin / 360.0f * twoPi;
            float twistEnd = this.twistEnd / 360.0f * twoPi;
            float twistTotal = twistEnd - twistBegin;
            float twistTotalAbs = Math.Abs(twistTotal);
            if (twistTotalAbs > 0.01f)
                steps += (int)(twistTotalAbs * 3.66); //  dahlia's magic number

            float start = -0.5f;
            float stepSize = length / (float)steps;
            float percentOfPathMultiplier = stepSize;
            float xProfileScale = 1.0f;
            float yProfileScale = 1.0f;
            float xOffset = 0.0f;
            float yOffset = 0.0f;
            float zOffset = start;
            float xOffsetStepIncrement = this.topShearX / steps;
            float yOffsetStepIncrement = this.topShearY / steps;

            float percentOfPath = this.pathCutBegin;
            zOffset += percentOfPath;

            float hollow = this.hollow;

            // sanity checks
            float initialProfileRot = 0.0f;
            if (this.sides == 3)
            {
                if (this.hollowSides == 4)
                {
                    if (hollow > 0.7f)
                        hollow = 0.7f;
                    hollow *= 0.707f;
                }
                else hollow *= 0.5f;
            }
            else if (this.sides == 4)
            {
                initialProfileRot = 1.25f * (float)Math.PI;
                if (this.hollowSides != 4)
                    hollow *= 0.707f;
            }
            else if (this.sides == 24 && this.hollowSides == 4)
                hollow *= 1.414f;

            MeshmerizerProfile profile = new MeshmerizerProfile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true);

            if (initialProfileRot != 0.0f)
                profile.AddRot(Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), initialProfileRot));

            bool done = false;
            while (!done)
            {
                MeshmerizerProfile newLayer = profile.Clone();

                if (this.taperX == 0.0f)
                    xProfileScale = 1.0f;
                else if (this.taperX > 0.0f)
                    xProfileScale = 1.0f - percentOfPath * this.taperX;
                else xProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperX;

                if (this.taperY == 0.0f)
                    yProfileScale = 1.0f;
                else if (this.taperY > 0.0f)
                    yProfileScale = 1.0f - percentOfPath * this.taperY;
                else yProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperY;

                if (xProfileScale != 1.0f || yProfileScale != 1.0f)
                    newLayer.Scale(xProfileScale, yProfileScale);

                float twist = twistBegin + twistTotal * percentOfPath;
                if (twist != 0.0f)
                    newLayer.AddRot(Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), twist));

                newLayer.AddPos(xOffset, yOffset, zOffset);

                if (step == 0)
                    newLayer.FlipNormals();

                // append this layer

                int coordsLen = this.coords.Count;
                newLayer.AddValue2Faces(coordsLen);

                this.coords.AddRange(newLayer.coords);

                if (percentOfPath <= this.pathCutBegin || percentOfPath >= this.pathCutEnd)
                    this.faces.AddRange(newLayer.faces);

                // fill faces between layers

                int numVerts = newLayer.coords.Count;
                MeshmerizerFace newFace = new MeshmerizerFace();
                if (step > 0)
                {
                    for (int i = coordsLen; i < this.coords.Count - 1; i++)
                    {
                        newFace.v1 = i;
                        newFace.v2 = i - numVerts;
                        newFace.v3 = i - numVerts + 1;
                        this.faces.Add(newFace);

                        newFace.v2 = i - numVerts + 1;
                        newFace.v3 = i + 1;
                        this.faces.Add(newFace);
                    }

                    newFace.v1 = coordsLen - 1;
                    newFace.v2 = coordsLen - numVerts;
                    newFace.v3 = coordsLen;
                    this.faces.Add(newFace);

                    newFace.v1 = coordsLen + numVerts - 1;
                    newFace.v2 = coordsLen - 1;
                    newFace.v3 = coordsLen;
                    this.faces.Add(newFace);
                }

                // calc the step for the next iteration of the loop

                if (step < steps)
                {
                    step += 1;
                    percentOfPath += percentOfPathMultiplier;
                    xOffset += xOffsetStepIncrement;
                    yOffset += yOffsetStepIncrement;
                    zOffset += stepSize;
                    if (percentOfPath > this.pathCutEnd)
                        done = true;
                }
                else done = true;
            }
        }
コード例 #5
0
        public void ExtrudeCircular()
        {
            this.coords = new List <Coord>();
            this.faces  = new List <MeshmerizerFace>();

            int step  = 0;
            int steps = 24;

            float twistBegin = this.twistBegin / 360.0f * twoPi;
            float twistEnd   = this.twistEnd / 360.0f * twoPi;
            float twistTotal = twistEnd - twistBegin;

            // if the profile has a lot of twist, add more layers otherwise the layers may overlap
            // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't
            // accurately match the viewer
            float twistTotalAbs = Math.Abs(twistTotal);

            if (twistTotalAbs > 0.01f)
            {
                if (twistTotalAbs > Math.PI * 1.5f)
                {
                    steps *= 2;
                }
                if (twistTotalAbs > Math.PI * 3.0f)
                {
                    steps *= 2;
                }
            }

            float yPathScale             = this.holeSizeY * 0.5f;
            float pathLength             = this.pathCutEnd - this.pathCutBegin;
            float totalSkew              = this.skew * 2.0f * pathLength;
            float skewStart              = this.pathCutBegin * 2.0f * this.skew - this.skew;
            float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY));
            float yShearCompensation     = 1.0f + Math.Abs(this.topShearY) * 0.25f;

            // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end
            // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used
            // to calculate the sine for generating the path radius appears to approximate it's effects there
            // too, but there are some subtle differences in the radius which are noticeable as the prim size
            // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on
            // the meshes generated with this technique appear nearly identical in shape to the same prims when
            // displayed by the viewer.

            float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f;
            float endAngle   = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f;
            float stepSize   = twoPi / this.stepsPerRevolution;

            step = (int)(startAngle / stepSize);
            int   firstStep = step;
            float angle     = startAngle;
            float hollow    = this.hollow;

            // sanity checks
            float initialProfileRot = 0.0f;

            if (this.sides == 3)
            {
                initialProfileRot = (float)Math.PI;
                if (this.hollowSides == 4)
                {
                    if (hollow > 0.7f)
                    {
                        hollow = 0.7f;
                    }
                    hollow *= 0.707f;
                }
                else
                {
                    hollow *= 0.5f;
                }
            }
            else if (this.sides == 4)
            {
                initialProfileRot = 0.25f * (float)Math.PI;
                if (this.hollowSides != 4)
                {
                    hollow *= 0.707f;
                }
            }
            else if (this.sides > 4)
            {
                initialProfileRot = (float)Math.PI;
                if (this.hollowSides == 4)
                {
                    if (hollow > 0.7f)
                    {
                        hollow = 0.7f;
                    }
                    hollow /= 0.7f;
                }
            }

            bool needEndFaces = false;

            if (this.pathCutBegin != 0.0 || this.pathCutEnd != 1.0)
            {
                needEndFaces = true;
            }
            else if (this.taperX != 0.0 || this.taperY != 0.0)
            {
                needEndFaces = true;
            }
            else if (this.skew != 0.0)
            {
                needEndFaces = true;
            }
            else if (twistTotal != 0.0)
            {
                needEndFaces = true;
            }

            MeshmerizerProfile profile = new MeshmerizerProfile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, needEndFaces);

            if (initialProfileRot != 0.0f)
            {
                profile.AddRot(Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), initialProfileRot));
            }

            bool done = false;

            while (!done) // loop through the length of the path and add the layers
            {
                bool isEndLayer = false;
                if (angle == startAngle || angle >= endAngle)
                {
                    isEndLayer = true;
                }

                MeshmerizerProfile newLayer = profile.Clone(isEndLayer && needEndFaces);

                float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX;
                float yProfileScale = this.holeSizeY;

                float percentOfPath   = angle / (twoPi * this.revolutions);
                float percentOfAngles = (angle - startAngle) / (endAngle - startAngle);

                if (this.taperX > 0.01f)
                {
                    xProfileScale *= 1.0f - percentOfPath * this.taperX;
                }
                else if (this.taperX < -0.01f)
                {
                    xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX;
                }

                if (this.taperY > 0.01f)
                {
                    yProfileScale *= 1.0f - percentOfPath * this.taperY;
                }
                else if (this.taperY < -0.01f)
                {
                    yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY;
                }

                if (xProfileScale != 1.0f || yProfileScale != 1.0f)
                {
                    newLayer.Scale(xProfileScale, yProfileScale);
                }

                float radiusScale = 1.0f;
                if (this.radius > 0.001f)
                {
                    radiusScale = 1.0f - this.radius * percentOfPath;
                }
                else if (this.radius < 0.001f)
                {
                    radiusScale = 1.0f + this.radius * (1.0f - percentOfPath);
                }

                float twist = twistBegin + twistTotal * percentOfPath;

                float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles);
                xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor;

                float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale;

                float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale;

                // next apply twist rotation to the profile layer
                if (twistTotal != 0.0f || twistBegin != 0.0f)
                {
                    newLayer.AddRot(Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), twist));
                }

                // now orient the rotation of the profile layer relative to it's position on the path
                // adding taperY to the angle used to generate the quat appears to approximate the viewer
                //newLayer.AddRot(new Quaternion(new MeshmerizerVertex(1.0f, 0.0f, 0.0f), angle + this.topShearY * 0.9f));
                newLayer.AddRot(Quaternion.CreateFromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), angle + this.topShearY));
                newLayer.AddPos(xOffset, yOffset, zOffset);

                if (angle == startAngle)
                {
                    newLayer.FlipNormals();
                }

                // append the layer and fill in the sides

                int coordsLen = this.coords.Count;
                newLayer.AddValue2Faces(coordsLen);

                this.coords.AddRange(newLayer.coords);

                if (isEndLayer)
                {
                    this.faces.AddRange(newLayer.faces);
                }

                // fill faces between layers

                int             numVerts = newLayer.coords.Count;
                MeshmerizerFace newFace  = new MeshmerizerFace();
                if (step > firstStep)
                {
                    for (int i = coordsLen; i < this.coords.Count - 1; i++)
                    {
                        newFace.v1 = i;
                        newFace.v2 = i - numVerts;
                        newFace.v3 = i - numVerts + 1;
                        this.faces.Add(newFace);

                        newFace.v2 = i - numVerts + 1;
                        newFace.v3 = i + 1;
                        this.faces.Add(newFace);
                    }

                    newFace.v1 = coordsLen - 1;
                    newFace.v2 = coordsLen - numVerts;
                    newFace.v3 = coordsLen;
                    this.faces.Add(newFace);

                    newFace.v1 = coordsLen + numVerts - 1;
                    newFace.v2 = coordsLen - 1;
                    newFace.v3 = coordsLen;
                    this.faces.Add(newFace);
                }

                // calculate terms for next iteration
                // calculate the angle for the next iteration of the loop

                if (angle >= endAngle)
                {
                    done = true;
                }
                else
                {
                    step += 1;
                    angle = stepSize * step;
                    if (angle > endAngle)
                    {
                        angle = endAngle;
                    }
                }
            }
        }
コード例 #6
0
        public void ExtrudeLinear()
        {
            this.coords = new List <Coord>();
            this.faces  = new List <MeshmerizerFace>();

            int step  = 0;
            int steps = 1;

            float length        = this.pathCutEnd - this.pathCutBegin;
            float twistBegin    = this.twistBegin / 360.0f * twoPi;
            float twistEnd      = this.twistEnd / 360.0f * twoPi;
            float twistTotal    = twistEnd - twistBegin;
            float twistTotalAbs = Math.Abs(twistTotal);

            if (twistTotalAbs > 0.01f)
            {
                steps += (int)(twistTotalAbs * 3.66); //  dahlia's magic number
            }
            float start    = -0.5f;
            float stepSize = length / (float)steps;
            float percentOfPathMultiplier = stepSize;
            float xProfileScale           = 1.0f;
            float yProfileScale           = 1.0f;
            float xOffset = 0.0f;
            float yOffset = 0.0f;
            float zOffset = start;
            float xOffsetStepIncrement = this.topShearX / steps;
            float yOffsetStepIncrement = this.topShearY / steps;

            float percentOfPath = this.pathCutBegin;

            zOffset += percentOfPath;

            float hollow = this.hollow;

            // sanity checks
            float initialProfileRot = 0.0f;

            if (this.sides == 3)
            {
                if (this.hollowSides == 4)
                {
                    if (hollow > 0.7f)
                    {
                        hollow = 0.7f;
                    }
                    hollow *= 0.707f;
                }
                else
                {
                    hollow *= 0.5f;
                }
            }
            else if (this.sides == 4)
            {
                initialProfileRot = 1.25f * (float)Math.PI;
                if (this.hollowSides != 4)
                {
                    hollow *= 0.707f;
                }
            }
            else if (this.sides == 24 && this.hollowSides == 4)
            {
                hollow *= 1.414f;
            }

            MeshmerizerProfile profile = new MeshmerizerProfile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true);

            if (initialProfileRot != 0.0f)
            {
                profile.AddRot(Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), initialProfileRot));
            }

            bool done = false;

            while (!done)
            {
                MeshmerizerProfile newLayer = profile.Clone();

                if (this.taperX == 0.0f)
                {
                    xProfileScale = 1.0f;
                }
                else if (this.taperX > 0.0f)
                {
                    xProfileScale = 1.0f - percentOfPath * this.taperX;
                }
                else
                {
                    xProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperX;
                }

                if (this.taperY == 0.0f)
                {
                    yProfileScale = 1.0f;
                }
                else if (this.taperY > 0.0f)
                {
                    yProfileScale = 1.0f - percentOfPath * this.taperY;
                }
                else
                {
                    yProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperY;
                }

                if (xProfileScale != 1.0f || yProfileScale != 1.0f)
                {
                    newLayer.Scale(xProfileScale, yProfileScale);
                }

                float twist = twistBegin + twistTotal * percentOfPath;
                if (twist != 0.0f)
                {
                    newLayer.AddRot(Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), twist));
                }

                newLayer.AddPos(xOffset, yOffset, zOffset);

                if (step == 0)
                {
                    newLayer.FlipNormals();
                }

                // append this layer

                int coordsLen = this.coords.Count;
                newLayer.AddValue2Faces(coordsLen);

                this.coords.AddRange(newLayer.coords);

                if (percentOfPath <= this.pathCutBegin || percentOfPath >= this.pathCutEnd)
                {
                    this.faces.AddRange(newLayer.faces);
                }

                // fill faces between layers

                int             numVerts = newLayer.coords.Count;
                MeshmerizerFace newFace  = new MeshmerizerFace();
                if (step > 0)
                {
                    for (int i = coordsLen; i < this.coords.Count - 1; i++)
                    {
                        newFace.v1 = i;
                        newFace.v2 = i - numVerts;
                        newFace.v3 = i - numVerts + 1;
                        this.faces.Add(newFace);

                        newFace.v2 = i - numVerts + 1;
                        newFace.v3 = i + 1;
                        this.faces.Add(newFace);
                    }

                    newFace.v1 = coordsLen - 1;
                    newFace.v2 = coordsLen - numVerts;
                    newFace.v3 = coordsLen;
                    this.faces.Add(newFace);

                    newFace.v1 = coordsLen + numVerts - 1;
                    newFace.v2 = coordsLen - 1;
                    newFace.v3 = coordsLen;
                    this.faces.Add(newFace);
                }

                // calc the step for the next iteration of the loop

                if (step < steps)
                {
                    step          += 1;
                    percentOfPath += percentOfPathMultiplier;
                    xOffset       += xOffsetStepIncrement;
                    yOffset       += yOffsetStepIncrement;
                    zOffset       += stepSize;
                    if (percentOfPath > this.pathCutEnd)
                    {
                        done = true;
                    }
                }
                else
                {
                    done = true;
                }
            }
        }