Exemple #1
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;
        }
        /// <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);
        }
Exemple #3
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;
        }
        /// <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);
        }