Пример #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
        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;
        }
Пример #4
0
        /// <summary>
        /// Creates an extrusion of a profile along a linear path. Used to create prim types box, cylinder, and prism.
        /// </summary>
        /// <param name="m"></param>
        /// <returns>A mesh of the extruded shape</returns>
        public MeshmerizerMesh ExtrudeLinearPath(MeshmerizerMesh m)
        {
            MeshmerizerMesh result = new MeshmerizerMesh();

            MeshmerizerMesh newLayer;
            MeshmerizerMesh lastLayer = null;

            int step = 0;
            int steps = 1;

            float twistTotal = twistTop - twistBot;
            // 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 may not
            // accurately match the viewer
            float twistTotalAbs = System.Math.Abs(twistTotal);
            if (twistTotalAbs > 0.01)
                steps += (int)(twistTotalAbs * 3.66f); // dahlia's magic number ;)

            double percentOfPathMultiplier = 1.0 / steps;

            float start = -0.5f;

            float stepSize = 1.0f / (float)steps;

            float xProfileScale = 1.0f;
            float yProfileScale = 1.0f;

            float xOffset = 0.0f;
            float yOffset = 0.0f;
            float zOffset = start;

            float xOffsetStepIncrement = pushX / steps;
            float yOffsetStepIncrement = pushY / steps;

            //float percentOfPath = 0.0f;
            float percentOfPath = (float)pathBegin * 2.0e-5f;
            zOffset += percentOfPath;
            bool done = false;
            do // loop through the length of the path and add the layers
            {
                newLayer = m.Clone();

                if (taperBotFactorX < 1.0f)
                    xProfileScale = 1.0f - (1.0f - percentOfPath) * (1.0f - taperBotFactorX);
                else if (taperTopFactorX < 1.0f)
                    xProfileScale = 1.0f - percentOfPath * (1.0f - taperTopFactorX);
                else xProfileScale = 1.0f;

                if (taperBotFactorY < 1.0f)
                    yProfileScale = 1.0f - (1.0f - percentOfPath) * (1.0f - taperBotFactorY);
                else if (taperTopFactorY < 1.0f)
                    yProfileScale = 1.0f - percentOfPath * (1.0f - taperTopFactorY);
                else yProfileScale = 1.0f;

                MeshmerizerVertex vTemp = new MeshmerizerVertex(0.0f, 0.0f, 0.0f);

                // apply the taper to the profile before any rotations
                if (xProfileScale != 1.0f || yProfileScale != 1.0f)
                {
                    foreach (MeshmerizerVertex v in newLayer.vertices)
                    {
                        if (v != null)
                        {
                            v.X *= xProfileScale;
                            v.Y *= yProfileScale;
                        }
                    }
                }


                float twist = twistBot + (twistTotal * (float)percentOfPath);
                // apply twist rotation to the profile layer and position the layer in the prim

                Quaternion profileRot = Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), twist);
                foreach (MeshmerizerVertex v in newLayer.vertices)
                {
                    if (v != null)
                    {
                        vTemp = v * profileRot;
                        v.X = vTemp.X + xOffset;
                        v.Y = vTemp.Y + yOffset;
                        v.Z = vTemp.Z + zOffset;
                    }
                }

                if (step == 0) // the first layer, invert normals
                {
                    foreach (Triangle t in newLayer.triangles)
                    {
                        t.invertNormal();
                    }
                }

                result.Append(newLayer);

                int iLastNull = 0;

                if (lastLayer != null)
                {
                    int i, count = newLayer.vertices.Count;

                    for (i = 0; i < count; i++)
                    {
                        int iNext = (i + 1);

                        if (lastLayer.vertices[i] == null) // cant make a simplex here
                        {
                            iLastNull = i + 1;
                        }
                        else
                        {
                            if (i == count - 1) // End of list
                                iNext = iLastNull;

                            if (lastLayer.vertices[iNext] == null) // Null means wrap to begin of last segment
                                iNext = iLastNull;

                            result.Add(new Triangle(newLayer.vertices[i], lastLayer.vertices[i], newLayer.vertices[iNext]));
                            result.Add(new Triangle(newLayer.vertices[iNext], lastLayer.vertices[i], lastLayer.vertices[iNext]));
                        }
                    }
                }
                lastLayer = newLayer;

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

                if (step < steps)
                {
                    step++;
                    percentOfPath += (float)percentOfPathMultiplier;

                    xOffset += xOffsetStepIncrement;
                    yOffset += yOffsetStepIncrement;
                    zOffset += stepSize;

                    if (percentOfPath > 1.0f - (float)pathEnd * 2.0e-5f)
                        done = true;
                }
                else done = true;

            } while (!done); // loop until all the layers in the path are completed

            return result;
        }
