Beispiel #1
0
        /// <summary>
        /// Rotates the view direction up or down relative to the locked up vector.
        /// </summary>
        /// <param name="radians">Amount to rotate.</param>
        public void Pitch(float radians)
        {
            //Do not allow the new view direction to violate the maximum pitch.
            float dot;

            Vector3.Dot(ref viewDirection, ref lockedUp, out dot);

            //While this could be rephrased in terms of dot products alone, converting to actual angles can be more intuitive.
            //Consider +Pi/2 to be up, and -Pi/2 to be down.
            float currentPitch = (float)Math.Acos(MathHelper.Clamp(-dot, -1, 1)) - MathHelper.PiOver2;
            //Compute our new pitch by clamping the current + change.
            float newPitch      = MathHelper.Clamp(currentPitch + radians, -maximumPitch, maximumPitch);
            float allowedChange = newPitch - currentPitch;

            //Compute and apply the rotation.
            Vector3 pitchAxis;

            Vector3.Cross(ref viewDirection, ref lockedUp, out pitchAxis);
            //This is guaranteed safe by all interaction points stopping viewDirection from being aligned with lockedUp.
            pitchAxis.Normalize();
            Matrix3x3 rotation;

            Matrix3x3.CreateFromAxisAngle(ref pitchAxis, allowedChange, out rotation);
            Matrix3x3.Transform(ref viewDirection, ref rotation, out viewDirection);

            //Avoid drift by renormalizing.
            viewDirection.Normalize();
        }
        /// <summary>
        /// Constructs a new demo.
        /// </summary>
        /// <param name="game">Game owning this demo.</param>
        public AddRemoveStressDemo(DemosGame game)
            : base(game)
        {
            Space.Remove(vehicle.Vehicle);

            var compoundShape = new CompoundShape(new List <CompoundShapeEntry>
            {
                new CompoundShapeEntry(new BoxShape(1, 1, 1), new Vector3(0, 1, 0), 1),
                new CompoundShapeEntry(new BoxShape(2, 1, 2), new Vector3(), 1),
                new CompoundShapeEntry(new BoxShape(1, 1, 1), new Vector3(0, -1, 0), 1)
            });

            for (int i = 0; i < 300; ++i)
            {
                var toAdd = new Entity(compoundShape, 10);
                addedEntities.Add(toAdd);
            }

            var boxShape = new BoxShape(1, 1, 1);

            for (int i = 0; i < 300; ++i)
            {
                var toAdd = new Entity(boxShape, 10);
                addedEntities.Add(toAdd);
            }

            Vector3[] vertices;
            int[]     indices;
            ModelDataExtractor.GetVerticesAndIndicesFromModel(game.Content.Load <Model>("cube"), out vertices, out indices);
            var mobileMeshShape = new MobileMeshShape(vertices, indices, new AffineTransform(Matrix3x3.CreateScale(1, 2, 1), new Vector3()), MobileMeshSolidity.Counterclockwise);

            for (int i = 0; i < 300; ++i)
            {
                var toAdd = new Entity(mobileMeshShape, 10);
                addedEntities.Add(toAdd);
            }

            for (int i = 0; i < addedEntities.Count; ++i)
            {
                var entity = addedEntities[i];
                entity.Gravity        = new Vector3();
                entity.Position       = GetRandomPosition(random);
                entity.LinearVelocity = 3 * Vector3.Normalize(entity.Position);
                Space.Add(entity);
            }


            var playgroundModel = game.Content.Load <Model>("playground");

            ModelDataExtractor.GetVerticesAndIndicesFromModel(playgroundModel, out vertices, out indices);
            var staticMesh = new StaticMesh(vertices, indices, new AffineTransform(Matrix3x3.CreateFromAxisAngle(Vector3.Up, MathHelper.Pi), new Vector3(0, -30, 0)));

            staticMesh.Sidedness = TriangleSidedness.Counterclockwise;

            Space.Add(staticMesh);
            game.ModelDrawer.Add(staticMesh);

            game.Camera.Position = new Vector3(0, 6, 15);
        }
Beispiel #3
0
        /// <summary>
        /// Rotates the camera around its locked up vector.
        /// </summary>
        /// <param name="radians">Amount to rotate.</param>
        public void Yaw(float radians)
        {
            //Rotate around the up vector.
            Matrix3x3 rotation;

            Matrix3x3.CreateFromAxisAngle(ref lockedUp, radians, out rotation);
            Matrix3x3.Transform(ref viewDirection, ref rotation, out viewDirection);

            //Avoid drift by renormalizing.
            viewDirection.Normalize();
        }
