예제 #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
        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);
        }
예제 #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, TriangleMesh mesh, float angleLimit)
        {
            VertexBuffer vertexBuffer;
              PrimitiveType primitiveType;
              int primitiveCount;
              CreateVertexBuffer(graphicsDevice, mesh, angleLimit, out vertexBuffer, out primitiveType, out primitiveCount);

              if (vertexBuffer == null)
            return null;

              return new Submesh
              {
            PrimitiveType = PrimitiveType.TriangleList,
            PrimitiveCount = primitiveCount,
            VertexBuffer = vertexBuffer,
            VertexCount = vertexBuffer.VertexCount
              };
        }
예제 #5
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);
    }
예제 #6
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);
    }
예제 #7
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));
        }
예제 #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 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;
 }
예제 #9
0
        public static void ToTriangleMesh(this Submesh submesh, TriangleMesh triangleMesh)
        {
            // This method is similar to TriangleMesh.FromModel().

              if (submesh == null)
            throw new ArgumentNullException("submesh");
              if (triangleMesh == null)
            throw new ArgumentNullException("triangleMesh");

              if (submesh.PrimitiveType != PrimitiveType.TriangleList)
            throw new NotSupportedException("All submeshes must be triangle lists. ToTriangleMesh() does not support other primitive types.");

              if (submesh.VertexBuffer == null)
            return;
              if (triangleMesh.Vertices == null)
            triangleMesh.Vertices = new List<Vector3F>(submesh.VertexCount);
              if (triangleMesh.Indices == null)
            triangleMesh.Indices = new List<int>(submesh.PrimitiveCount * 3);

              // Get vertex element info.
              var vertexDeclaration = submesh.VertexBuffer.VertexDeclaration;
              var vertexElements = vertexDeclaration.GetVertexElements();

              // Get the vertex positions.
              var positionElement = vertexElements.First(e => e.VertexElementUsage == VertexElementUsage.Position);
              if (positionElement.VertexElementFormat != VertexElementFormat.Vector3)
            throw new NotSupportedException("For vertex positions only VertexElementFormat.Vector3 is supported.");

              Vector3[] positions = new Vector3[submesh.VertexCount];
              submesh.VertexBuffer.GetData(
            submesh.StartVertex * vertexDeclaration.VertexStride + positionElement.Offset,
            positions,
            0,
            submesh.VertexCount,
            vertexDeclaration.VertexStride);

              if (submesh.IndexBuffer != null)
              {
            // Remember the number of vertices already in the mesh.
            int vertexCount = triangleMesh.Vertices.Count;

            // Add the vertices of the current modelMeshPart.
            foreach (Vector3 p in positions)
              triangleMesh.Vertices.Add((Vector3F)p);

            // Get indices.
            int indexElementSize = (submesh.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits) ? 2 : 4;
            if (indexElementSize == 2)
            {
              ushort[] indices = new ushort[submesh.PrimitiveCount * 3];
              submesh.IndexBuffer.GetData(
            submesh.StartIndex * 2,
            indices,
            0,
            submesh.PrimitiveCount * 3);

              // Add indices to triangle mesh.
              for (int i = 0; i < submesh.PrimitiveCount; i++)
              {
            // The three indices of the next triangle.
            // We add 'vertexCount' because the triangleMesh already contains other mesh parts.
            int i0 = indices[i * 3 + 0] + vertexCount;
            int i1 = indices[i * 3 + 1] + vertexCount;
            int i2 = indices[i * 3 + 2] + vertexCount;

            triangleMesh.Indices.Add(i0);
            triangleMesh.Indices.Add(i2);     // DigitalRune Geometry uses other winding order!
            triangleMesh.Indices.Add(i1);
              }
            }
            else
            {
              Debug.Assert(indexElementSize == 4);
              int[] indices = new int[submesh.PrimitiveCount * 3];
              submesh.IndexBuffer.GetData(
            submesh.StartIndex * 4,
            indices,
            0,
            submesh.PrimitiveCount * 3);

              // Add indices to triangle mesh.
              for (int i = 0; i < submesh.PrimitiveCount; i++)
              {
            // The three indices of the next triangle.
            // We add 'vertexCount' because the triangleMesh already contains other mesh parts.
            int i0 = indices[i * 3 + 0] + vertexCount;
            int i1 = indices[i * 3 + 1] + vertexCount;
            int i2 = indices[i * 3 + 2] + vertexCount;

            triangleMesh.Indices.Add(i0);
            triangleMesh.Indices.Add(i2);     // DigitalRune Geometry uses other winding order!
            triangleMesh.Indices.Add(i1);
              }
            }
              }
              else
              {
            // No index buffer:
            int vertexCount = triangleMesh.Vertices.Count;
            for (int i = 0; i < submesh.VertexCount; i += 3)
            {
              triangleMesh.Vertices.Add((Vector3F)positions[i]);
              triangleMesh.Vertices.Add((Vector3F)positions[i + 1]);
              triangleMesh.Vertices.Add((Vector3F)positions[i + 2]);

              triangleMesh.Indices.Add(i + vertexCount);
              triangleMesh.Indices.Add(i + 2 + vertexCount);     // DigitalRune Geometry uses other winding order!
              triangleMesh.Indices.Add(i + 1 + vertexCount);
            }
              }
        }
