Example #1
0
        private static void Subdivide(SubdivisionMesh subdivisionMesh, TriangleIndicesUnsignedInt triangle, int level)
        {
            if (level > 0)
            {
                IList <Vector3D> positions = subdivisionMesh.Positions;
                Vector3D         n01       = ((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize();
                Vector3D         n12       = ((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize();
                Vector3D         n20       = ((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize();

                Vector3D p01 = n01.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii);
                Vector3D p12 = n12.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii);
                Vector3D p20 = n20.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii);

                positions.Add(p01);
                positions.Add(p12);
                positions.Add(p20);

                int i01 = positions.Count - 3;
                int i12 = positions.Count - 2;
                int i20 = positions.Count - 1;

                if ((subdivisionMesh.Normals != null) || (subdivisionMesh.TextureCoordinate != null))
                {
                    Vector3D d01 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p01);
                    Vector3D d12 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p12);
                    Vector3D d20 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p20);

                    if (subdivisionMesh.Normals != null)
                    {
                        subdivisionMesh.Normals.Add(d01.ToVector3H());
                        subdivisionMesh.Normals.Add(d12.ToVector3H());
                        subdivisionMesh.Normals.Add(d20.ToVector3H());
                    }

                    if (subdivisionMesh.TextureCoordinate != null)
                    {
                        subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d01));
                        subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d12));
                        subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d20));
                    }
                }

                //
                // Subdivide input triangle into four triangles
                //
                --level;
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, i12, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level);
            }
            else
            {
                subdivisionMesh.Indices.AddTriangle(triangle);
            }
        }