Beispiel #4
0
    // Use this for initialization
    public override void XStart()
    {
        if (!isInit)
        {
            meshfilter = transform.GetComponent <MeshFilter>();
            position   = meshfilter.transform.position;
            rotation   = meshfilter.transform.rotation;
            mesh       = meshfilter.sharedMesh;

            if (transform.GetComponent <Rigidbody>() != null)
            {
                rigid = transform.GetComponent <Rigidbody>();
                mass  = rigid.mass;
            }

            List <BEPUutilities.Vector3> vertices = new List <BEPUutilities.Vector3>();
            int[] indices = new int[mesh.GetIndexCount(0)];
            indices = mesh.GetIndices(0);

            for (int i = 0; i < mesh.vertices.Length; i++)
            {
                vertices.Add(mesh.vertices[i].ToBEPU());
            }

            entity = new BEPUphysics.Entities.Prefabs.MobileMesh(vertices.ToArray(), indices,
                                                                 new AffineTransform(Matrix3x3.CreateFromAxisAngle(BEPUutilities.Vector3.Up, MathHelper.Pi),
                                                                                     new BEPUutilities.Vector3(0, -10, 0)), BEPUphysics.CollisionShapes.MobileMeshSolidity.Solid);

            entity.Orientation    = rotation.ToBEPU();
            entity.LinearDamping  = damping;
            entity.AngularDamping = angdamping;
            PhysicsManagerBehavior.Space.Add(entity);

            this.enabled = false;
            isInit       = true;
        }
    }
        public override void Update(Fix64 dt)
        {
            if (Game.KeyboardInput.IsKeyDown(Keys.Left))
            {
                rayCastDirection = Matrix3x3.Transform(rayCastDirection, Matrix3x3.CreateFromAxisAngle(Vector3.Forward, .01m));
            }
            if (Game.KeyboardInput.IsKeyDown(Keys.Right))
            {
                rayCastDirection = Matrix3x3.Transform(rayCastDirection, Matrix3x3.CreateFromAxisAngle(Vector3.Forward, -.01m));
            }
            if (Game.KeyboardInput.IsKeyDown(Keys.Down))
            {
                rayCastDirection = Matrix3x3.Transform(rayCastDirection, Matrix3x3.CreateFromAxisAngle(Vector3.Right, .01m));
            }
            if (Game.KeyboardInput.IsKeyDown(Keys.Up))
            {
                rayCastDirection = Matrix3x3.Transform(rayCastDirection, Matrix3x3.CreateFromAxisAngle(Vector3.Right, -.01m));
            }


            if (Game.KeyboardInput.IsKeyDown(Keys.P))
            {
                Debug.WriteLine("Break.");
            }

            base.Update(dt);

            RigidTransform localTransformB;
            RigidTransform aTransform = a.CollisionInformation.WorldTransform, bTransform = b.CollisionInformation.WorldTransform;

            MinkowskiToolbox.GetLocalTransform(ref aTransform, ref bTransform, out localTransformB);

            Vector3 position;

            if (MPRToolbox.GetLocalOverlapPosition((a.CollisionInformation.Shape as ConvexShape), (b.CollisionInformation.Shape as ConvexShape), ref localTransformB, out position))
            {
                //Vector3 rayCastDirection = new Vector3(1,0,0);// (Vector3.Normalize(localDirection) + Vector3.Normalize(collidableB.worldTransform.Position - collidableA.worldTransform.Position)) / 2;
                Fix64   previousT;
                Vector3 previousNormal;
                Fix64   t;
                Vector3 normal;

                rayCastDirection = localTransformB.Position;
                MPRToolbox.LocalSurfaceCast((a.CollisionInformation.Shape as ConvexShape), (b.CollisionInformation.Shape as ConvexShape), ref localTransformB, ref rayCastDirection, out previousT, out previousNormal);
                //Vector3 secondDirection = Vector3.Cross(rayCastDirection, Vector3.Up);
                //MPRTesting.LocalSurfaceCast((a.CollisionInformation.Shape as ConvexShape), (b.CollisionInformation.Shape as ConvexShape), ref localTransformB, ref secondDirection, out t, out normal);
                //if (t < previousT)
                //{
                //    previousNormal = normal;
                //    previousT = t;
                //}
                //Vector3 thirdDirection = Vector3.Cross(secondDirection, rayCastDirection);
                //MPRTesting.LocalSurfaceCast((a.CollisionInformation.Shape as ConvexShape), (b.CollisionInformation.Shape as ConvexShape), ref localTransformB, ref thirdDirection, out t, out normal);
                //if (t < previousT)
                //{
                //    previousNormal = normal;
                //    previousT = t;
                //}
                //Vector3 fourthDirection = -secondDirection;
                //MPRTesting.LocalSurfaceCast((a.CollisionInformation.Shape as ConvexShape), (b.CollisionInformation.Shape as ConvexShape), ref localTransformB, ref fourthDirection, out t, out normal);
                //if (t < previousT)
                //{
                //    previousNormal = normal;
                //    previousT = t;
                //}
                //Vector3 fifthDirection = -thirdDirection;
                //MPRTesting.LocalSurfaceCast((a.CollisionInformation.Shape as ConvexShape), (b.CollisionInformation.Shape as ConvexShape), ref localTransformB, ref fifthDirection, out t, out normal);
                //if (t < previousT)
                //{
                //    previousNormal = normal;
                //    previousT = t;
                //}

                //Correct the penetration depth.

                MPRToolbox.LocalSurfaceCast((a.CollisionInformation.Shape as ConvexShape), (b.CollisionInformation.Shape as ConvexShape), ref localTransformB, ref previousNormal, out t, out normal);
                contactDepth  = t;
                contactNormal = previousNormal;

                ////Converge to local minimum.
                //while (true)
                //{
                //    MPRTesting.LocalSurfaceCast((a.CollisionInformation.Shape as ConvexShape), (b.CollisionInformation.Shape as ConvexShape), ref localTransformB, ref previousNormal, out t, out normal);
                //    if (previousT - t <= Toolbox.BigEpsilon)
                //        break;

                //    previousT = t;
                //    previousNormal = normal;
                //}
            }

            #region Box Box minkowski sum
            ////Construct explicit minkowski sum.
            //Vector3[] aLines = new Vector3[8];
            //aLines[0] = new Vector3(-boxWidth / 2, -boxHeight / 2, -boxLength / 2);
            //aLines[1] = new Vector3(-boxWidth / 2, -boxHeight / 2, boxLength / 2);
            //aLines[2] = new Vector3(-boxWidth / 2, boxHeight / 2, -boxLength / 2);
            //aLines[3] = new Vector3(-boxWidth / 2, boxHeight / 2, boxLength / 2);
            //aLines[4] = new Vector3(boxWidth / 2, -boxHeight / 2, -boxLength / 2);
            //aLines[5] = new Vector3(boxWidth / 2, -boxHeight / 2, boxLength / 2);
            //aLines[6] = new Vector3(boxWidth / 2, boxHeight / 2, -boxLength / 2);
            //aLines[7] = new Vector3(boxWidth / 2, boxHeight / 2, boxLength / 2);

            //Vector3[] bLines = new Vector3[8];
            //bLines[0] = new Vector3(-groundWidth / 2, -groundHeight / 2, -groundLength / 2);
            //bLines[1] = new Vector3(-groundWidth / 2, -groundHeight / 2, groundLength / 2);
            //bLines[2] = new Vector3(-groundWidth / 2, groundHeight / 2, -groundLength / 2);
            //bLines[3] = new Vector3(-groundWidth / 2, groundHeight / 2, groundLength / 2);
            //bLines[4] = new Vector3(groundWidth / 2, -groundHeight / 2, -groundLength / 2);
            //bLines[5] = new Vector3(groundWidth / 2, -groundHeight / 2, groundLength / 2);
            //bLines[6] = new Vector3(groundWidth / 2, groundHeight / 2, -groundLength / 2);
            //bLines[7] = new Vector3(groundWidth / 2, groundHeight / 2, groundLength / 2);

            //for (int i = 0; i < 8; i++)
            //    aLines[i] = Vector3.Transform(aLines[i], localTransformB.Matrix);

            //List<Vector3> vertices = new List<Vector3>();
            //for (int i = 0; i < 8; i++)
            //{
            //    for (int j = 0; j < 8; j++)
            //    {

            //        if (b.CollisionInformation.Pairs.Count > 0)
            //        {
            //            if (b.CollisionInformation.Pairs[0].BroadPhaseOverlap.EntryA == b.CollisionInformation)
            //                vertices.Add(aLines[i] - bLines[j]);
            //            else
            //                vertices.Add(bLines[i] - aLines[j]);
            //        }
            //        else
            //        {
            //            vertices.Add(bLines[i] - aLines[j]);
            //        }
            //    }
            //}

            //var indices = new List<int>();
            //Toolbox.GetConvexHull(vertices, indices);
            #endregion

            #region Arbitrary minkowski sum
            var     vertices = new List <Vector3>();
            Vector3 max;
            var     direction   = new Vector3();
            int     NumSamples  = 16;
            Fix64   angleChange = MathHelper.TwoPi / NumSamples;

            for (int i = 1; i < NumSamples / 2 - 1; i++)
            {
                Fix64 phi    = MathHelper.PiOver2 - i * angleChange;
                var   sinPhi = Fix64.Sin(phi);
                var   cosPhi = Fix64.Cos(phi);
                for (int j = 0; j < NumSamples; j++)
                {
                    Fix64 theta = j * angleChange;
                    direction.X = Fix64.Cos(theta) * cosPhi;
                    direction.Y = sinPhi;
                    direction.Z = Fix64.Sin(theta) * cosPhi;


                    MinkowskiToolbox.GetLocalMinkowskiExtremePoint(a.CollisionInformation.Shape as ConvexShape, b.CollisionInformation.Shape as ConvexShape, ref direction, ref localTransformB, out max);

                    vertices.Add(max);
                }
            }


            MinkowskiToolbox.GetLocalMinkowskiExtremePoint(a.CollisionInformation.Shape as ConvexShape, b.CollisionInformation.Shape as ConvexShape, ref Toolbox.UpVector, ref localTransformB, out max);
            vertices.Add(max);
            MinkowskiToolbox.GetLocalMinkowskiExtremePoint(a.CollisionInformation.Shape as ConvexShape, b.CollisionInformation.Shape as ConvexShape, ref Toolbox.DownVector, ref localTransformB, out max);
            vertices.Add(max);



            var indices = new List <int>();
            ConvexHullHelper.GetConvexHull(vertices, indices);
            #endregion

            minkowskiLines.Clear();
            for (int i = 0; i < indices.Count; i += 3)
            {
                minkowskiLines.Add(new VertexPositionColor(MathConverter.Convert(vertices[indices[i]]), Microsoft.Xna.Framework.Color.Blue));
                minkowskiLines.Add(new VertexPositionColor(MathConverter.Convert(vertices[indices[i + 1]]), Microsoft.Xna.Framework.Color.Blue));

                minkowskiLines.Add(new VertexPositionColor(MathConverter.Convert(vertices[indices[i + 1]]), Microsoft.Xna.Framework.Color.Blue));
                minkowskiLines.Add(new VertexPositionColor(MathConverter.Convert(vertices[indices[i + 2]]), Microsoft.Xna.Framework.Color.Blue));

                minkowskiLines.Add(new VertexPositionColor(MathConverter.Convert(vertices[indices[i + 2]]), Microsoft.Xna.Framework.Color.Blue));
                minkowskiLines.Add(new VertexPositionColor(MathConverter.Convert(vertices[indices[i]]), Microsoft.Xna.Framework.Color.Blue));
            }
        }
