예제 #1
0
        public void ComputeCollision()
        {
            CollisionObject a = new CollisionObject();
              TriangleMesh mesh = new TriangleMesh();
              mesh.Add(new Triangle(new Vector3F(0, 0, 0), new Vector3F(0, 0, 1), new Vector3F(1, 0, 0)), false);
              mesh.Add(new Triangle(new Vector3F(1, 0, 0), new Vector3F(0, 0, 1), new Vector3F(1, 0, 1)), false);
              TriangleMeshShape meshShape = new TriangleMeshShape();
              meshShape.Mesh = mesh;
              a.GeometricObject = new GeometricObject(meshShape, Pose.Identity);

              CollisionObject b = new CollisionObject(new GeometricObject
                  {
                    Shape = new SphereShape(1),
                    Pose = new Pose(new Vector3F(0, 0.9f, 0)),
                  });

              ContactSet set;
              TriangleMeshAlgorithm algo = new TriangleMeshAlgorithm(new CollisionDetection());

              set = algo.GetClosestPoints(a, b);
              Assert.AreEqual(true, algo.HaveContact(a, b));
              Assert.AreEqual(true, algo.HaveContact(b, a));
              Assert.AreEqual(1, set.Count);
              Assert.IsTrue(Numeric.AreEqual(0.1f, set[0].PenetrationDepth, 0.001f));
              //Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0, 0, 0), set[0].PositionALocal, 0.01f));  // MPR will not return the perfect contact point.
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0, 1, 0), set[0].Normal, 0.1f));

              ((GeometricObject)b.GeometricObject).Pose = new Pose(new Vector3F(0.1f, 0.9f, 0.1f));
              algo.UpdateContacts(set, 0);
              Assert.AreEqual(true, algo.HaveContact(a, b));
              Assert.AreEqual(true, algo.HaveContact(b, a));
              Assert.AreEqual(1, set.Count);
              Assert.IsTrue(Numeric.AreEqual(0.1f, set[0].PenetrationDepth, 0.001f));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0.1f, 0, 0.1f), set[0].PositionALocal, 0.01f));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0, 1, 0), set[0].Normal, 0.1f));

              // The same with a swapped set.
              set = set.Swapped;
              algo.UpdateContacts(set, 0);
              Assert.AreEqual(1, set.Count);
              Assert.IsTrue(Numeric.AreEqual(0.1f, set[0].PenetrationDepth, 0.001f));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0.1f, 0, 0.1f), set[0].PositionBLocal, 0.01f));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0, -1, 0), set[0].Normal, 0.1f));

              // Separation.
              ((GeometricObject)b.GeometricObject).Pose = new Pose(new Vector3F(0.2f, 1.2f, 0.3f));
              set = set.Swapped;
              Assert.AreEqual(false, algo.HaveContact(a, b));
              Assert.AreEqual(false, algo.HaveContact(b, a));
              algo.UpdateClosestPoints(set, 0);
              Assert.IsTrue(Numeric.AreEqual(-0.2f, set[0].PenetrationDepth, 0.001f));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0.2f, 0, 0.3f), set[0].PositionALocal, 0.01f));
              Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0, 1, 0), set[0].Normal, 0.1f));
              algo.UpdateContacts(set, 0);
              Assert.AreEqual(0, set.Count);
        }
예제 #2
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;
    }
예제 #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
        /// <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));
        }
예제 #5
0
    public ConvexDecompositionSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;
      GraphicsScreen.ClearBackground = true;
      GraphicsScreen.BackgroundColor = Color.CornflowerBlue;
      SetCamera(new Vector3F(3, 3, 3), 0.8f, -0.6f);

      // Load model.
      _modelNode = ContentManager.Load<ModelNode>("Saucer/Saucer").Clone();

      // Combine all meshes of the model into a single TriangleMesh.
      TriangleMesh mesh = new TriangleMesh();
      foreach (var meshNode in _modelNode.GetChildren().OfType<MeshNode>())
      {
        var childMesh = MeshHelper.ToTriangleMesh(meshNode.Mesh);
        childMesh.Transform(meshNode.PoseWorld * Matrix44F.CreateScale(meshNode.ScaleWorld));
        mesh.Add(childMesh);
      }

      // Start convex decomposition on another thread.
      _convexDecomposition = new ConvexDecomposition();
      _convexDecomposition.ProgressChanged += OnProgressChanged;
      _convexDecomposition.AllowedConcavity = 0.8f;
      _convexDecomposition.IntermediateVertexLimit = 65536;
      _convexDecomposition.VertexLimit = 64;

      // 0 gives optimal results but is the slowest. Small positive values improve
      // speed but the result might be less optimal.
      _convexDecomposition.SmallIslandBoost = 0.02f;

      _convexDecomposition.SampleTriangleCenters = true;
      _convexDecomposition.SampleTriangleVertices = true;

      // Experimental multithreading. Enable at own risk ;-)
      _convexDecomposition.EnableMultithreading = true;

      _convexDecomposition.DecomposeAsync(mesh);
    }
