예제 #1
0
    /// <summary>
    /// Converts mesh content to model content with a <see cref="TriangleMeshShape"/>.
    /// </summary>
    /// <param name="input">The root node content.</param>
    /// <param name="context">Context for the specified processor.</param>
    /// <returns>The <see cref="Shape"/>.</returns>
    public override DRModelNodeContent Process(NodeContent input, ContentProcessorContext context)
    {
      // ----- Process Model
      var model = base.Process(input, context);

      // ----- Extract Triangles
      var triangleMesh = new TriangleMesh();

      // The input node is usually a tree of nodes. We need to collect all MeshContent nodes
      // in the tree. The DigitalRune Helper library provides a TreeHelper that can be used 
      // to traverse trees using LINQ.
      // The following returns an IEnumerable that returns all nodes of the tree.
      var nodes = TreeHelper.GetSubtree(input, n => n.Children);

      // We only need nodes of type MeshContent.
      var meshes = nodes.OfType<MeshContent>();

      foreach (var mesh in meshes)
      {
        // Apply any transformations to vertices.
        Matrix transform = mesh.AbsoluteTransform;
        for (int i = 0; i < mesh.Positions.Count; i++)
          mesh.Positions[i] = Vector3.Transform(mesh.Positions[i], transform);

        // Extract triangles from submeshes.
        foreach (var geometry in mesh.Geometry)
        {
          int numberOfTriangles = geometry.Indices.Count / 3;
          for (int i = 0; i < numberOfTriangles; i++)
          {
            int index0 = geometry.Indices[3 * i + 0];
            int index1 = geometry.Indices[3 * i + 2]; // Note: DigitalRune Geometry uses a different winding
            int index2 = geometry.Indices[3 * i + 1]; // order. Therefore, the indices need to be swapped.

            Vector3F vertex0 = (Vector3F)geometry.Vertices.Positions[index0];
            Vector3F vertex1 = (Vector3F)geometry.Vertices.Positions[index1];
            Vector3F vertex2 = (Vector3F)geometry.Vertices.Positions[index2];

            triangleMesh.Add(new Triangle(vertex0, vertex1, vertex2), false, Numeric.EpsilonF, true);
          }
        }
      }

      // Remove duplicate vertices.
      triangleMesh.WeldVertices();

      // ----- Create TriangleMeshShape
      // Create a TriangleMeshShape that can be used for collision detection.
      // Note: 
      // - Contact-welding is enabled to improve the results of the collision detection.
      // - A CompressedAabbTree is used for spatial partitioning to speed up collision detection.
      var triangleMeshShape = new TriangleMeshShape(triangleMesh, true, new CompressedAabbTree());

      // Export the ModelNode together with the TriangleMeshShape.
      model.UserData = triangleMeshShape;
      return model;
    }
예제 #2
0
        /// <overloads>
        /// <summary>
        /// Converts the given <see cref="ITriangleMesh"/> to a <see cref="DcelMesh"/>.
        /// </summary>
        /// </overloads>
        /// 
        /// <summary>
        /// Converts the given <see cref="ITriangleMesh"/> to a <see cref="DcelMesh"/>.
        /// </summary>
        /// <param name="mesh">The triangle mesh.</param>
        /// <returns>
        /// The <see cref="DcelMesh"/>.
        /// </returns>
        /// <remarks>
        /// Currently, creating <see cref="DcelMesh"/>es is not supported if the triangle mesh consists
        /// of unconnected sub-meshes or unconnected triangles. All parts of the triangle mesh must be
        /// connected via an edge. (But it is not required that the mesh is closed.)
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="mesh"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="mesh"/> has no vertices or vertex indices.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// <paramref name="mesh"/> consists of several unconnected components or sub-meshes.
        /// </exception>
        public static DcelMesh FromTriangleMesh(ITriangleMesh mesh)
        {
            if (mesh == null)
            throw new ArgumentNullException("mesh");

              // The simple way: Create a TriangleMesh first.
              var triangleMesh = new TriangleMesh();
              triangleMesh.Add(mesh, false);
              triangleMesh.WeldVertices();

              return FromTriangleMesh(triangleMesh);
        }
