Beispiel #1
0
        /// <summary>
        /// Generate a debug mesh containing the centroids of the primary mesh's triangles as points.
        /// </summary>
        /// <returns>A new mesh for debug</returns>
        public Mesh <Vertex3D> GenerateCentroidPointMesh()
        {
            // Doesn't rely on topology
            int numTriangles = indices.Length / 3;

            Vertex3D[]      centroidVerts  = new Vertex3D[numTriangles];
            Vertex3D        centroidVertex = new Vertex3D();
            Mesh <Vertex3D> centroidMesh   = new Mesh <Vertex3D>(centroidVerts);
            int             triangleIndex  = 0;

            for (int i = 0; i < numTriangles; ++i)
            {
                Vector3         centroid = Topology.CalculateCentroid(i);
                IPositionVertex ipv      = centroidVertex as IPositionVertex;
                if (ipv != null)
                {
                    ipv.SetPosition(centroid);
                }
                centroidMesh.vertices[triangleIndex++] = (Vertex3D)ipv;
            }
            return(centroidMesh);
        }
Beispiel #2
0
        public float RelaxTriangles(float multiplier)
        {
            NeedsUpdate = true;

            double totalSurfaceArea        = 4.0 * Math.PI;
            double idealFaceArea           = totalSurfaceArea / (indices.Length / 3);
            double idealEdgeLength         = Math.Sqrt(idealFaceArea * 4.0 / Math.Sqrt(3.0));
            double idealDistanceToCentroid = idealEdgeLength * Math.Sqrt(3) / 3.0 * 0.9;

            Vector3[] shiftPositions = new Vector3[mesh.vertices.Length];
            for (int i = 0; i < mesh.vertices.Length; ++i)
            {
                shiftPositions[i] = new Vector3(Vector3.Zero);
            }
            int numIndices = indices.Length;

            TVertex[] centroidVerts  = new TVertex[numIndices / 3];
            TVertex   centroidVertex = new TVertex();

            for (int i = 0; i < numIndices; i += 3)
            {
                Vector3 centroid = Topology.CalculateCentroid(i / 3);
                centroid.Normalize();
                MeshAttr.SetPosition(ref centroidVertex, ref centroid);

                Vector3[] oldPositions = new Vector3[3]
                {
                    new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i]])),
                    new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i + 1]])),
                    new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i + 2]])),
                };

                for (int j = 0; j < 3; ++j)
                {
                    Vector3 midLine   = centroid - oldPositions[j];
                    float   midLength = midLine.Length;
                    midLine *= (float)(multiplier * (midLength - idealDistanceToCentroid) / midLength);
                    shiftPositions[indices[i + j]] += midLine;
                }
            }

            var   origin = Vector3.Zero;
            Plane p      = new Plane(Vector3.UnitY, Vector3.Zero);

            for (int i = 0; i < mesh.vertices.Length; ++i)
            {
                Vector3 vertexPosition = MeshAttr.GetPosition(ref mesh.vertices[i]);
                p.Redefine(vertexPosition, origin);
                shiftPositions[i] = vertexPosition + p.ProjectPoint(shiftPositions[i]);
                shiftPositions[i].Normalize();
            }

            // Stop poylgons rotating about their centroid.
            // Doesn't stop triangles flipping.
            float[] rotationSuppressions = new float[mesh.vertices.Length];
            rotationSuppressions.Initialize();

            Topology.GenerateEdges();
            float minEdgeLength = (float)idealEdgeLength * 0.8f;
            float maxEdgeLength = (float)idealEdgeLength * 1.2f;

            foreach (var iter in Topology.Edges)
            {
                Int64   key     = iter.Key;
                int     index1  = (int)(key & 0xffffffff);
                int     index2  = (int)((key >> 32) & 0xffffffff);
                Vector3 oldPos1 = MeshAttr.GetPosition(ref mesh.vertices[index1]);
                Vector3 oldPos2 = MeshAttr.GetPosition(ref mesh.vertices[index2]);
                Vector3 newPos1 = shiftPositions[index1];
                Vector3 newPos2 = shiftPositions[index2];
                Vector3 oldEdge = oldPos2 - oldPos1;
                Vector3 newEdge = newPos2 - newPos1;
                if (newEdge.Length < minEdgeLength)
                {
                    // Move shift positions back out to ensure that the edge is never too small.
                    Vector3 midPt = newPos1 + 0.5f * newEdge;
                    newEdge.Normalize();
                    newEdge *= minEdgeLength * 0.5f;
                    shiftPositions[index1] = midPt - newEdge;
                    shiftPositions[index2] = midPt + newEdge;
                    newEdge = shiftPositions[index2] - shiftPositions[index1];
                }
                if (newEdge.Length > maxEdgeLength)
                {
                    // Move shift positions back in to ensure that the edge is never too large.
                    Vector3 midPt = newPos1 + 0.5f * newEdge;
                    newEdge.Normalize();
                    newEdge *= (maxEdgeLength * 0.5f);
                    shiftPositions[index1] = midPt - newEdge;
                    shiftPositions[index2] = midPt + newEdge;
                    newEdge = shiftPositions[index2] - shiftPositions[index1];
                }
                oldEdge.Normalize();
                newEdge.Normalize();
                float suppression = (1.0f - Vector3.Dot(oldEdge, newEdge)) * 0.5f;
                rotationSuppressions[index1] = Math.Max(suppression, rotationSuppressions[index1]);
                rotationSuppressions[index2] = Math.Max(suppression, rotationSuppressions[index2]);
            }

            for (int i = 0; i < mesh.vertices.Length; ++i)
            {
                Vector3 pos   = MeshAttr.GetPosition(ref mesh.vertices[i]);
                Vector3 delta = pos;
                pos = Math2.Lerp(pos, shiftPositions[i], (float)(1.0f - Math.Sqrt(rotationSuppressions[i])));
                pos.Normalize();
                shiftPositions[i] = pos;
            }

            float totalShift = 0;

            for (int i = 0; i < mesh.vertices.Length; ++i)
            {
                Vector3 delta = MeshAttr.GetPosition(ref mesh.vertices[i]);
                MeshAttr.SetPosition(ref mesh.vertices[i], ref shiftPositions[i]);
                delta      -= shiftPositions[i];
                totalShift += delta.Length;
            }

            Topology.Regenerate();

            return(totalShift);
        }