예제 #6
0
        public void ComputeCollisionBvh()
        {
            CollisionObject a = new CollisionObject();
              TriangleMesh meshA = new TriangleMesh();
              meshA.Add(new Triangle(new Vector3F(0, 0, 0), new Vector3F(0, 0, 1), new Vector3F(1, 0, 0)), false);
              var meshShapeA = new TriangleMeshShape();
              meshShapeA.Mesh = meshA;
              meshShapeA.Partition = new AabbTree<int>();
              ((GeometricObject)a.GeometricObject).Shape = meshShapeA;

              CollisionObject b = new CollisionObject();
              TriangleMesh meshB = new TriangleMesh();
              meshB.Add(new Triangle(new Vector3F(2, 0, 0), new Vector3F(2, 0, 1), new Vector3F(3, 0, 0)), false);
              TriangleMeshShape meshShapeB = new TriangleMeshShape();
              meshShapeB.Mesh = meshB;
              meshShapeB.Partition = new AabbTree<int>();
              ((GeometricObject)b.GeometricObject).Shape = meshShapeB;
              ((GeometricObject)b.GeometricObject).Pose = new Pose(new Vector3F(-2, 0, 0));

              CollisionAlgorithm algo = new TriangleMeshAlgorithm(new CollisionDetection());
              Assert.AreEqual(true, algo.HaveContact(a, b));
        }
예제 #7
0
        public void Validate6()
        {
            GlobalSettings.ValidationLevel = 0xff;
              var scene = new Scene();
              // This is allowed.
              var n = new TestSceneNode { Shape = Shape.Empty };
              scene.Children.Add(n);

              // Invalid changes of already added node:
              var mesh = new TriangleMesh();
              mesh.Add(new Triangle(new Vector3F(1), new Vector3F(2), new Vector3F(3)));
              mesh.Add(new Triangle(new Vector3F(4), new Vector3F(float.NaN, 5, 5), new Vector3F(6)));
              var meshShape = new TriangleMeshShape(mesh);
              Assert.Throws<GraphicsException>(() => n.Shape = meshShape);
        }
예제 #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>
    /// This method creates a triangle mesh that represents a square lying in the plane. The square
    /// has an edge length of <see cref="MeshSize"/>.
    /// </remarks>
    protected override TriangleMesh OnGetMesh(float absoluteDistanceThreshold, int iterationLimit)
    {
      Vector3F center = Normal * DistanceFromOrigin;
      Vector3F orthoNormal1 = Normal.Orthonormal1;
      Vector3F orthoNormal2 = Normal.Orthonormal2;

      // Plane 

      // Make 4 triangles around the center.
      TriangleMesh mesh = new TriangleMesh();
      mesh.Add(new Triangle
      {
        Vertex0 = center,
        Vertex1 = center + orthoNormal1 * MeshSize / 2 - orthoNormal2 * MeshSize / 2,
        Vertex2 = center + orthoNormal1 * MeshSize / 2 + orthoNormal2 * MeshSize / 2,
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = center,
        Vertex1 = center + orthoNormal1 * MeshSize / 2 + orthoNormal2 * MeshSize / 2,
        Vertex2 = center - orthoNormal1 * MeshSize / 2 + orthoNormal2 * MeshSize / 2,
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = center,
        Vertex1 = center - orthoNormal1 * MeshSize / 2 + orthoNormal2 * MeshSize / 2,
        Vertex2 = center - orthoNormal1 * MeshSize / 2 - orthoNormal2 * MeshSize / 2,
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = center,
        Vertex1 = center - orthoNormal1 * MeshSize / 2 - orthoNormal2 * MeshSize / 2,
        Vertex2 = center + orthoNormal1 * MeshSize / 2 - orthoNormal2 * MeshSize / 2,
      }, true);

      return mesh;
    }
