Ejemplo n.º 1
0
 /// <summary>
 /// Gets the bounding sphere of a geometric object.
 /// </summary>
 /// <param name="geometricObject">The geometric object.</param>
 /// <param name="radius">The radius of the bounding sphere.</param>
 /// <param name="center">The center of the bounding sphere in world space.</param>
 internal static void GetBoundingSphere(IGeometricObject geometricObject, out float radius, out Vector3F center)
 {
     // Get sphere from AABB.
       Aabb aabb = geometricObject.Aabb;
       center = aabb.Center;
       radius = aabb.Extent.Length * 0.5f;
 }
Ejemplo n.º 2
0
        public void LinearConvexHull()
        {
            var start = new Vector3F(1, 10, 20);
              var end = new Vector3F(10, 10, 20);
              var points = new[] { start, end };
              var mesh = GeometryHelper.CreateConvexHull(points);
              Assert.AreEqual(2, mesh.Vertices.Count);
              Assert.IsTrue(mesh.Vertices.Any(v => v.Position == start));
              Assert.IsTrue(mesh.Vertices.Any(v => v.Position == end));
              Assert.AreEqual(null, mesh.Vertex.Edge.Face);

              points = new[] { start, end, start, end, start, new Vector3F(1.00001f, 10.00001f, 20.00001f),  };
              mesh = GeometryHelper.CreateConvexHull(points);
              Assert.AreEqual(2, mesh.Vertices.Count);
              Assert.IsTrue(mesh.Vertices.Any(v => v.Position == start));
              Assert.IsTrue(mesh.Vertices.Any(v => v.Position == end));
              Assert.AreEqual(null, mesh.Vertex.Edge.Face);

              points = new[] { new Vector3F(2, 10, 20), new Vector3F(9.00001f, 10, 20), start, end, start };
              mesh = GeometryHelper.CreateConvexHull(points);
              Assert.AreEqual(2, mesh.Vertices.Count);
              Assert.IsTrue(mesh.Vertices.Any(v => v.Position == start));
              Assert.IsTrue(mesh.Vertices.Any(v => v.Position == end));
              Assert.AreEqual(null, mesh.Vertex.Edge.Face);
        }
Ejemplo n.º 3
0
        public override bool Prepare(Vector3I[] marks) {
            a = marks[0];
            b = marks[1];
            c = marks[2];

            if (a == b || b == c || c == a) {
                if (a != c) b = c;
                isLine = true;
            }

            Bounds = new BoundingBox(
                Math.Min(Math.Min(a.X, b.X), c.X),
                Math.Min(Math.Min(a.Y, b.Y), c.Y),
                Math.Min(Math.Min(a.Z, b.Z), c.Z),
                Math.Max(Math.Max(a.X, b.X), c.X),
                Math.Max(Math.Max(a.Y, b.Y), c.Y),
                Math.Max(Math.Max(a.Z, b.Z), c.Z)
                );

            Coords = Bounds.MinVertex;

            if (!base.Prepare(marks)) return false;

            normal = (b - a).Cross(c - a);
            normalF = normal.Normalize();
            BlocksTotalEstimate = GetBlockTotalEstimate();

            s1 = normal.Cross(a - b).Normalize();
            s2 = normal.Cross(b - c).Normalize();
            s3 = normal.Cross(c - a).Normalize();

            return true;
        }
        public void GetClosestPointCandidates(Vector3F scale, Pose pose, ISpatialPartition<int> otherPartition, Vector3F otherScale, Pose otherPose, Func<int, int, float> callback)
        {
            if (otherPartition == null)
            throw new ArgumentNullException("otherPartition");

              if (callback == null)
            throw new ArgumentNullException("callback");

              // Make sure we are up-to-date.
              var otherBasePartition = otherPartition as BasePartition<int>;
              if (otherBasePartition != null)
            otherBasePartition.UpdateInternal();
              else
            otherPartition.Update(false);

              Update(false);

              if (_numberOfItems == 0)
            return;

              if (otherPartition is ISupportClosestPointQueries<int>)
              {
            // ----- CompressedAabbTree vs. ISupportClosestPointQueries<int>
            GetClosestPointCandidatesImpl(scale, pose, (ISupportClosestPointQueries<int>)otherPartition, otherScale, otherPose, callback);
              }
              else
              {
            // ----- CompressedAabbTree vs. *
            GetClosestPointCandidatesImpl(otherPartition, callback);
              }
        }
Ejemplo n.º 5
0
    public SphereStackSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      // Add basic force effects.
      Simulation.ForceEffects.Add(new Gravity());
      Simulation.ForceEffects.Add(new Damping());

      // Add a ground plane.
      RigidBody groundPlane = new RigidBody(new PlaneShape(Vector3F.UnitY, 0))
      {
        Name = "GroundPlane",           // Names are not required but helpful for debugging.
        MotionType = MotionType.Static,
      };
      Simulation.RigidBodies.Add(groundPlane);

      // ----- Add a stack of spheres.
      const int numberOfSpheres = 10;
      const float sphereRadius = 0.4f;
      Shape sphereShape = new SphereShape(sphereRadius);

      // Optional: Use a small overlap between spheres to improve the stability.
      float overlap = Simulation.Settings.Constraints.AllowedPenetration * 0.5f;
      Vector3F position = new Vector3F(0, sphereRadius - overlap, 0);
      for (int i = 0; i < numberOfSpheres; i++)
      {
        RigidBody sphere = new RigidBody(sphereShape)
        {
          Name = "Sphere" + i,
          Pose = new Pose(position),
        };
        Simulation.RigidBodies.Add(sphere);
        position.Y += 2 * sphereRadius - overlap;
      }
    }
Ejemplo n.º 6
0
        public void PoseTest()
        {
            CameraInstance cameraInstance = new CameraInstance(new Camera(new PerspectiveProjection()));
              Assert.IsNotNull(cameraInstance.PoseWorld);
              Assert.AreEqual(Vector3F.Zero, cameraInstance.PoseWorld.Position);
              Assert.AreEqual(Matrix33F.Identity, cameraInstance.PoseWorld.Orientation);

              // Set new Pose
              Vector3F position = new Vector3F(1, 2, 3);
              QuaternionF orientation = QuaternionF.CreateRotation(new Vector3F(3, 4, 5), 0.123f);
              cameraInstance.PoseWorld = new Pose(position, orientation);
              Assert.AreEqual(position, cameraInstance.PoseWorld.Position);
              Assert.AreEqual(orientation.ToRotationMatrix33(), cameraInstance.PoseWorld.Orientation);
              Assert.IsTrue(Matrix44F.AreNumericallyEqual(cameraInstance.PoseWorld.ToMatrix44F(), cameraInstance.ViewInverse));
              Assert.IsTrue(Matrix44F.AreNumericallyEqual(cameraInstance.PoseWorld.Inverse.ToMatrix44F(), cameraInstance.View));

              // Set Position and Orientation
              position = new Vector3F(5, 6, 7);
              orientation = QuaternionF.CreateRotation(new Vector3F(1, -1, 6), -0.123f);
              cameraInstance.PoseWorld = new Pose(position, orientation);
              Assert.AreEqual(position, cameraInstance.PoseWorld.Position);
              Assert.AreEqual(orientation.ToRotationMatrix33(), cameraInstance.PoseWorld.Orientation);
              Assert.IsTrue(Matrix44F.AreNumericallyEqual(cameraInstance.PoseWorld.Inverse.ToMatrix44F(), cameraInstance.View));
              Assert.IsTrue(Matrix44F.AreNumericallyEqual(cameraInstance.PoseWorld.ToMatrix44F(), cameraInstance.ViewInverse));
        }
Ejemplo n.º 7
0
 //--------------------------------------------------------------
 public KinectWrapper(Game game)
     : base(game)
 {
     Offset = new Vector3F(0, 0, 0);
       Scale = new Vector3F(1, 1, 1);
       InitializeSkeletonPoses();
 }
Ejemplo n.º 8
0
 //--------------------------------------------------------------
 /// <summary>
 /// Initializes a new instance of the <see cref="PlanarReflectionNode" /> class.
 /// </summary>
 /// <param name="renderToTexture">The render texture target.</param>
 /// <exception cref="ArgumentNullException">
 /// <paramref name="renderToTexture"/> is <see langword="null"/>.
 /// </exception>
 public PlanarReflectionNode(RenderToTexture renderToTexture)
     : base(renderToTexture)
 {
     CameraNode = new CameraNode(new Camera(new PerspectiveProjection()));
       FieldOfViewScale = 1;
       _normalLocal = new Vector3F(0, 0, 1);
 }
Ejemplo n.º 9
0
        public override void Update(GameTime gameTime)
        {
            float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

              // ----- Move target if <NumPad4-9> are pressed.
              Vector3F translation = new Vector3F();
              if (InputService.IsDown(Keys.NumPad4))
            translation.X -= 1;
              if (InputService.IsDown(Keys.NumPad6))
            translation.X += 1;
              if (InputService.IsDown(Keys.NumPad8))
            translation.Y += 1;
              if (InputService.IsDown(Keys.NumPad5))
            translation.Y -= 1;
              if (InputService.IsDown(Keys.NumPad9))
            translation.Z += 1;
              if (InputService.IsDown(Keys.NumPad7))
            translation.Z -= 1;

              translation = translation * deltaTime;
              _targetPosition += translation;

              // Convert target world space position to model space. - The IK solvers work in model space.
              Vector3F localTargetPosition = _pose.ToLocalPosition(_targetPosition);

              // Reset the affected bones. This is optional. It removes unwanted twist from the bones.
              _skeletonPose.ResetBoneTransforms(_ikSolver.RootBoneIndex, _ikSolver.TipBoneIndex);

              // Let IK solver update the bones.
              _ikSolver.Target = localTargetPosition;
              _ikSolver.Solve(deltaTime);

              base.Update(gameTime);
        }
Ejemplo n.º 10
0
        public static void ComputeBoundingSphere(IEnumerable<Vector3F> points, out float radius, out Vector3F center)
        {
            if (points == null)
            throw new ArgumentNullException("points");

              List<Vector3F> pointList = DigitalRune.ResourcePools<Vector3F>.Lists.Obtain();

              // Copy points into new list because the order of the points need to be changed.
              // (Try to avoid garbage when enumerating 'points'.)
              if (points is Vector3F[])
              {
            foreach (Vector3F p in (Vector3F[])points)
              pointList.Add(p);
              }
              else if (points is List<Vector3F>)
              {
            foreach (Vector3F p in (List<Vector3F>)points)
              pointList.Add(p);
              }
              else
              {
            foreach (Vector3F p in points)
              pointList.Add(p);
              }

              if (pointList.Count == 0)
            throw new ArgumentException("The list of 'points' is empty.");

              ComputeWelzlSphere(pointList, 0, pointList.Count - 1, 0, out radius, out center);

              DigitalRune.ResourcePools<Vector3F>.Lists.Recycle(pointList);
        }
Ejemplo n.º 11
0
    private void InitializeSimulation(Simulation simulation, Vector3F offset)
    {
      // Add default force effects.
      simulation.ForceEffects.Add(new Gravity());
      simulation.ForceEffects.Add(new Damping());

      // Add a ground plane.
      RigidBody groundPlane = new RigidBody(new PlaneShape(Vector3F.UnitY, 0))
      {
        Name = "GroundPlane",
        MotionType = MotionType.Static,
      };
      simulation.RigidBodies.Add(groundPlane);

      // Add a stack of boxes.
      const float boxSize = 0.8f;
      float overlap = simulation.Settings.Constraints.AllowedPenetration * 0.5f;
      float yPosition = boxSize / 2 - overlap;
      BoxShape boxShape = new BoxShape(boxSize, boxSize, boxSize);
      for (int i = 0; i < 15; i++)
      {
        RigidBody stackBox = new RigidBody(boxShape)
        {
          Name = "StackBox" + i,
          Pose = new Pose(new Vector3F(0, yPosition, 0) + offset),
        };
        simulation.RigidBodies.Add(stackBox);
        yPosition += boxSize - overlap;
      }
    }