Example #2
0
        public void TriangleIndicesTest()
        {
            TriangleIndicesUnsignedInt triangle = new TriangleIndicesUnsignedInt(0, 1, 2);

            Assert.AreEqual(0, triangle.UI0);
            Assert.AreEqual(1, triangle.UI1);
            Assert.AreEqual(2, triangle.UI2);

            TriangleIndicesUnsignedInt triangle2 = triangle;

            Assert.AreEqual(triangle, triangle2);

            TriangleIndicesUnsignedInt triangle3 = new TriangleIndicesUnsignedInt(3, 4, 5);

            Assert.AreNotEqual(triangle, triangle3);
        }
        private static void Subdivide(SubdivisionMesh subdivisionMesh, TriangleIndicesUnsignedInt triangle, int level)
        {
            if (level > 0)
            {
                IList <Vector3D> positions = subdivisionMesh.Positions;
                Vector3D         p01       = ((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize();
                Vector3D         p12       = ((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize();
                Vector3D         p20       = ((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize();

                positions.Add(p01);
                positions.Add(p12);
                positions.Add(p20);

                int i01 = positions.Count - 3;
                int i12 = positions.Count - 2;
                int i20 = positions.Count - 1;

                if (subdivisionMesh.Normals != null)
                {
                    subdivisionMesh.Normals.Add(p01.ToVector3H());
                    subdivisionMesh.Normals.Add(p12.ToVector3H());
                    subdivisionMesh.Normals.Add(p20.ToVector3H());
                }

                if (subdivisionMesh.TextureCoordinate != null)
                {
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p01));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p12));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p20));
                }

                //
                // Subdivide input triangle into four triangles
                //
                --level;
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, i12, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level);
            }
            else
            {
                subdivisionMesh.Indices.AddTriangle(triangle);
            }
        }
        private static void Subdivide(IList <Vector3D> positions, IndicesUnsignedInt indices, TriangleIndicesUnsignedInt triangle, int level)
        {
            if (level > 0)
            {
                positions.Add(((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize());
                positions.Add(((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize());
                positions.Add(((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize());

                int i01 = positions.Count - 3;
                int i12 = positions.Count - 2;
                int i20 = positions.Count - 1;

                //
                // Subdivide input triangle into four triangles
                //
                --level;
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level);
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level);
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i01, i12, i20), level);
                Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level);
            }
            else
            {
                indices.AddTriangle(triangle);
            }
        }
        public static TriangleMeshSubdivisionResult Compute(IEnumerable <Vector3D> positions, IndicesUnsignedInt indices, double granularity)
        {
            if (positions == null)
            {
                throw new ArgumentNullException("positions");
            }

            if (indices == null)
            {
                throw new ArgumentNullException("positions");
            }

            if (indices.Values.Count < 3)
            {
                throw new ArgumentOutOfRangeException("indices", "At least three indices are required.");
            }

            if (indices.Values.Count % 3 != 0)
            {
                throw new ArgumentException("indices", "The number of indices must be divisable by three.");
            }

            if (granularity <= 0.0)
            {
                throw new ArgumentOutOfRangeException("granularity", "Granularity must be greater than zero.");
            }

            //
            // Use two queues:  one for triangles that need (or might need) to be
            // subdivided and other for triangles that are fully subdivided.
            //
            Queue <TriangleIndicesUnsignedInt> triangles = new Queue <TriangleIndicesUnsignedInt>(indices.Values.Count / 3);
            Queue <TriangleIndicesUnsignedInt> done      = new Queue <TriangleIndicesUnsignedInt>(indices.Values.Count / 3);

            IList <uint> indicesValues = indices.Values;

            for (int i = 0; i < indicesValues.Count; i += 3)
            {
                triangles.Enqueue(new TriangleIndicesUnsignedInt(indicesValues[i], indicesValues[i + 1], indicesValues[i + 2]));
            }

            //
            // New positions due to edge splits are appended to the positions list.
            //
            IList <Vector3D> subdividedPositions = CollectionAlgorithms.CopyEnumerableToList(positions);

            //
            // Used to make sure shared edges are not split more than once.
            //
            Dictionary <Edge, int> edges = new Dictionary <Edge, int>();

            //
            // Subdivide triangles until we run out
            //
            while (triangles.Count != 0)
            {
                TriangleIndicesUnsignedInt triangle = triangles.Dequeue();

                Vector3D v0 = subdividedPositions[triangle.I0];
                Vector3D v1 = subdividedPositions[triangle.I1];
                Vector3D v2 = subdividedPositions[triangle.I2];

                double g0 = v0.AngleBetween(v1);
                double g1 = v1.AngleBetween(v2);
                double g2 = v2.AngleBetween(v0);

                double max = Math.Max(g0, Math.Max(g1, g2));

                if (max > granularity)
                {
                    if (g0 == max)
                    {
                        Edge edge = new Edge(Math.Min(triangle.I0, triangle.I1), Math.Max(triangle.I0, triangle.I1));
                        int  i;
                        if (!edges.TryGetValue(edge, out i))
                        {
                            subdividedPositions.Add((v0 + v1) * 0.5);
                            i = subdividedPositions.Count - 1;
                            edges.Add(edge, i);
                        }

                        triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I0, i, triangle.I2));
                        triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I1, triangle.I2));
                    }
                    else if (g1 == max)
                    {
                        Edge edge = new Edge(Math.Min(triangle.I1, triangle.I2), Math.Max(triangle.I1, triangle.I2));
                        int  i;
                        if (!edges.TryGetValue(edge, out i))
                        {
                            subdividedPositions.Add((v1 + v2) * 0.5);
                            i = subdividedPositions.Count - 1;
                            edges.Add(edge, i);
                        }

                        triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I1, i, triangle.I0));
                        triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I2, triangle.I0));
                    }
                    else if (g2 == max)
                    {
                        Edge edge = new Edge(Math.Min(triangle.I2, triangle.I0), Math.Max(triangle.I2, triangle.I0));
                        int  i;
                        if (!edges.TryGetValue(edge, out i))
                        {
                            subdividedPositions.Add((v2 + v0) * 0.5);
                            i = subdividedPositions.Count - 1;
                            edges.Add(edge, i);
                        }

                        triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I2, i, triangle.I1));
                        triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I0, triangle.I1));
                    }
                }
                else
                {
                    done.Enqueue(triangle);
                }
            }

            //
            // New indices
            //
            IndicesUnsignedInt subdividedIndices = new IndicesUnsignedInt(done.Count * 3);

            foreach (TriangleIndicesUnsignedInt t in done)
            {
                subdividedIndices.AddTriangle(t);
            }

            return(new TriangleMeshSubdivisionResult(subdividedPositions, subdividedIndices));
        }
 public void AddTriangle(TriangleIndicesUnsignedInt triangle)
 {
     _values.Add(triangle.UI0);
     _values.Add(triangle.UI1);
     _values.Add(triangle.UI2);
 }