Beispiel #6
0
        ///<summary>
        /// Performs the frame's configuration step.
        ///</summary>
        ///<param name="dt">Timestep duration.</param>
        public override void Update(float dt)
        {
            //Transform the axes into world space.
            basis.rotationMatrix4 = connectionA.orientationMatrix4;
            basis.ComputeWorldSpaceAxes();
            Matrix3x3.Transform(ref localTestAxis, ref connectionB.orientationMatrix4, out worldTestAxis);

            //Compute the plane normals.
            Vector3 minPlaneNormal, maxPlaneNormal;
            //Rotate basisA y axis around the basisA primary axis.
            Matrix3x3 rotation;

            Matrix3x3.CreateFromAxisAngle(ref basis.primaryAxis, minimumAngle + MathHelper.PiOver2, out rotation);
            Matrix3x3.Transform(ref basis.xAxis, ref rotation, out minPlaneNormal);
            Matrix3x3.CreateFromAxisAngle(ref basis.primaryAxis, maximumAngle - MathHelper.PiOver2, out rotation);
            Matrix3x3.Transform(ref basis.xAxis, ref rotation, out maxPlaneNormal);

            //Compute the errors along the two normals.
            float planePositionMin, planePositionMax;

            Vector3.Dot(ref minPlaneNormal, ref worldTestAxis, out planePositionMin);
            Vector3.Dot(ref maxPlaneNormal, ref worldTestAxis, out planePositionMax);


            float span = GetDistanceFromMinimum(maximumAngle);

            //Early out and compute the determine the plane normal.
            if (span >= MathHelper.Pi)
            {
                if (planePositionMax > 0 || planePositionMin > 0)
                {
                    //It's in a perfectly valid configuration, so skip.
                    isActiveInSolver   = false;
                    minIsActive        = false;
                    maxIsActive        = false;
                    error              = Vector2.Zero;
                    accumulatedImpulse = Vector2.Zero;
                    isLimitActive      = false;
                    return;
                }

                if (planePositionMax > planePositionMin)
                {
                    //It's quicker to escape out to the max plane than the min plane.
                    error.X = 0;
                    error.Y = -planePositionMax;
                    accumulatedImpulse.X = 0;
                    minIsActive          = false;
                    maxIsActive          = true;
                }
                else
                {
                    //It's quicker to escape out to the min plane than the max plane.
                    error.X = -planePositionMin;
                    error.Y = 0;
                    accumulatedImpulse.Y = 0;
                    minIsActive          = true;
                    maxIsActive          = false;
                }
                //There's never a non-degenerate situation where having both planes active with a span
                //greater than pi is useful.
            }
            else
            {
                if (planePositionMax > 0 && planePositionMin > 0)
                {
                    //It's in a perfectly valid configuration, so skip.
                    isActiveInSolver   = false;
                    minIsActive        = false;
                    maxIsActive        = false;
                    error              = Vector2.Zero;
                    accumulatedImpulse = Vector2.Zero;
                    isLimitActive      = false;
                    return;
                }

                if (planePositionMin <= 0 && planePositionMax <= 0)
                {
                    //Escape upward.
                    //Activate both planes.
                    error.X     = -planePositionMin;
                    error.Y     = -planePositionMax;
                    minIsActive = true;
                    maxIsActive = true;
                }
                else if (planePositionMin <= 0)
                {
                    //It's quicker to escape out to the min plane than the max plane.
                    error.X = -planePositionMin;
                    error.Y = 0;
                    accumulatedImpulse.Y = 0;
                    minIsActive          = true;
                    maxIsActive          = false;
                }
                else
                {
                    //It's quicker to escape out to the max plane than the min plane.
                    error.X = 0;
                    error.Y = -planePositionMax;
                    accumulatedImpulse.X = 0;
                    minIsActive          = false;
                    maxIsActive          = true;
                }
            }
            isLimitActive = true;


            //****** VELOCITY BIAS ******//
            //Compute the correction velocity
            float errorReduction;

            springSettings.ComputeErrorReductionAndSoftness(dt, 1 / dt, out errorReduction, out softness);

            //Compute the jacobians
            if (minIsActive)
            {
                Vector3.Cross(ref minPlaneNormal, ref worldTestAxis, out jacobianMinA);
                if (jacobianMinA.LengthSquared < Toolbox.Epsilon)
                {
                    //The plane normal is aligned with the test axis.
                    //Use the basis's free axis.
                    jacobianMinA = basis.primaryAxis;
                }
                jacobianMinA.Normalize();
                jacobianMinB.X = -jacobianMinA.X;
                jacobianMinB.Y = -jacobianMinA.Y;
                jacobianMinB.Z = -jacobianMinA.Z;
            }
            if (maxIsActive)
            {
                Vector3.Cross(ref maxPlaneNormal, ref worldTestAxis, out jacobianMaxA);
                if (jacobianMaxA.LengthSquared < Toolbox.Epsilon)
                {
                    //The plane normal is aligned with the test axis.
                    //Use the basis's free axis.
                    jacobianMaxA = basis.primaryAxis;
                }
                jacobianMaxA.Normalize();
                jacobianMaxB.X = -jacobianMaxA.X;
                jacobianMaxB.Y = -jacobianMaxA.Y;
                jacobianMaxB.Z = -jacobianMaxA.Z;
            }

            //Error is always positive
            if (minIsActive)
            {
                biasVelocity.X = MathHelper.Min(MathHelper.Max(0, error.X - margin) * errorReduction, maxCorrectiveVelocity);
                if (bounciness > 0)
                {
                    float relativeVelocity;
                    float dot;
                    //Find the velocity contribution from each connection
                    Vector3.Dot(ref connectionA.angularVelocity, ref jacobianMinA, out relativeVelocity);
                    Vector3.Dot(ref connectionB.angularVelocity, ref jacobianMinB, out dot);
                    relativeVelocity += dot;
                    biasVelocity.X    = MathHelper.Max(biasVelocity.X, ComputeBounceVelocity(-relativeVelocity));
                }
            }
            if (maxIsActive)
            {
                biasVelocity.Y = MathHelper.Min(MathHelper.Max(0, error.Y - margin) * errorReduction, maxCorrectiveVelocity);
                if (bounciness > 0)
                {
                    //Find the velocity contribution from each connection
                    if (maxIsActive)
                    {
                        float relativeVelocity;
                        Vector3.Dot(ref connectionA.angularVelocity, ref jacobianMaxA, out relativeVelocity);
                        float dot;
                        Vector3.Dot(ref connectionB.angularVelocity, ref jacobianMaxB, out dot);
                        relativeVelocity += dot;
                        biasVelocity.Y    = MathHelper.Max(biasVelocity.Y, ComputeBounceVelocity(-relativeVelocity));
                    }
                }
            }


            //****** EFFECTIVE MASS Matrix4 ******//
            //Connection A's contribution to the mass Matrix4
            float   minEntryA, minEntryB;
            float   maxEntryA, maxEntryB;
            Vector3 transformedAxis;

            if (connectionA.isDynamic)
            {
                if (minIsActive)
                {
                    Matrix3x3.Transform(ref jacobianMinA, ref connectionA.inertiaTensorInverse, out transformedAxis);
                    Vector3.Dot(ref transformedAxis, ref jacobianMinA, out minEntryA);
                }
                else
                {
                    minEntryA = 0;
                }
                if (maxIsActive)
                {
                    Matrix3x3.Transform(ref jacobianMaxA, ref connectionA.inertiaTensorInverse, out transformedAxis);
                    Vector3.Dot(ref transformedAxis, ref jacobianMaxA, out maxEntryA);
                }
                else
                {
                    maxEntryA = 0;
                }
            }
            else
            {
                minEntryA = 0;
                maxEntryA = 0;
            }
            //Connection B's contribution to the mass Matrix4
            if (connectionB.isDynamic)
            {
                if (minIsActive)
                {
                    Matrix3x3.Transform(ref jacobianMinB, ref connectionB.inertiaTensorInverse, out transformedAxis);
                    Vector3.Dot(ref transformedAxis, ref jacobianMinB, out minEntryB);
                }
                else
                {
                    minEntryB = 0;
                }
                if (maxIsActive)
                {
                    Matrix3x3.Transform(ref jacobianMaxB, ref connectionB.inertiaTensorInverse, out transformedAxis);
                    Vector3.Dot(ref transformedAxis, ref jacobianMaxB, out maxEntryB);
                }
                else
                {
                    maxEntryB = 0;
                }
            }
            else
            {
                minEntryB = 0;
                maxEntryB = 0;
            }
            //Compute the inverse mass Matrix4
            //Notice that the mass Matrix4 isn't linked, it's two separate ones.
            velocityToImpulse.X = 1 / (softness + minEntryA + minEntryB);
            velocityToImpulse.Y = 1 / (softness + maxEntryA + maxEntryB);
        }
        /// <summary>
        /// Constructs a new demo.
        /// </summary>
        /// <param name="game">Game owning this demo.</param>
        public StaticMeshDemo(DemosGame game)
            : base(game)
        {
            //Load in mesh data and create the collision mesh.
            Vector3[] staticTriangleVertices;
            int[]     staticTriangleIndices;

            var playgroundModel = game.Content.Load <Model>("playground");

            //This is a little convenience method used to extract vertices and indices from a model.
            //It doesn't do anything special; any approach that gets valid vertices and indices will work.
            ModelDataExtractor.GetVerticesAndIndicesFromModel(playgroundModel, out staticTriangleVertices, out staticTriangleIndices);
            var staticMesh = new StaticMesh(staticTriangleVertices, staticTriangleIndices, new AffineTransform(Matrix3x3.CreateFromAxisAngle(Vector3.Up, MathHelper.Pi), new Vector3(0, -10, 0)));

            staticMesh.Sidedness = TriangleSidedness.Counterclockwise;

            Space.Add(staticMesh);
            game.ModelDrawer.Add(staticMesh);


            //Dump some boxes on top of it for fun.
            int   numColumns = 8;
            int   numRows    = 8;
            int   numHigh    = 1;
            Fix64 separation = 8;

            for (int i = 0; i < numRows; i++)
            {
                for (int j = 0; j < numColumns; j++)
                {
                    for (int k = 0; k < numHigh; k++)
                    {
                        var toAdd = new Box(
                            new Vector3(
                                separation * i - numRows * separation / 2,
                                30 + k * separation,
                                separation * j - numColumns * separation / 2),
                            2, 2, 2, 15);
                        Space.Add(toAdd);
                    }
                }
            }



            game.Camera.Position = new Vector3(0, 10, 40);
        }
        /// <summary>
        /// Constructs a new demo.
        /// </summary>
        /// <param name="game">Game owning this demo.</param>
        public DogbotDemo(DemosGame game)
            : base(game)
        {
            Entity body = new Box(new Vector3(0, 0, 0), 4, 2, 2, 20);

            Space.Add(body);

            Entity head = new Cone(body.Position + new Vector3(3.2f, .3f, 0), 1.5f, .7f, 4);

            head.OrientationMatrix = Matrix3x3.CreateFromAxisAngle(Vector3.Forward, MathHelper.PiOver2);
            Space.Add(head);

            //Attach the head to the body
            var universalJoint = new UniversalJoint(body, head, head.Position + new Vector3(-.8f, 0, 0));

            Space.Add(universalJoint);
            //Keep the head from swinging around too much.
            var angleLimit = new SwingLimit(body, head, Vector3.Right, Vector3.Right, MathHelper.PiOver4);

            Space.Add(angleLimit);

            var tail = new Box(body.Position + new Vector3(-3f, 1f, 0), 1.6f, .1f, .1f, 4);

            Space.Add(tail);
            //Keep the tail from twisting itself off.
            universalJoint = new UniversalJoint(body, tail, tail.Position + new Vector3(.8f, 0, 0));
            Space.Add(universalJoint);

            //Give 'em some floppy ears.
            var ear = new Box(head.Position + new Vector3(-.2f, 0, -.65f), .01f, .7f, .2f, 1);

            Space.Add(ear);

            var ballSocketJoint = new BallSocketJoint(head, ear, head.Position + new Vector3(-.2f, .35f, -.65f));

            Space.Add(ballSocketJoint);

            ear = new Box(head.Position + new Vector3(-.2f, 0, .65f), .01f, .7f, .3f, 1);
            Space.Add(ear);

            ballSocketJoint = new BallSocketJoint(head, ear, head.Position + new Vector3(-.2f, .35f, .65f));
            Space.Add(ballSocketJoint);


            Box              arm;
            Cylinder         shoulder;
            PointOnLineJoint pointOnLineJoint;

            //*************  First Arm   *************//
            arm = new Box(body.Position + new Vector3(-1.8f, -.5f, 1.5f), .5f, 3, .2f, 20);
            Space.Add(arm);

            shoulder = new Cylinder(body.Position + new Vector3(-1.8f, .3f, 1.25f), .1f, .7f, 10);
            shoulder.OrientationMatrix = Matrix3x3.CreateFromAxisAngle(Vector3.Right, MathHelper.PiOver2);
            Space.Add(shoulder);

            //Connect the shoulder to the body.
            var axisJoint = new RevoluteJoint(body, shoulder, shoulder.Position, Vector3.Forward);

            //Motorize the connection.
            axisJoint.Motor.IsActive = true;
            axisJoint.Motor.Settings.VelocityMotor.GoalVelocity = 1;

            Space.Add(axisJoint);

            //Connect the arm to the shoulder.
            axisJoint = new RevoluteJoint(shoulder, arm, shoulder.Position + new Vector3(0, .6f, 0), Vector3.Forward);
            Space.Add(axisJoint);

            //Connect the arm to the body.
            pointOnLineJoint = new PointOnLineJoint(arm, body, arm.Position, Vector3.Up, arm.Position + new Vector3(0, -.4f, 0));
            Space.Add(pointOnLineJoint);


            shoulder.OrientationMatrix *= Matrix3x3.CreateFromAxisAngle(Vector3.Forward, MathHelper.Pi); //Force the walker's legs out of phase.

            //*************  Second Arm   *************//
            arm = new Box(body.Position + new Vector3(1.8f, -.5f, 1.5f), .5f, 3, .2f, 20);
            Space.Add(arm);

            shoulder = new Cylinder(body.Position + new Vector3(1.8f, .3f, 1.25f), .1f, .7f, 10);
            shoulder.OrientationMatrix = Matrix3x3.CreateFromAxisAngle(Vector3.Right, MathHelper.PiOver2);
            Space.Add(shoulder);

            //Connect the shoulder to the body.
            axisJoint = new RevoluteJoint(body, shoulder, shoulder.Position, Vector3.Forward);

            //Motorize the connection.
            axisJoint.Motor.IsActive = true;
            axisJoint.Motor.Settings.VelocityMotor.GoalVelocity = 1;

            Space.Add(axisJoint);

            //Connect the arm to the shoulder.
            axisJoint = new RevoluteJoint(shoulder, arm, shoulder.Position + new Vector3(0, .6f, 0), Vector3.Forward);
            Space.Add(axisJoint);


            //Connect the arm to the body.
            pointOnLineJoint = new PointOnLineJoint(arm, body, arm.Position, Vector3.Up, arm.Position + new Vector3(0, -.4f, 0));
            Space.Add(pointOnLineJoint);

            //*************  Third Arm   *************//
            arm = new Box(body.Position + new Vector3(-1.8f, -.5f, -1.5f), .5f, 3, .2f, 20);
            Space.Add(arm);

            shoulder = new Cylinder(body.Position + new Vector3(-1.8f, .3f, -1.25f), .1f, .7f, 10);
            shoulder.OrientationMatrix = Matrix3x3.CreateFromAxisAngle(Vector3.Right, MathHelper.PiOver2);
            Space.Add(shoulder);

            //Connect the shoulder to the body.
            axisJoint = new RevoluteJoint(body, shoulder, shoulder.Position, Vector3.Forward);

            //Motorize the connection.
            axisJoint.Motor.IsActive = true;
            axisJoint.Motor.Settings.VelocityMotor.GoalVelocity = 1;

            Space.Add(axisJoint);

            //Connect the arm to the shoulder.
            axisJoint = new RevoluteJoint(shoulder, arm, shoulder.Position + new Vector3(0, .6f, 0), Vector3.Forward);
            Space.Add(axisJoint);

            //Connect the arm to the body.
            pointOnLineJoint = new PointOnLineJoint(arm, body, arm.Position, Vector3.Up, arm.Position + new Vector3(0, -.4f, 0));
            Space.Add(pointOnLineJoint);


            shoulder.OrientationMatrix *= Matrix3x3.CreateFromAxisAngle(Vector3.Forward, MathHelper.Pi); //Force the walker's legs out of phase.

            //*************  Fourth Arm   *************//
            arm = new Box(body.Position + new Vector3(1.8f, -.5f, -1.5f), .5f, 3, .2f, 20);
            Space.Add(arm);

            shoulder = new Cylinder(body.Position + new Vector3(1.8f, .3f, -1.25f), .1f, .7f, 10);
            shoulder.OrientationMatrix = Matrix3x3.CreateFromAxisAngle(Vector3.Right, MathHelper.PiOver2);
            Space.Add(shoulder);

            //Connect the shoulder to the body.
            axisJoint = new RevoluteJoint(body, shoulder, shoulder.Position, Vector3.Forward);

            //Motorize the connection.
            axisJoint.Motor.IsActive = true;
            axisJoint.Motor.Settings.VelocityMotor.GoalVelocity = 1;

            Space.Add(axisJoint);

            //Connect the arm to the shoulder.
            axisJoint = new RevoluteJoint(shoulder, arm, shoulder.Position + new Vector3(0, .6f, 0), Vector3.Forward);
            Space.Add(axisJoint);

            //Connect the arm to the body.
            pointOnLineJoint = new PointOnLineJoint(arm, body, arm.Position, Vector3.Up, arm.Position + new Vector3(0, -.4f, 0));
            Space.Add(pointOnLineJoint);

            //Add some ground.
            Space.Add(new Box(new Vector3(0, -3.5f, 0), 20f, 1, 20f));

            game.Camera.Position = new Vector3(0, 2, 20);
        }