Ejemplo n.º 12
0
        public void NegativeUniformScaling()
        {
            Vector3F point0 = new Vector3F(1, 0.5f, 0.5f);
              Vector3F point1 = new Vector3F(0.5f, 1, 0.5f);
              Vector3F point2 = new Vector3F(0.5f, 0.5f, 1);
              Plane plane = new Plane(point0, point1, point2);

              Vector3F pointAbove = plane.Normal * plane.DistanceFromOrigin * 2;
              Vector3F pointBelow = plane.Normal * plane.DistanceFromOrigin * 0.5f;

              Vector3F scale = new Vector3F(-3.5f);
              point0 *= scale;
              point1 *= scale;
              point2 *= scale;
              pointAbove *= scale;
              pointBelow *= scale;
              plane.Scale(ref scale);

              Assert.IsTrue(plane.Normal.IsNumericallyNormalized);

              Vector3F dummy;
              Assert.IsTrue(GeometryHelper.GetClosestPoint(plane, point0, out dummy));
              Assert.IsTrue(GeometryHelper.GetClosestPoint(plane, point1, out dummy));
              Assert.IsTrue(GeometryHelper.GetClosestPoint(plane, point2, out dummy));
              Assert.IsTrue(Vector3F.Dot(plane.Normal, pointAbove) > plane.DistanceFromOrigin);
              Assert.IsTrue(Vector3F.Dot(plane.Normal, pointBelow) < plane.DistanceFromOrigin);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Determines whether the specified point is contained in the mesh. (This method assumes that
        /// the mesh is a convex polyhedron.)
        /// </summary>
        /// <param name="point">The point.</param>
        /// <param name="epsilon">
        /// The epsilon tolerance. A point counts as "contained" if the distance to the mesh surface is
        /// less than this value. Use a small positive value, e.g. 0.001f, for numerical robustness.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the specified point is contained; otherwise, 
        /// <see langword="false"/>. (The result is undefined if the mesh is not a convex polyhedron.)
        /// </returns>
        public bool Contains(Vector3F point, float epsilon)
        {
            foreach (var face in Faces)
              {
            // Get normal vector.
            var normal = face.Normal;

            // Skip degenerate faces.
            float normalLength = normal.Length;
            if (Numeric.IsZero(normalLength))
              continue;

            // Normalize.
            normal = normal / normalLength;

            // Create a plane for the face.
            Plane plane = new Plane(normal, face.Boundary.Origin.Position);

            // Get distance from plane.
            float d = Vector3F.Dot(point, plane.Normal) - plane.DistanceFromOrigin;

            // Check distance with epsilon tolerance.
            if (d > epsilon * (1 + normalLength + (point - face.Boundary.Origin.Position).Length))
              return false;
              }
              return true;
        }
Ejemplo n.º 14
0
 public static bool GetClosestPoint(Line line, Vector3F point, out Vector3F closestPointOnLine)
 {
     float parameter;
       GetLineParameter(new LineSegment(line.PointOnLine, line.PointOnLine + line.Direction), point, out parameter);
       closestPointOnLine = line.PointOnLine + parameter * line.Direction;
       return Vector3F.AreNumericallyEqual(point, closestPointOnLine);
 }
Ejemplo n.º 15
0
        /// <summary>
        /// Diagonalizes the inertia matrix.
        /// </summary>
        /// <param name="inertia">The inertia matrix.</param>
        /// <param name="inertiaDiagonal">The inertia of the principal axes.</param>
        /// <param name="rotation">
        /// The rotation that rotates from principal axis space to parent/world space.
        /// </param>
        /// <remarks>
        /// All valid inertia matrices can be transformed into a coordinate space where all elements
        /// non-diagonal matrix elements are 0. The axis of this special space are the principal axes.
        /// </remarks>
        internal static void DiagonalizeInertia(Matrix33F inertia, out Vector3F inertiaDiagonal, out Matrix33F rotation)
        {
            // Alternatively we could use Jacobi transformation (iterative method, see Bullet/btMatrix3x3.diagonalize()
              // and Numerical Recipes book) or we could find the eigenvalues using the characteristic
              // polynomial which is a cubic polynomial and then solve for the eigenvectors (see Numeric
              // Recipes and "Mathematics for 3D Game Programming and Computer Graphics" chapter ray-tracing
              // for cubic equations and computation of bounding boxes.

              // Perform eigenvalue decomposition.
              var eigenValueDecomposition = new EigenvalueDecompositionF(inertia.ToMatrixF());
              inertiaDiagonal = eigenValueDecomposition.RealEigenvalues.ToVector3F();
              rotation = eigenValueDecomposition.V.ToMatrix33F();

              if (!rotation.IsRotation)
              {
            // V is orthogonal but not necessarily a rotation. If it is no rotation
            // we have to swap two columns.
            MathHelper.Swap(ref inertiaDiagonal.Y, ref inertiaDiagonal.Z);

            Vector3F dummy = rotation.GetColumn(1);
            rotation.SetColumn(1, rotation.GetColumn(2));
            rotation.SetColumn(2, dummy);

            Debug.Assert(rotation.IsRotation);
              }
        }
Ejemplo n.º 16
0
        public override bool Prepare(Vector3I[] marks)
        {
            a = marks[0];
            c = marks[1];
            b = marks[2];

            d = new Vector3I(a.X + c.X - b.X, a.Y + c.Y - b.Y, a.Z + c.Z - b.Z);

            Bounds = new BoundingBox(
                Math.Min(Math.Min(a.X, b.X), Math.Min(c.X, d.X)),
                Math.Min(Math.Min(a.Y, b.Y), Math.Min(c.Y, d.Y)),
                Math.Min(Math.Min(a.Z, b.Z), Math.Min(c.Z, d.Z)),
                Math.Max(Math.Max(a.X, b.X), Math.Max(c.X, d.X)),
                Math.Max(Math.Max(a.Y, b.Y), Math.Max(c.Y, d.Y)),
                Math.Max(Math.Max(a.Z, b.Z), Math.Max(c.Z, d.Z))
            );

            Coords = Bounds.MinVertex;

            if (!base.Prepare(marks))
                return false;

            normal = (b - a).Cross(c - a);
            normalF = normal.Normalize();
            BlocksTotalEstimate = GetBlockTotalEstimate();

            s1 = normal.Cross(a - b).Normalize();
            s2 = normal.Cross(b - c).Normalize();
            s3 = normal.Cross(c - d).Normalize();
            s4 = normal.Cross(d - a).Normalize();

            return true;
        }
Ejemplo n.º 17
0
        private float[] GenData(Vector3F origin, int width, int height, int depth)
        {
            var data = new float[width*height*depth];
            for (var x = 0; x < width; x++)
            {
                for (var y = 0; y < height; y++)
                {
                    for (var z = 0; z < depth; z++)
                    {
                        var i = x + width*(y + height*z);

                        if (y == height - 1)
                        {
                            data[i] = -1;
                            continue;
                        }

                        if (y == 0)
                        {
                            data[i] = 1;
                            continue;
                        }

                        data[i] = (float) _b.Get(_seed, origin.x + x, origin.y + y, origin.z + z, OpenSimplex.Get);
                    }
                }
            }
            return data;
        }
Ejemplo n.º 18
0
        public void Normalize()
        {
            Vector3F v, n1, n2;
            float magnitude;

            v = new Vector3F(3.0f, 4.0f, 0.0f);
            n1 = v.Normalize();
            n2 = v.Normalize(out magnitude);
            Assert.AreEqual(1.0f, n1.Magnitude, 1e-7);
            Assert.AreEqual(1.0f, n2.Magnitude, 1e-7);
            Assert.AreEqual(5.0f, magnitude, 1e-7);

            v = new Vector3F(3.0f, 0.0f, 4.0f);
            n1 = v.Normalize();
            n2 = v.Normalize(out magnitude);
            Assert.AreEqual(1.0f, n1.Magnitude, 1e-7);
            Assert.AreEqual(1.0f, n2.Magnitude, 1e-7);
            Assert.AreEqual(5.0f, magnitude, 1e-7);

            v = new Vector3F(0.0f, 3.0f, 4.0f);
            n1 = v.Normalize();
            n2 = v.Normalize(out magnitude);
            Assert.AreEqual(1.0f, n1.Magnitude, 1e-7);
            Assert.AreEqual(1.0f, n2.Magnitude, 1e-7);
            Assert.AreEqual(5.0f, magnitude, 1e-7);
        }
Ejemplo n.º 19
0
        //--------------------------------------------------------------
        /// <summary>
        /// Initializes a new instance of the <see cref="GodRayFilter"/> class.
        /// </summary>
        /// <param name="graphicsService">The graphics service.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="graphicsService"/> is <see langword="null"/>.
        /// </exception>
        public GodRayFilter(IGraphicsService graphicsService)
            : base(graphicsService)
        {
            Effect effect = GraphicsService.Content.Load<Effect>("DigitalRune/PostProcessing/GodRayFilter");
              _viewportSizeParameter = effect.Parameters["ViewportSize"];
              _parameters0Parameter = effect.Parameters["Parameters0"];
              _parameters1Parameter = effect.Parameters["Parameters1"];
              _intensityParameter = effect.Parameters["Intensity"];
              _numberOfSamplesParameter = effect.Parameters["NumberOfSamples"];
              _sourceTextureParameter = effect.Parameters["SourceTexture"];
              _gBuffer0Parameter = effect.Parameters["GBuffer0"];
              _rayTextureParameter = effect.Parameters["RayTexture"];
              _createMaskPass = effect.CurrentTechnique.Passes["CreateMask"];
              _blurPass = effect.CurrentTechnique.Passes["Blur"];
              _combinePass = effect.CurrentTechnique.Passes["Combine"];

              _downsampleFilter = graphicsService.GetDownsampleFilter();

              Scale = 1;
              LightDirection = new Vector3F(0, -1, 0);
              LightRadius = 0.2f;
              Intensity = new Vector3F(1, 1, 1);
              DownsampleFactor = 4;
              NumberOfSamples = 8;
              NumberOfPasses = 2;
              Softness = 1;
        }
Ejemplo n.º 20
0
        public void SceneWithStaticMeshLODandVisObj()
        {
            TestManager.Helpers.OpenSceneFromFile(TestManager.Helpers.TestDataDir + @"\VisibilityTests\VisibilityObjLinking.scene");
              TestManager.Helpers.ProcessEvents();

              // Start the simulation
              EditorManager.EditorMode = EditorManager.Mode.EM_ANIMATING; // update view
              TestManager.Helpers.ProcessEvents();

              // Let the simulation run for some seconds
              DateTime timeBefore = DateTime.Now;
              EditorManager.ActiveView.SetCameraRotation(new Vector3F(90, 0, 0));

              while (true)
              {
            TimeSpan passedTime = DateTime.Now - timeBefore;
            if (passedTime.TotalSeconds > 5)
              break;
            Vector3F pos = new Vector3F(50.0f,(float)passedTime.TotalSeconds * -150.0f-150.0f,  120.0f);
            EditorManager.ActiveView.SetCameraPosition(pos);
            TestManager.Helpers.ProcessEvents();
              }

              // Stop simulation, set back
              EditorManager.EditorMode = EditorManager.Mode.EM_NONE;

              TextToWrite = null;
              TestManager.Helpers.CloseActiveProject();
        }
Ejemplo n.º 21
0
    /// <summary>
    /// Initializes the 1-dimensional constraint.
    /// </summary>
    public void Prepare(RigidBody bodyA, RigidBody bodyB, Vector3F jLinA, Vector3F jAngA, Vector3F jLinB, Vector3F jAngB)
    {
      JLinA = jLinA;
      JAngA = jAngA;
      JLinB = jLinB;
      JAngB = jAngB;

      WJTLinA.X = bodyA.MassInverse * jLinA.X;
      WJTLinA.Y = bodyA.MassInverse * jLinA.Y;
      WJTLinA.Z = bodyA.MassInverse * jLinA.Z;
      Matrix33F matrix = bodyA.InertiaInverseWorld;
      WJTAngA.X = matrix.M00 * jAngA.X + matrix.M01 * jAngA.Y + matrix.M02 * jAngA.Z;
      WJTAngA.Y = matrix.M10 * jAngA.X + matrix.M11 * jAngA.Y + matrix.M12 * jAngA.Z;
      WJTAngA.Z = matrix.M20 * jAngA.X + matrix.M21 * jAngA.Y + matrix.M22 * jAngA.Z;
      WJTLinB.X = bodyB.MassInverse * jLinB.X;
      WJTLinB.Y = bodyB.MassInverse * jLinB.Y;
      WJTLinB.Z = bodyB.MassInverse * jLinB.Z;
      matrix = bodyB.InertiaInverseWorld;
      WJTAngB.X = matrix.M00 * jAngB.X + matrix.M01 * jAngB.Y + matrix.M02 * jAngB.Z;
      WJTAngB.Y = matrix.M10 * jAngB.X + matrix.M11 * jAngB.Y + matrix.M12 * jAngB.Z;
      WJTAngB.Z = matrix.M20 * jAngB.X + matrix.M21 * jAngB.Y + matrix.M22 * jAngB.Z;

      float JWJT = jLinA.X * WJTLinA.X + jLinA.Y * WJTLinA.Y + jLinA.Z * WJTLinA.Z
                   + jAngA.X * WJTAngA.X + jAngA.Y * WJTAngA.Y + jAngA.Z * WJTAngA.Z
                   + jLinB.X * WJTLinB.X + jLinB.Y * WJTLinB.Y + jLinB.Z * WJTLinB.Z
                   + jAngB.X * WJTAngB.X + jAngB.Y * WJTAngB.Y + jAngB.Z * WJTAngB.Z;

      JWJT += Softness;
      JWJTInverse = 1 / JWJT;
    }
Ejemplo n.º 22
0
 public void Construct01()
 {
     Vector3F v = new Vector3F(new Vector2F(1.0f, 2.0f), 3.0f);
     Assert.AreEqual(1.0f, v.X);
     Assert.AreEqual(2.0f, v.Y);
     Assert.AreEqual(3.0f, v.Z);
 }
Ejemplo n.º 23
0
 public void Addition()
 {
     Vector3F a = new Vector3F(1.0f, 2.0f, 3.0f);
       Vector3F b = new Vector3F(2.0f, 3.0f, 4.0f);
       Vector3F c = Vector3F.Add(a, b);
       Assert.AreEqual(new Vector3F(3.0f, 5.0f, 7.0f), c);
 }
Ejemplo n.º 24
0
 public void AdditionOperator()
 {
     Vector3F a = new Vector3F(1.0f, 2.0f, 3.0f);
       Vector3F b = new Vector3F(2.0f, 3.0f, 4.0f);
       Vector3F c = a + b;
       Assert.AreEqual(new Vector3F(3.0f, 5.0f, 7.0f), c);
 }
Ejemplo n.º 25
0
        public static Matrix4x4F MatrixLookAtLH(Vector3F eye, Vector3F at, Vector3F up)
        {
            Vector3F right, vec;
            
            vec = at - eye;
            vec.NormalizeInPlace();
            right = Vector3F.Cross(up, vec);
            up = Vector3F.Cross(vec, right);
            right.NormalizeInPlace();
            up.NormalizeInPlace();
            return new Matrix4x4F(
                right.X,
                up.X,
                vec.X,
                0.0f,

                right.Y,
                up.Y,
                vec.Y,
                0.0f,

                right.Z,
                up.Z,
                vec.Z,
                0.0f,

                -Vector3F.Dot(right, eye),
                -Vector3F.Dot(up, eye),
                -Vector3F.Dot(vec, eye),
                1.0f
            );
        }
Ejemplo n.º 26
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SkyboxNode" /> class.
 /// </summary>
 /// <param name="texture">The cube map texture (using premultiplied alpha).</param>
 public SkyboxNode(TextureCube texture)
 {
     Texture = texture;
       Color = new Vector3F(1, 1, 1);
       Alpha = 1.0f;
       Encoding = ColorEncoding.SRgb;
 }
Ejemplo n.º 27
0
        public void AdditivePath()
        {
            var animation = new Path3FAnimation();
              animation.Path = new Path3F
              {
            new PathKey3F { Parameter = 2.0f, Point = new Vector3F(2.0f, 22.0f, 10.0f), Interpolation = SplineInterpolation.Linear },
            new PathKey3F { Parameter = 3.0f, Point = new Vector3F(3.0f, 33.0f, 20.0f), Interpolation = SplineInterpolation.Linear },
            new PathKey3F { Parameter = 4.0f, Point = new Vector3F(4.0f, 44.0f, 30.0f), Interpolation = SplineInterpolation.Linear },
              };
              animation.Path.PreLoop = CurveLoopType.Linear;
              animation.Path.PostLoop = CurveLoopType.Cycle;
              animation.EndParameter = float.PositiveInfinity;
              animation.IsAdditive = true;

              Vector3F defaultSource = new Vector3F(1.0f, 2.0f, 3.0f);
              Vector3F defaultTarget = new Vector3F(10.0f, 20.0f, 30.0f);

              // Pre-Loop
              Assert.AreEqual(defaultSource + new Vector3F(0.0f, 0.0f, -10.0f), animation.GetValue(TimeSpan.FromSeconds(0.0), defaultSource, defaultTarget));
              Assert.AreEqual(defaultSource + new Vector3F(1.0f, 11.0f, 0.0f), animation.GetValue(TimeSpan.FromSeconds(1.0), defaultSource, defaultTarget));

              Assert.AreEqual(defaultSource + new Vector3F(2.0f, 22.0f, 10.0f), animation.GetValue(TimeSpan.FromSeconds(2.0), defaultSource, defaultTarget));
              Assert.AreEqual(defaultSource + new Vector3F(3.0f, 33.0f, 20.0f), animation.GetValue(TimeSpan.FromSeconds(3.0), defaultSource, defaultTarget));
              Assert.AreEqual(defaultSource + new Vector3F(4.0f, 44.0f, 30.0f), animation.GetValue(TimeSpan.FromSeconds(4.0), defaultSource, defaultTarget));

              // Post-Loop
              Assert.AreEqual(defaultSource + new Vector3F(3.0f, 33.0f, 20.0f), animation.GetValue(TimeSpan.FromSeconds(5.0), defaultSource, defaultTarget));
        }
Ejemplo n.º 28
0
    public override void Update(GameTime gameTime)
    {
      // If <Space> is pressed, we fire a shot.
      if (InputService.IsPressed(Keys.Space, true))
      {
        // Get a random angle and a random distance from the target.
        float angle = _angleDistribution.Next(_random);
        float distance = _distanceDistribution.Next(_random);

        // Create a vector v with the length of distance.
        Vector3F v = new Vector3F(0, distance, 0);

        // Rotate v.
        QuaternionF rotation = QuaternionF.CreateRotationZ(MathHelper.ToRadians(angle));
        v = rotation.Rotate(v);

        // Draw a small cross for the hit.
        var debugRenderer = GraphicsScreen.DebugRenderer2D;
        debugRenderer.DrawLine(
          _center + v + new Vector3F(-10, -10, 0),
          _center + v + new Vector3F(10, 10, 0),
          Color.Black,
          true);
        debugRenderer.DrawLine(
          _center + v + new Vector3F(10, -10, 0),
          _center + v + new Vector3F(-10, 10, 0),
          Color.Black, true);
      }

      base.Update(gameTime);
    }
Ejemplo n.º 29
0
 public void IdentityTest()
 {
     var traits = Vector3FTraits.Instance;
       var value = new Vector3F(-1, -2, 3);
       Assert.AreEqual(value, traits.Add(value, traits.Identity()));
       Assert.AreEqual(value, traits.Add(traits.Identity(), value));
 }
Ejemplo n.º 30
0
        public RedSquareObject(Vector3F position)
        {
            _position = position;
            _color = new Vector4(1.0f, 0.0f, 0.0f, 1.0f);

            var graphicsService = ServiceLocator.Current.GetInstance<IGraphicsService>();
            var screen = ((GameScreen)graphicsService.Screens["Default"]);
            var contentManager = ServiceLocator.Current.GetInstance<ContentManager>();

            _model = contentManager.Load<ModelNode>("redSquare").Clone();

            screen.Scene.Children.Add(_model);

            _model.PoseWorld = new Pose(_position);

            foreach (var meshNode in _model.GetSubtree().OfType<MeshNode>())
            {
                Mesh mesh = meshNode.Mesh;
                foreach (var material in mesh.Materials)
                {
                    var effectBinding = material["Default"];
                    effectBinding.Set("DiffuseColor", _color);
                    ((BasicEffectBinding)effectBinding).LightingEnabled = false;
                }
            }

            InUse = true;
        }
Ejemplo n.º 31
0
        private static Matrix4F smethod_0(Vector3F xaxis, Vector3F zaxis)
        {
            Vector3F yaxis = Vector3F.CrossProduct(zaxis, xaxis);

            return(Transformation4F.GetCoordSystem(xaxis, yaxis, zaxis));
        }
Ejemplo n.º 32
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Segment"/> class with serialized data.
 /// </summary>
 /// <param name="info">The object that holds the serialized object data.</param>
 /// <param name="context">The contextual information about the source or destination.</param>
 private Segment(SerializationInfo info, StreamingContext context)
 {
     _p0 = (Vector3F)info.GetValue("P0", typeof(Vector3F));
     _p1 = (Vector3F)info.GetValue("P1", typeof(Vector3F));
 }
Ejemplo n.º 33
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Segment"/> class using an existing <see cref="Segment"/> instance.
 /// </summary>
 /// <param name="l">A <see cref="Segment"/> instance.</param>
 public Segment(Segment l)
 {
     _p0 = l.P0;
     _p1 = l.P1;
 }
Ejemplo n.º 34
0
        public override void ComputeCollision(ContactSet contactSet, CollisionQueryType type)
        {
            // Object A should be the height field.
            CollisionObject heightFieldCollisionObject = contactSet.ObjectA;
            CollisionObject otherCollisionObject       = contactSet.ObjectB;

            // Swap objects if necessary.
            bool swapped = !(heightFieldCollisionObject.GeometricObject.Shape is HeightField);

            if (swapped)
            {
                MathHelper.Swap(ref heightFieldCollisionObject, ref otherCollisionObject);
            }

            IGeometricObject heightFieldGeometricObject = heightFieldCollisionObject.GeometricObject;
            IGeometricObject otherGeometricObject       = otherCollisionObject.GeometricObject;
            HeightField      heightField = heightFieldGeometricObject.Shape as HeightField;
            Shape            otherShape  = otherGeometricObject.Shape;

            // Check if collision object shapes are correct.
            if (heightField == null)
            {
                throw new ArgumentException("The contact set must contain a height field.", "contactSet");
            }

            if (heightField.UseFastCollisionApproximation && type != CollisionQueryType.ClosestPoints)
            {
                // If other object is convex, use the new fast collision detection algorithm.
                ConvexShape convex = otherShape as ConvexShape;
                if (convex != null)
                {
                    ComputeCollisionFast(
                        contactSet,
                        type,
                        heightFieldGeometricObject,
                        otherGeometricObject,
                        heightField,
                        convex,
                        swapped);
                    return;
                }
            }

            #region ----- Precomputations -----

            Vector3F scaleHeightField = heightFieldGeometricObject.Scale;
            Vector3F scaleOther       = otherGeometricObject.Scale;
            Pose     heightFieldPose  = heightFieldGeometricObject.Pose;

            // We do not support negative scaling. It is not clear what should happen when y is
            // scaled with a negative factor and triangle orders would be wrong... Not worth the trouble.
            if (scaleHeightField.X < 0 || scaleHeightField.Y < 0 || scaleHeightField.Z < 0)
            {
                throw new NotSupportedException("Computing collisions for height fields with a negative scaling is not supported.");
            }

            // Get height field and basic info.
            Vector3F heightFieldUpAxis = heightFieldPose.ToWorldDirection(Vector3F.UnitY);
            int      arrayLengthX      = heightField.NumberOfSamplesX;
            int      arrayLengthZ      = heightField.NumberOfSamplesZ;
            Debug.Assert(arrayLengthX > 1 && arrayLengthZ > 1, "A height field should contain at least 2 x 2 elements (= 1 cell).");
            float cellWidthX = heightField.WidthX * scaleHeightField.X / (arrayLengthX - 1);
            float cellWidthZ = heightField.WidthZ * scaleHeightField.Z / (arrayLengthZ - 1);

            // The search-space is the rectangular region on the height field where the closest points
            // must lie in. For contacts we do not have to search neighbor cells. For closest-point
            // queries and separation we have to search neighbor cells.
            // We compute the search-space using a current maximum search distance.
            float   currentSearchDistance = 0;
            Contact guessedClosestPair    = null;
            if (!contactSet.HaveContact && type == CollisionQueryType.ClosestPoints)
            {
                // Make a guess for the closest pair using SupportMapping or InnerPoints.
                bool isOverHole;
                guessedClosestPair = GuessClosestPair(contactSet, swapped, out isOverHole);
                if (isOverHole)
                {
                    // Guesses over holes are useless. --> Check the whole terrain.
                    currentSearchDistance = heightFieldGeometricObject.Aabb.Extent.Length;
                }
                else if (guessedClosestPair.PenetrationDepth < 0)
                {
                    currentSearchDistance = -guessedClosestPair.PenetrationDepth;
                }
                else
                {
                    contactSet.HaveContact = true;
                }
            }
            else
            {
                // Assume no contact.
                contactSet.HaveContact = false;
            }

            // Get AABB of the other object in local space of the height field.
            Aabb aabbOfOther = otherShape.GetAabb(scaleOther, heightFieldPose.Inverse * otherGeometricObject.Pose);

            float originX = heightField.OriginX * scaleHeightField.X;
            float originZ = heightField.OriginZ * scaleHeightField.Z;

            // ----- Compute the cell indices of the search-space.
            // Estimate start and end indices from our search distance.
            int xIndexStartEstimated = (int)((aabbOfOther.Minimum.X - currentSearchDistance - originX) / cellWidthX);
            int xIndexEndEstimated   = (int)((aabbOfOther.Maximum.X + currentSearchDistance - originX) / cellWidthX);
            int zIndexStartEstimated = (int)((aabbOfOther.Minimum.Z - currentSearchDistance - originZ) / cellWidthZ);
            int zIndexEndEstimated   = (int)((aabbOfOther.Maximum.Z + currentSearchDistance - originZ) / cellWidthZ);

            // Clamp indices to valid range.
            int xIndexMax = arrayLengthX - 2;
            int zIndexMax = arrayLengthZ - 2;

            int xIndexStart = Math.Max(xIndexStartEstimated, 0);
            int xIndexEnd   = Math.Min(xIndexEndEstimated, xIndexMax);
            int zIndexStart = Math.Max(zIndexStartEstimated, 0);
            int zIndexEnd   = Math.Min(zIndexEndEstimated, zIndexMax);

            // Find collision algorithm for MinkowskiSum vs. other object's shape.
            CollisionAlgorithm collisionAlgorithm = CollisionDetection.AlgorithmMatrix[typeof(ConvexShape), otherShape.GetType()];

            int numberOfContactsInLastFrame = contactSet.Count;
            #endregion

            #region ----- Test all height field cells in the search space. -----

            // Create several temporary test objects:
            // Instead of the original height field geometric object, we test against a shape for each
            // height field triangle. For the test shape we "extrude" the triangle under the height field.
            // To create the extrusion we "add" a line segment to the triangle using a Minkowski sum.
            // TODO: We can make this faster with a special shape that knows that the child poses are Identity (instead of the standard MinkowskiSumShape).
            // This special shape could compute its InnerPoint without applying the poses.

            var triangleShape = ResourcePools.TriangleShapes.Obtain();
            // (Vertices will be set in the loop below.)

            var triangleGeometricObject = TestGeometricObject.Create();
            triangleGeometricObject.Shape = triangleShape;

            var lineSegment = ResourcePools.LineSegmentShapes.Obtain();
            lineSegment.Start = Vector3F.Zero;
            lineSegment.End   = -heightField.Depth * Vector3F.UnitY;

            var lineSegmentGeometricObject = TestGeometricObject.Create();
            lineSegmentGeometricObject.Shape = lineSegment;

            var extrudedTriangleShape = TestMinkowskiSumShape.Create();
            extrudedTriangleShape.ObjectA = triangleGeometricObject;
            extrudedTriangleShape.ObjectB = lineSegmentGeometricObject;

            var extrudedTriangleGeometricObject = TestGeometricObject.Create();
            extrudedTriangleGeometricObject.Shape = extrudedTriangleShape;
            extrudedTriangleGeometricObject.Pose  = heightFieldPose;

            var testCollisionObject = ResourcePools.TestCollisionObjects.Obtain();
            testCollisionObject.SetInternal(heightFieldCollisionObject, extrudedTriangleGeometricObject);

            var testContactSet = swapped ? ContactSet.Create(contactSet.ObjectA, testCollisionObject)
                                   : ContactSet.Create(testCollisionObject, contactSet.ObjectB);
            testContactSet.IsPerturbationTestAllowed = false;

            // We compute closest points with a preferred normal direction: the height field up-axis.

            // Loop over the cells in the search space.
            // (The inner loop can reduce the search space. Therefore, when we increment the indices
            // xIndex and zIndex we also check if the start indices have changed.)
            for (int xIndex = xIndexStart; xIndex <= xIndexEnd; xIndex = Math.Max(xIndexStart, xIndex + 1))
            {
                for (int zIndex = zIndexStart; zIndex <= zIndexEnd; zIndex = Math.Max(zIndexStart, zIndex + 1))
                {
                    // Test the two cell triangles.
                    for (int triangleIndex = 0; triangleIndex < 2; triangleIndex++)
                    {
                        // Get triangle 0 or 1.
                        var triangle = heightField.GetTriangle(xIndex, zIndex, triangleIndex != 0);

                        var triangleIsHole = Numeric.IsNaN(triangle.Vertex0.Y * triangle.Vertex1.Y * triangle.Vertex2.Y);
                        if (triangleIsHole)
                        {
                            continue;
                        }

                        triangleShape.Vertex0 = triangle.Vertex0 * scaleHeightField;
                        triangleShape.Vertex1 = triangle.Vertex1 * scaleHeightField;
                        triangleShape.Vertex2 = triangle.Vertex2 * scaleHeightField;

                        if (type == CollisionQueryType.Boolean)
                        {
                            collisionAlgorithm.ComputeCollision(testContactSet, CollisionQueryType.Boolean);
                            contactSet.HaveContact = contactSet.HaveContact || testContactSet.HaveContact;
                            if (contactSet.HaveContact)
                            {
                                // We can stop tests here for boolean queries.
                                // Update end indices to exit the outer loops.
                                xIndexEnd = -1;
                                zIndexEnd = -1;
                                break;
                            }
                        }
                        else
                        {
                            Debug.Assert(testContactSet.Count == 0, "testContactSet needs to be cleared.");

                            // If we know that we have a contact, then we can make a faster contact query
                            // instead of a closest-point query.
                            CollisionQueryType queryType = (contactSet.HaveContact) ? CollisionQueryType.Contacts : type;

                            collisionAlgorithm.ComputeCollision(testContactSet, queryType);

                            if (testContactSet.HaveContact)
                            {
                                contactSet.HaveContact = true;

                                if (testContactSet.Count > 0)
                                {
                                    // Get neighbor triangle.

                                    // To compute the triangle normal we take the normal of the unscaled triangle and transform
                                    // the normal with: (M^-1)^T = 1 / scale
                                    // Note: We cannot use the scaled vertices because negative scalings change the
                                    // face-order of the vertices.
                                    Vector3F triangleNormal = triangle.Normal / scaleHeightField;
                                    triangleNormal = heightFieldPose.ToWorldDirection(triangleNormal);
                                    triangleNormal.TryNormalize();

                                    // Assuming the last contact is the newest. (With closest-point queries
                                    // and the CombinedCollisionAlgo, testContactSet[0] could be a (not so useful)
                                    // closest-point result, and testContactSet[1] the better contact query result.)
                                    var testContact   = testContactSet[testContactSet.Count - 1];
                                    var contactNormal = swapped ? -testContact.Normal : testContact.Normal;
                                    if (Vector3F.Dot(contactNormal, triangleNormal) < WeldingLimit)
                                    {
                                        // Contact normal deviates by more than the welding limit. --> Check the contact.

                                        // If we do not find a neighbor, we assume the neighbor has the same normal.
                                        var neighborNormal = triangleNormal;

                                        #region ----- Get Neighbor Triangle Normal -----

                                        // Get barycentric coordinates of contact position.
                                        Vector3F contactPositionOnHeightField = swapped ? testContact.PositionBLocal / scaleHeightField : testContact.PositionALocal / scaleHeightField;
                                        float    u, v, w;
                                        // TODO: GetBaryCentricFromPoint computes the triangle normal, which we already know - optimize.
                                        GeometryHelper.GetBarycentricFromPoint(triangle, contactPositionOnHeightField, out u, out v, out w);

                                        // If one coordinate is near 0, the contact is near an edge.
                                        if (u < 0.05f || v < 0.05f || w < 0.05f)
                                        {
                                            if (triangleIndex == 0)
                                            {
                                                if (u < v && u < w)
                                                {
                                                    neighborNormal = heightFieldPose.ToWorldDirection(heightField.GetTriangle(xIndex, zIndex, true).Normal / scaleHeightField);
                                                    neighborNormal.TryNormalize();
                                                }
                                                else if (v < w)
                                                {
                                                    if (zIndex > 0)
                                                    {
                                                        neighborNormal = heightFieldPose.ToWorldDirection(heightField.GetTriangle(xIndex, zIndex - 1, true).Normal / scaleHeightField);
                                                        neighborNormal.TryNormalize();
                                                    }
                                                    else
                                                    {
                                                        // The contact is at the border of the whole height field. Set a normal which disables all bad contact filtering.
                                                        neighborNormal = new Vector3F(float.NaN);
                                                    }
                                                }
                                                else
                                                {
                                                    if (xIndex > 0)
                                                    {
                                                        neighborNormal = heightFieldPose.ToWorldDirection(heightField.GetTriangle(xIndex - 1, zIndex, true).Normal / scaleHeightField);
                                                        neighborNormal.TryNormalize();
                                                    }
                                                    else
                                                    {
                                                        neighborNormal = new Vector3F(float.NaN);
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                if (u < v && u < w)
                                                {
                                                    if (xIndex + 2 < arrayLengthX)
                                                    {
                                                        neighborNormal = heightFieldPose.ToWorldDirection(heightField.GetTriangle(xIndex + 1, zIndex, false).Normal / scaleHeightField);
                                                        neighborNormal.TryNormalize();
                                                    }
                                                    else
                                                    {
                                                        neighborNormal = new Vector3F(float.NaN);
                                                    }
                                                }
                                                else if (v < w)
                                                {
                                                    neighborNormal = heightFieldPose.ToWorldDirection(heightField.GetTriangle(xIndex, zIndex, false).Normal / scaleHeightField);
                                                    neighborNormal.TryNormalize();
                                                }
                                                else
                                                {
                                                    if (zIndex + 2 < arrayLengthZ)
                                                    {
                                                        neighborNormal = heightFieldPose.ToWorldDirection(heightField.GetTriangle(xIndex, zIndex + 1, true).Normal / scaleHeightField);
                                                        neighborNormal.TryNormalize();
                                                    }
                                                    else
                                                    {
                                                        neighborNormal = new Vector3F(float.NaN);
                                                    }
                                                }
                                            }
                                        }
                                        #endregion

                                        // Contact normals in the range triangleNormal - neighborNormal are allowed.
                                        // Others, especially vertical contacts in slopes or horizontal normals are not
                                        // allowed.
                                        var cosMinAngle = Vector3F.Dot(neighborNormal, triangleNormal) - CollisionDetection.Epsilon;
                                        RemoveBadContacts(swapped, testContactSet, triangleNormal, cosMinAngle);

                                        // If we have no contact yet, we retry with a preferred normal identical to the up axis.
                                        // (Note: contactSet.Count will be > 0 for closest-point queries but will
                                        // probably constraint separated contacts and not real contacts.)
                                        if (testContactSet.Count == 0 &&
                                            (contactSet.Count == 0 || type == CollisionQueryType.ClosestPoints))
                                        {
                                            testContactSet.PreferredNormal = (swapped) ? -heightFieldUpAxis : heightFieldUpAxis;
                                            collisionAlgorithm.ComputeCollision(testContactSet, CollisionQueryType.Contacts);
                                            testContactSet.PreferredNormal = Vector3F.Zero;
                                            RemoveBadContacts(swapped, testContactSet, triangleNormal, cosMinAngle);
                                        }

                                        // If we have no contact yet, we retry with a preferred normal identical to the triangle normal.
                                        // But only if the triangle normal differs significantly from the up axis.
                                        if (testContactSet.Count == 0 &&
                                            (contactSet.Count == 0 || type == CollisionQueryType.ClosestPoints) &&
                                            Vector3F.Dot(heightFieldUpAxis, triangleNormal) < WeldingLimit)
                                        {
                                            testContactSet.PreferredNormal = (swapped) ? -triangleNormal : triangleNormal;
                                            collisionAlgorithm.ComputeCollision(testContactSet, CollisionQueryType.Contacts);
                                            testContactSet.PreferredNormal = Vector3F.Zero;
                                            RemoveBadContacts(swapped, testContactSet, triangleNormal, cosMinAngle);
                                        }
                                    }
                                }
                            }

                            if (testContactSet.Count > 0)
                            {
                                // Remember separation distance for later.
                                float separationDistance = -testContactSet[0].PenetrationDepth;

                                // Set the shape feature of the new contacts.
                                // The features is the height field triangle index (see HeightField documentation).
                                int numberOfContacts = testContactSet.Count;
                                for (int i = 0; i < numberOfContacts; i++)
                                {
                                    Contact contact      = testContactSet[i];
                                    int     featureIndex = (zIndex * (arrayLengthX - 1) + xIndex) * 2 + triangleIndex;
                                    if (swapped)
                                    {
                                        contact.FeatureB = featureIndex;
                                    }
                                    else
                                    {
                                        contact.FeatureA = featureIndex;
                                    }
                                }

                                // Merge the contact info. (Contacts in testContactSet are recycled!)
                                ContactHelper.Merge(contactSet, testContactSet, type, CollisionDetection.ContactPositionTolerance);

                                #region ----- Update search space -----

                                // Update search space if possible.
                                // The best search distance is 0. For separation we can use the current smallest
                                // separation as search distance. As soon as we have a contact, we set the
                                // search distance to 0.
                                if (currentSearchDistance > 0 &&                  // No need to update search space if search distance is already 0.
                                    (contactSet.HaveContact || // If we have a contact, we set the search distance to 0.
                                     separationDistance < currentSearchDistance)) // If we have closer separation, we use this.
                                {
                                    // Note: We only check triangleContactSet[0] in the if condition.
                                    // triangleContactSet could contain several contacts, but we don't bother with
                                    // this special case.

                                    // Update search distance.
                                    if (contactSet.HaveContact)
                                    {
                                        currentSearchDistance = 0;
                                    }
                                    else
                                    {
                                        currentSearchDistance = Math.Max(0, separationDistance);
                                    }

                                    // Update search space indices.
                                    xIndexStartEstimated = (int)((aabbOfOther.Minimum.X - currentSearchDistance - originX) / cellWidthX);
                                    xIndexEndEstimated   = (int)((aabbOfOther.Maximum.X + currentSearchDistance - originX) / cellWidthX);
                                    zIndexStartEstimated = (int)((aabbOfOther.Minimum.Z - currentSearchDistance - originZ) / cellWidthZ);
                                    zIndexEndEstimated   = (int)((aabbOfOther.Maximum.Z + currentSearchDistance - originZ) / cellWidthZ);

                                    xIndexStart = Math.Max(xIndexStart, xIndexStartEstimated);
                                    xIndexEnd   = Math.Min(xIndexEndEstimated, xIndexMax);
                                    zIndexStart = Math.Max(zIndexStart, zIndexStartEstimated);
                                    zIndexEnd   = Math.Min(zIndexEndEstimated, zIndexMax);
                                }
                                #endregion
                            }
                        }
                    }
                }
            }

            // Recycle temporary objects.
            testContactSet.Recycle();
            ResourcePools.TestCollisionObjects.Recycle(testCollisionObject);
            extrudedTriangleGeometricObject.Recycle();
            extrudedTriangleShape.Recycle();
            lineSegmentGeometricObject.Recycle();
            ResourcePools.LineSegmentShapes.Recycle(lineSegment);
            triangleGeometricObject.Recycle();
            ResourcePools.TriangleShapes.Recycle(triangleShape);
            #endregion

            #region ----- Handle missing contact info -----

            if (contactSet.Count == 0 &&
                (contactSet.HaveContact && type == CollisionQueryType.Contacts || type == CollisionQueryType.ClosestPoints))
            {
                // ----- Bad contact info:
                // We should have contact data because this is either a contact query and the objects touch
                // or this is a closest-point query.
                // Use our guess as the contact info.
                Contact closestPair = guessedClosestPair;
                bool    isOverHole  = false;
                if (closestPair == null)
                {
                    closestPair = GuessClosestPair(contactSet, swapped, out isOverHole);
                }

                // Guesses over holes are useless. :-(
                if (!isOverHole)
                {
                    ContactHelper.Merge(contactSet, closestPair, type, CollisionDetection.ContactPositionTolerance);
                }
            }
            #endregion


            if (CollisionDetection.FullContactSetPerFrame &&
                type == CollisionQueryType.Contacts &&
                numberOfContactsInLastFrame == 0 &&
                contactSet.Count > 0 &&
                contactSet.Count < 4)
            {
                // Try to find full contact set.
                // TODO: This can be optimized by not doing the whole overhead of ComputeCollision again.
                ContactHelper.TestWithPerturbations(
                    CollisionDetection,
                    contactSet,
                    !swapped, // Perturb objectB not the height field.
                    _computeContactsMethod);
            }
        }
Ejemplo n.º 35
0
        protected override void OnHandleInput(InputContext context)
        {
            if (_cameraObject.CameraNode == null)
            {
                return;
            }

            // The input context contains the mouse position that is used by the UI controls of this
            // screen. The mouse position is stored in the following properties:
            // - context.ScreenMousePosition
            // - context.ScreenMousePositionDelta
            // - context.MousePosition
            // - context.MousePositionDelta
            //
            // Currently, these properties contain the mouse position relative to the game window.
            // But the mouse position of the in-game screen is determined by the reticle of the
            // game camera. We need to make a ray-cast to see which part of the screen is hit and
            // override the properties.
            bool screenHit = false;

            // Get the camera position and the view direction in world space.
            Vector3F cameraPosition  = _cameraObject.CameraNode.PoseWorld.Position;
            Vector3F cameraDirection = _cameraObject.CameraNode.PoseWorld.ToWorldDirection(Vector3F.Forward);

            // Create a ray (ideally this shape should be cached and reused).
            var ray = new RayShape(cameraPosition, cameraDirection, 1000);

            // We are only interested in the first object that is hit by the ray.
            ray.StopsAtFirstHit = true;

            // Create a collision object for this shape.
            var rayCollisionObject = new CollisionObject(new GeometricObject(ray, Pose.Identity));

            // Use the CollisionDomain of the physics simulation to perform a ray cast.
            ContactSet contactSet = _simulation.CollisionDomain.GetContacts(rayCollisionObject).FirstOrDefault();

            if (contactSet != null && contactSet.Count > 0)
            {
                // We have hit something :-)

                // Get the contact information of the ray hit.
                Contact contact = contactSet[0];

                // Get the hit object (one object in the contact set is the ray and the other object is the hit object).
                CollisionObject hitCollisionObject = (contactSet.ObjectA == rayCollisionObject) ? contactSet.ObjectB : contactSet.ObjectA;

                RigidBody hitBody = hitCollisionObject.GeometricObject as RigidBody;
                if (hitBody != null && hitBody.UserData is string && (string)hitBody.UserData == "TV")
                {
                    // We have hit a dynamic rigid body of a TV object.

                    // Get the normal vector of the contact.
                    var normal = (contactSet.ObjectA == rayCollisionObject) ? -contact.Normal : contact.Normal;

                    // Convert the normal vector to the local space of the TV box.
                    normal = hitBody.Pose.ToLocalDirection(normal);

                    // The InGameUIScreen texture is only mapped onto the -Y sides of the boxes. If the user
                    // looks onto another side, he cannot interact with the game screen.
                    if (normal.Y < 0.5f)
                    {
                        // The user looks onto the TV's front side. Now, we have to map the ray hit position
                        // to the texture coordinate of the InGameUIScreen render target/texture.
                        var localHitPosition   = (contactSet.ObjectA == rayCollisionObject) ? contact.PositionBLocal : contact.PositionALocal;
                        var normalizedPosition = GetTextureCoordinate(localHitPosition);

                        // The texture coordinate is in the range [0, 0] to [1, 1]. If we multiply it with the
                        // screen extent to the position in pixels.
                        var inGameScreenMousePosition      = normalizedPosition * new Vector2F(ActualWidth, ActualHeight);
                        var inGameScreenMousePositionDelta = inGameScreenMousePosition - _lastMousePosition;

                        // Finally, we can set the mouse positions that are relative to the InGame screen. Hurray!
                        context.ScreenMousePosition      = inGameScreenMousePosition;
                        context.ScreenMousePositionDelta = inGameScreenMousePositionDelta;

                        context.MousePosition      = inGameScreenMousePosition;
                        context.MousePositionDelta = inGameScreenMousePositionDelta;

                        // Store the mouse position so that we can compute MousePositionDelta in the next frame.
                        _lastMousePosition = context.MousePosition;
                        screenHit          = true;
                    }
                }
            }

            if (screenHit)
            {
                // Call base class to call HandleInput for all child controls. The child controls will
                // use the overridden mouse positions.
                base.OnHandleInput(context);
            }
        }
Ejemplo n.º 36
0
 public static Matrix4F Translation(Vector3F v)
 {
     return(new Matrix4F(1f, 0.0f, 0.0f, v.X, 0.0f, 1f, 0.0f, v.Y, 0.0f, 0.0f, 1f, v.Z, 0.0f, 0.0f, 0.0f, 1f));
 }
Ejemplo n.º 37
0
        public static Matrix4F Scaling(Vector3F v, Point3F origin)
        {
            Vector3F v1 = (Vector3F)origin;

            return(Transformation4F.Translation(v1) * Transformation4F.Scaling(v) * Transformation4F.Translation(-v1));
        }
Ejemplo n.º 38
0
 public static Point3D ToPoint3D(this Vector3F value) => new Point3D(value.X, value.Y, value.Z);
        //--------------------------------------------------------------
        #region Methods
        //--------------------------------------------------------------

        /// <summary>
        /// Gets the cube map indices from a direction vector.
        /// </summary>
        /// <param name="direction">The direction vector.</param>
        /// <param name="x">The x index.</param>
        /// <param name="y">The y index.</param>
        /// <param name="face">The face index.</param>
        private void GetIndices(ref Vector3F direction, out int x, out int y, out int face)
        {
            // Precompute factor used for lookup.
            int   width = CubeMap.GetLength(1);
            float s     = 0.5f * width;

            // Convert the direction vector to indices.
            Vector3F abs = Vector3F.Absolute(direction);

            if (abs.X >= abs.Y && abs.X >= abs.Z)
            {
                float oneOverX = 1.0f / abs.X;
                if (direction.X >= 0)
                {
                    x    = (int)((direction.Z * oneOverX + 1.0f) * s);
                    y    = (int)((direction.Y * oneOverX + 1.0f) * s);
                    face = PositiveX;
                }
                else
                {
                    x    = (int)((-direction.Z * oneOverX + 1.0f) * s);
                    y    = (int)((direction.Y * oneOverX + 1.0f) * s);
                    face = NegativeX;
                }
            }
            else if (abs.Y >= abs.Z)
            {
                float oneOverY = 1.0f / abs.Y;
                if (direction.Y >= 0)
                {
                    x    = (int)((direction.X * oneOverY + 1.0f) * s);
                    y    = (int)((direction.Z * oneOverY + 1.0f) * s);
                    face = PositiveY;
                }
                else
                {
                    x    = (int)((-direction.X * oneOverY + 1.0f) * s);
                    y    = (int)((direction.Z * oneOverY + 1.0f) * s);
                    face = NegativeY;
                }
            }
            else
            {
                float oneOverZ = 1.0f / abs.Z;
                if (direction.Z >= 0)
                {
                    x    = (int)((-direction.X * oneOverZ + 1.0f) * s);
                    y    = (int)((direction.Y * oneOverZ + 1.0f) * s);
                    face = PositiveZ;
                }
                else
                {
                    x    = (int)((direction.X * oneOverZ + 1.0f) * s);
                    y    = (int)((direction.Y * oneOverZ + 1.0f) * s);
                    face = NegativeZ;
                }
            }

            // Clamp indices. (Necessary if direction points exactly to edge.)
            int maxIndex = width - 1;

            if (x > maxIndex)
            {
                x = maxIndex;
            }

            if (y > maxIndex)
            {
                y = maxIndex;
            }
        }
Ejemplo n.º 40
0
        //--------------------------------------------------------------
        #region Properties & Events
        //--------------------------------------------------------------
        #endregion


        //--------------------------------------------------------------
        #region Creation & Cleanup
        //--------------------------------------------------------------
        #endregion


        //--------------------------------------------------------------
        #region Methods
        //--------------------------------------------------------------

        /// <summary>
        /// Initializes the 1-dimensional constraint.
        /// </summary>
        public void Prepare(RigidBody bodyA, RigidBody bodyB, Vector3F jLinA, Vector3F jAngA, Vector3F jLinB, Vector3F jAngB)
        {
            JLinA = jLinA;
            JAngA = jAngA;
            JLinB = jLinB;
            JAngB = jAngB;

            //WJTLinA = bodyA.MassInverse * jLinA;
            //WJTAngA = bodyA.InertiaInverseWorld * jAngA;
            //WJTLinB = bodyB.MassInverse * jLinB;
            //WJTAngB = bodyB.InertiaInverseWorld * jAngB;
            // ----- Optimized version:
            WJTLinA.X = bodyA.MassInverse * jLinA.X;
            WJTLinA.Y = bodyA.MassInverse * jLinA.Y;
            WJTLinA.Z = bodyA.MassInverse * jLinA.Z;
            Matrix33F matrix = bodyA.InertiaInverseWorld;

            WJTAngA.X = matrix.M00 * jAngA.X + matrix.M01 * jAngA.Y + matrix.M02 * jAngA.Z;
            WJTAngA.Y = matrix.M10 * jAngA.X + matrix.M11 * jAngA.Y + matrix.M12 * jAngA.Z;
            WJTAngA.Z = matrix.M20 * jAngA.X + matrix.M21 * jAngA.Y + matrix.M22 * jAngA.Z;
            WJTLinB.X = bodyB.MassInverse * jLinB.X;
            WJTLinB.Y = bodyB.MassInverse * jLinB.Y;
            WJTLinB.Z = bodyB.MassInverse * jLinB.Z;
            matrix    = bodyB.InertiaInverseWorld;
            WJTAngB.X = matrix.M00 * jAngB.X + matrix.M01 * jAngB.Y + matrix.M02 * jAngB.Z;
            WJTAngB.Y = matrix.M10 * jAngB.X + matrix.M11 * jAngB.Y + matrix.M12 * jAngB.Z;
            WJTAngB.Z = matrix.M20 * jAngB.X + matrix.M21 * jAngB.Y + matrix.M22 * jAngB.Z;

            //float JWJT = Vector3F.Dot(jLinA, WJTLinA) + Vector3F.Dot(jAngA, WJTAngA)
            //             + Vector3F.Dot(jLinB, WJTLinB) + Vector3F.Dot(jAngB, WJTAngB);
            // ----- Optimized version:
            float JWJT = jLinA.X * WJTLinA.X + jLinA.Y * WJTLinA.Y + jLinA.Z * WJTLinA.Z
                         + jAngA.X * WJTAngA.X + jAngA.Y * WJTAngA.Y + jAngA.Z * WJTAngA.Z
                         + jLinB.X * WJTLinB.X + jLinB.Y * WJTLinB.Y + jLinB.Z * WJTLinB.Z
                         + jAngB.X * WJTAngB.X + jAngB.Y * WJTAngB.Y + jAngB.Z * WJTAngB.Z;

            JWJT       += Softness;
            JWJTInverse = 1 / JWJT;
        }
Ejemplo n.º 41
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Triangle"/> class.
 /// </summary>
 /// <param name="p0">A <see cref="Vector3F"/> instance.</param>
 /// <param name="p1">A <see cref="Vector3F"/> instance.</param>
 /// <param name="p2">A <see cref="Vector3F"/> instance.</param>
 public Triangle(Vector3F p0, Vector3F p1, Vector3F p2)
 {
     _p0 = p0;
     _p1 = p1;
     _p2 = p2;
 }
Ejemplo n.º 42
0
 public static Matrix4F GetCoordSystem(Vector3F xaxis, Vector3F yaxis, Vector3F zaxis)
 {
     return(new Matrix4F(xaxis.X, yaxis.X, zaxis.X, 0.0f, xaxis.Y, yaxis.Y, zaxis.Y, 0.0f, xaxis.Z, yaxis.Z, zaxis.Z, 0.0f, 0.0f, 0.0f, 0.0f, 1f));
 }
Ejemplo n.º 43
0
 public static Matrix4F Scaling(Vector3F v)
 {
     return(new Matrix4F(v.X, 0.0f, 0.0f, 0.0f, 0.0f, v.Y, 0.0f, 0.0f, 0.0f, 0.0f, v.Z, 0.0f, 0.0f, 0.0f, 0.0f, 1f));
 }
Ejemplo n.º 44
0
        private void SetupConstraint(int index, float targetVelocity, Vector3F axis, Vector3F rA, Vector3F rB, float deltaTime)
        {
            Constraint1D constraint = _constraints[index];

            constraint.TargetRelativeVelocity = targetVelocity;

            // Impulse limits
            float impulseLimit = MaxForce * deltaTime;

            _minImpulseLimits[index] = -impulseLimit;
            _maxImpulseLimits[index] = impulseLimit;

            // Note: Softness must be set before!
            constraint.Softness = Softness / deltaTime;
            constraint.Prepare(BodyA, BodyB, -axis, -Vector3F.Cross(rA, axis), axis, Vector3F.Cross(rB, axis));
        }
Ejemplo n.º 45
0
        public static Matrix4F Scaling(float s, Point3F origin)
        {
            Vector3F v = (Vector3F)origin;

            return(Transformation4F.Translation(v) * Transformation4F.Scaling(s) * Transformation4F.Translation(-v));
        }
Ejemplo n.º 46
0
        private void CreateScene()
        {
            var random = new Random(1234567);

            // 3 empty scene nodes act as the root nodes for 3 different scene graphs.
            _originalMeshNodes = new SceneNode {
                Children = new SceneNodeCollection()
            };
            _staticInstancingNodes = new SceneNode {
                Children = new SceneNodeCollection()
            };
            _staticBatchingNodes = new SceneNode {
                Children = new SceneNodeCollection()
            };

            // Load several model nodes. Each of these models contains only one mesh node.
            // Store the mesh nodes in a list.
            MeshNode[] meshNodePrototypes =
            {
                (MeshNode)ContentManager.Load <ModelNode>("Grass/Grass").Children[0],
                (MeshNode)ContentManager.Load <ModelNode>("Parviflora/Parviflora").Children[0],
                (MeshNode)ContentManager.Load <ModelNode>("PalmTree/palm_tree").Children[0],
                (MeshNode)ContentManager.Load <ModelNode>("Rock/rock_05").Children[0],
                (MeshNode)ContentManager.Load <ModelNode>("GlassBox/GlassBox").Children[0],
                (MeshNode)ContentManager.Load <ModelNode>("Building/wall_concrete_1").Children[0],
            };

            for (int meshIndex = 0; meshIndex < meshNodePrototypes.Length; meshIndex++)
            {
                var meshNode = meshNodePrototypes[meshIndex];
                var mesh     = meshNode.Mesh;
#if WINDOWS
                int numberOfInstances = (meshIndex == 0) ? 5000 : 200;
#else
                int numberOfInstances = (meshIndex == 0) ? 1000 : 50;
#endif

                int extent = (meshIndex < 2) ? 20 : 100;

                // Create a list of random scales and poses.
                var scales = new Vector3F[numberOfInstances];
                var poses  = new Pose[numberOfInstances];
                for (int i = 0; i < numberOfInstances; i++)
                {
                    // Combine a random scale with the original scale of the mesh.
                    scales[i] = new Vector3F(random.NextFloat(0.5f, 1.2f)) * meshNode.ScaleWorld;

                    // Combine a random pose with the original pose of the mesh.
                    Vector3F  position    = new Vector3F(random.NextFloat(-extent, extent), 0, random.NextFloat(-extent, extent));
                    Matrix33F orientation = Matrix33F.CreateRotationY(random.NextFloat(0, ConstantsF.TwoPi));

                    poses[i] = new Pose(position, orientation) * meshNode.PoseLocal;
                }

                // Strategy A or B: Create a MeshNode for each mesh instance.
                for (int i = 0; i < numberOfInstances; i++)
                {
                    var clone = meshNode.Clone();
                    clone.ScaleLocal = scales[i];
                    clone.PoseLocal  = poses[i];
                    _originalMeshNodes.Children.Add(clone);
                }

                // Strategy C: Create one MeshInstancingNode which contains all instances for one mesh.
                var instances = new InstanceData[numberOfInstances];
                for (int i = 0; i < numberOfInstances; i++)
                {
                    instances[i] = new InstanceData(scales[i], poses[i], new Vector4F(1));
                }

                // Create MeshInstancingNode.
                var instancingMeshNode = new MeshInstancingNode <InstanceData>(mesh, instances)
                {
                    // It is recommended to manually set a suitable pose and shape, so that
                    // the bounding shape contains all instances.
                    PoseLocal = new Pose(new Vector3F(0, 2, 0)),
                    Shape     = new BoxShape(2 * extent, 4, 2 * extent),
                };
                _staticInstancingNodes.Children.Add(instancingMeshNode);

                // Strategy D: We merge all instances of the mesh into one huge static mesh.
                var mergedMesh = MeshHelper.Merge(mesh, scales, poses);
                _staticBatchingNodes.Children.Add(new MeshNode(mergedMesh));
            }

            // For static batching, instead of creating one merged mesh per mesh type,
            // we could also merge all mesh instances into a single huge static mesh.
            //var mergedMesh = MeshHelper.Merge(_originalMeshNodes.Children);
            //_staticBatchingNodes = new MeshNode(mergedMesh);
        }
Ejemplo n.º 47
0
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

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

            int numberOfNodes = nodes.Count;

            if (nodes.Count == 0)
            {
                return;
            }

            context.Validate(_spriteBatch);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = context.GraphicsService.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            // Camera properties
            var       cameraNode     = context.CameraNode;
            Matrix44F viewProjection = cameraNode.Camera.Projection * cameraNode.View;
            var       viewport       = graphicsDevice.Viewport;

            // Update SceneNode.LastFrame for all visible nodes.
            int frame = context.Frame;

            cameraNode.LastFrame = frame;

            SpriteSortMode sortMode;

            switch (order)
            {
            case RenderOrder.Default:
                sortMode = SpriteSortMode.Texture;
                break;

            case RenderOrder.FrontToBack:
                sortMode = SpriteSortMode.FrontToBack;
                break;

            case RenderOrder.BackToFront:
                sortMode = SpriteSortMode.BackToFront;
                break;

            case RenderOrder.UserDefined:
            default:
                sortMode = SpriteSortMode.Deferred;
                break;
            }

            _spriteBatch.Begin(sortMode, graphicsDevice.BlendState, null, graphicsDevice.DepthStencilState, null);

            for (int i = 0; i < numberOfNodes; i++)
            {
                var node = nodes[i] as SpriteNode;
                if (node == null)
                {
                    continue;
                }

                // SpriteNode is visible in current frame.
                node.LastFrame = frame;

                // Position, size, and origin in pixels.
                Vector3F position = new Vector3F();
                Vector2  size     = new Vector2();
                Vector2  origin   = new Vector2();

                var bitmapSprite = node.Sprite as ImageSprite;
                if (bitmapSprite != null)
                {
                    var packedTexture = bitmapSprite.Texture;
                    if (packedTexture != null)
                    {
                        // Project into viewport and snap to pixels.
                        position   = viewport.ProjectToViewport(node.PoseWorld.Position, viewProjection);
                        position.X = (int)(position.X + 0.5f);
                        position.Y = (int)(position.Y + 0.5f);

                        // Get source rectangle (pixel bounds).
                        var sourceRectangle = packedTexture.GetBounds(node.AnimationTime);
                        size = new Vector2(sourceRectangle.Width, sourceRectangle.Height);

                        // Premultiply color.
                        Vector3F color3F = node.Color;
                        float    alpha   = node.Alpha;
                        Color    color   = new Color(color3F.X * alpha, color3F.Y * alpha, color3F.Z * alpha, alpha);

                        // Get absolute origin (relative to pixel bounds).
                        origin = (Vector2)node.Origin * size;

                        // Draw using SpriteBatch.
                        _spriteBatch.Draw(
                            packedTexture.TextureAtlas, new Vector2(position.X, position.Y), sourceRectangle,
                            color, node.Rotation, origin, (Vector2)node.Scale, SpriteEffects.None, position.Z);
                    }
                }
                else
                {
                    var textSprite = node.Sprite as TextSprite;
                    if (textSprite != null)
                    {
                        var font = textSprite.Font ?? _spriteFont;
                        if (font != null)
                        {
                            // Text can be a string or StringBuilder.
                            var text = textSprite.Text as string;
                            if (text != null)
                            {
                                if (text.Length > 0)
                                {
                                    // Project into viewport and snap to pixels.
                                    position   = viewport.ProjectToViewport(node.PoseWorld.Position, viewProjection);
                                    position.X = (int)(position.X + 0.5f);
                                    position.Y = (int)(position.Y + 0.5f);

                                    // Premultiply color.
                                    Vector3F color3F = node.Color;
                                    float    alpha   = node.Alpha;
                                    Color    color   = new Color(color3F.X * alpha, color3F.Y * alpha, color3F.Z * alpha, alpha);

                                    // Get absolute origin (relative to pixel bounds).
                                    size   = font.MeasureString(text);
                                    origin = (Vector2)node.Origin * size;

                                    // Draw using SpriteBatch.
                                    _spriteBatch.DrawString(
                                        font, text, new Vector2(position.X, position.Y),
                                        color, node.Rotation, origin, (Vector2)node.Scale,
                                        SpriteEffects.None, position.Z);
                                }
                            }
                            else
                            {
                                var stringBuilder = textSprite.Text as StringBuilder;
                                if (stringBuilder != null && stringBuilder.Length > 0)
                                {
                                    // Project into viewport and snap to pixels.
                                    position   = viewport.ProjectToViewport(node.PoseWorld.Position, viewProjection);
                                    position.X = (int)(position.X + 0.5f);
                                    position.Y = (int)(position.Y + 0.5f);

                                    // Premultiply color.
                                    Vector3F color3F = node.Color;
                                    float    alpha   = node.Alpha;
                                    Color    color   = new Color(color3F.X * alpha, color3F.Y * alpha, color3F.Z * alpha, alpha);

                                    // Get absolute origin (relative to pixel bounds).
                                    size   = font.MeasureString(stringBuilder);
                                    origin = (Vector2)node.Origin * size;

                                    // Draw using SpriteBatch.
                                    _spriteBatch.DrawString(
                                        font, stringBuilder, new Vector2(position.X, position.Y),
                                        color, node.Rotation, origin, (Vector2)node.Scale,
                                        SpriteEffects.None, position.Z);
                                }
                            }
                        }
                    }
                }

                // Store bounds an depth for hit tests.
                node.LastBounds = new Rectangle(
                    (int)(position.X - origin.X),
                    (int)(position.Y - origin.Y),
                    (int)(size.X * node.Scale.X),
                    (int)(size.Y * node.Scale.Y));

                node.LastDepth = position.Z;
            }

            _spriteBatch.End();
            savedRenderState.Restore();
        }
Ejemplo n.º 48
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);
        }
Ejemplo n.º 49
0
 public VsIn(Vector3F position, Vector4F color)
 {
     Position = position;
     Color    = color;
 }
 private static bool TRI_TRI_3D(ref Vector3F p1, ref Vector3F q1, ref Vector3F r1,
                                ref Vector3F p2, ref Vector3F q2, ref Vector3F r2,
                                float dp2, float dq2, float dr2, ref Vector3F N1)
 {
     // Permutation in a canonical form of T2's vertices
     if (dp2 > 0.0f)
     {
         if (dq2 > 0.0f)
         {
             return(CHECK_MIN_MAX(ref p1, ref r1, ref q1, ref r2, ref p2, ref q2));
         }
         else if (dr2 > 0.0f)
         {
             return(CHECK_MIN_MAX(ref p1, ref r1, ref q1, ref q2, ref r2, ref p2));
         }
         else
         {
             return(CHECK_MIN_MAX(ref p1, ref q1, ref r1, ref p2, ref q2, ref r2));
         }
     }
     else if (dp2 < 0.0f)
     {
         if (dq2 < 0.0f)
         {
             return(CHECK_MIN_MAX(ref p1, ref q1, ref r1, ref r2, ref p2, ref q2));
         }
         else if (dr2 < 0.0f)
         {
             return(CHECK_MIN_MAX(ref p1, ref q1, ref r1, ref q2, ref r2, ref p2));
         }
         else
         {
             return(CHECK_MIN_MAX(ref p1, ref r1, ref q1, ref p2, ref q2, ref r2));
         }
     }
     else
     {
         if (dq2 < 0.0f)
         {
             if (dr2 >= 0.0f)
             {
                 return(CHECK_MIN_MAX(ref p1, ref r1, ref q1, ref q2, ref r2, ref p2));
             }
             else
             {
                 return(CHECK_MIN_MAX(ref p1, ref q1, ref r1, ref p2, ref q2, ref r2));
             }
         }
         else if (dq2 > 0.0f)
         {
             if (dr2 > 0.0f)
             {
                 return(CHECK_MIN_MAX(ref p1, ref r1, ref q1, ref p2, ref q2, ref r2));
             }
             else
             {
                 return(CHECK_MIN_MAX(ref p1, ref q1, ref r1, ref q2, ref r2, ref p2));
             }
         }
         else
         {
             if (dr2 > 0.0f)
             {
                 return(CHECK_MIN_MAX(ref p1, ref q1, ref r1, ref r2, ref p2, ref q2));
             }
             else if (dr2 < 0.0f)
             {
                 return(CHECK_MIN_MAX(ref p1, ref r1, ref q1, ref r2, ref p2, ref q2));
             }
             else
             {
                 return(coplanar_tri_tri3d(ref p1, ref q1, ref r1, ref p2, ref q2, ref r2, ref N1));
             }
         }
     }
 }
Ejemplo n.º 51
0
        protected override void OnUpdateParticles(TimeSpan deltaTime, int startIndex, int count)
        {
            if (_positionParameter == null ||
                _targetPositionParameter == null ||
                _speedParameter == null ||
                _sizeXParameter == null)
            {
                return;
            }

            Vector3F[] positions       = _positionParameter.Values;
            Vector3F[] targetPositions = _targetPositionParameter.Values;
            float[]    speeds          = _speedParameter.Values;
            float[]    sizes           = _sizeXParameter.Values;
            Pose       cameraPose      = (_cameraPoseParameter != null) ? _cameraPoseParameter.DefaultValue : Pose.Identity;

            if (positions == null || targetPositions == null || speeds == null)
            {
                // This effector only works with varying parameters.
                return;
            }

            Random   random = ParticleSystem.Random;
            Vector3F center = ParticleSystem.Pose.Position;
            float    dt     = (float)deltaTime.TotalSeconds;

            for (int i = startIndex; i < startIndex + count; i++)
            {
                Vector3F targetPosition = targetPositions[i];
                Vector3F lineSegment    = targetPosition - positions[i];
                float    distance       = lineSegment.Length;
                if (Numeric.IsZero(distance))
                {
                    // The bee has reached the target position. Choose a new direction and distance.
                    Vector3F d = _distribution.Next(random);

                    // Keep the new target position within a certain range.
                    if (Math.Abs(targetPosition.X + d.X - center.X) > MaxRange)
                    {
                        d.X = -d.X;
                    }
                    if (Math.Abs(targetPosition.Y + d.Y - center.Y) > MaxRange)
                    {
                        d.Y = -d.Y;
                    }
                    if (Math.Abs(targetPosition.Z + d.Z - center.Z) > MaxRange)
                    {
                        d.Z = -d.Z;
                    }

                    targetPositions[i] = targetPosition + d;
                }
                else
                {
                    // Move bee towards target position.
                    Vector3F movementDirection = lineSegment / distance;
                    float    movementDistance  = speeds[i] * dt;
                    if (movementDistance > distance)
                    {
                        movementDistance = distance;
                    }

                    positions[i] += movementDirection * movementDistance;

                    // The bee should look in the direction it is flying. Transform the direction
                    // into the view space and check the sign of x-component.
                    movementDirection = cameraPose.ToLocalDirection(movementDirection);
                    float sign = (movementDirection.X >= 0) ? +1 : -1;
                    if (InvertLookDirection)
                    {
                        sign *= -1;
                    }

                    if (Math.Sign(sizes[i]) != (int)sign)
                    {
                        sizes[i] *= -1;
                    }
                }
            }
        }
Ejemplo n.º 52
0
 /// <inheritdoc/>
 public override Aabb GetAabb(Vector3F scale, Pose pose)
 {
     return(new Aabb(pose.Position, pose.Position));
 }
Ejemplo n.º 53
0
 /// <summary>
 /// Computes a mass frame for the given shape and target mass.
 /// </summary>
 /// <param name="shape">The shape.</param>
 /// <param name="scale">The scale of the shape.</param>
 /// <param name="mass">
 /// The target mass. The mass of the computed <see cref="MassFrame"/> will be equal to this
 /// value. Other mass properties are adjusted to match the target mass.
 /// </param>
 /// <param name="relativeDistanceThreshold">
 /// The relative distance threshold. If no mass or inertia formula for the given shape are known
 /// the shape is approximated with a triangle mesh and the mass frame of this mesh is returned.
 /// The relative distance threshold controls the accuracy of the approximated mesh. Good default
 /// values are 0.05 to get an approximation with an error of about 5%.
 /// </param>
 /// <param name="iterationLimit">
 /// The iteration limit. For some shapes the mass properties are computed with an iterative
 /// algorithm. No more than <paramref name="iterationLimit"/> iterations will be performed.
 /// A value of 3 gives good results in most cases. Use a value of -1 to get only a coarse
 /// approximation.
 /// </param>
 /// <returns>
 /// A new <see cref="MassFrame"/> for the given parameters is returned.
 /// </returns>
 /// <remarks>
 /// <para>
 /// <strong>Composite shapes:</strong> If the given <paramref name="shape"/> is a
 /// <see cref="CompositeShape"/>, the computed mass properties are only correct if the children
 /// of the composite shape do not overlap. Overlapping parts are counted twice and so the result
 /// will not be correct. If a child of a composite shape is a <see cref="RigidBody"/> the
 /// <see cref="MassFrame"/> of the rigid body will be used for this child.
 /// </para>
 /// <para>
 /// <strong>Density:</strong> Since this method does not use a density value, the
 /// <see cref="Density"/> property of the <see cref="MassFrame"/> is set to 0.
 /// </para>
 /// </remarks>
 /// <exception cref="ArgumentNullException">
 /// <paramref name="shape"/> is <see langword="null"/>.
 /// </exception>
 /// <exception cref="ArgumentOutOfRangeException">
 /// <paramref name="mass"/> is negative or 0.
 /// </exception>
 /// <exception cref="ArgumentOutOfRangeException">
 /// <paramref name="relativeDistanceThreshold"/> is negative.
 /// </exception>
 public static MassFrame FromShapeAndMass(Shape shape, Vector3F scale, float mass, float relativeDistanceThreshold, int iterationLimit)
 {
     return(ComputeMassProperties(shape, scale, mass, false, relativeDistanceThreshold, iterationLimit));
 }
Ejemplo n.º 54
0
        /// <summary>
        /// Computes the mass properties for the given shape and parameters.
        /// </summary>
        /// <param name="shape">The shape.</param>
        /// <param name="scale">The scale.</param>
        /// <param name="densityOrMass">The density or target mass value.</param>
        /// <param name="isDensity">
        /// If set to <see langword="true"/> <paramref name="densityOrMass"/> is interpreted as density;
        /// otherwise, <paramref name="densityOrMass"/> is interpreted as the desired target mass.
        /// </param>
        /// <param name="relativeDistanceThreshold">The relative distance threshold.</param>
        /// <param name="iterationLimit">
        /// The iteration limit. Can be -1 or 0 to use an approximation.
        /// </param>
        /// <returns>
        /// A new <see cref="MassFrame"/> instance.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="shape"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="densityOrMass"/> is negative or 0.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="relativeDistanceThreshold"/> is negative.
        /// </exception>
        private static MassFrame ComputeMassProperties(Shape shape, Vector3F scale, float densityOrMass, bool isDensity, float relativeDistanceThreshold, int iterationLimit)
        {
            if (shape == null)
            {
                throw new ArgumentNullException("shape");
            }
            if (densityOrMass <= 0)
            {
                throw new ArgumentOutOfRangeException("densityOrMass", "Density and mass must be greater than 0.");
            }
            if (relativeDistanceThreshold < 0)
            {
                throw new ArgumentOutOfRangeException("relativeDistanceThreshold", "Relative distance threshold must not be negative.");
            }

            // Call MassHelper to compute mass, COM and inertia matrix (not diagonalized).
            float     mass;
            Vector3F  centerOfMass;
            Matrix33F inertia;

            MassHelper.GetMass(shape, scale, densityOrMass, isDensity, relativeDistanceThreshold, iterationLimit,
                               out mass, out centerOfMass, out inertia);

            // If anything is NaN, we use default values for a static/kinematic body.
            if (Numeric.IsNaN(mass) || centerOfMass.IsNaN || inertia.IsNaN)
            {
                return new MassFrame {
                           Mass = 0, Inertia = Vector3F.Zero
                }
            }
            ;

            if (!Numeric.IsZero(inertia.M01) || !Numeric.IsZero(inertia.M02) || !Numeric.IsZero(inertia.M12))
            {
                // Inertia off-diagonal elements are not 0.
                // --> Have to make inertia a diagonal matrix.
                Vector3F inertiaDiagonal;

                Matrix33F rotation;
                MassHelper.DiagonalizeInertia(inertia, out inertiaDiagonal, out rotation);

                MassFrame massFrame = new MassFrame
                {
                    Mass    = mass,
                    Inertia = inertiaDiagonal,
                    Pose    = new Pose(centerOfMass, rotation),
                    Density = isDensity ? densityOrMass : 0
                };
                return(massFrame);
            }
            else
            {
                // Inertia is already a diagonal matrix.
                MassFrame massFrame = new MassFrame
                {
                    Mass    = mass,
                    Inertia = new Vector3F(inertia.M00, inertia.M11, inertia.M22),
                    Pose    = new Pose(centerOfMass),
                    Density = isDensity ? densityOrMass : 0
                };
                return(massFrame);
            }
        }
Ejemplo n.º 55
0
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Vector3F obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }
Ejemplo n.º 56
0
 /// <summary>
 /// Computes a mass frame for the given shape and density.
 /// </summary>
 /// <param name="shape">The shape.</param>
 /// <param name="scale">The scale of the shape.</param>
 /// <param name="density">The density.</param>
 /// <param name="relativeDistanceThreshold">
 /// The relative distance threshold. If no mass or inertia formula for the given shape are known
 /// the shape is approximated with a triangle mesh and the mass frame of this mesh is returned.
 /// The relative distance threshold controls the accuracy of the approximated mesh. Good default
 /// values are 0.05 to get an approximation with an error of about 5%.
 /// </param>
 /// <param name="iterationLimit">
 /// The iteration limit. For some shapes the mass properties are computed with an iterative
 /// algorithm. No more than <paramref name="iterationLimit"/> iterations will be performed.
 /// A value of 3 gives good results in most cases. Use a value of -1 to get only a coarse
 /// approximation.
 /// </param>
 /// <returns>
 /// A new <see cref="MassFrame"/> for the given parameters is returned.
 /// </returns>
 /// <remarks>
 /// <strong>Composite shapes:</strong> If the given <paramref name="shape"/> is a
 /// <see cref="CompositeShape"/>, the computed mass properties are only correct if the children
 /// of the composite shape do not overlap. Overlapping parts are counted twice and so the result
 /// will not be correct. If a child of a composite shape is a <see cref="RigidBody"/> the
 /// <see cref="MassFrame"/> of the rigid body will be used for this child.
 /// </remarks>
 /// <exception cref="ArgumentNullException">
 /// <paramref name="shape"/> is <see langword="null"/>.
 /// </exception>
 /// <exception cref="ArgumentOutOfRangeException">
 /// <paramref name="density"/> is negative or 0.
 /// </exception>
 /// <exception cref="ArgumentOutOfRangeException">
 /// <paramref name="relativeDistanceThreshold"/> is negative.
 /// </exception>
 public static MassFrame FromShapeAndDensity(Shape shape, Vector3F scale, float density, float relativeDistanceThreshold, int iterationLimit)
 {
     return(ComputeMassProperties(shape, scale, density, true, relativeDistanceThreshold, iterationLimit));
 }