Пример #5
0
        /// <summary>
        /// Extrudes a shape around a circular path. Used to create prim types torus, ring, and tube.
        /// </summary>
        /// <param name="m"></param>
        /// <returns>a mesh of the extruded shape</returns>
        public MeshmerizerMesh ExtrudeCircularPath(MeshmerizerMesh m)
        {
            MeshmerizerMesh result = new MeshmerizerMesh();

            MeshmerizerMesh newLayer;
            MeshmerizerMesh lastLayer = null;

            int step;
            int steps = 24;

            float twistTotal = twistTop - twistBot;
            // 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
            if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 1.5f) steps *= 2;
            if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 3.0f) steps *= 2;

            // double percentOfPathMultiplier = 1.0 / steps;
            // double angleStepMultiplier = System.Math.PI * 2.0 / steps;

            float yPathScale = pathScaleY * 0.5f;
            float pathLength = pathCutEnd - pathCutBegin;
            float totalSkew = skew * 2.0f * pathLength;
            float skewStart = (-skew) + pathCutBegin * 2.0f * skew;

            // 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 = (float)(System.Math.PI * 2.0 * pathCutBegin * revolutions) - pushY * 0.9f;
            float endAngle = (float)(System.Math.PI * 2.0 * pathCutEnd * revolutions) - pushY * 0.9f;
            float stepSize = (float)0.2617993878; // 2*PI / 24 segments per revolution

            step = (int)(startAngle / stepSize);
            float angle = startAngle;

            float xProfileScale = 1.0f;
            float yProfileScale = 1.0f;

            bool done = false;
            do // loop through the length of the path and add the layers
            {
                newLayer = m.Clone();

                float percentOfPath = (angle - startAngle) / (endAngle - startAngle); // endAngle should always be larger than startAngle

                if (pathTaperX > 0.001f) // can't really compare to 0.0f as the value passed is never exactly zero
                    xProfileScale = 1.0f - percentOfPath * pathTaperX;
                else if (pathTaperX < -0.001f)
                    xProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperX;
                else xProfileScale = 1.0f;

                if (pathTaperY > 0.001f)
                    yProfileScale = 1.0f - percentOfPath * pathTaperY;
                else if (pathTaperY < -0.001f)
                    yProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperY;
                else yProfileScale = 1.0f;

                MeshmerizerVertex vTemp = new MeshmerizerVertex(0.0f, 0.0f, 0.0f);

                // apply the taper to the profile before any rotations
                if (xProfileScale != 1.0f || yProfileScale != 1.0f)
                {
                    foreach (MeshmerizerVertex v in newLayer.vertices)
                    {
                        if (v != null)
                        {
                            v.X *= xProfileScale;
                            v.Y *= yProfileScale;
                        }
                    }
                }

                float radiusScale;

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

                float twist = twistBot + (twistTotal * (float)percentOfPath);

                float xOffset;
                float yOffset;
                float zOffset;

                xOffset = 0.5f * (skewStart + totalSkew * (float)percentOfPath);
                xOffset += (float)System.Math.Sin(angle) * pushX * 0.45f;
                yOffset = (float)(System.Math.Cos(angle) * (0.5f - yPathScale)) * radiusScale;
                zOffset = (float)(System.Math.Sin(angle + pushY * 0.9f) * (0.5f - yPathScale)) * radiusScale;

                // next apply twist rotation to the profile layer
                if (twistTotal != 0.0f || twistBot != 0.0f)
                {
                    Quaternion profileRot = new Quaternion(new Vector3(0.0f, 0.0f, 1.0f), twist);
                    foreach (MeshmerizerVertex v in newLayer.vertices)
                    {
                        if (v != null)
                        {
                            vTemp = v * profileRot;
                            v.X = vTemp.X;
                            v.Y = vTemp.Y;
                            v.Z = vTemp.Z;
                        }
                    }
                }

                // now orient the rotation of the profile layer relative to it's position on the path
                // adding pushY to the angle used to generate the quat appears to approximate the viewer
                Quaternion layerRot = Quaternion.CreateFromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), (float)angle + pushY * 0.9f);
                foreach (MeshmerizerVertex v in newLayer.vertices)
                {
                    if (v != null)
                    {
                        vTemp = v * layerRot;
                        v.X = vTemp.X + xOffset;
                        v.Y = vTemp.Y + yOffset;
                        v.Z = vTemp.Z + zOffset;
                    }
                }

                if (angle == startAngle) // the first layer, invert normals
                {
                    foreach (Triangle t in newLayer.triangles)
                    {
                        t.invertNormal();
                    }
                }

                result.Append(newLayer);

                int iLastNull = 0;

                if (lastLayer != null)
                {
                    int i, count = newLayer.vertices.Count;

                    for (i = 0; i < count; i++)
                    {
                        int iNext = (i + 1);

                        if (lastLayer.vertices[i] == null) // cant make a simplex here
                        {
                            iLastNull = i + 1;
                        }
                        else
                        {
                            if (i == count - 1) // End of list
                                iNext = iLastNull;

                            if (lastLayer.vertices[iNext] == null) // Null means wrap to begin of last segment
                                iNext = iLastNull;

                            result.Add(new Triangle(newLayer.vertices[i], lastLayer.vertices[i], newLayer.vertices[iNext]));
                            result.Add(new Triangle(newLayer.vertices[iNext], lastLayer.vertices[i], lastLayer.vertices[iNext]));
                        }
                    }
                }
                lastLayer = newLayer;

                // calc the angle for the next interation of the loop
                if (angle >= endAngle)
                {
                    done = true;
                }
                else
                {
                    angle = stepSize * ++step;
                    if (angle > endAngle)
                        angle = endAngle;
                }
            } while (!done); // loop until all the layers in the path are completed

            return result;
        }