예제 #9
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)
    {
      // Get coordinates of corners:
      float near = -Math.Min(Near, Far);
      float far = -Math.Max(Near, Far);
      float leftNear = Math.Min(Left, Right);
      float rightNear = Math.Max(Left, Right);
      float topNear = Math.Max(Top, Bottom);
      float bottomNear = Math.Min(Top, Bottom);
      float farFactor = 1 / near * far;    // Multiply near-values by this factor to get far-values.
      float leftFar = leftNear * farFactor;
      float rightFar = rightNear * farFactor;
      float topFar = topNear * farFactor;
      float bottomFar = bottomNear * farFactor;

      TriangleMesh mesh = new TriangleMesh();

      // -y face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(leftNear, bottomNear, near), 
        Vertex1 = new Vector3F(leftFar, bottomFar, far),
        Vertex2 = new Vector3F(rightFar, bottomFar, far),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(rightFar, bottomFar, far),
        Vertex1 = new Vector3F(rightNear, bottomNear, near),
        Vertex2 = new Vector3F(leftNear, bottomNear, near),
      }, true);

      // +x face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(rightNear, topNear, near),
        Vertex1 = new Vector3F(rightNear, bottomNear, near),
        Vertex2 = new Vector3F(rightFar, bottomFar, far),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(rightFar, bottomFar, far),
        Vertex1 = new Vector3F(rightFar, topFar, far),
        Vertex2 = new Vector3F(rightNear, topNear, near),
      }, true);

      // -z face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(rightFar, topFar, far),
        Vertex1 = new Vector3F(rightFar, bottomFar, far),
        Vertex2 = new Vector3F(leftFar, bottomFar, far),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(leftFar, bottomFar, far),
        Vertex1 = new Vector3F(leftFar, topFar, far),
        Vertex2 = new Vector3F(rightFar, topFar, far),
      }, true);

      // -x face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(leftFar, topFar, far),
        Vertex1 = new Vector3F(leftFar, bottomFar, far),
        Vertex2 = new Vector3F(leftNear, bottomNear, near),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(leftNear, bottomNear, near),
        Vertex1 = new Vector3F(leftNear, topNear, near),
        Vertex2 = new Vector3F(leftFar, topFar, far),
      }, true);
      
      // +z face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(leftNear, topNear, near),
        Vertex1 = new Vector3F(leftNear, bottomNear, near),
        Vertex2 = new Vector3F(rightNear, bottomNear, near),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(rightNear, bottomNear, near),
        Vertex1 = new Vector3F(rightNear, topNear, near),
        Vertex2 = new Vector3F(leftNear, topNear, near),
      }, true);

      // +y face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(leftFar, topFar, far),
        Vertex1 = new Vector3F(leftNear, topNear, near),
        Vertex2 = new Vector3F(rightNear, topNear, near),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(rightNear, topNear, near),
        Vertex1 = new Vector3F(rightFar, topFar, far),
        Vertex2 = new Vector3F(leftFar, topFar, far),
      }, true);

      return mesh;
    }
예제 #10
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.
        }
예제 #11
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)
 {
   TriangleMesh mesh = new TriangleMesh();
   mesh.Add(new Triangle
   {
     Vertex0 = new Vector3F(_widthX / 2, _widthY / 2, 0),
     Vertex1 = new Vector3F(-_widthX / 2, _widthY / 2, 0),
     Vertex2 = new Vector3F(-_widthX / 2, -_widthY / 2, 0),
   }, true);
   mesh.Add(new Triangle
   {
     Vertex0 = new Vector3F(-_widthX / 2, -_widthY / 2, 0),
     Vertex1 = new Vector3F(_widthX / 2, -_widthY / 2, 0),
     Vertex2 = new Vector3F(_widthX / 2, _widthY / 2, 0),
   }, true);
   return mesh;
 }
예제 #12
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)
 {
   TriangleMesh mesh = new TriangleMesh();
   mesh.Add(new Triangle(this), true);
   return mesh;
 }
예제 #13
0
        public void Setup()
        {
            // Make a unit cube.
              _mesh = new TriangleMesh();
              // Bottom
              _mesh.Add(new Triangle(new Vector3F(0, 0, 0), new Vector3F(1, 1, 0), new Vector3F(1, 0, 0)), true);
              _mesh.Add(new Triangle(new Vector3F(0, 0, 0), new Vector3F(0, 1, 0), new Vector3F(1, 1, 0)), true);
              // Top
              _mesh.Add(new Triangle(new Vector3F(0, 0, 1), new Vector3F(1, 0, 1), new Vector3F(1, 1, 1)), true);
              _mesh.Add(new Triangle(new Vector3F(0, 0, 1), new Vector3F(1, 1, 1), new Vector3F(0, 1, 1)), true);
              // Left
              _mesh.Add(new Triangle(new Vector3F(0, 0, 0), new Vector3F(1, 0, 0), new Vector3F(1, 0, 1)), true);
              _mesh.Add(new Triangle(new Vector3F(0, 0, 0), new Vector3F(1, 0, 1), new Vector3F(0, 0, 1)), true);
              // Right
              _mesh.Add(new Triangle(new Vector3F(0, 1, 0), new Vector3F(0, 1, 1), new Vector3F(1, 1, 1)), true);
              _mesh.Add(new Triangle(new Vector3F(0, 1, 0), new Vector3F(1, 1, 1), new Vector3F(1, 1, 0)), true);
              // Front
              _mesh.Add(new Triangle(new Vector3F(1, 0, 0), new Vector3F(1, 1, 0), new Vector3F(1, 1, 1)), true);
              _mesh.Add(new Triangle(new Vector3F(1, 0, 0), new Vector3F(1, 1, 1), new Vector3F(1, 0, 1)), true);
              // Back
              _mesh.Add(new Triangle(new Vector3F(0, 0, 0), new Vector3F(0, 0, 1), new Vector3F(0, 1, 1)), true);
              _mesh.Add(new Triangle(new Vector3F(0, 0, 0), new Vector3F(0, 1, 1), new Vector3F(0, 1, 0)), true);

              _meshShape = new TriangleMeshShape { Mesh = _mesh };
        }
