Example #1
0
    /// <summary>
    /// Initializes a new instance of the <see cref="ProceduralTerrainCreator"/> class.
    /// </summary>
    /// <param name="seed">The seed for the random number generator (e.g. 7777).</param>
    /// <param name="permutationTableSize">
    /// The size of the permutation table (e.g. 256). Must be a power of two.
    /// </param>
    /// <param name="mu">
    /// The constant µ that defines the exponential distribution. Use a value of 1 to get standard
    /// Perlin noise. Use a value greater than 1 (e.g. 1.02) to get Perlin noise with exponentially
    /// distributed gradients. For a <paramref name="permutationTableSize"/> of 256, µ should be in
    /// the range [1, 1.16].
    /// </param>
    public ProceduralTerrainCreator(int seed, int permutationTableSize, float mu)
    {
      if (!MathHelper.IsPowerOf2(permutationTableSize))
        throw new ArgumentException("The permutation table size must be a power of 2 (e.g. 256).");

      _maskB = permutationTableSize - 1;

      var random = new Random(seed);

      // Create table of random gradient vectors (normalized).
      _gradients = new Vector2F[permutationTableSize];
      for (int i = 0; i < _gradients.Length; i++)
      {
        var direction = random.NextVector2F(-1, 1);
        if (!direction.TryNormalize())
          direction = new Vector2F(1, 0);

        _gradients[i] = direction;
      }

      // Create table with a permutation of the values 0 to permutationTableSize.
      _permutations = new int[permutationTableSize];
      for (int i = 0; i < _permutations.Length; i++)
        _permutations[i] = i;
      for (int i = _permutations.Length - 1; i > 0; i--)
        MathHelper.Swap(ref _permutations[i], ref _permutations[random.NextInteger(0, i)]);

      // Create table with gradient magnitudes.
      _magnitudes = new float[permutationTableSize];
      float s = 1; // First magnitude.
      for (int i = 0; i < _magnitudes.Length; i++)
      {
        _magnitudes[i] = s;
        s /= mu;
      }
    }