Пример #6
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;
        }
Пример #7
0
        private MeshmerizerMesh GenerateMeshmerizerMesh(Primitive prim)
        {
            PrimitiveBaseShape primShape = new PrimitiveBaseShape(prim);
            MeshmerizerMesh mesh = new MeshmerizerMesh();

            float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f;
            float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f;
            float pathBegin = (float)primShape.PathBegin * 2.0e-5f;
            float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f;
            float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f;
            float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f;

            float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
            float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
            float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;

            int sides = 4;
            if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
                sides = 3;
            else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
                sides = 24;
            else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
            {
                // half circle, prim is a sphere
                sides = 24;

                profileBegin = 0.5f * profileBegin + 0.5f;
                profileEnd = 0.5f * profileEnd + 0.5f;
            }

            int hollowSides = sides;
            if (primShape.HollowShape == HollowShape.Circle)
                hollowSides = 24;
            else if (primShape.HollowShape == HollowShape.Square)
                hollowSides = 4;
            else if (primShape.HollowShape == HollowShape.Triangle)
                hollowSides = 3;

            PrimMesh primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
            primMesh.topShearX = pathShearX;
            primMesh.topShearY = pathShearY;
            primMesh.pathCutBegin = pathBegin;
            primMesh.pathCutEnd = pathEnd;

            if (primShape.PathCurve == (byte)Extrusion.Straight)
            {
                primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10;
                primMesh.twistEnd = primShape.PathTwist * 18 / 10;
                primMesh.taperX = pathScaleX;
                primMesh.taperY = pathScaleY;

                try
                {
                    primMesh.ExtrudeLinear();
                }
                catch (Exception)
                {
                    return null;
                }
            }
            else
            {
                primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f;
                primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f;
                primMesh.radius = 0.01f * primShape.PathRadiusOffset;
                primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
                primMesh.skew = 0.01f * primShape.PathSkew;
                primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10;
                primMesh.twistEnd = primShape.PathTwist * 36 / 10;
                primMesh.taperX = primShape.PathTaperX * 0.01f;
                primMesh.taperY = primShape.PathTaperY * 0.01f;

                try
                {
                    primMesh.ExtrudeCircular();
                }
                catch (Exception)
                {
                    return null;
                }
            }

            int numCoords = primMesh.coords.Count;
            //int numFaces = primMesh.faces.Count;

            List<Coord> coords = primMesh.coords;
            for (int i = 0; i < numCoords; i++)
            {
                Coord c = coords[i];
                mesh.vertices.Add(new MeshmerizerVertex(c.X, c.Y, c.Z));
            }

            mesh.primMesh = primMesh;

            // trim the vertex and triangle lists to free up memory
            mesh.vertices.TrimExcess();
            mesh.triangles.TrimExcess();

            return mesh;
        }