예제 #10
0
        /// <overloads>
        /// <summary>
        /// Creates a <see cref="TriangleMesh"/> (DigitalRune.Geometry) for the <see cref="Mesh"/> or 
        /// <see cref="Submesh"/> (DigitalRune.Graphics).
        /// </summary>
        /// </overloads>
        ///
        /// <summary>
        /// Creates a <see cref="TriangleMesh"/> from a <see cref="Mesh"/>. 
        /// </summary>
        /// <param name="mesh">The mesh.</param>
        /// <returns>A triangle mesh containing all triangles of the specified mesh.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="mesh"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// A submeshes uses a primitive type other than triangle lists. Other primitive types are not 
        /// supported.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// The vertex position format of a submesh is not <see cref="Vector3"/>. Only 
        /// <see cref="Vector3"/> is supported
        /// </exception>
        public static TriangleMesh ToTriangleMesh(this Mesh mesh)
        {
            if (mesh == null)
            throw new ArgumentNullException("mesh");

              var triangleMesh = new TriangleMesh();
              foreach (var submesh in mesh.Submeshes)
            ToTriangleMesh(submesh, triangleMesh);

              return triangleMesh;
        }
예제 #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)
    {
      // 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;
    }
예제 #12
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 };
        }
예제 #13
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.
        }
예제 #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)
 {
   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;
 }
예제 #15
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;
        }
예제 #16
0
        private static TriangleMesh CreateIcosahedron()
        {
            var triangleMesh = new TriangleMesh();

              // 12 vertices
              var vertices = triangleMesh.Vertices;
              vertices.Add(new Vector3F(0.0f, 1.0f, 0.0f));
              vertices.Add(new Vector3F(0.894425f, 0.447215f, 0.0f));
              vertices.Add(new Vector3F(0.276385f, 0.447215f, -0.85064f));
              vertices.Add(new Vector3F(-0.7236f, 0.447215f, -0.52572f));
              vertices.Add(new Vector3F(-0.7236f, 0.447215f, 0.52572f));
              vertices.Add(new Vector3F(0.276385f, 0.447215f, 0.85064f));
              vertices.Add(new Vector3F(0.7236f, -0.447215f, -0.52572f));
              vertices.Add(new Vector3F(-0.276385f, -0.447215f, -0.85064f));
              vertices.Add(new Vector3F(-0.894425f, -0.447215f, 0.0f));
              vertices.Add(new Vector3F(-0.276385f, -0.447215f, 0.85064f));
              vertices.Add(new Vector3F(0.7236f, -0.447215f, 0.52572f));
              vertices.Add(new Vector3F(0.0f, -1.0f, 0.0f));

              // 20 faces
              var indices = triangleMesh.Indices;
              indices.Add(0); indices.Add(1); indices.Add(2);
              indices.Add(0); indices.Add(2); indices.Add(3);
              indices.Add(0); indices.Add(3); indices.Add(4);
              indices.Add(0); indices.Add(4); indices.Add(5);
              indices.Add(0); indices.Add(5); indices.Add(1);
              indices.Add(1); indices.Add(10); indices.Add(6);
              indices.Add(1); indices.Add(6); indices.Add(2);
              indices.Add(2); indices.Add(6); indices.Add(7);
              indices.Add(2); indices.Add(7); indices.Add(3);
              indices.Add(3); indices.Add(7); indices.Add(8);
              indices.Add(3); indices.Add(8); indices.Add(4);
              indices.Add(4); indices.Add(8); indices.Add(9);
              indices.Add(4); indices.Add(9); indices.Add(5);
              indices.Add(5); indices.Add(9); indices.Add(10);
              indices.Add(5); indices.Add(10); indices.Add(1);
              indices.Add(11); indices.Add(10); indices.Add(9);
              indices.Add(11); indices.Add(9); indices.Add(8);
              indices.Add(11); indices.Add(8); indices.Add(7);
              indices.Add(11); indices.Add(7); indices.Add(6);
              indices.Add(11); indices.Add(6); indices.Add(10);

              return triangleMesh;
        }