Ejemplo n.º 57
0
 public VsIn(Vector3F position, Vector2F textureCoordinate)
 {
     Position          = position;
     TextureCoordinate = textureCoordinate;
 }
Ejemplo n.º 58
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Segment"/> class.
 /// </summary>
 /// <param name="p0">A <see cref="Vector3F"/> instance marking the segment's starting point.</param>
 /// <param name="p1">A <see cref="Vector3F"/> instance marking the segment's ending point.</param>
 public Segment(Vector3F p0, Vector3F p1)
 {
     _p0 = p0;
     _p1 = p1;
 }
Ejemplo n.º 59
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Triangle"/> class using a given Triangle.
 /// </summary>
 /// <param name="t">A <see cref="Triangle"/> instance.</param>
 public Triangle(Triangle t)
 {
     _p0 = t._p0;
     _p1 = t._p1;
     _p2 = t._p2;
 }
Ejemplo n.º 60
0
        /// <inheritdoc/>
        /// <exception cref="ArgumentException">
        /// Neither <paramref name="objectA"/> nor <paramref name="objectB"/> contains a
        /// <see cref="HeightField"/>.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="objectA"/> or <paramref name="objectB"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// <paramref name="objectA"/> or <paramref name="objectB"/> contains a
        /// <see cref="HeightField"/> with a negative scaling. Computing collisions for height fields
        /// with a negative scaling is not supported.
        /// </exception>
        public override float GetTimeOfImpact(CollisionObject objectA, Pose targetPoseA, CollisionObject objectB, Pose targetPoseB, float allowedPenetration)
        {
            if (objectA == null)
            {
                throw new ArgumentNullException("objectA");
            }
            if (objectB == null)
            {
                throw new ArgumentNullException("objectB");
            }

            // Object A should be the height field, swap objects if necessary.
            if (!(objectA.GeometricObject.Shape is HeightField))
            {
                MathHelper.Swap(ref objectA, ref objectB);
                MathHelper.Swap(ref targetPoseA, ref targetPoseB);
            }

            IGeometricObject geometricObjectA = objectA.GeometricObject;
            IGeometricObject geometricObjectB = objectB.GeometricObject;

            HeightField heightFieldA = geometricObjectA.Shape as HeightField;

            // Check if collision object shapes are correct.
            if (heightFieldA == null)
            {
                throw new ArgumentException("One object must be a height field.");
            }

            // Height field vs height field makes no sense.
            if (objectB.GeometricObject.Shape is HeightField)
            {
                return(1);
            }

            Pose     startPoseA = geometricObjectA.Pose;
            Pose     startPoseB = geometricObjectB.Pose;
            Vector3F scaleA     = geometricObjectA.Scale;
            Vector3F scaleB     = geometricObjectB.Scale;

            // We do not support negative scaling (see comments in ComputeCollision).
            if (scaleA.X < 0 || scaleA.Y < 0 || scaleA.Z < 0)
            {
                throw new NotSupportedException("Computing collisions for height fields with a negative scaling is not supported.");
            }

            // Get an AABB of the swept B in the space of A.
            // This simplified AABB can miss some rotational movement.
            // To simplify, we assume that A is static and B is moving relative to A.
            // In general, this is not correct! But for CCD we make this simplification.
            // We convert everything to the space of A.
            var aabbSweptBInA = geometricObjectB.Shape.GetAabb(scaleB, startPoseA.Inverse * startPoseB);

            aabbSweptBInA.Grow(geometricObjectB.Shape.GetAabb(scaleB, targetPoseA.Inverse * targetPoseB));

            // Use temporary object.
            var triangleShape = ResourcePools.TriangleShapes.Obtain();
            // (Vertices will be set in the loop below.)

            var testGeometricObject = TestGeometricObject.Create();

            testGeometricObject.Shape = triangleShape;
            testGeometricObject.Scale = Vector3F.One;
            testGeometricObject.Pose  = startPoseA;

            var testCollisionObject = ResourcePools.TestCollisionObjects.Obtain();

            testCollisionObject.SetInternal(objectA, testGeometricObject);

            var collisionAlgorithm = CollisionDetection.AlgorithmMatrix[typeof(TriangleShape), geometricObjectB.Shape.GetType()];

            // Get height field and basic info.
            int arrayLengthX = heightFieldA.NumberOfSamplesX;
            int arrayLengthZ = heightFieldA.NumberOfSamplesZ;

            Debug.Assert(arrayLengthX > 1 && arrayLengthZ > 1, "A height field should contain at least 2 x 2 elements (= 1 cell).");
            float cellWidthX = heightFieldA.WidthX * scaleA.X / (arrayLengthX - 1);
            float cellWidthZ = heightFieldA.WidthZ * scaleA.Z / (arrayLengthZ - 1);

            float originX = heightFieldA.OriginX;
            float originZ = heightFieldA.OriginZ;

            // ----- Compute the cell indices for the AABB.
            // Estimate start and end indices from our search distance.
            int xIndexStartEstimated = (int)((aabbSweptBInA.Minimum.X - originX) / cellWidthX);
            int xIndexEndEstimated   = (int)((aabbSweptBInA.Maximum.X - originX) / cellWidthX);
            int zIndexStartEstimated = (int)((aabbSweptBInA.Minimum.Z - originZ) / cellWidthZ);
            int zIndexEndEstimated   = (int)((aabbSweptBInA.Maximum.Z - originZ) / cellWidthZ);

            // Clamp indices to valid range.
            int xIndexMax = arrayLengthX - 2;
            int zIndexMax = arrayLengthZ - 2;

            int xIndexStart = Math.Max(xIndexStartEstimated, 0);
            int xIndexEnd   = Math.Min(xIndexEndEstimated, xIndexMax);
            int zIndexStart = Math.Max(zIndexStartEstimated, 0);
            int zIndexEnd   = Math.Min(zIndexEndEstimated, zIndexMax);

            float timeOfImpact = 1;

            for (int xIndex = xIndexStart; xIndex <= xIndexEnd; xIndex = Math.Max(xIndexStart, xIndex + 1))
            {
                for (int zIndex = zIndexStart; zIndex <= zIndexEnd; zIndex = Math.Max(zIndexStart, zIndex + 1))
                {
                    // Test the two cell triangles.
                    for (int triangleIndex = 0; triangleIndex < 2; triangleIndex++)
                    {
                        // Get triangle 0 or 1.
                        var triangle = heightFieldA.GetTriangle(xIndex, zIndex, triangleIndex != 0);

                        // Apply scale.
                        triangle.Vertex0 = triangle.Vertex0 * scaleA;
                        triangle.Vertex1 = triangle.Vertex1 * scaleA;
                        triangle.Vertex2 = triangle.Vertex2 * scaleA;

                        // Make AABB test of triangle vs. sweep of B.
                        if (!GeometryHelper.HaveContact(aabbSweptBInA, triangle.Aabb))
                        {
                            continue;
                        }

                        triangleShape.Vertex0 = triangle.Vertex0;
                        triangleShape.Vertex1 = triangle.Vertex1;
                        triangleShape.Vertex2 = triangle.Vertex2;

                        float triangleTimeOfImpact = collisionAlgorithm.GetTimeOfImpact(
                            testCollisionObject,
                            targetPoseA,
                            objectB,
                            targetPoseB,
                            allowedPenetration);

                        timeOfImpact = Math.Min(timeOfImpact, triangleTimeOfImpact);
                    }
                }
            }

            // Recycle temporary objects.
            ResourcePools.TestCollisionObjects.Recycle(testCollisionObject);
            testGeometricObject.Recycle();
            ResourcePools.TriangleShapes.Recycle(triangleShape);

            return(timeOfImpact);
        }