Пример #8
0
        private MeshmerizerMesh GenerateMeshmerizerMesh(Primitive prim)
        {
            PrimitiveBaseShape primShape = new PrimitiveBaseShape(prim);
            MeshmerizerMesh    mesh      = new MeshmerizerMesh();

            float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f;
            float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f;
            float pathBegin  = (float)primShape.PathBegin * 2.0e-5f;
            float pathEnd    = 1.0f - (float)primShape.PathEnd * 2.0e-5f;
            float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f;
            float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f;

            float profileBegin  = (float)primShape.ProfileBegin * 2.0e-5f;
            float profileEnd    = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
            float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;

            int sides = 4;

            if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
            {
                sides = 3;
            }
            else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
            {
                sides = 24;
            }
            else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
            {
                // half circle, prim is a sphere
                sides = 24;

                profileBegin = 0.5f * profileBegin + 0.5f;
                profileEnd   = 0.5f * profileEnd + 0.5f;
            }

            int hollowSides = sides;

            if (primShape.HollowShape == HollowShape.Circle)
            {
                hollowSides = 24;
            }
            else if (primShape.HollowShape == HollowShape.Square)
            {
                hollowSides = 4;
            }
            else if (primShape.HollowShape == HollowShape.Triangle)
            {
                hollowSides = 3;
            }

            PrimMesh primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);

            primMesh.topShearX    = pathShearX;
            primMesh.topShearY    = pathShearY;
            primMesh.pathCutBegin = pathBegin;
            primMesh.pathCutEnd   = pathEnd;

            if (primShape.PathCurve == (byte)Extrusion.Straight)
            {
                primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10;
                primMesh.twistEnd   = primShape.PathTwist * 18 / 10;
                primMesh.taperX     = pathScaleX;
                primMesh.taperY     = pathScaleY;

                try
                {
                    primMesh.ExtrudeLinear();
                }
                catch (Exception)
                {
                    return(null);
                }
            }
            else
            {
                primMesh.holeSizeX   = (200 - primShape.PathScaleX) * 0.01f;
                primMesh.holeSizeY   = (200 - primShape.PathScaleY) * 0.01f;
                primMesh.radius      = 0.01f * primShape.PathRadiusOffset;
                primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
                primMesh.skew        = 0.01f * primShape.PathSkew;
                primMesh.twistBegin  = primShape.PathTwistBegin * 36 / 10;
                primMesh.twistEnd    = primShape.PathTwist * 36 / 10;
                primMesh.taperX      = primShape.PathTaperX * 0.01f;
                primMesh.taperY      = primShape.PathTaperY * 0.01f;

                try
                {
                    primMesh.ExtrudeCircular();
                }
                catch (Exception)
                {
                    return(null);
                }
            }

            int numCoords = primMesh.coords.Count;
            //int numFaces = primMesh.faces.Count;

            List <Coord> coords = primMesh.coords;

            for (int i = 0; i < numCoords; i++)
            {
                Coord c = coords[i];
                mesh.vertices.Add(new MeshmerizerVertex(c.X, c.Y, c.Z));
            }

            mesh.primMesh = primMesh;

            // trim the vertex and triangle lists to free up memory
            mesh.vertices.TrimExcess();
            mesh.triangles.TrimExcess();

            return(mesh);
        }