예제 #14
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;
    }
예제 #15
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)
    {
      // Get coordinates of corners:
      float near = -Math.Min(Near, Far);
      float far = -Math.Max(Near, Far);
      float left = Math.Min(Left, Right);
      float right = Math.Max(Left, Right);
      float top = Math.Max(Top, Bottom);
      float bottom = Math.Min(Top, Bottom);

      TriangleMesh mesh = new TriangleMesh();
      // -y face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(left, bottom, near),
        Vertex1 = new Vector3F(left, bottom, far),
        Vertex2 = new Vector3F(right, bottom, far),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(right, bottom, far),
        Vertex1 = new Vector3F(right, bottom, near),
        Vertex2 = new Vector3F(left, bottom, near),
      }, true);
      
      // +x face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(right, top, near),
        Vertex1 = new Vector3F(right, bottom, near),
        Vertex2 = new Vector3F(right, bottom, far),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(right, bottom, far),
        Vertex1 = new Vector3F(right, top, far),
        Vertex2 = new Vector3F(right, top, near),
      }, true);
        
      // -z face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(right, top, far),
        Vertex1 = new Vector3F(right, bottom, far),
        Vertex2 = new Vector3F(left, bottom, far),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(left, bottom, far),
        Vertex1 = new Vector3F(left, top, far),
        Vertex2 = new Vector3F(right, top, far),
      }, true);

      // -x face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(left, top, far),
        Vertex1 = new Vector3F(left, bottom, far),
        Vertex2 = new Vector3F(left, bottom, near),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(left, bottom, near),
        Vertex1 = new Vector3F(left, top, near),
        Vertex2 = new Vector3F(left, top, far),
      }, true);

      // +z face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(left, top, near),
        Vertex1 = new Vector3F(left, bottom, near),
        Vertex2 = new Vector3F(right, bottom, near),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(right, bottom, near),
        Vertex1 = new Vector3F(right, top, near),
        Vertex2 = new Vector3F(left, top, near),
      }, true);

      // +y face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(left, top, far),
        Vertex1 = new Vector3F(left, top, near),
        Vertex2 = new Vector3F(right, top, near),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(right, top, near),
        Vertex1 = new Vector3F(right, top, far),
        Vertex2 = new Vector3F(left, top, far),
      }, true);

      return mesh;
    }
예제 #16
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>
 /// This method returns a mesh with a single degenerate triangle. The triangle represents a
 /// line with the length <see cref="MeshSize"/>. The triangle is centered on 
 /// <see cref="PointOnLine"/>.
 /// </remarks>
 protected override TriangleMesh OnGetMesh(float absoluteDistanceThreshold, int iterationLimit)
 {
   Vector3F start = PointOnLine - Direction * (MeshSize / 2);
   Vector3F end = PointOnLine + Direction * (MeshSize / 2);
   // Make a mesh with 1 degenerate triangle
   TriangleMesh mesh = new TriangleMesh();
   mesh.Add(new Triangle
   {
     Vertex0 = start,
     Vertex1 = start,
     Vertex2 = end,
   }, true, Numeric.EpsilonF, false);
   return mesh;
 }
예제 #17
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)
    {
      // Convert absolute error to relative error.
      float maxExtent = GetAabb(Vector3F.One, Pose.Identity).Extent.LargestComponent;
      float relativeThreshold = !Numeric.IsZero(maxExtent)
                                ? absoluteDistanceThreshold / maxExtent
                                : Numeric.EpsilonF;

      // Get meshes of children and add them to mesh in parent space.
      TriangleMesh mesh = new TriangleMesh();
      int numberOfGeometries = Children.Count;
      for (int childIndex = 0; childIndex < numberOfGeometries; childIndex++)
      {
        IGeometricObject geometricObject = Children[childIndex];

        // Get child mesh.
        var childMesh = geometricObject.Shape.GetMesh(relativeThreshold, iterationLimit);

        // Transform child mesh into local space of this parent shape.
        childMesh.Transform(geometricObject.Pose.ToMatrix44F() * Matrix44F.CreateScale(geometricObject.Scale));

        // Add to parent mesh.
        mesh.Add(childMesh, false);
      }

      return mesh;
    }