Beispiel #3
0
        // Alternative algorithm
        // for each triangle
        //   find normal
        //      find centroid radius
        //        Tilt triangle towards centroid radius
        //        moving edges towards symmetry.
        //        generate new point for each tri vert
        // for each vert, calc average of all new verts, normalise and apply
        // Algorithm is nearly there, but on some triangles, there is a potential that converging on
        // centroid tilts through random moves away from centroidal radius, and they become thin / start overlapping.
        public float RelaxTriangles1(float multiplier)
        {
            NeedsUpdate = true;

            double totalSurfaceArea        = 4.0 * Math.PI;
            double idealFaceArea           = totalSurfaceArea / (indices.Length / 3);
            double idealEdgeLength         = Math.Sqrt(idealFaceArea * 4.0 / Math.Sqrt(3.0));
            double idealDistanceToCentroid = idealEdgeLength * Math.Sqrt(3) / 3.0 * 0.9;

            int numIndices = indices.Length;

            Vector3[] shiftPositions = new Vector3[mesh.vertices.Length];
            for (int i = 0; i < mesh.vertices.Length; ++i)
            {
                shiftPositions[i] = new Vector3(Vector3.Zero);
            }

            for (int i = 0; i < numIndices; i += 3)
            {
                if (1 == 1)//TooThin(i))
                {
                    Vector3 centroid = Topology.CalculateCentroid(i / 3);
                    centroid.Normalize();

                    // Compare each corner to the centroid
                    // if too far off some ideal length ( the centroid of an equilateral triangle ),
                    // pull vertex closer to centroid, (without buggering up the other triangles using
                    // this point.)
                    Vector3[] oldPositions = new Vector3[3]
                    {
                        new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i]])),
                        new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i + 1]])),
                        new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i + 2]])),
                    };
                    Vector3[] newPositions = new Vector3[3];
                    for (int j = 0; j < 3; ++j)
                    {
                        TVertex v1    = mesh.vertices[indices[i + j]];
                        Vector3 v1Pos = MeshAttr.GetPosition(ref v1);
                        Vector3 e1    = centroid - v1Pos;

                        if (e1.Length > idealDistanceToCentroid * 1.1)
                        {
                            // Move vertex closer to centroid
                            float factor   = 1.0f - (float)idealDistanceToCentroid / e1.Length;
                            float fraction = (multiplier * (1.0f - (float)idealDistanceToCentroid / e1.Length));
                            factor = factor * fraction;
                            v1Pos  = Vector3.Normalize(v1Pos + e1 * factor);
                        }
                        else if (e1.Length < idealDistanceToCentroid * 0.9)
                        {
                            // Move vertex away from the centroid
                            float factor   = 1 - e1.Length / (float)idealDistanceToCentroid;
                            float fraction = (multiplier * (e1.Length / (float)idealDistanceToCentroid));
                            factor = factor * fraction;
                            v1Pos  = Vector3.Normalize(v1Pos - e1 * factor);
                        }
                        newPositions[j] = v1Pos;
                    }

                    // If this makes the triangle less parallel to the sphere, don't do it.
                    Vector3 a      = newPositions[1] - newPositions[0];
                    Vector3 b      = newPositions[2] - newPositions[1];
                    Vector3 normal = Vector3.Cross(a, b);
                    normal.Normalize();
                    float  dot = Vector3.Dot(centroid, normal);
                    double phi = Math.Acos(dot);

                    a      = oldPositions[1] - oldPositions[0];
                    b      = oldPositions[2] - oldPositions[1];
                    normal = Vector3.Cross(a, b);
                    normal.Normalize();
                    dot = Vector3.Dot(centroid, normal);
                    double theta = Math.Acos(dot);
                    if (phi < dot)
                    {
                        for (int j = 0; j < 3; ++j)
                        {
                            //SetPosition(ref mesh.vertices[indices[i + j]], ref newPositions[j]);
                            shiftPositions[indices[i + j]] = newPositions[j];
                        }
                    }

                    // If any surrounding triangles would be less parallel to the sphere than
                    // this is more parallel, don't do it.
                }
            }

            TVertex[] vertices   = new TVertex[mesh.vertices.Length];
            float     totalShift = 0;

            for (int i = 0; i < mesh.vertices.Length; ++i)
            {
                Vector3 delta = shiftPositions[i] - MeshAttr.GetPosition(ref mesh.vertices[i]);
                MeshAttr.SetPosition(ref mesh.vertices[i], ref shiftPositions[i]);
                totalShift += delta.Length;
            }

            Topology.Regenerate();
            return(totalShift);
        }