Пример #9
0
        /// <summary>
        /// Creates an extrusion of a profile along a linear path. Used to create prim types box, cylinder, and prism.
        /// </summary>
        /// <param name="m"></param>
        /// <returns>A mesh of the extruded shape</returns>
        public MeshmerizerMesh ExtrudeLinearPath(MeshmerizerMesh m)
        {
            MeshmerizerMesh result = new MeshmerizerMesh();

            MeshmerizerMesh newLayer;
            MeshmerizerMesh lastLayer = null;

            int step  = 0;
            int steps = 1;

            float twistTotal = twistTop - twistBot;
            // 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 may not
            // accurately match the viewer
            float twistTotalAbs = System.Math.Abs(twistTotal);

            if (twistTotalAbs > 0.01)
            {
                steps += (int)(twistTotalAbs * 3.66f); // dahlia's magic number ;)
            }
            double percentOfPathMultiplier = 1.0 / steps;

            float start = -0.5f;

            float stepSize = 1.0f / (float)steps;

            float xProfileScale = 1.0f;
            float yProfileScale = 1.0f;

            float xOffset = 0.0f;
            float yOffset = 0.0f;
            float zOffset = start;

            float xOffsetStepIncrement = pushX / steps;
            float yOffsetStepIncrement = pushY / steps;

            //float percentOfPath = 0.0f;
            float percentOfPath = (float)pathBegin * 2.0e-5f;

            zOffset += percentOfPath;
            bool done = false;

            do // loop through the length of the path and add the layers
            {
                newLayer = m.Clone();

                if (taperBotFactorX < 1.0f)
                {
                    xProfileScale = 1.0f - (1.0f - percentOfPath) * (1.0f - taperBotFactorX);
                }
                else if (taperTopFactorX < 1.0f)
                {
                    xProfileScale = 1.0f - percentOfPath * (1.0f - taperTopFactorX);
                }
                else
                {
                    xProfileScale = 1.0f;
                }

                if (taperBotFactorY < 1.0f)
                {
                    yProfileScale = 1.0f - (1.0f - percentOfPath) * (1.0f - taperBotFactorY);
                }
                else if (taperTopFactorY < 1.0f)
                {
                    yProfileScale = 1.0f - percentOfPath * (1.0f - taperTopFactorY);
                }
                else
                {
                    yProfileScale = 1.0f;
                }

                MeshmerizerVertex vTemp = new MeshmerizerVertex(0.0f, 0.0f, 0.0f);

                // apply the taper to the profile before any rotations
                if (xProfileScale != 1.0f || yProfileScale != 1.0f)
                {
                    foreach (MeshmerizerVertex v in newLayer.vertices)
                    {
                        if (v != null)
                        {
                            v.X *= xProfileScale;
                            v.Y *= yProfileScale;
                        }
                    }
                }


                float twist = twistBot + (twistTotal * (float)percentOfPath);
                // apply twist rotation to the profile layer and position the layer in the prim

                Quaternion profileRot = Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), twist);
                foreach (MeshmerizerVertex v in newLayer.vertices)
                {
                    if (v != null)
                    {
                        vTemp = v * profileRot;
                        v.X   = vTemp.X + xOffset;
                        v.Y   = vTemp.Y + yOffset;
                        v.Z   = vTemp.Z + zOffset;
                    }
                }

                if (step == 0) // the first layer, invert normals
                {
                    foreach (Triangle t in newLayer.triangles)
                    {
                        t.invertNormal();
                    }
                }

                result.Append(newLayer);

                int iLastNull = 0;

                if (lastLayer != null)
                {
                    int i, count = newLayer.vertices.Count;

                    for (i = 0; i < count; i++)
                    {
                        int iNext = (i + 1);

                        if (lastLayer.vertices[i] == null) // cant make a simplex here
                        {
                            iLastNull = i + 1;
                        }
                        else
                        {
                            if (i == count - 1) // End of list
                            {
                                iNext = iLastNull;
                            }

                            if (lastLayer.vertices[iNext] == null) // Null means wrap to begin of last segment
                            {
                                iNext = iLastNull;
                            }

                            result.Add(new Triangle(newLayer.vertices[i], lastLayer.vertices[i], newLayer.vertices[iNext]));
                            result.Add(new Triangle(newLayer.vertices[iNext], lastLayer.vertices[i], lastLayer.vertices[iNext]));
                        }
                    }
                }
                lastLayer = newLayer;

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

                if (step < steps)
                {
                    step++;
                    percentOfPath += (float)percentOfPathMultiplier;

                    xOffset += xOffsetStepIncrement;
                    yOffset += yOffsetStepIncrement;
                    zOffset += stepSize;

                    if (percentOfPath > 1.0f - (float)pathEnd * 2.0e-5f)
                    {
                        done = true;
                    }
                }
                else
                {
                    done = true;
                }
            } while (!done); // loop until all the layers in the path are completed

            return(result);
        }