예제 #18
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;
    }
예제 #19
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.
        }
예제 #20
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;
    }
예제 #21
0
    private void CreateObjects()
    {
      // Create two collision objects with triangle mesh shapes.
      var meshA = new TriangleMesh();
      meshA.Add(new Triangle(new Vector3F(0, 1, 0), new Vector3F(0, 1, 0), new Vector3F(0, 1, 0)));
      meshA.Add(new Triangle(new Vector3F(0, 1, 0), new Vector3F(0, 1, 0), new Vector3F(0, 1, 0)));
      var shapeA = new TriangleMeshShape() { Partition = new CompressedAabbTree() }; 
      var poseA = new Pose(new Vector3F(-1, 0, 0));
      _objectA = new CollisionObject(new GeometricObject(shapeA, poseA));

      var meshB = new BoxShape(0.2f, 2, 1f).GetMesh(0.05f, 4);
      var shapeB = new TriangleMeshShape(meshB, true) { Partition = new CompressedAabbTree() };
      var poseB = new Pose(new Vector3F(0.1f, 0, 0));
      _objectB = new CollisionObject(new GeometricObject(shapeB, poseB)); 
    }
예제 #22
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>
 /// This creates a mesh with a single degenerate triangle that represents the ray.
 /// </remarks>
 protected override TriangleMesh OnGetMesh(float absoluteDistanceThreshold, int iterationLimit)
 {
   // Make a mesh with 1 degenerate triangle
   TriangleMesh mesh = new TriangleMesh();
   mesh.Add(
     new Triangle
     {
       Vertex0 = Origin,
       Vertex1 = Origin,
       Vertex2 = Origin + Direction * Length,
     }, 
     true, 
     Numeric.EpsilonF, 
     false);
   return mesh;
 }
예제 #23
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)
    {
      // Half extent:
      float halfExtentX = _widthX / 2;
      float halfExtentY = _widthY / 2;
      float halfExtentZ = _widthZ / 2;

      TriangleMesh mesh = new TriangleMesh();

      // -y face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(-halfExtentX, -halfExtentY, halfExtentZ),
        Vertex1 = new Vector3F(-halfExtentX, -halfExtentY, -halfExtentZ),
        Vertex2 = new Vector3F(halfExtentX, -halfExtentY, -halfExtentZ),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(halfExtentX, -halfExtentY, -halfExtentZ),
        Vertex1 = new Vector3F(halfExtentX, -halfExtentY, halfExtentZ),
        Vertex2 = new Vector3F(-halfExtentX, -halfExtentY, halfExtentZ),
      }, true);

      // +x face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(halfExtentX, halfExtentY, halfExtentZ),
        Vertex1 = new Vector3F(halfExtentX, -halfExtentY, halfExtentZ),
        Vertex2 = new Vector3F(halfExtentX, -halfExtentY, -halfExtentZ),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(halfExtentX, -halfExtentY, -halfExtentZ),
        Vertex1 = new Vector3F(halfExtentX, halfExtentY, -halfExtentZ),
        Vertex2 = new Vector3F(halfExtentX, halfExtentY, halfExtentZ),
      }, true);

      // -z face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(halfExtentX, halfExtentY, -halfExtentZ),
        Vertex1 = new Vector3F(halfExtentX, -halfExtentY, -halfExtentZ),
        Vertex2 = new Vector3F(-halfExtentX, -halfExtentY, -halfExtentZ),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(-halfExtentX, -halfExtentY, -halfExtentZ),
        Vertex1 = new Vector3F(-halfExtentX, halfExtentY, -halfExtentZ),
        Vertex2 = new Vector3F(halfExtentX, halfExtentY, -halfExtentZ),
      }, true);

      // -x face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(-halfExtentX, halfExtentY, -halfExtentZ),
        Vertex1 = new Vector3F(-halfExtentX, -halfExtentY, -halfExtentZ),
        Vertex2 = new Vector3F(-halfExtentX, -halfExtentY, halfExtentZ),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(-halfExtentX, -halfExtentY, halfExtentZ),
        Vertex1 = new Vector3F(-halfExtentX, halfExtentY, halfExtentZ),
        Vertex2 = new Vector3F(-halfExtentX, halfExtentY, -halfExtentZ),
      }, true);

      // +z face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(-halfExtentX, halfExtentY, halfExtentZ),
        Vertex1 = new Vector3F(-halfExtentX, -halfExtentY, halfExtentZ),
        Vertex2 = new Vector3F(halfExtentX, -halfExtentY, halfExtentZ),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(halfExtentX, -halfExtentY, halfExtentZ),
        Vertex1 = new Vector3F(halfExtentX, halfExtentY, halfExtentZ),
        Vertex2 = new Vector3F(-halfExtentX, halfExtentY, halfExtentZ),
      }, true);

      // +y face
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(-halfExtentX, halfExtentY, -halfExtentZ),
        Vertex1 = new Vector3F(-halfExtentX, halfExtentY, halfExtentZ),
        Vertex2 = new Vector3F(halfExtentX, halfExtentY, halfExtentZ),
      }, true);
      mesh.Add(new Triangle
      {
        Vertex0 = new Vector3F(halfExtentX, halfExtentY, halfExtentZ),
        Vertex1 = new Vector3F(halfExtentX, halfExtentY, -halfExtentZ),
        Vertex2 = new Vector3F(-halfExtentX, halfExtentY, -halfExtentZ),
      }, true);

      return mesh;
    }