Example #2
0
        private float GetConcavity(int vertexLimit, bool sampleVertices, bool sampleCenters)
        {
            // Initially we assume that the new vertices are simply the union of the islands' vertices.
              Vertices = IslandA.Vertices.Union(IslandB.Vertices).ToArray();

              try
              {
            // Create hull mesh.

            // Incremental hull building.
            // Note: Commented out because this building the hull this way is less stable.
            //bool rebuild = true;
            //try
            //{
            //  if (IslandA.ConvexHullBuilder != null)
            //  {
            //    if (IslandB.ConvexHullBuilder == null || IslandA.Vertices.Length > IslandB.Vertices.Length)
            //    {
            //      ConvexHullBuilder = IslandA.ConvexHullBuilder.Clone();
            //      ConvexHullBuilder.Grow(IslandB.Vertices, vertexLimit, 0);
            //    }
            //    else
            //    {
            //      ConvexHullBuilder = IslandB.ConvexHullBuilder.Clone();
            //      ConvexHullBuilder.Grow(IslandA.Vertices, vertexLimit, 0);
            //    }
            //    rebuild = false;
            //  }
            //  else if (IslandB.ConvexHullBuilder != null)
            //  {
            //    ConvexHullBuilder = IslandB.ConvexHullBuilder.Clone();
            //    ConvexHullBuilder.Grow(IslandA.Vertices, vertexLimit, 0);
            //    rebuild = false;
            //  }
            //}
            //catch (GeometryException)
            //{
            //  rebuild = true;
            //}

            //if (rebuild)
            {
              try
              {
            ConvexHullBuilder = new ConvexHullBuilder();
            ConvexHullBuilder.Grow(Vertices, vertexLimit, 0);
              }
              catch (GeometryException)
              {
            // Hull building failed. Try again with a randomized order.
            var random = new Random(1234567);
            // Fisher-Yates shuffle:
            for (int i = Vertices.Length - 1; i >= 1; i--)
            {
              var v = Vertices[i];
              var j = random.NextInteger(0, i);
              Vertices[i] = Vertices[j];
              Vertices[j] = v;
            }
              }
            }

            var hullMesh = ConvexHullBuilder.Mesh.ToTriangleMesh();

            // Now, we have a reduced set of vertices.
            Vertices = hullMesh.Vertices.ToArray();

            // For larger meshes we create an AabbTree as acceleration structure.
            AabbTree<int> partition = null;
            if (hullMesh.NumberOfTriangles > 12)
            {
              partition = new AabbTree<int>
              {
            GetAabbForItem = i => hullMesh.GetTriangle(i).Aabb,
            BottomUpBuildThreshold = 0,
              };
              for (int i = 0; i < hullMesh.NumberOfTriangles; i++)
            partition.Add(i);

              partition.Update(true);
            }

            Aabb aabb = Aabb;
            float aabbExtent = aabb.Extent.Length;

            // Note: For a speed-up we could skip some ray tests in the next loop and only sample
            // a few vertices if there would be a lot of tests.

            // The next loop performs ray casts against the hull mesh to determine the maximum
            // concavity. We ensure that we make only one ray cast per vertex even if a vertex
            // is shared by many triangles.
            float maxConcavity = 0;
            foreach (var triangle in IslandA.Triangles.Union(IslandB.Triangles))
            {
              if (sampleVertices)
              {
            for (int i = 0; i < triangle.Vertices.Length; i++)
            {
              // Each vertex can be shared by several triangles of the current islands.
              // Therefore, we check the edges that contain this vertex. If an edge neighbor
              // is in the same island, we make sure that the vertex concavity is computed only once
              // in the triangle with the smallest Id.
              var neighbor0 = triangle.Neighbors[(i + 1) % 3];
              var neighbor1 = triangle.Neighbors[(i + 2) % 3];

              if (neighbor0 != null
                  && (neighbor0.Island == IslandA || neighbor0.Island == IslandB)
                  && triangle.Id > neighbor0.Id)
              {
                // No need to test: The neighbor is in the same islands and this triangle Id is larger.
                continue;
              }

              if (neighbor1 != null
                  && (neighbor1.Island == IslandA || neighbor1.Island == IslandB)
                  && triangle.Id > neighbor1.Id)
              {
                // No need to test: The neighbor is in the same islands and this triangle Id is larger.
                continue;
              }

              var position = triangle.Vertices[i];
              var normal = triangle.VertexNormals[i];

              // Degenerate triangles are ignored.
              if (normal.IsNumericallyZero)
                continue;

              // Shoot a ray from outside the hull mesh to the vertex.
              float hitDistance;
              Vector3F rayOrigin = position + normal * aabbExtent;
              float rayLength = (position - rayOrigin).Length;
              var ray = new Ray(rayOrigin, -normal, rayLength);
              if (partition != null)
              {
                // Use AABB tree for better performance.
                foreach (var triangleIndex in partition.GetOverlaps(ray))
                {
                  var candidateTriangle = hullMesh.GetTriangle(triangleIndex);
                  var hit = GeometryHelper.GetContact(ray, candidateTriangle, false, out hitDistance);
                  if (hit)
                  {
                    // The concavity is the distance from the hull to the vertex.
                    float concavity = rayLength - hitDistance;
                    maxConcavity = Math.Max(maxConcavity, concavity);
                    break;
                  }
                }
              }
              else
              {
                // No AABB tree.
                var hit = GeometryHelper.GetContact(hullMesh, ray, out hitDistance);
                if (hit)
                {
                  float concavity = rayLength - hitDistance;
                  maxConcavity = Math.Max(maxConcavity, concavity);
                }
              }
            }
              }

              if (sampleCenters)
              {
            // Test: Also shoot from the triangle centers.
            var center = (triangle.Vertices[0] + triangle.Vertices[1] + triangle.Vertices[2]) / 3;
            var normal = triangle.Normal;

            // Degenerate triangles are ignored.
            if (normal.IsNumericallyZero)
              continue;

            // Shoot a ray from outside the hull mesh to the vertex.
            float hitDistance;
            Vector3F rayOrigin = center + normal * aabbExtent;
            float rayLength = (center - rayOrigin).Length;
            var ray = new Ray(rayOrigin, -normal, rayLength);
            if (partition != null)
            {
              // Use AABBTree for better performance.
              foreach (var triangleIndex in partition.GetOverlaps(ray))
              {
                var candidateTriangle = hullMesh.GetTriangle(triangleIndex);
                var hit = GeometryHelper.GetContact(ray, candidateTriangle, false, out hitDistance);
                if (hit)
                {
                  // The concavity is the distance from the hull to the vertex.
                  float concavity = rayLength - hitDistance;
                  maxConcavity = Math.Max(maxConcavity, concavity);
                  break;
                }
              }
            }
            else
            {
              // No AABBTree.
              var hit = GeometryHelper.GetContact(hullMesh, ray, out hitDistance);
              if (hit)
              {
                float concavity = rayLength - hitDistance;
                maxConcavity = Math.Max(maxConcavity, concavity);
              }
            }
              }
            }

            return maxConcavity;
              }
              catch (GeometryException)
              {
            // Ouch, the convex hull generation failed. This can happen for degenerate inputs
            // and numerical problems in the convex hull builder.
            ConvexHullBuilder = null;
            return 0;
              }
        }