예제 #17
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;
        }
예제 #18
0
 public void EmptyTriangleMesh()
 {
     var m = new TriangleMesh();
       Assert.AreEqual(0, m.GetVolume());
 }
예제 #19
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;
    }
예제 #20
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)); 
    }
예제 #21
0
        public static DcelMesh FromTriangleMesh(TriangleMesh mesh)
        {
            // TODO: To optimize, check tricks of TriangleMeshShape.ComputeNeighbors.

            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }
            if (mesh.Vertices == null || mesh.Indices == null)
            {
                throw new ArgumentException("Input mesh has no vertices or vertex indices.");
            }

            // Create vertices.
            int numberOfVertices = mesh.Vertices.Count;
            var vertices         = new List <DcelVertex>(numberOfVertices);

            foreach (var position in mesh.Vertices)
            {
                vertices.Add(new DcelVertex(position, null));
            }

            // Weld similar vertices.
            for (int i = 0; i < numberOfVertices; i++)
            {
                for (int j = i + 1; j < numberOfVertices; j++)
                {
                    if (Vector3F.AreNumericallyEqual(vertices[i].Position, vertices[j].Position))
                    {
                        vertices[i] = vertices[j];
                    }
                }
            }

            // Create edges and faces for each triangle.
            // We need at least 3 edges for each triangle. We might need more edges if we have to
            // connect unconnected islands of triangles.
            var edges = new List <DcelEdge>(mesh.NumberOfTriangles * 3 * 2);
            var faces = new List <DcelFace>(mesh.NumberOfTriangles);

            for (int i = 0; i < mesh.NumberOfTriangles; i++)
            {
                // Get triangle indices.
                var index0 = mesh.Indices[i * 3 + 0];
                var index1 = mesh.Indices[i * 3 + 1];
                var index2 = mesh.Indices[i * 3 + 2];

                // Get DCEL vertices.
                var vertex0 = vertices[index0];
                var vertex1 = vertices[index1];
                var vertex2 = vertices[index2];

                // Create 3 edges.
                var edge0 = new DcelEdge();
                var edge1 = new DcelEdge();
                var edge2 = new DcelEdge();

                // Create 1 face.
                var face = new DcelFace();

                // Fill out face info.
                face.Boundary = edge0;

                // Fill out vertex info.
                vertex0.Edge = edge0;
                vertex1.Edge = edge1;
                vertex2.Edge = edge2;

                // Fill out edge info.
                // Twin links are created later.
                edge0.Face     = face;
                edge0.Origin   = vertex0;
                edge0.Next     = edge1;
                edge0.Previous = edge2;

                edge1.Face     = face;
                edge1.Origin   = vertex1;
                edge1.Next     = edge2;
                edge1.Previous = edge0;

                edge2.Face     = face;
                edge2.Origin   = vertex2;
                edge2.Next     = edge0;
                edge2.Previous = edge1;

                // Add to lists.
                edges.Add(edge0);
                edges.Add(edge1);
                edges.Add(edge2);
                faces.Add(face);
            }

            // Connect triangles that share an edge.
            for (int i = 0; i < faces.Count; i++)
            {
                // Get face and its 3 edges.
                var faceI  = faces[i];
                var edgeI0 = faceI.Boundary;
                var edgeI1 = edgeI0.Next;
                var edgeI2 = edgeI1.Next;
                Debug.Assert(edgeI2.Next == edgeI0);

                for (int j = i + 1; j < faces.Count; j++)
                {
                    // Get face and its 3 edges.
                    var faceJ  = faces[j];
                    var edgeJ0 = faceJ.Boundary;
                    var edgeJ1 = edgeJ0.Next;
                    var edgeJ2 = edgeJ1.Next;
                    Debug.Assert(edgeJ2.Next == edgeJ0);

                    TryLink(edgeI0, edgeJ0);
                    TryLink(edgeI0, edgeJ1);
                    TryLink(edgeI0, edgeJ2);

                    TryLink(edgeI1, edgeJ0);
                    TryLink(edgeI1, edgeJ1);
                    TryLink(edgeI1, edgeJ2);

                    TryLink(edgeI2, edgeJ0);
                    TryLink(edgeI2, edgeJ1);
                    TryLink(edgeI2, edgeJ2);
                }
            }

            // If the mesh is not closed, we have to add twin edges at the boundaries
            foreach (var edge in edges.ToArray())
            {
                if (edge.Twin == null)
                {
                    var twin = new DcelEdge();
                    twin.Origin = edge.Next.Origin;
                    twin.Twin   = edge;
                    edge.Twin   = twin;
                    edges.Add(twin);
                }
            }

            // Yet, twin.Next/Previous were not set.
            foreach (var edge in edges)
            {
                if (edge.Previous == null)
                {
                    // The previous edge has not been set.
                    // Search the edges around the origin until we find the previous unconnected edge.
                    var origin     = edge.Origin;
                    var originEdge = edge.Twin.Next; // Another edge with the same origin.
                    while (originEdge.Twin.Next != null)
                    {
                        Debug.Assert(originEdge.Origin == origin);
                        originEdge = originEdge.Twin.Next;
                    }

                    var previous = originEdge.Twin;
                    previous.Next = edge;
                    edge.Previous = previous;
                }
            }

            // Check if we have one connected mesh.
            if (vertices.Count > 0)
            {
                const int Tag = 1;
                TagLinkedComponents(vertices[0], Tag);

                // Check if all components were reached.
                if (vertices.Any(v => v.Tag != Tag) ||
                    edges.Any(e => e.Tag != Tag) ||
                    faces.Any(f => f.Tag != Tag))
                {
                    throw new NotSupportedException("The triangle mesh consists of several unconnected components or sub-meshes.");
                }
            }

            var dcelMesh = new DcelMesh {
                Vertex = vertices.FirstOrDefault()
            };

            dcelMesh.ResetTags();

            return(dcelMesh);
        }