예제 #24
0
    private void CreateRigidBody()
    {
      var triangleMesh = new TriangleMesh();

      foreach (var meshNode in _modelNode.GetSubtree().OfType<MeshNode>())
      {
        // Extract the triangle mesh from the DigitalRune Graphics Mesh instance. 
        var subTriangleMesh = new TriangleMesh();
        foreach (var submesh in meshNode.Mesh.Submeshes)
        {
          submesh.ToTriangleMesh(subTriangleMesh);
        }

        // Apply the transformation of the mesh node.
        subTriangleMesh.Transform(meshNode.PoseWorld * Matrix44F.CreateScale(meshNode.ScaleWorld));

        // Combine into final triangle mesh.
        triangleMesh.Add(subTriangleMesh);
      }

      // Create a collision shape that uses the mesh.
      var triangleMeshShape = new TriangleMeshShape(triangleMesh);

      // Optional: Assign a spatial partitioning scheme to the triangle mesh. (A spatial partition
      // adds an additional memory overhead, but it improves collision detection speed tremendously!)
      triangleMeshShape.Partition = new CompressedAabbTree
      {
        // The tree is automatically built using a mixed top-down/bottom-up approach. Bottom-up
        // building is slower but produces better trees. If the tree building takes too long,
        // we can lower the BottomUpBuildThreshold (default is 128).
        BottomUpBuildThreshold = 0,
      };

      _rigidBody = new RigidBody(triangleMeshShape, new MassFrame(), null)
      {
        Pose = _pose,
        Scale = _scale,
        MotionType = MotionType.Static
      };

      // Add rigid body to physics simulation and model to scene.
      var simulation = _services.GetInstance<Simulation>();
      simulation.RigidBodies.Add(_rigidBody);
    }
예제 #25
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);
        }