Пример #10
0
        /// <summary>
        /// Extrudes a shape around a circular path. Used to create prim types torus, ring, and tube.
        /// </summary>
        /// <param name="m"></param>
        /// <returns>a mesh of the extruded shape</returns>
        public MeshmerizerMesh ExtrudeCircularPath(MeshmerizerMesh m)
        {
            MeshmerizerMesh result = new MeshmerizerMesh();

            MeshmerizerMesh newLayer;
            MeshmerizerMesh lastLayer = null;

            int step;
            int steps = 24;

            float twistTotal = twistTop - twistBot;

            // 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
            if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 1.5f)
            {
                steps *= 2;
            }
            if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 3.0f)
            {
                steps *= 2;
            }

            // double percentOfPathMultiplier = 1.0 / steps;
            // double angleStepMultiplier = System.Math.PI * 2.0 / steps;

            float yPathScale = pathScaleY * 0.5f;
            float pathLength = pathCutEnd - pathCutBegin;
            float totalSkew  = skew * 2.0f * pathLength;
            float skewStart  = (-skew) + pathCutBegin * 2.0f * skew;

            // 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 = (float)(System.Math.PI * 2.0 * pathCutBegin * revolutions) - pushY * 0.9f;
            float endAngle   = (float)(System.Math.PI * 2.0 * pathCutEnd * revolutions) - pushY * 0.9f;
            float stepSize   = (float)0.2617993878; // 2*PI / 24 segments per revolution

            step = (int)(startAngle / stepSize);
            float angle = startAngle;

            float xProfileScale = 1.0f;
            float yProfileScale = 1.0f;

            bool done = false;

            do // loop through the length of the path and add the layers
            {
                newLayer = m.Clone();

                float percentOfPath = (angle - startAngle) / (endAngle - startAngle); // endAngle should always be larger than startAngle

                if (pathTaperX > 0.001f)                                              // can't really compare to 0.0f as the value passed is never exactly zero
                {
                    xProfileScale = 1.0f - percentOfPath * pathTaperX;
                }
                else if (pathTaperX < -0.001f)
                {
                    xProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperX;
                }
                else
                {
                    xProfileScale = 1.0f;
                }

                if (pathTaperY > 0.001f)
                {
                    yProfileScale = 1.0f - percentOfPath * pathTaperY;
                }
                else if (pathTaperY < -0.001f)
                {
                    yProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperY;
                }
                else
                {
                    yProfileScale = 1.0f;
                }

                MeshmerizerVertex vTemp = new MeshmerizerVertex(0.0f, 0.0f, 0.0f);

                // apply the taper to the profile before any rotations
                if (xProfileScale != 1.0f || yProfileScale != 1.0f)
                {
                    foreach (MeshmerizerVertex v in newLayer.vertices)
                    {
                        if (v != null)
                        {
                            v.X *= xProfileScale;
                            v.Y *= yProfileScale;
                        }
                    }
                }

                float radiusScale;

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

                float twist = twistBot + (twistTotal * (float)percentOfPath);

                float xOffset;
                float yOffset;
                float zOffset;

                xOffset  = 0.5f * (skewStart + totalSkew * (float)percentOfPath);
                xOffset += (float)System.Math.Sin(angle) * pushX * 0.45f;
                yOffset  = (float)(System.Math.Cos(angle) * (0.5f - yPathScale)) * radiusScale;
                zOffset  = (float)(System.Math.Sin(angle + pushY * 0.9f) * (0.5f - yPathScale)) * radiusScale;

                // next apply twist rotation to the profile layer
                if (twistTotal != 0.0f || twistBot != 0.0f)
                {
                    Quaternion profileRot = new Quaternion(new Vector3(0.0f, 0.0f, 1.0f), twist);
                    foreach (MeshmerizerVertex v in newLayer.vertices)
                    {
                        if (v != null)
                        {
                            vTemp = v * profileRot;
                            v.X   = vTemp.X;
                            v.Y   = vTemp.Y;
                            v.Z   = vTemp.Z;
                        }
                    }
                }

                // now orient the rotation of the profile layer relative to it's position on the path
                // adding pushY to the angle used to generate the quat appears to approximate the viewer
                Quaternion layerRot = Quaternion.CreateFromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), (float)angle + pushY * 0.9f);
                foreach (MeshmerizerVertex v in newLayer.vertices)
                {
                    if (v != null)
                    {
                        vTemp = v * layerRot;
                        v.X   = vTemp.X + xOffset;
                        v.Y   = vTemp.Y + yOffset;
                        v.Z   = vTemp.Z + zOffset;
                    }
                }

                if (angle == startAngle) // the first layer, invert normals
                {
                    foreach (Triangle t in newLayer.triangles)
                    {
                        t.invertNormal();
                    }
                }

                result.Append(newLayer);

                int iLastNull = 0;

                if (lastLayer != null)
                {
                    int i, count = newLayer.vertices.Count;

                    for (i = 0; i < count; i++)
                    {
                        int iNext = (i + 1);

                        if (lastLayer.vertices[i] == null) // cant make a simplex here
                        {
                            iLastNull = i + 1;
                        }
                        else
                        {
                            if (i == count - 1) // End of list
                            {
                                iNext = iLastNull;
                            }

                            if (lastLayer.vertices[iNext] == null) // Null means wrap to begin of last segment
                            {
                                iNext = iLastNull;
                            }

                            result.Add(new Triangle(newLayer.vertices[i], lastLayer.vertices[i], newLayer.vertices[iNext]));
                            result.Add(new Triangle(newLayer.vertices[iNext], lastLayer.vertices[i], lastLayer.vertices[iNext]));
                        }
                    }
                }
                lastLayer = newLayer;

                // calc the angle for the next interation of the loop
                if (angle >= endAngle)
                {
                    done = true;
                }
                else
                {
                    angle = stepSize * ++step;
                    if (angle > endAngle)
                    {
                        angle = endAngle;
                    }
                }
            } while (!done); // loop until all the layers in the path are completed

            return(result);
        }