예제 #22
0
        // Computes the volume of the submerged mesh part and the center of buoyancy.
        private float GetSubmergedVolume(Vector3F scale, Pose pose, TriangleMesh mesh, out Vector3F center)
        {
            center = Vector3F.Zero;

              // Get surface plane in local space.
              Plane planeLocal = new Plane
              {
            Normal = pose.ToLocalDirection(Surface.Normal),
            DistanceFromOrigin = Surface.DistanceFromOrigin - Vector3F.Dot(Surface.Normal, pose.Position),
              };

              const float tinyDepth = -1e-6f;

              // Vertex heights relative to surface plane. Positive = above water.
              int numberOfVertices = mesh.Vertices.Count;

              // Compute depth of each vertex.
              List<float> depths = ResourcePools<float>.Lists.Obtain();

              // Use try-finally block to properly recycle resources from pool.
              try
              {
            int numberOfSubmergedVertices = 0;
            int sampleVertexIndex = 0;
            for (int i = 0; i < numberOfVertices; i++)
            {
              float depth = Vector3F.Dot(planeLocal.Normal, mesh.Vertices[i] * scale) - planeLocal.DistanceFromOrigin;
              if (depth < tinyDepth)
              {
            numberOfSubmergedVertices++;
            sampleVertexIndex = i;
              }

              depths.Add(depth);
            }

            // Abort if no vertex is in water.
            if (numberOfSubmergedVertices == 0)
              return 0;

            // Get the reference point. We project a submerged vertex onto the surface plane.
            Vector3F point = mesh.Vertices[sampleVertexIndex] - depths[sampleVertexIndex] * planeLocal.Normal;

            float volume = 0;

            // Add contribution of each triangle.
            int numberOfTriangles = mesh.NumberOfTriangles;
            for (int i = 0; i < numberOfTriangles; i++)
            {
              // Triangle vertex indices.
              int i0 = mesh.Indices[i * 3 + 0];
              int i1 = mesh.Indices[i * 3 + 1];
              int i2 = mesh.Indices[i * 3 + 2];

              // Vertices and depths.
              Vector3F v0 = mesh.Vertices[i0] * scale;
              float d0 = depths[i0];
              Vector3F v1 = mesh.Vertices[i1] * scale;
              float d1 = depths[i1];
              Vector3F v2 = mesh.Vertices[i2] * scale;
              float d2 = depths[i2];

              if (d0 * d1 < 0)
              {
            // v0 - v1 crosses the surface.
            volume += ClipTriangle(point, v0, v1, v2, d0, d1, d2, ref center);
              }
              else if (d0 * d2 < 0)
              {
            // v0 - v2 crosses the surface.
            volume += ClipTriangle(point, v2, v0, v1, d2, d0, d1, ref center);
              }
              else if (d1 * d2 < 0)
              {
            // v1 - v2 crosses the surface.
            volume += ClipTriangle(point, v1, v2, v0, d1, d2, d0, ref center);
              }
              else if (d0 < 0 || d1 < 0 || d2 < 0)
              {
            // Fully submerged triangle.
            volume += GetSignedTetrahedronVolume(point, v0, v1, v2, ref center);
              }
            }

            // If the volume is near zero or negative (numerical errors), we abort.
            const float tinyVolume = 1e-6f;
            if (volume <= tinyVolume)
            {
              center = Vector3F.Zero;
              return 0;
            }

            // Normalize the center (was weighted by volume).
            center = center / volume;

            // Transform center to world space.
            center = pose.ToWorldPosition(center);

            return volume;
              }
              finally
              {
            // Recycle temporary collections.
            ResourcePools<float>.Lists.Recycle(depths);
              }
        }