예제 #26
0
        private static Submesh CreateGeoClipmapMesh(GraphicsDevice graphicsDevice, int numberOfLevels, 
            int cellsPerLevel, bool useDiamondTessellation)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (cellsPerLevel < 1)
            throw new ArgumentOutOfRangeException("cellsPerLevel", "The number of cells per level must be greater than 0.");

              // Round to even number of cells.
              if (cellsPerLevel % 2 != 0)
            cellsPerLevel++;

              // Allocate a mesh with conservative list capacities.
              int cellsPerLevelUpperBound = (cellsPerLevel + 3) * (cellsPerLevel + 3);
              int verticesPerLevelUpperBound = useDiamondTessellation ? cellsPerLevelUpperBound * 9 : cellsPerLevelUpperBound * 4;
              int indicesPerLevelUpperBound = useDiamondTessellation ? cellsPerLevelUpperBound * 8 * 3 : cellsPerLevelUpperBound * 2 * 3;
              var triangleMesh = new TriangleMesh(verticesPerLevelUpperBound * numberOfLevels, indicesPerLevelUpperBound * numberOfLevels);

              // The levels are created in a separate mesh and then combined into the final mesh.
              var triangleMeshes = new TriangleMesh[numberOfLevels];
              triangleMeshes[0] = triangleMesh;
              for (int i = 1; i < numberOfLevels; i++)
            triangleMeshes[i] = new TriangleMesh(verticesPerLevelUpperBound, indicesPerLevelUpperBound);

              //for (int level = 0; level < numberOfLevels; level++)
              Parallel.For(0, numberOfLevels, level =>
              {
            var levelTriangleMesh = triangleMeshes[level];
            int cellSize = (1 << level);
            float y = level;  // Store LOD in Y coordinate.

            Debug.Assert(cellsPerLevel % 2 == 0);

            int halfWidthInCells = cellsPerLevel / 2;
            int halfWidth = cellSize * (halfWidthInCells);
            int minInclusive = -halfWidth - cellSize;  // We add an extra border on the top and left.
            int maxInclusive = halfWidth - cellSize;   // Normal loop limit without extra border.

            int previousHalfWidth = (level > 0) ? halfWidth / 2 : -1;

            if (useDiamondTessellation)
            {
              #region ----- Diamond tessellation -----

              int index = 0;
              for (int z = minInclusive; z <= maxInclusive; z += cellSize)
              {
            for (int x = minInclusive; x <= maxInclusive; x += cellSize)
            {
              // No triangles in the area which are covered by previous levels.
              // (We compare cell centers with radius of last LOD.)
              if (Math.Max(Math.Abs(x + cellSize / 2), Math.Abs(z + cellSize / 2)) < previousHalfWidth)
                continue;

              // Each cell will be tessellated like this:
              //   A-----B-----C
              //   | \   |   / |
              //   |   \ | /   |
              //   D-----E-----F
              //   |   / | \   |
              //   | /   |   \ |
              //   G-----H-----I

              var indexA = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x, y, z));

              var indexB = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x + 0.5f * cellSize, y, z));

              var indexC = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x + cellSize, y, z));

              var indexD = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x, y, z + 0.5f * cellSize));

              var indexE = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x + 0.5f * cellSize, y, z + 0.5f * cellSize));

              var indexF = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x + cellSize, y, z + 0.5f * cellSize));

              var indexG = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x, y, z + cellSize));

              var indexH = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x + 0.5f * cellSize, y, z + cellSize));

              var indexI = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x + cellSize, y, z + cellSize));

              // Triangles using ADEG:
              if (x != minInclusive)
              {
                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexD);
                levelTriangleMesh.Indices.Add(indexA);

                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexG);
                levelTriangleMesh.Indices.Add(indexD);
              }
              else
              {
                // The outer cells are tessellated differently to stitch to the next level.
                //   A-----B-----C
                //   | \   |   / |
                //   |   \ | /   |
                //   |     E-----F
                //   |   / | \   |
                //   | /   |   \ |
                //   G-----H-----I
                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexG);
                levelTriangleMesh.Indices.Add(indexA);
              }

              // Triangles using ABCE:
              if (z != minInclusive)
              {
                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexB);
                levelTriangleMesh.Indices.Add(indexC);

                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexA);
                levelTriangleMesh.Indices.Add(indexB);
              }
              else
              {
                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexA);
                levelTriangleMesh.Indices.Add(indexC);
              }

              // Triangles using CEFI:
              if (x != maxInclusive)
              {
                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexF);
                levelTriangleMesh.Indices.Add(indexI);

                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexC);
                levelTriangleMesh.Indices.Add(indexF);
              }
              else
              {
                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexC);
                levelTriangleMesh.Indices.Add(indexI);
              }

              // Triangles using EGHI:
              if (z != maxInclusive)
              {
                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexH);
                levelTriangleMesh.Indices.Add(indexG);

                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexI);
                levelTriangleMesh.Indices.Add(indexH);
              }
              else
              {
                levelTriangleMesh.Indices.Add(indexE);
                levelTriangleMesh.Indices.Add(indexI);
                levelTriangleMesh.Indices.Add(indexG);
              }
            }
              }

              Debug.Assert(levelTriangleMesh.Vertices.Count <= verticesPerLevelUpperBound, "Bad estimate for upper bound of vertices.");
              Debug.Assert(levelTriangleMesh.Indices.Count <= indicesPerLevelUpperBound, "Bad estimate for upper bound of indices.");

              levelTriangleMesh.WeldVertices(0.1f);
              #endregion
            }
            else
            {
              #region ----- Simple tessellation -----

              // Add one extra border to hide gaps.
              minInclusive -= cellSize;
              maxInclusive += cellSize;

              int index = 0;
              for (int z = minInclusive; z <= maxInclusive; z += cellSize)
              {
            for (int x = minInclusive; x <= maxInclusive; x += cellSize)
            {
              // No triangles in the area which are covered by previous levels.
              // (We compare cell centers with radius of last LOD.)
              if (Math.Max(Math.Abs(x + cellSize / 2), Math.Abs(z + cellSize / 2)) < previousHalfWidth)
                continue;

              // Each 2x2 cells will be tessellated like this:
              //   A-----B
              //   |   / |
              //   | /   |
              //   C-----D

              int indexA = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x, y, z));

              int indexB = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x + cellSize, y, z));

              int indexC = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x, y, z + cellSize));

              int indexD = index++;
              levelTriangleMesh.Vertices.Add(new Vector3F(x + cellSize, y, z + cellSize));

              levelTriangleMesh.Indices.Add(indexA);
              levelTriangleMesh.Indices.Add(indexB);
              levelTriangleMesh.Indices.Add(indexC);

              levelTriangleMesh.Indices.Add(indexC);
              levelTriangleMesh.Indices.Add(indexB);
              levelTriangleMesh.Indices.Add(indexD);
            }
              }

              Debug.Assert(levelTriangleMesh.Vertices.Count <= verticesPerLevelUpperBound, "Bad estimate for upper bound of vertices.");
              Debug.Assert(levelTriangleMesh.Indices.Count <= indicesPerLevelUpperBound, "Bad estimate for upper bound of indices.");

              levelTriangleMesh.WeldVertices(0.1f);
              #endregion
            }
              });

              // Combine meshes.
              for (int i = 1; i < numberOfLevels; i++)
            triangleMesh.Add(triangleMeshes[i]);

              var vertices = new TerrainVertex[triangleMesh.Vertices.Count];
              {
            int index = 0;
            for (int i = 0; i < vertices.Length; i++)
            {
              Vector3F v = triangleMesh.Vertices[i];
              vertices[index++] = new TerrainVertex(new HalfVector4(v.X, v.Y, v.Z, 1));
            }
              }

              var submesh = CreateSubmesh(graphicsDevice, vertices, triangleMesh.Indices.ToArray());

              //Debug.WriteLine("Number of terrain vertices:" + vertices.Length);
              //Debug.WriteLine("Number of terrain triangles:" + triangleMesh.Indices.Count / 3);

              return submesh;
        }