예제 #3
0
        /// <overloads>
        /// <summary>
        /// Converts the given <see cref="ITriangleMesh"/> to a <see cref="DcelMesh"/>.
        /// </summary>
        /// </overloads>
        ///
        /// <summary>
        /// Converts the given <see cref="ITriangleMesh"/> to a <see cref="DcelMesh"/>.
        /// </summary>
        /// <param name="mesh">The triangle mesh.</param>
        /// <returns>
        /// The <see cref="DcelMesh"/>.
        /// </returns>
        /// <remarks>
        /// Currently, creating <see cref="DcelMesh"/>es is not supported if the triangle mesh consists
        /// of unconnected sub-meshes or unconnected triangles. All parts of the triangle mesh must be
        /// connected via an edge. (But it is not required that the mesh is closed.)
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="mesh"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="mesh"/> has no vertices or vertex indices.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// <paramref name="mesh"/> consists of several unconnected components or sub-meshes.
        /// </exception>
        public static DcelMesh FromTriangleMesh(ITriangleMesh mesh)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }

            // The simple way: Create a TriangleMesh first.
            var triangleMesh = new TriangleMesh();

            triangleMesh.Add(mesh, false);
            triangleMesh.WeldVertices();

            return(FromTriangleMesh(triangleMesh));
        }
예제 #4
0
        public static Submesh CreateSubmesh(GraphicsDevice graphicsDevice, ITriangleMesh mesh, float angleLimit)
        {
            var tm = mesh as TriangleMesh;
              if (tm == null)
              {
            tm = new TriangleMesh();
            tm.Add(mesh);
            tm.WeldVertices();
              }

              return CreateSubmesh(graphicsDevice, tm, angleLimit);
        }
예제 #5
0
    /// <summary>
    /// Called when a mesh should be generated for the shape.
    /// </summary>
    /// <param name="absoluteDistanceThreshold">The absolute distance threshold.</param>
    /// <param name="iterationLimit">The iteration limit.</param>
    /// <returns>The triangle mesh for this shape.</returns>
    protected override TriangleMesh OnGetMesh(float absoluteDistanceThreshold, int iterationLimit)
    {
      // Estimate required segment angle for given accuracy. 
      // (Easy to derive from simple drawing of a circle segment with a triangle used to represent
      // the segment.)
      float alpha = (float)Math.Acos((Radius - absoluteDistanceThreshold) / Radius) * 2;
      int numberOfSegments = (int)Math.Ceiling(ConstantsF.PiOver2 / alpha) * 4;

      // Apply the iteration limit - in case absoluteDistanceThreshold is 0.
      // Lets say each iteration doubles the number of segments. This is an arbitrary interpretation
      // of the "iteration limit".
      numberOfSegments = Math.Min(numberOfSegments, 2 << iterationLimit);
      
      alpha = ConstantsF.TwoPi / numberOfSegments;

      TriangleMesh mesh = new TriangleMesh();

      // The world space vertices are created by rotating "radius vectors" with this rotations.
      QuaternionF rotationY = QuaternionF.CreateRotationY(alpha);
      QuaternionF rotationZ = QuaternionF.CreateRotationZ(alpha);

      // We use two nested loops: In each loop a "radius vector" is rotated further to get a 
      // new vertex.
      Vector3F rLow = Vector3F.UnitX * Radius;    // Radius vector for the lower vertex.
      for (int i = 1; i <= numberOfSegments / 4; i++)
      {
        Vector3F rHigh = rotationZ.Rotate(rLow);  // Radius vector for the higher vertex.

        // In the inner loop we create lines and triangles between 4 vertices, which are created
        // with the radius vectors rLow0, rLow1, rHigh0, rHigh1.
        Vector3F rLow0 = rLow;
        Vector3F rHigh0 = rHigh;
        for (int j = 1; j <= numberOfSegments; j++)
        {
          Vector3F rLow1 = rotationY.Rotate(rLow0);
          Vector3F rHigh1 = rotationY.Rotate(rHigh0);

          // Two top hemisphere triangles
          mesh.Add(new Triangle
          {
            Vertex0 = new Vector3F(0, Height / 2 - Radius, 0) + rLow0,
            Vertex1 = new Vector3F(0, Height / 2 - Radius, 0) + rLow1,
            Vertex2 = new Vector3F(0, Height / 2 - Radius, 0) + rHigh0,
          }, false);
          if (i < numberOfSegments / 4)  // At the "northpole" only a triangle is needed. No quad.
          {
            mesh.Add(new Triangle
            {
              Vertex0 = new Vector3F(0, Height / 2 - Radius, 0) + rLow1,
              Vertex1 = new Vector3F(0, Height / 2 - Radius, 0) + rHigh1,
              Vertex2 = new Vector3F(0, Height / 2 - Radius, 0) + rHigh0,
            }, false);
          }

          // Two bottom hemisphere triangles
          mesh.Add(new Triangle
          {
            Vertex0 = new Vector3F(0, -Height / 2 + Radius, 0) - rLow0,
            Vertex1 = new Vector3F(0, -Height / 2 + Radius, 0) - rHigh0,
            Vertex2 = new Vector3F(0, -Height / 2 + Radius, 0) - rLow1,
          }, false);
          if (i < numberOfSegments / 4)  // At the "southpole" only a triangle is needed. No quad.
          {
            mesh.Add(new Triangle
            {
              Vertex0 = new Vector3F(0, -Height / 2 + Radius, 0) - rLow1,
              Vertex1 = new Vector3F(0, -Height / 2 + Radius, 0) - rHigh0,
              Vertex2 = new Vector3F(0, -Height / 2 + Radius, 0) - rHigh1,
            }, false);
          }

          // Two side triangles
          if (i == 1)
          {
            mesh.Add(new Triangle
            {
              Vertex0 = new Vector3F(0, -Height / 2 + Radius, 0) + rLow0,
              Vertex1 = new Vector3F(0, -Height / 2 + Radius, 0) + rLow1,
              Vertex2 = new Vector3F(0, Height / 2 - Radius, 0) + rLow0,
            }, false);
            mesh.Add(new Triangle
            {
              Vertex0 = new Vector3F(0, -Height / 2 + Radius, 0) + rLow1,
              Vertex1 = new Vector3F(0, Height / 2 - Radius, 0) + rLow1,
              Vertex2 = new Vector3F(0, Height / 2 - Radius, 0) + rLow0,
            }, false);
          }

          rLow0 = rLow1;
          rHigh0 = rHigh1;
        }

        rLow = rHigh;
      }

      mesh.WeldVertices();

      return mesh;
    }