예제 #23
0
 public TriangulationSample(Microsoft.Xna.Framework.Game game)
   : base(game)
 {
   GraphicsScreen.ClearBackground = true;
   _mesh = new TriangleMesh();
 }
예제 #24
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;
    }
예제 #25
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;
    }
예제 #26
0
 public static TriangleMesh ToTriangleMesh(this Submesh submesh)
 {
     var triangleMesh = new TriangleMesh();
       ToTriangleMesh(submesh, triangleMesh);
       return triangleMesh;
 }
예제 #27
0
        /// <summary>
        /// Converts this mesh to a <see cref="TriangleMesh"/>.
        /// </summary>
        /// <returns>A triangle mesh that represents the same mesh.</returns>
        /// <remarks>
        /// This mesh must consist only of faces that are convex polygons (triangles, quads, etc.).
        /// Concave faces will not be triangulated correctly.
        /// </remarks>
        /// <exception cref="GeometryException">The DCEL mesh is invalid.</exception>
        public TriangleMesh ToTriangleMesh()
        {
            TriangleMesh triMesh = new TriangleMesh();

              UpdateCache();

              int numberOfVertices = Vertices.Count;
              int numberOfFaces = Faces.Count;

              for (int i = 0; i < numberOfVertices; i++)
              {
            DcelVertex vertex = Vertices[i];

            // Store the vertex indices in the InternalTags of the vertices.
            vertex.InternalTag = i;

            // Add all vertices to the triangle mesh.
            triMesh.Vertices.Add(vertex.Position);
              }

              for (int i = 0; i < numberOfFaces; i++)
              {
            var face = Faces[i];
            var startEdge = face.Boundary;
            var nextEdge = startEdge.Next;

            // Tag edges to see if they have been visited.
            startEdge.InternalTag = 1;
            nextEdge.InternalTag = 1;

            // Triangulate polygon.
            var v0 = startEdge.Origin;
            var v1 = nextEdge.Origin;
            nextEdge = nextEdge.Next;
            while (nextEdge != startEdge)
            {
              if (nextEdge == null || nextEdge.InternalTag == 1)
            throw new GeometryException("DCEL mesh is invalid.");

              nextEdge.InternalTag = 1;
              var v2 = nextEdge.Origin;

              // The tags of the vertices store their index number.
              triMesh.Indices.Add(v0.InternalTag);
              triMesh.Indices.Add(v1.InternalTag);
              triMesh.Indices.Add(v2.InternalTag);

              v1 = v2;
              nextEdge = nextEdge.Next;
            }
              }

              ResetInternalTags();

              return triMesh;
        }