예제 #27
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);
      alpha = ConstantsF.TwoPi / numberOfSegments;

      Vector3F r0 = new Vector3F(_radius, 0, 0);
      QuaternionF rotation = QuaternionF.CreateRotationZ(alpha);

      TriangleMesh mesh = new TriangleMesh();

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

        mesh.Add(new Triangle
        {
          Vertex0 = Vector3F.Zero,
          Vertex1 = r0,
          Vertex2 = r1,
        }, true);
        r0 = r1;
      }

      return mesh;
    }
예제 #28
0
        public static TriangleMesh CreateIcosphere(int subdivisions, bool hemisphere)
        {
            if (subdivisions < 0)
            throw new ArgumentOutOfRangeException("subdivisions", "The number of subdivisions must not be negative.");

              if (hemisphere && subdivisions < 1)
            throw new ArgumentException("The number of subdivisions must greater than 0 to create a hemisphere.");

              // The icosphere is created by subdividing an icosahedron.
              // (http://en.wikipedia.org/wiki/Icosahedron)

              var mesh = CreateIcosahedron();
              var tempMesh = new TriangleMesh();
              for (int s = 0; s < subdivisions; s++)
              {
            int numberOfTriangles = mesh.NumberOfTriangles;
            for (int i = 0; i < numberOfTriangles; i++)
            {
              // Split triangle into 4 triangles.
              Triangle triangle = mesh.GetTriangle(i);

              Vector3F v01 = (triangle.Vertex0 + triangle.Vertex1) / 2;
              Vector3F v12 = (triangle.Vertex1 + triangle.Vertex2) / 2;
              Vector3F v20 = (triangle.Vertex2 + triangle.Vertex0) / 2;

              tempMesh.Add(new Triangle(triangle.Vertex0, v01, v20));
              tempMesh.Add(new Triangle(v01, v12, v20));
              tempMesh.Add(new Triangle(v01, triangle.Vertex1, v12));
              tempMesh.Add(new Triangle(v20, v12, triangle.Vertex2));
            }

            MathHelper.Swap(ref mesh, ref tempMesh);
            tempMesh.Vertices.Clear();
            tempMesh.Indices.Clear();

            if (hemisphere && s == 0)
            {
              // Delete negative hemisphere after first subdivision.
              numberOfTriangles = mesh.NumberOfTriangles;
              for (int i = 0; i < numberOfTriangles; i++)
              {
            Triangle triangle = mesh.GetTriangle(i);
            if (Numeric.IsLess(triangle.Vertex0.Y, 0) || Numeric.IsLess(triangle.Vertex1.Y, 0) || Numeric.IsLess(triangle.Vertex2.Y, 0))
            {
              // Skip triangles in negative hemisphere.
              continue;
            }

            tempMesh.Add(triangle);
              }

              MathHelper.Swap(ref mesh, ref tempMesh);
              tempMesh.Vertices.Clear();
              tempMesh.Indices.Clear();
            }
              }

              mesh.WeldVertices();

              // The mesh is now a refined icosahedron. Adjust the position of the
              // vertices to approximate a sphere.
              int numberOfVertices = mesh.Vertices.Count;
              for (int i = 0; i < numberOfVertices; i++)
              {
            Vector3F v = mesh.Vertices[i];

            // Unit sphere: ||v|| = 1
            v.Normalize();

            mesh.Vertices[i] = v;
              }

              return mesh;
        }