Example #3
0
    public CollisionFilterSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;
      GraphicsScreen.ClearBackground = true;
      GraphicsScreen.BackgroundColor = Color.Gray;
      GraphicsScreen.DrawReticle = true;
      SetCamera(new Vector3F(0, 0, 10), 0, 0);

      // ----- Initialize collision detection system.
      // We use one collision domain that manages all objects.
      var domain = new CollisionDomain();

      // Let's set a filter which disables collision between object in the same collision group.
      // We can use a broad phase or a narrow phase filter:

      // Option A) Broad phase filter
      // The collision detection broad phase computes bounding box overlaps. 
      // A broad phase filter is best used if the filtering rules are simple and do not change 
      // during the runtime of your application.
      //domain.BroadPhase.Filter = new DelegatePairFilter<CollisionObject>(
      //  pair => pair.First.CollisionGroup != pair.Second.CollisionGroup);

      // Option B) Narrow phase filter
      // The collision detection narrow phase computes contacts between objects where the broad
      // phase has detected a bounding box overlap. Use a narrow phase filter if the filtering rules 
      // are complex or can change during the runtime of your application.
      var filter = new CollisionFilter();
      // Disable collision between objects in the same groups.
      filter.Set(0, 0, false);
      filter.Set(1, 1, false);
      filter.Set(2, 2, false);
      filter.Set(3, 3, false);
      domain.CollisionDetection.CollisionFilter = filter;

      // Create a random list of points.
      var points = new List<Vector3F>();
      for (int i = 0; i < 100; i++)
        points.Add(RandomHelper.Random.NextVector3F(-1.5f, 1.5f));

      // Add lots of spheres to the collision domain. Assign spheres to different collision groups.
      var random = new Random();
      var sphereShape = new SphereShape(0.7f);
      for (int i = 0; i < 20; i++)
      {
        var randomPosition = new Vector3F(random.NextFloat(-6, 6), random.NextFloat(-3, 3), 0);
        var geometricObject = new GeometricObject(sphereShape, new Pose(randomPosition));
        var collisionObject = new CollisionObject(geometricObject)
        {
          // A collision group is simply an integer. We can assign collision objects to collision
          // groups to control the collision filtering.
          CollisionGroup = random.NextInteger(0, 3),
        };
        domain.CollisionObjects.Add(collisionObject);
      }

      // Compute collisions. (The objects do not move in this sample. Therefore, we only have to 
      // call Update once.)
      domain.Update(0);

      // Draw objects. The color depends on the collision group.
      var debugRenderer = GraphicsScreen.DebugRenderer;
      debugRenderer.Clear();
      foreach (var collisionObject in domain.CollisionObjects)
      {
        Color color;
        switch (collisionObject.CollisionGroup)
        {
          case 0: color = Color.LightBlue; break;
          case 1: color = Color.Yellow; break;
          case 2: color = Color.Orange; break;
          default: color = Color.LightGreen; break;
        }

        debugRenderer.DrawObject(collisionObject.GeometricObject, color, false, false);
      }

      debugRenderer.DrawContacts(domain.ContactSets, 0.1f, Color.Red, true);
    }