예제 #28
0
        internal static void CreateVertexBuffer(GraphicsDevice graphicsDevice, TriangleMesh mesh, float angleLimit, out VertexBuffer vertexBuffer, out PrimitiveType primitiveType, out int primitiveCount)
        {
            // Note: We do not use shared vertices and an IndexBuffer because a vertex can be used by
              // several triangles with different normals.

              if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (mesh == null)
            throw new ArgumentNullException("mesh");

              var numberOfTriangles = mesh.NumberOfTriangles;

              if (numberOfTriangles == 0)
              {
            primitiveType = PrimitiveType.TriangleList;
            primitiveCount = 0;
            vertexBuffer = null;
            return;
              }

              primitiveType = PrimitiveType.TriangleList;
              primitiveCount = numberOfTriangles;
              int vertexCount = numberOfTriangles * 3;

              // Create vertex data for a triangle list.
              var vertices = new VertexPositionNormal[vertexCount];

              // Create vertex normals.
              var normals = mesh.ComputeNormals(false, angleLimit);

              for (int i = 0; i < numberOfTriangles; i++)
              {
            var i0 = mesh.Indices[i * 3 + 0];
            var i1 = mesh.Indices[i * 3 + 1];
            var i2 = mesh.Indices[i * 3 + 2];

            var v0 = mesh.Vertices[i0];
            var v1 = mesh.Vertices[i1];
            var v2 = mesh.Vertices[i2];

            Vector3F n0, n1, n2;
            if (angleLimit < 0)
            {
              // If the angle limit is negative, ComputeNormals() returns one normal per vertex.
              n0 = normals[i0];
              n1 = normals[i1];
              n2 = normals[i2];
            }
            else
            {
              // If the angle limits is >= 0, ComputeNormals() returns 3 normals per triangle.
              n0 = normals[i * 3 + 0];
              n1 = normals[i * 3 + 1];
              n2 = normals[i * 3 + 2];
            }

            // Add new vertex data.
            // DigitalRune.Geometry uses counter-clockwise front faces. XNA uses
            // clockwise front faces (CullMode.CullCounterClockwiseFace) per default.
            // Therefore we change the vertex orientation of the triangles.
            vertices[i * 3 + 0] = new VertexPositionNormal((Vector3)v0, (Vector3)n0);
            vertices[i * 3 + 1] = new VertexPositionNormal((Vector3)v2, (Vector3)n2);  // v2 instead of v1!
            vertices[i * 3 + 2] = new VertexPositionNormal((Vector3)v1, (Vector3)n1);
              }

              // Create a vertex buffer.
              vertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionNormal), vertexCount, BufferUsage.None);
              vertexBuffer.SetData(vertices);
        }