예제 #6
0
    /// <summary>
    /// Called when a mesh should be generated for the shape.
    /// </summary>
    /// <param name="absoluteDistanceThreshold">The absolute distance threshold.</param>
    /// <param name="iterationLimit">The iteration limit.</param>
    /// <returns>The triangle mesh for this shape.</returns>
    protected override TriangleMesh OnGetMesh(float absoluteDistanceThreshold, int iterationLimit)
    {
      // Estimate required segment angle for given accuracy. 
      // (Easy to derive from simple drawing of a circle segment with a triangle used to represent
      // the segment.)
      float alpha = (float)Math.Acos((Radius - absoluteDistanceThreshold) / Radius) * 2;
      int numberOfSegments = (int)Math.Ceiling(ConstantsF.TwoPi / alpha);      

      // Apply the iteration limit - in case absoluteDistanceThreshold is 0.
      // Lets say each iteration doubles the number of segments. This is an arbitrary interpretation
      // of the "iteration limit".
      numberOfSegments = Math.Min(numberOfSegments, 2 << iterationLimit);

      alpha = ConstantsF.TwoPi / numberOfSegments;

      Vector3F r0 = new Vector3F(Radius, 0, 0);
      QuaternionF rotation = QuaternionF.CreateRotationY(alpha);

      TriangleMesh mesh = new TriangleMesh();

      for (int i = 1; i <= numberOfSegments; i++)
      {
        Vector3F r1 = rotation.Rotate(r0);

        // Bottom triangle
        mesh.Add(new Triangle
        {
          Vertex0 = new Vector3F(0, -Height / 2, 0),
          Vertex1 = new Vector3F(0, -Height / 2, 0) + r1,
          Vertex2 = new Vector3F(0, -Height / 2, 0) + r0,
        }, false);

        // Top triangle
        mesh.Add(new Triangle
        {
          Vertex0 = new Vector3F(0, +Height / 2, 0),
          Vertex1 = new Vector3F(0, +Height / 2, 0) + r0,
          Vertex2 = new Vector3F(0, +Height / 2, 0) + r1,
        }, false);

        // Two side triangles
        mesh.Add(new Triangle
        {
          Vertex0 = new Vector3F(0, -Height / 2, 0) + r0,
          Vertex1 = new Vector3F(0, -Height / 2, 0) + r1,
          Vertex2 = new Vector3F(0, +Height / 2, 0) + r0,
        }, false);
        mesh.Add(new Triangle
        {
          Vertex0 = new Vector3F(0, -Height / 2, 0) + r1,
          Vertex1 = new Vector3F(0, +Height / 2, 0) + r1,
          Vertex2 = new Vector3F(0, +Height / 2, 0) + r0,
        }, false);

        r0 = r1;
      }

      mesh.WeldVertices();

      return mesh;
    }
