Exemple #1
0
        private uint GenerateVertex(ref List <TVertex> verts, int a, int b)
        {
            Int64 key1 = Geometry.Topology.CreateEdgeKey(indices[a], indices[b]);
            uint  middlePt;

            if (!subDivideEdgeCache.TryGetValue(key1, out middlePt))
            {
                Vector3 pos1 = MeshAttr.GetPosition(ref mesh.vertices[indices[a]]);
                Vector3 pos2 = MeshAttr.GetPosition(ref mesh.vertices[indices[b]]);
                Vector3 e1   = Vector3.Normalize(pos1 + (pos2 - pos1) * 0.5f);
                TVertex v1   = mesh.vertices[indices[a]];
                MeshAttr.SetPosition(ref v1, ref e1);
                middlePt = (uint)verts.Count;
                subDivideEdgeCache.Add(key1, middlePt);
                verts.Add(v1);
            }
            return(middlePt);
        }
Exemple #2
0
        /// <summary>
        /// Adds a triangle with vertex format Position, Normal and UV, calculating the normal from the origin, and
        /// using a defined UV of top center, bottom left, bottom right.
        /// </summary>
        /// <typeparam name="AltVertex"></typeparam>
        /// <param name="newVerts"></param>
        /// <param name="newIndices"></param>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <param name="v3"></param>
        /// <param name="isAnticlockwise"></param>
        public void AddTriangle <AltVertex>(ref List <AltVertex> newVerts, ref List <uint> newIndices, ref Vector3 v1, ref Vector3 v2, ref Vector3 v3, bool isAnticlockwise)
            where AltVertex : struct, IVertex
        {
            AltVertex[] triVerts = new AltVertex[3];
            triVerts.Initialize();
            MeshAttr.SetPosition(ref triVerts[0], ref v1);
            MeshAttr.SetPosition(ref triVerts[1], ref v2);
            MeshAttr.SetPosition(ref triVerts[2], ref v3);
            Vector3 v1N = v1;

            v1N.Normalize();
            for (int i = 0; i < 3; i++)
            {
                MeshAttr.SetNormal(ref triVerts[i], ref v1N);
            }

            Vector2 uv0 = new Vector2(0.5f, 1);
            Vector2 uv1 = new Vector2(0, 0);
            Vector2 uv2 = new Vector2(1, 0);

            MeshAttr.SetUV(ref triVerts[0], ref uv0);
            MeshAttr.SetUV(ref triVerts[1], ref uv1);
            MeshAttr.SetUV(ref triVerts[2], ref uv2);
            int index = newVerts.Count;

            for (int i = 0; i < 3; i++)
            {
                newVerts.Add(triVerts[i]);
            }

            if (isAnticlockwise)
            {
                newIndices.Add((uint)index);
                newIndices.Add((uint)index + 1);
                newIndices.Add((uint)index + 2);
            }
            else
            {
                newIndices.Add((uint)index);
                newIndices.Add((uint)index + 2);
                newIndices.Add((uint)index + 1);
            }
        }
Exemple #3
0
        /// <summary>
        /// Adds a triangle based on the current mesh with the vertex format Position, Normal, UV and Color.
        /// It sets the normal for each vertex to the original position vector,
        /// UV is set to top center, bottom left, bottom right, with original vert being top center
        /// It sets color of all verts to the color of the original vertex.
        /// </summary>
        /// <typeparam name="AltVertex"></typeparam>
        /// <param name="newVerts">The new set of vertices</param>
        /// <param name="newIndices">The new set of indices</param>
        /// <param name="v1index">The index of the vertex in the original mesh</param>
        /// <param name="v2">the position of the first new vertex</param>
        /// <param name="v3">the position of the second new vertex</param>
        /// <param name="color">The new vertex color</param>"
        public void AddTriangle2 <AltVertex>(ref List <AltVertex> newVerts, ref List <uint> newIndices, int v1index, ref Vector3 v2, ref Vector3 v3, Vector4 color)
            where AltVertex : struct, IVertex
        {
            AltVertex[] triVerts = new AltVertex[3];
            triVerts.Initialize();

            Vector3 v1Pos = MeshAttr.GetPosition(ref mesh.vertices[v1index]);

            MeshAttr.SetPosition(ref triVerts[0], ref v1Pos);
            MeshAttr.SetPosition(ref triVerts[1], ref v2);
            MeshAttr.SetPosition(ref triVerts[2], ref v3);

            v1Pos.Normalize();
            for (int i = 0; i < 3; i++)
            {
                MeshAttr.SetNormal(ref triVerts[i], ref v1Pos);
            }

            Vector2 uv0 = new Vector2(0.5f, 1);
            Vector2 uv1 = new Vector2(0, 0);
            Vector2 uv2 = new Vector2(1, 0);

            MeshAttr.SetUV(ref triVerts[0], ref uv0);
            MeshAttr.SetUV(ref triVerts[1], ref uv1);
            MeshAttr.SetUV(ref triVerts[2], ref uv2);

            MeshAttr.SetColor(ref triVerts[0], ref color);
            MeshAttr.SetColor(ref triVerts[1], ref color);
            MeshAttr.SetColor(ref triVerts[2], ref color);

            newVerts[v1index] = triVerts[0];
            int index = newVerts.Count;

            newVerts.Add(triVerts[1]);
            newVerts.Add(triVerts[2]);

            newIndices.Add((uint)v1index);
            newIndices.Add((uint)index++);
            newIndices.Add((uint)index++);
        }
Exemple #4
0
        public IGeometry ClonePosition <TVertex2>() where TVertex2 : struct, IVertex
        {
            TVertex2[] newVerts = new TVertex2[mesh.vertices.Length];
            int        index    = 0;

            foreach (var iter in mesh.vertices)
            {
                TVertex vertex = iter;
                Vector3 pos    = MeshAttr.GetPosition(ref vertex);
                newVerts[index] = new TVertex2();
                MeshAttr.SetPosition(ref newVerts[index], ref pos);
                index++;
            }
            Mesh <TVertex2> newMesh    = new Mesh <TVertex2>(newVerts);
            Indices         newIndices = null;

            if (indices != null)
            {
                newIndices = indices.Clone();
            }
            Geometry <TVertex2> newGeom = new Geometry <TVertex2>(newMesh, newIndices);

            return(newGeom);
        }
Exemple #5
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);
        }
Exemple #6
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);
        }
Exemple #7
0
 public void SetPosition(int index, ref Vector3 position)
 {
     MeshAttr.SetPosition(ref vertices[index], ref position);
 }