예제 #29
0
        public static DcelMesh FromTriangleMesh(TriangleMesh mesh)
        {
            // TODO: To optimize, check tricks of TriangleMeshShape.ComputeNeighbors.

              if (mesh == null)
            throw new ArgumentNullException("mesh");
              if (mesh.Vertices == null || mesh.Indices == null)
            throw new ArgumentException("Input mesh has no vertices or vertex indices.");

              // Create vertices.
              int numberOfVertices = mesh.Vertices.Count;
              var vertices = new List<DcelVertex>(numberOfVertices);
              foreach (var position in mesh.Vertices)
            vertices.Add(new DcelVertex(position, null));

              // Weld similar vertices.
              for (int i = 0; i < numberOfVertices; i++)
            for (int j = i + 1; j < numberOfVertices; j++)
              if (Vector3F.AreNumericallyEqual(vertices[i].Position, vertices[j].Position))
            vertices[i] = vertices[j];

              // Create edges and faces for each triangle.
              // We need at least 3 edges for each triangle. We might need more edges if we have to
              // connect unconnected islands of triangles.
              var edges = new List<DcelEdge>(mesh.NumberOfTriangles * 3 * 2);
              var faces = new List<DcelFace>(mesh.NumberOfTriangles);
              for (int i = 0; i < mesh.NumberOfTriangles; i++)
              {
            // Get triangle indices.
            var index0 = mesh.Indices[i * 3 + 0];
            var index1 = mesh.Indices[i * 3 + 1];
            var index2 = mesh.Indices[i * 3 + 2];

            // Get DCEL vertices.
            var vertex0 = vertices[index0];
            var vertex1 = vertices[index1];
            var vertex2 = vertices[index2];

            // Create 3 edges.
            var edge0 = new DcelEdge();
            var edge1 = new DcelEdge();
            var edge2 = new DcelEdge();

            // Create 1 face.
            var face = new DcelFace();

            // Fill out face info.
            face.Boundary = edge0;

            // Fill out vertex info.
            vertex0.Edge = edge0;
            vertex1.Edge = edge1;
            vertex2.Edge = edge2;

            // Fill out edge info.
            // Twin links are created later.
            edge0.Face = face;
            edge0.Origin = vertex0;
            edge0.Next = edge1;
            edge0.Previous = edge2;

            edge1.Face = face;
            edge1.Origin = vertex1;
            edge1.Next = edge2;
            edge1.Previous = edge0;

            edge2.Face = face;
            edge2.Origin = vertex2;
            edge2.Next = edge0;
            edge2.Previous = edge1;

            // Add to lists.
            edges.Add(edge0);
            edges.Add(edge1);
            edges.Add(edge2);
            faces.Add(face);
              }

              // Connect triangles that share an edge.
              for (int i = 0; i < faces.Count; i++)
              {
            // Get face and its 3 edges.
            var faceI = faces[i];
            var edgeI0 = faceI.Boundary;
            var edgeI1 = edgeI0.Next;
            var edgeI2 = edgeI1.Next;
            Debug.Assert(edgeI2.Next == edgeI0);

            for (int j = i + 1; j < faces.Count; j++)
            {
              // Get face and its 3 edges.
              var faceJ = faces[j];
              var edgeJ0 = faceJ.Boundary;
              var edgeJ1 = edgeJ0.Next;
              var edgeJ2 = edgeJ1.Next;
              Debug.Assert(edgeJ2.Next == edgeJ0);

              TryLink(edgeI0, edgeJ0);
              TryLink(edgeI0, edgeJ1);
              TryLink(edgeI0, edgeJ2);

              TryLink(edgeI1, edgeJ0);
              TryLink(edgeI1, edgeJ1);
              TryLink(edgeI1, edgeJ2);

              TryLink(edgeI2, edgeJ0);
              TryLink(edgeI2, edgeJ1);
              TryLink(edgeI2, edgeJ2);
            }
              }

              // If the mesh is not closed, we have to add twin edges at the boundaries
              foreach (var edge in edges.ToArray())
              {
            if (edge.Twin == null)
            {
              var twin = new DcelEdge();
              twin.Origin = edge.Next.Origin;
              twin.Twin = edge;
              edge.Twin = twin;
              edges.Add(twin);
            }
              }

              // Yet, twin.Next/Previous were not set.
              foreach (var edge in edges)
              {
            if (edge.Previous == null)
            {
              // The previous edge has not been set.
              // Search the edges around the origin until we find the previous unconnected edge.
              var origin = edge.Origin;
              var originEdge = edge.Twin.Next;  // Another edge with the same origin.
              while (originEdge.Twin.Next != null)
              {
            Debug.Assert(originEdge.Origin == origin);
            originEdge = originEdge.Twin.Next;
              }

              var previous = originEdge.Twin;
              previous.Next = edge;
              edge.Previous = previous;
            }
              }

              // Check if we have one connected mesh.
              if (vertices.Count > 0)
              {
            const int Tag = 1;
            TagLinkedComponents(vertices[0], Tag);

            // Check if all components were reached.
            if (vertices.Any(v => v.Tag != Tag)
            || edges.Any(e => e.Tag != Tag)
            || faces.Any(f => f.Tag != Tag))
            {
              throw new NotSupportedException("The triangle mesh consists of several unconnected components or sub-meshes.");
            }
              }

              var dcelMesh = new DcelMesh { Vertex = vertices.FirstOrDefault() };
              dcelMesh.ResetTags();

              return dcelMesh;
        }
예제 #30
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);
        }
예제 #31
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();

              int numberOfCellsInX = _numberOfSamplesX - 1;
              int numberOfCellsInZ = _numberOfSamplesZ - 1;

              // Add vertex positions.
              for (int z = 0; z < _numberOfSamplesZ; z++)
              {
            for (int x = 0; x < _numberOfSamplesX; x++)
            {
              mesh.Vertices.Add(
            new Vector3F(
              _originX + (float)x / numberOfCellsInX * WidthX,
              _samples[z * NumberOfSamplesX + x],
              _originZ + (float)z / numberOfCellsInZ * WidthZ));
            }
              }

              // Add triangle indices.
              for (int z = 0; z < numberOfCellsInZ; z++)
              {
            for (int x = 0; x < numberOfCellsInX; x++)
            {
              // Check for holes.
              // Shared vertices of both triangles.
              var height = _samples[(z + 1) * _numberOfSamplesX + x] * _samples[z * _numberOfSamplesX + (x + 1)];
              if (!Numeric.IsFinite(height))
            continue;

              // First triangle.
              if (Numeric.IsFinite(_samples[z * _numberOfSamplesX + x]))
              {
            mesh.Indices.Add(z * _numberOfSamplesX + x);
            mesh.Indices.Add((z + 1) * _numberOfSamplesX + x);
            mesh.Indices.Add(z * _numberOfSamplesX + x + 1);
              }

              // Second triangle.
              if (Numeric.IsFinite(_samples[(z + 1) * _numberOfSamplesX + (x + 1)]))
              {
            mesh.Indices.Add(z * _numberOfSamplesX + x + 1);
            mesh.Indices.Add((z + 1) * _numberOfSamplesX + x);
            mesh.Indices.Add((z + 1) * _numberOfSamplesX + x + 1);
              }
            }
              }
              return mesh;
        }