예제 #7
0
        private void CreateDualGraph()
        {
            var triangles = new List <CDTriangle>();

            // Convert to TriangleMesh.
            var triangleMesh = _mesh as TriangleMesh;

            if (triangleMesh == null)
            {
                triangleMesh = new TriangleMesh();
                triangleMesh.Add(_mesh, false);
                triangleMesh.WeldVertices();
            }

            // Initialize vertex normals.
            var normals        = new Vector3F[triangleMesh.Vertices.Count]; // Vertex normals.
            var neighborCounts = new int[triangleMesh.Vertices.Count];      // Numbers of triangles that touch each vertex.

            for (int i = 0; i < triangleMesh.Vertices.Count; i++)
            {
                normals[i]        = Vector3F.Zero;
                neighborCounts[i] = 0;
            }

            // Go through all triangles. Add the normal to normals and increase the neighborCounts
            for (int i = 0; i < triangleMesh.NumberOfTriangles; i++)
            {
                Triangle triangle = triangleMesh.GetTriangle(i);
                var      normal   = triangle.Normal;

                for (int j = 0; j < 3; j++)
                {
                    var vertexIndex = triangleMesh.Indices[(i * 3) + j];
                    normals[vertexIndex]        = normals[vertexIndex] + normal;
                    neighborCounts[vertexIndex] = neighborCounts[vertexIndex] + 1;
                }
            }

            // Create triangles.
            for (int i = 0; i < triangleMesh.NumberOfTriangles; i++)
            {
                Triangle triangle   = triangleMesh.GetTriangle(i);
                var      cdTriangle = new CDTriangle
                {
                    Id       = i,
                    Vertices = new[] { triangle.Vertex0, triangle.Vertex1, triangle.Vertex2 },
                    Normal   = triangle.Normal, // TODO: Special care for degenerate triangles needed?
                };

                for (int j = 0; j < 3; j++)
                {
                    var vertexIndex   = triangleMesh.Indices[(i * 3) + j];
                    var normalSum     = normals[vertexIndex];
                    var neighborCount = neighborCounts[vertexIndex];
                    if (neighborCount > 0)
                    {
                        var normal = normalSum / neighborCount;
                        normal.TryNormalize();
                        cdTriangle.VertexNormals[j] = normal;
                    }
                }

                triangles.Add(cdTriangle);
            }

            // Create an island for each triangle.
            _islands = new List <CDIsland>(triangles.Count);
            for (int i = 0; i < triangles.Count; i++)
            {
                var triangle = triangles[i];

                var island = new CDIsland();
                island.Id        = i;
                island.Triangles = new[] { triangle };
                island.Vertices  = triangle.Vertices;

                island.Aabb = new Aabb(triangle.Vertices[0], triangle.Vertices[0]);
                island.Aabb.Grow(triangle.Vertices[1]);
                island.Aabb.Grow(triangle.Vertices[2]);

                triangle.Island = island;

                _islands.Add(island);
            }

            // Find connectivity (= add neighbor links).
            for (int i = 0; i < triangles.Count; i++)
            {
                var a = triangles[i];
                for (int j = i + 1; j < triangles.Count; j++)
                {
                    var b = triangles[j];
                    CDTriangle.FindNeighbors(a, b);
                }
            }

            // Create links.
            _links = new List <CDIslandLink>();
            for (int i = 0; i < _islands.Count; i++)
            {
                var island   = _islands[i];
                var triangle = island.Triangles[0];

                // Go through all neighbors.
                // If there is a neighbor, create a link.
                // To avoid two links per triangle, we create the link only if the id of this triangle
                // is less than the other island id.
                for (int j = 0; j < 3; j++)
                {
                    CDTriangle neighborTriangle = triangle.Neighbors[j];
                    if (neighborTriangle != null && neighborTriangle.Island.Id > i)
                    {
                        var link = new CDIslandLink(island, neighborTriangle.Island, AllowedConcavity, SmallIslandBoost, IntermediateVertexLimit, SampleTriangleVertices, SampleTriangleCenters);
                        _links.Add(link);
                    }
                }
            }

            // Now, we have a lot of islands with 1 triangle each.
        }
예제 #8
0
    /// <summary>
    /// Called when a mesh should be generated for the shape.
    /// </summary>
    /// <param name="absoluteDistanceThreshold">The absolute distance threshold.</param>
    /// <param name="iterationLimit">The iteration limit.</param>
    /// <returns>The triangle mesh for this shape.</returns>
    /// <remarks>
    /// A deep copy of the <see cref="Mesh"/> is returned.
    /// </remarks>
    protected override TriangleMesh OnGetMesh(float absoluteDistanceThreshold, int iterationLimit)
    {
      var triangleMesh = Mesh as TriangleMesh;
      if (triangleMesh != null)
        return triangleMesh.Clone();

      // Return a copy of the mesh.
      TriangleMesh mesh = new TriangleMesh();
      int numberOfTriangles = _mesh.NumberOfTriangles;
      for (int i = 0; i < numberOfTriangles; i++)
      {
        Triangle triangle = _mesh.GetTriangle(i);
        mesh.Add(triangle, false);
      }
      mesh.WeldVertices();

      return mesh;
    }