Beispiel #9
0
        public static void Test()
        {
            var random = new Random(4);
            var timer  = new Stopwatch();
            var symmetricVectorSandwichTime        = 0.0;
            var symmetricWideVectorSandwichTime    = 0.0;
            var triangularWideVectorSandwichTime   = 0.0;
            var symmetricWide2x3SandwichTime       = 0.0;
            var triangularWide2x3SandwichTime      = 0.0;
            var symmetricSkewSandwichTime          = 0.0;
            var symmetricWideSkewSandwichTime      = 0.0;
            var triangularWideSkewSandwichTime     = 0.0;
            var symmetricRotationSandwichTime      = 0.0;
            var symmetricWideRotationSandwichTime  = 0.0;
            var triangularWideRotationSandwichTime = 0.0;
            var symmetricInvertTime      = 0.0;
            var symmetricWideInvertTime  = 0.0;
            var triangularWideInvertTime = 0.0;

            for (int i = 0; i < 1000; ++i)
            {
                var axis = Vector3.Normalize(new Vector3((float)random.NextDouble() * 2 - 1, (float)random.NextDouble() * 2 - 1, (float)random.NextDouble() * 2 - 1));
                Vector3Wide.Broadcast(axis, out var axisWide);
                var           rotation = Matrix3x3.CreateFromAxisAngle(axis, (float)random.NextDouble());
                Matrix3x3Wide rotationWide;
                Vector3Wide.Broadcast(rotation.X, out rotationWide.X);
                Vector3Wide.Broadcast(rotation.Y, out rotationWide.Y);
                Vector3Wide.Broadcast(rotation.Z, out rotationWide.Z);

                var m2x3Wide = new Matrix2x3Wide()
                {
                    X = axisWide, Y = new Vector3Wide {
                        X = -axisWide.Y, Y = axisWide.Z, Z = axisWide.X
                    }
                };

                var triangular = new Symmetric3x3
                {
                    XX = (float)random.NextDouble() * 2 + 1,
                    YX = (float)random.NextDouble() * 1 + 1,
                    YY = (float)random.NextDouble() * 2 + 1,
                    ZX = (float)random.NextDouble() * 1 + 1,
                    ZY = (float)random.NextDouble() * 1 + 1,
                    ZZ = (float)random.NextDouble() * 2 + 1,
                };
                Symmetric3x3Wide triangularWide;
                triangularWide.XX = new Vector <float>(triangular.XX);
                triangularWide.YX = new Vector <float>(triangular.YX);
                triangularWide.YY = new Vector <float>(triangular.YY);
                triangularWide.ZX = new Vector <float>(triangular.ZX);
                triangularWide.ZY = new Vector <float>(triangular.ZY);
                triangularWide.ZZ = new Vector <float>(triangular.ZZ);

                var symmetric = new Matrix3x3
                {
                    X = new Vector3(triangular.XX, triangular.YX, triangular.ZX),
                    Y = new Vector3(triangular.YX, triangular.YY, triangular.ZY),
                    Z = new Vector3(triangular.ZX, triangular.ZY, triangular.ZZ),
                };
                Matrix3x3Wide symmetricWide;
                Vector3Wide.Broadcast(symmetric.X, out symmetricWide.X);
                Vector3Wide.Broadcast(symmetric.Y, out symmetricWide.Y);
                Vector3Wide.Broadcast(symmetric.Z, out symmetricWide.Z);

                var symmetricVectorSandwich = new SymmetricVectorSandwich()
                {
                    v = axis, symmetric = symmetric
                };
                var symmetricWideVectorSandwich = new SymmetricWideVectorSandwich()
                {
                    v = axisWide, symmetric = symmetricWide
                };
                var triangularWideVectorSandwich = new TriangularWideVectorSandwich()
                {
                    v = axisWide, triangular = triangularWide
                };
                var symmetricWide2x3Sandwich = new SymmetricWide2x3Sandwich()
                {
                    m = m2x3Wide, symmetric = symmetricWide
                };
                var triangularWide2x3Sandwich = new TriangularWide2x3Sandwich()
                {
                    m = m2x3Wide, triangular = triangularWide
                };
                var symmetricSkewSandwich = new SymmetricSkewSandwich()
                {
                    v = axis, symmetric = symmetric
                };
                var symmetricWideSkewSandwich = new SymmetricWideSkewSandwich()
                {
                    v = axisWide, symmetric = symmetricWide
                };
                var triangularWideSkewSandwich = new TriangularWideSkewSandwich()
                {
                    v = axisWide, triangular = triangularWide
                };
                var symmetricSandwich = new SymmetricRotationSandwich()
                {
                    rotation = rotation, symmetric = symmetric
                };
                var symmetricWideSandwich = new SymmetricRotationSandwichWide()
                {
                    rotation = rotationWide, symmetric = symmetricWide
                };
                var triangularWideSandwich = new TriangularRotationSandwichWide()
                {
                    rotation = rotationWide, triangular = triangularWide
                };
                var symmetricInvert = new SymmetricInvert()
                {
                    symmetric = symmetric
                };
                var symmetricWideInvert = new SymmetricInvertWide()
                {
                    symmetric = symmetricWide
                };
                var triangularWideInvert = new TriangularInvertWide()
                {
                    triangular = triangularWide
                };


                const int innerIterations = 100000;
                symmetricVectorSandwichTime        += TimeTest(innerIterations, ref symmetricVectorSandwich);
                symmetricWideVectorSandwichTime    += TimeTest(innerIterations, ref symmetricWideVectorSandwich);
                triangularWideVectorSandwichTime   += TimeTest(innerIterations, ref triangularWideVectorSandwich);
                symmetricWide2x3SandwichTime       += TimeTest(innerIterations, ref symmetricWide2x3Sandwich);
                triangularWide2x3SandwichTime      += TimeTest(innerIterations, ref triangularWide2x3Sandwich);
                symmetricSkewSandwichTime          += TimeTest(innerIterations, ref symmetricSkewSandwich);
                symmetricWideSkewSandwichTime      += TimeTest(innerIterations, ref symmetricWideSkewSandwich);
                triangularWideSkewSandwichTime     += TimeTest(innerIterations, ref triangularWideSkewSandwich);
                symmetricRotationSandwichTime      += TimeTest(innerIterations, ref symmetricSandwich);
                symmetricWideRotationSandwichTime  += TimeTest(innerIterations, ref symmetricWideSandwich);
                triangularWideRotationSandwichTime += TimeTest(innerIterations, ref triangularWideSandwich);
                symmetricInvertTime      += TimeTest(innerIterations, ref symmetricInvert);
                symmetricWideInvertTime  += TimeTest(innerIterations, ref symmetricWideInvert);
                triangularWideInvertTime += TimeTest(innerIterations, ref triangularWideInvert);

                Compare(symmetricVectorSandwich.result, ref symmetricWideVectorSandwich.result);
                Compare(symmetricVectorSandwich.result, ref triangularWideVectorSandwich.result);
                Compare(ref symmetricWide2x3Sandwich.result, ref triangularWide2x3Sandwich.result);
                Compare(ref symmetricSkewSandwich.result, ref symmetricWideSkewSandwich.result);
                Compare(ref symmetricSkewSandwich.result, ref triangularWideSkewSandwich.result);
                Compare(ref symmetricSandwich.result, ref symmetricWideSandwich.result);
                Compare(ref symmetricSandwich.result, ref triangularWideSandwich.result);
                Compare(ref symmetricInvert.result, ref symmetricWideInvert.result);
                Compare(ref symmetricInvert.result, ref triangularWideInvert.result);
            }

            Console.WriteLine($"Symmetric vector sandwich:       {symmetricVectorSandwichTime}");
            Console.WriteLine($"Symmetric wide vector sandwich:  {symmetricWideVectorSandwichTime}");
            Console.WriteLine($"Triangular wide vector sandwich: {triangularWideVectorSandwichTime}");
            Console.WriteLine($"Symmetric wide 2x3 sandwich:  {symmetricWide2x3SandwichTime}");
            Console.WriteLine($"Triangular wide 2x3 sandwich: {triangularWide2x3SandwichTime}");
            Console.WriteLine($"Symmetric skew sandwich:       {symmetricSkewSandwichTime}");
            Console.WriteLine($"Symmetric wide skew sandwich:  {symmetricWideSkewSandwichTime}");
            Console.WriteLine($"Triangular wide skew sandwich: {triangularWideSkewSandwichTime}");
            Console.WriteLine($"Symmetric rotation sandwich:       {symmetricRotationSandwichTime}");
            Console.WriteLine($"Symmetric wide rotation sandwich:  {symmetricWideRotationSandwichTime}");
            Console.WriteLine($"Triangular wide rotation sandwich: {triangularWideRotationSandwichTime}");
            Console.WriteLine($"Symmetric invert:       {symmetricInvertTime}");
            Console.WriteLine($"Symmetric wide invert:  {symmetricWideInvertTime}");
            Console.WriteLine($"Triangular wide invert: {triangularWideInvertTime}");
        }