Example #4
0
        public void RandomizedMassSceneUpdate2()
        {
            const int NumberOfSceneNodes = 10;
              const int NumberOfSteps = 10000;
              const float WorldSize = 1000;

              var random = new Random(123457);
              var scene = new Scene();
              scene.EnableMultithreading = false;

              var nodes = new TestSceneNode[NumberOfSceneNodes];

              // Create random nodes.
              for (int i = 0; i < NumberOfSceneNodes; i++)
              {
            var node = new TestSceneNode();
            nodes[i] = node;

            var position = random.NextVector3F(0, WorldSize);
            var orientation = random.NextQuaternionF();
            node.PoseLocal = new Pose(position, orientation);

            float p = random.NextFloat(0, 100);
            if (p < 0.1f)
              node.Shape = Shape.Empty;
            else if (p < 0.2f)
              node.Shape = Shape.Infinite;
            else if (p < 0.6f)
              node.Shape = new BoxShape(random.NextVector3F(0, WorldSize));
            else
              node.Shape = new SphereShape(random.NextFloat(0, WorldSize));
              }

              var projection = new PerspectiveProjection();
              projection.SetFieldOfView(0.8f, 1, WorldSize / 10000, WorldSize);
              var camera = new Camera(projection);
              var cameraNode = new CameraNode(camera);

              for (int updateIndex = 0; updateIndex < NumberOfSteps; updateIndex++)
              {
            int actionsPerFrame = random.NextInteger(0, 100);
            for (int i = 0; i < actionsPerFrame; i++)
            {
              var node = nodes[random.Next(0, NumberOfSceneNodes)];

              const int numberOfActions = 100;
              int action = random.Next(0, numberOfActions);

              //scene.Validate();

              if (action == 0)
              {
            // Add
            if (node.Parent == null)
            {
              scene.Children.Add(node);
              //scene.Validate();
            }
              }
              else if (action == 1)
              {
            // Remove
            if (node.Parent != null)
            {
              node.Parent.Children.Remove(node);
              //scene.Validate();
            }
              }
              else if (action == 2)
              {
            // Move
            var pose = node.PoseWorld;
            pose.Position = random.NextVector3F(0, WorldSize);
            node.PoseWorld = pose;
            //scene.Validate();
              }
              else if (action == 3)
              {
            // Very small Move
            var pose = node.PoseWorld;
            const float maxDistance = WorldSize / 10000;
            pose.Position += random.NextVector3F(-maxDistance, maxDistance);
            node.PoseWorld = pose;
            //scene.Validate();
              }
              else if (action == 4)
              {
            // Small Move
            var pose = node.PoseWorld;
            const float maxDistance = WorldSize / 100;
            pose.Position += random.NextVector3F(-maxDistance, maxDistance);
            node.PoseWorld = pose;
            //scene.Validate();
              }
              else if (action == 5)
              {
            // Scale
            node.ScaleLocal = random.NextVector3F(0.0f, 10f);
            //scene.Validate();
              }
              else if (action == 6)
              {
            // Rotate
            node.PoseWorld = new Pose(node.PoseWorld.Position, random.NextQuaternionF());
            //scene.Validate();
              }
              else if (action == 7)
              {
            // Query
            var query = scene.Query<CameraFrustumQuery>(cameraNode, null);
            //Debug.WriteLine("Camera queried nodes: " + query.SceneNodes.Count);
            //scene.Validate();
              }
              else if (action == 8)
              {
            // Move camera.
            cameraNode.PoseWorld = new Pose(random.NextVector3F(0, WorldSize), random.NextQuaternionF());
            //scene.Validate();
              }
              else if (action == 9)
              {
            // Change shape.
            int type = random.NextInteger(0, 5);
            if (type == 0)
              node.Shape = new BoxShape(random.NextVector3F(0, WorldSize));
            else if (type == 1)
              node.Shape = new SphereShape(random.NextFloat(0, WorldSize));
            else if (type == 2)
              node.Shape = new BoxShape(new Vector3F(Single.MaxValue));
            else if (type == 3)
              node.Shape = new BoxShape(new Vector3F(0));
            else if (type == 4)
              node.Shape = Shape.Empty;
            //scene.Validate();
              }
              else if (action == 10)
              {
            // Add to random parent.
            if (node.Parent == null)
            {
              var randomParent = nodes[random.NextInteger(0, NumberOfSceneNodes - 1)];

              // Avoid loops:
              bool isLoop = node.GetSubtree().Contains(randomParent);
              if (!isLoop)
              {
                if (randomParent.Children == null)
                  randomParent.Children = new SceneNodeCollection();

                randomParent.Children.Add(node);
              }
            }
              }
              else if (action == 11)
              {
            if (node.Parent != null && node.Parent != scene)
              node.Parent.Children.Remove(node);
              }
              else if (action == 13)
              {
            if (random.NextInteger(0, 100) < 5)
            scene.Children.Clear();
              }
              else if (action == 14)
              {
            if (random.NextInteger(0, 100) < 5)
              scene.Children = new SceneNodeCollection();
              }
            }

            //Debug.WriteLine("Number of nodes in scene: " + scene.GetDescendants().Count());

            //scene.Validate();
            scene.Update(TimeSpan.FromSeconds(0.016666666f));
            //scene.Validate();
              }
        }