예제 #9
0
        private void CreateDualGraph()
        {
            var triangles = new List<CDTriangle>();

              // Convert to TriangleMesh.
              var triangleMesh = _mesh as TriangleMesh;
              if (triangleMesh == null)
              {
            triangleMesh = new TriangleMesh();
            triangleMesh.Add(_mesh, false);
            triangleMesh.WeldVertices();
              }

              // Initialize vertex normals.
              var normals = new Vector3F[triangleMesh.Vertices.Count];    // Vertex normals.
              var neighborCounts = new int[triangleMesh.Vertices.Count];  // Numbers of triangles that touch each vertex.
              for (int i = 0; i < triangleMesh.Vertices.Count; i++)
              {
            normals[i] = Vector3F.Zero;
            neighborCounts[i] = 0;
              }

              // Go through all triangles. Add the normal to normals and increase the neighborCounts
              for (int i = 0; i < triangleMesh.NumberOfTriangles; i++)
              {
            Triangle triangle = triangleMesh.GetTriangle(i);
            var normal = triangle.Normal;

            for (int j = 0; j < 3; j++)
            {
              var vertexIndex = triangleMesh.Indices[(i * 3) + j];
              normals[vertexIndex] = normals[vertexIndex] + normal;
              neighborCounts[vertexIndex] = neighborCounts[vertexIndex] + 1;
            }
              }

              // Create triangles.
              for (int i = 0; i < triangleMesh.NumberOfTriangles; i++)
              {
            Triangle triangle = triangleMesh.GetTriangle(i);
            var cdTriangle = new CDTriangle
            {
              Id = i,
              Vertices = new[] { triangle.Vertex0, triangle.Vertex1, triangle.Vertex2 },
              Normal = triangle.Normal,   // TODO: Special care for degenerate triangles needed?
            };

            for (int j = 0; j < 3; j++)
            {
              var vertexIndex = triangleMesh.Indices[(i * 3) + j];
              var normalSum = normals[vertexIndex];
              var neighborCount = neighborCounts[vertexIndex];
              if (neighborCount > 0)
              {
            var normal = normalSum / neighborCount;
            normal.TryNormalize();
            cdTriangle.VertexNormals[j] = normal;
              }
            }

            triangles.Add(cdTriangle);
              }

              // Create an island for each triangle.
              _islands = new List<CDIsland>(triangles.Count);
              for (int i = 0; i < triangles.Count; i++)
              {
            var triangle = triangles[i];

            var island = new CDIsland();
            island.Id = i;
            island.Triangles = new[] { triangle };
            island.Vertices = triangle.Vertices;

            island.Aabb = new Aabb(triangle.Vertices[0], triangle.Vertices[0]);
            island.Aabb.Grow(triangle.Vertices[1]);
            island.Aabb.Grow(triangle.Vertices[2]);

            triangle.Island = island;

            _islands.Add(island);
              }

              // Find connectivity (= add neighbor links).
              for (int i = 0; i < triangles.Count; i++)
              {
            var a = triangles[i];
            for (int j = i + 1; j < triangles.Count; j++)
            {
              var b = triangles[j];
              CDTriangle.FindNeighbors(a, b);
            }
              }

              // Create links.
              _links = new List<CDIslandLink>();
              for (int i = 0; i < _islands.Count; i++)
              {
            var island = _islands[i];
            var triangle = island.Triangles[0];

            // Go through all neighbors.
            // If there is a neighbor, create a link.
            // To avoid two links per triangle, we create the link only if the id of this triangle
            // is less than the other island id.
            for (int j = 0; j < 3; j++)
            {
              CDTriangle neighborTriangle = triangle.Neighbors[j];
              if (neighborTriangle != null && neighborTriangle.Island.Id > i)
              {
            var link = new CDIslandLink(island, neighborTriangle.Island, AllowedConcavity, SmallIslandBoost, IntermediateVertexLimit, SampleTriangleVertices, SampleTriangleCenters);
            _links.Add(link);
              }
            }
              }

              // Now, we have a lot of islands with 1 triangle each.
        }