Beispiel #10
0
        /// <summary>
        /// Initializes a new instance of the HingeJoint class.
        /// </summary>
        /// <param name="world">The world class where the constraints get added to.</param>
        /// <param name="body1">The first body connected to the second one.</param>
        /// <param name="body2">The second body connected to the first one.</param>
        /// <param name="position">The position in world space where both bodies get connected.</param>
        /// <param name="hingeAxis">The axis if the hinge.</param>
        public LimitedHingeJoint(World world, RigidBody body1, RigidBody body2, Vector3 position, Vector3 hingeAxis,
                                 float hingeFwdAngle, float hingeBckAngle)
            : base(world)
        {
            // Create the hinge first, two point constraints

            worldPointConstraint = new PointOnPoint[2];

            hingeAxis *= 0.5f;

            Vector3 pos1 = position; Vector3.Add(ref pos1, ref hingeAxis, out pos1);
            Vector3 pos2 = position; Vector3.Subtract(ref pos2, ref hingeAxis, out pos2);

            worldPointConstraint[0] = new PointOnPoint(body1, body2, pos1);
            worldPointConstraint[1] = new PointOnPoint(body1, body2, pos2);


            // Now the limit, one max distance constraint

            hingeAxis.Normalize();

            // choose a direction that is perpendicular to the hinge
            Vector3 perpDir = Vector3.up;

            if (Vector3.Dot(perpDir, hingeAxis) > 0.1f)
            {
                perpDir = Vector3.right;
            }

            // now make it perpendicular to the hinge
            Vector3 sideAxis = Vector3.Cross(hingeAxis, perpDir);

            perpDir = Vector3.Cross(sideAxis, hingeAxis);
            perpDir.Normalize();

            // the length of the "arm" TODO take this as a parameter? what's
            // the effect of changing it?
            float len = 10.0f * 3;

            // Choose a position using that dir. this will be the anchor point
            // for body 0. relative to hinge
            Vector3 hingeRelAnchorPos0 = perpDir * len;


            // anchor point for body 2 is chosen to be in the middle of the
            // angle range.  relative to hinge
            float   angleToMiddle      = 0.5f * (hingeFwdAngle - hingeBckAngle);
            Vector3 hingeRelAnchorPos1 = Vector3.Transform(hingeRelAnchorPos0, Matrix3x3.CreateFromAxisAngle(hingeAxis, -angleToMiddle / 360.0f * 2.0f * Mathf.PI));

            // work out the "string" length
            float hingeHalfAngle  = 0.5f * (hingeFwdAngle + hingeBckAngle);
            float allowedDistance = len * 2.0f * Mathf.Sin(hingeHalfAngle * 0.5f / 360.0f * 2.0f * Mathf.PI);

            Vector3 hingePos = body1.Position;
            Vector3 relPos0c = hingePos + hingeRelAnchorPos0;
            Vector3 relPos1c = hingePos + hingeRelAnchorPos1;

            distance          = new PointPointDistance(body1, body2, relPos0c, relPos1c);
            distance.Distance = allowedDistance;
            distance.Behavior = PointPointDistance.DistanceBehavior.LimitMaximumDistance;
        }