예제 #32
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;
    }
예제 #33
0
        public static TriangleMesh FromModel(Model model)
        {
            // Similar code can be found on http://www.enchantedage.com/node/30 (by Jon Watte).
            // But this code was developed independently.

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

            var triangleMesh = new TriangleMesh();

            foreach (var modelMesh in model.Meshes)
            {
                // Get bone transformation.
                Matrix transform = GetAbsoluteTransform(modelMesh.ParentBone);

                foreach (var modelMeshPart in modelMesh.MeshParts)
                {
                    // Get vertex element info.
                    var vertexDeclaration = modelMeshPart.VertexBuffer.VertexDeclaration;
                    var vertexElements    = vertexDeclaration.GetVertexElements();

                    // Get the vertex positions.
                    var positionElement = vertexElements.First(e => e.VertexElementUsage == VertexElementUsage.Position);
                    if (positionElement.VertexElementFormat != VertexElementFormat.Vector3)
                    {
                        throw new NotSupportedException("For vertex positions only VertexElementFormat.Vector3 is supported.");
                    }

                    var positions = new Vector3[modelMeshPart.NumVertices];
                    modelMeshPart.VertexBuffer.GetData(
                        modelMeshPart.VertexOffset * vertexDeclaration.VertexStride + positionElement.Offset,
                        positions,
                        0,
                        modelMeshPart.NumVertices,
                        vertexDeclaration.VertexStride);

                    // Apply bone transformation.
                    for (int i = 0; i < positions.Length; i++)
                    {
                        positions[i] = Vector3.Transform(positions[i], transform);
                    }

                    // Remember the number of vertices already in the mesh.
                    int vertexCount = triangleMesh.Vertices.Count;

                    // Add the vertices of the current modelMeshPart.
                    foreach (Vector3 p in positions)
                    {
                        triangleMesh.Vertices.Add((Vector3F)p);
                    }

                    // Get indices.
                    var indexElementSize = (modelMeshPart.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits) ? 2 : 4;
                    if (indexElementSize == 2)
                    {
                        ushort[] indices = new ushort[modelMeshPart.PrimitiveCount * 3];
                        modelMeshPart.IndexBuffer.GetData(
                            modelMeshPart.StartIndex * 2,
                            indices,
                            0,
                            modelMeshPart.PrimitiveCount * 3);

                        // Add indices to triangle mesh.
                        for (int i = 0; i < modelMeshPart.PrimitiveCount; i++)
                        {
                            // The three indices of the next triangle.
                            // We add 'vertexCount' because the triangleMesh already contains other mesh parts.
                            int i0 = indices[i * 3 + 0] + vertexCount;
                            int i1 = indices[i * 3 + 1] + vertexCount;
                            int i2 = indices[i * 3 + 2] + vertexCount;

                            triangleMesh.Indices.Add(i0);
                            triangleMesh.Indices.Add(i2); // DigitalRune Geometry uses other winding order!
                            triangleMesh.Indices.Add(i1);
                        }
                    }
                    else
                    {
                        Debug.Assert(indexElementSize == 4);

                        int[] indices = new int[modelMeshPart.PrimitiveCount * 3];
                        modelMeshPart.IndexBuffer.GetData(
                            modelMeshPart.StartIndex * 4,
                            indices,
                            0,
                            modelMeshPart.PrimitiveCount * 3);

                        // Add indices to triangle mesh.
                        for (int i = 0; i < modelMeshPart.PrimitiveCount; i++)
                        {
                            // The three indices of the next triangle.
                            // We add 'vertexCount' because the triangleMesh already contains other mesh parts.
                            int i0 = indices[i * 3 + 0] + vertexCount;
                            int i1 = indices[i * 3 + 1] + vertexCount;
                            int i2 = indices[i * 3 + 2] + vertexCount;

                            triangleMesh.Indices.Add(i0);
                            triangleMesh.Indices.Add(i2); // DigitalRune Geometry uses other winding order!
                            triangleMesh.Indices.Add(i1);
                        }
                    }
                }
            }

            return(triangleMesh);
        }