Beispiel #11
0
        /// <summary>
        /// Constructs a new demo.
        /// </summary>
        /// <param name="game">Game owning this demo.</param>
        public ScaleDemo(DemosGame game)
            : base(game)
        {
            //Pick a scale!
            //Beware: If you go too far (particularly 0.01 and lower) issues could start to crop up.
            float scale = 1;

            //Load in mesh data and create the collision mesh.
            //The 'mesh' will be a supergiant triangle.
            //Triangles in meshes have a collision detection system which bypasses most numerical issues for collisions on the face of the triangle.
            //Edge collisions fall back to the general case collision detection system which is susceptible to numerical issues at extreme scales.
            //For our simulation, the edges will be too far away to worry about!
            Vector3[] vertices;
            int[]     indices;
            vertices = new Vector3[] { new Vector3(-10000, 0, -10000), new Vector3(-10000, 0, 20000), new Vector3(20000, 0, -10000) };
            indices  = new int[] { 2, 1, 0 };
            var staticMesh = new StaticMesh(vertices, indices, new AffineTransform(Matrix3x3.CreateFromAxisAngle(Vector3.Up, MathHelper.Pi), new Vector3(0, 0, 0)));

            staticMesh.Sidedness = TriangleSidedness.Counterclockwise;

            Space.Add(staticMesh);
            game.ModelDrawer.Add(staticMesh);

            //Since everything's pretty large, increase the gravity a whole bunch to make things fall fast.
            Space.ForceUpdater.Gravity *= scale;

            //Change the various engine tuning factors so that collision detection and collision response handle the changed scale better.
            ConfigurationHelper.ApplyScale(Space, scale);

            //When dealing with objects that generally have high velocities and accelerations relative to their size, having a shorter time step duration can boost quality
            //a whole lot.  Once the configuration is set properly, most of any remaining 'unsmoothness' in the simulation is due to a lack of temporal resolution;
            //one discrete step can take an object from a valid state to an unpleasing state due to the high rates of motion.
            //To simulate the same amount of time with a smaller time step duration requires taking more time steps.
            //This is a quality-performance tradeoff.  If you want to do this, set the time step duration like so:

            //Space.TimeStepSettings.TimeStepDuration = 1 / 120f;

            //And then, in the update, either call the Space.Update() method proportionally more often or use the Space.Update(dt) version, which takes as many timesteps are necessary to simulate dt time.
            //Watch out: when using the internal timestepping method, you may notice slight motion jitter since the number of updates per frame isn't fixed.  Interpolation buffers can be used
            //to address this; check the Asynchronous Update documentation for more information on using internal time stepping.
            //[Asynchronously updating isn't required to use internal timestepping, but it is a common use case.]

            //Dump some boxes on top of it for fun.
            int    numColumns = 8;
            int    numRows    = 8;
            int    numHigh    = 1;
            float  separation = 2 * scale;
            float  baseWidth  = 0.5f;
            float  baseHeight = 1;
            float  baseLength = 1.5f;
            Entity toAdd;

            for (int i = 0; i < numRows; i++)
            {
                for (int j = 0; j < numColumns; j++)
                {
                    for (int k = 0; k < numHigh; k++)
                    {
                        toAdd = new Box(
                            new Vector3(
                                separation * i - numRows * separation / 2,
                                2 * scale + k * separation,
                                separation * j - numColumns * separation / 2),
                            baseWidth * scale, baseHeight * scale, baseLength * scale, 15);

                        Space.Add(toAdd);
                    }
                }
            }

            //Dump some stuff on top of it that use general case collision detection when they collide with boxes.
            numColumns = 3;
            numRows    = 3;
            numHigh    = 4;
            separation = 2 * scale;
            baseWidth  = 1f;
            baseHeight = 1;
            for (int i = 0; i < numRows; i++)
            {
                for (int j = 0; j < numColumns; j++)
                {
                    for (int k = 0; k < numHigh; k++)
                    {
                        toAdd = new Cylinder(
                            new Vector3(
                                separation * i - numRows * separation / 2,
                                8 * scale + k * separation,
                                separation * j - numColumns * separation / 2),
                            baseHeight * scale, 0.5f * baseWidth * scale, 15);

                        Space.Add(toAdd);
                    }
                }
            }



            game.Camera.Position           = scale * new Vector3(0, 4, 10);
            originalCameraSpeed            = freeCameraControlScheme.Speed;
            freeCameraControlScheme.Speed *= scale;
        }