public override CollisionShape GetCollisionShape()
        {
            if (collisionShapePtr == null) {
                Terrain t = GetComponent<Terrain>();
                if (t == null)
                {
                    Debug.LogError("Needs to be attached to a game object with a Terrain component." + name);
                    return null;
                }
                BTerrainCollisionObject tco = GetComponent<BTerrainCollisionObject>();
                if (tco == null)
                {
                    Debug.LogError("Needs to be attached to a game object with a BTerrainCollisionObject." + name);
                }
                TerrainData td = t.terrainData;
                int width = td.heightmapWidth;
                int length = td.heightmapHeight;
                float maxHeight = td.size.y;

                //generate procedural data
                byte[] terr = new byte[width * length * sizeof(float)];
                System.IO.MemoryStream file = new System.IO.MemoryStream(terr);
                System.IO.BinaryWriter writer = new System.IO.BinaryWriter(file);

                for (int i = 0; i < length; i++)
                {
                    float[,] row = td.GetHeights(0, i, width, 1);
                    for (int j = 0; j < width; j++)
                    {
                        writer.Write((float)row[0, j] * maxHeight);
                    }
                }

                writer.Flush();
                file.Position = 0;

                pinnedTerrainData = GCHandle.Alloc(terr,GCHandleType.Pinned);

                collisionShapePtr = new HeightfieldTerrainShape(width, length, pinnedTerrainData.AddrOfPinnedObject(), 1f, 0f, maxHeight, upIndex, scalarType, false);
                ((HeightfieldTerrainShape)collisionShapePtr).SetUseDiamondSubdivision(true);
                ((HeightfieldTerrainShape)collisionShapePtr).LocalScaling = new BulletSharp.Math.Vector3(td.heightmapScale.x, 1f, td.heightmapScale.z);
                //just allocated several hundred float arrays. Garbage collect now since 99% likely we just loaded the scene
                GC.Collect();
            }
            return collisionShapePtr;
        }
 protected override CollisionShape CreateShape()
 {
     if (this.ms == null)
     {
         byte[] terr = new byte[this.w * this.l * 4];
         ms = new MemoryStream(terr);
         BinaryWriter writer = new BinaryWriter(ms);
         for (int i = 0; i < this.w * this.l; i++)
         {
             writer.Write(this.h[i]);
         }
         writer.Flush();
     }
     ms.Position = 0;
     HeightfieldTerrainShape hs = new HeightfieldTerrainShape(w, l, ms, 0.0f, minh, maxh, 1, PhyScalarType.PhyFloat, false);
     hs.SetUseDiamondSubdivision(true);
     //hs.LocalScaling = new Vector3(this.sx, 1.0f, this.sz);
     return hs;
 }
Example #3
0
        float wheelFriction = 1000; //BT_LARGE_FLOAT;

        #endregion Fields

        #region Constructors

        public Physics(VehicleDemo game)
        {
            CollisionShape groundShape = new BoxShape(50, 3, 50);
            CollisionShapes.Add(groundShape);

            CollisionConf = new DefaultCollisionConfiguration();
            Dispatcher = new CollisionDispatcher(CollisionConf);
            Solver = new SequentialImpulseConstraintSolver();

            Vector3 worldMin = new Vector3(-10000, -10000, -10000);
            Vector3 worldMax = new Vector3(10000, 10000, 10000);
            Broadphase = new AxisSweep3(worldMin, worldMax);
            //Broadphase = new DbvtBroadphase();

            World = new DiscreteDynamicsWorld(Dispatcher, Broadphase, Solver, CollisionConf);

            int i;
            Matrix tr;
            Matrix vehicleTr;
            if (UseTrimeshGround)
            {
                const float scale = 20.0f;

                //create a triangle-mesh ground
                int vertStride = Vector3.SizeInBytes;
                int indexStride = 3 * sizeof(int);

                const int NUM_VERTS_X = 20;
                const int NUM_VERTS_Y = 20;
                const int totalVerts = NUM_VERTS_X * NUM_VERTS_Y;

                const int totalTriangles = 2 * (NUM_VERTS_X - 1) * (NUM_VERTS_Y - 1);

                TriangleIndexVertexArray vertexArray = new TriangleIndexVertexArray();
                IndexedMesh mesh = new IndexedMesh();
                mesh.Allocate(totalVerts, vertStride, totalTriangles, indexStride);

                BulletSharp.DataStream data = mesh.LockVerts();
                for (i = 0; i < NUM_VERTS_X; i++)
                {
                    for (int j = 0; j < NUM_VERTS_Y; j++)
                    {
                        float wl = .2f;
                        float height = 20.0f * (float)(Math.Sin(i * wl) * Math.Cos(j * wl));

                        data.Write((i - NUM_VERTS_X * 0.5f) * scale);
                        data.Write(height);
                        data.Write((j - NUM_VERTS_Y * 0.5f) * scale);
                    }
                }

                int index = 0;
                IntArray idata = mesh.TriangleIndices;
                for (i = 0; i < NUM_VERTS_X - 1; i++)
                {
                    for (int j = 0; j < NUM_VERTS_Y - 1; j++)
                    {
                        idata[index++] = j * NUM_VERTS_X + i;
                        idata[index++] = j * NUM_VERTS_X + i + 1;
                        idata[index++] = (j + 1) * NUM_VERTS_X + i + 1;

                        idata[index++] = j * NUM_VERTS_X + i;
                        idata[index++] = (j + 1) * NUM_VERTS_X + i + 1;
                        idata[index++] = (j + 1) * NUM_VERTS_X + i;
                    }
                }

                vertexArray.AddIndexedMesh(mesh);
                groundShape = new BvhTriangleMeshShape(vertexArray, true);

                tr = Matrix.Identity;
                vehicleTr = Matrix.Translation(0, -2, 0);
            }
            else
            {
                // Use HeightfieldTerrainShape

                int width = 40, length = 40;
                //int width = 128, length = 128; // Debugging is too slow for this
                float maxHeight = 10.0f;
                float heightScale = maxHeight / 256.0f;
                Vector3 scale = new Vector3(20.0f, maxHeight, 20.0f);

                //PhyScalarType scalarType = PhyScalarType.PhyUChar;
                //FileStream file = new FileStream(heightfieldFile, FileMode.Open, FileAccess.Read);

                // Use float data
                PhyScalarType scalarType = PhyScalarType.PhyFloat;
                byte[] terr = new byte[width * length * 4];
                MemoryStream file = new MemoryStream(terr);
                BinaryWriter writer = new BinaryWriter(file);
                for (i = 0; i < width; i++)
                    for (int j = 0; j < length; j++)
                        writer.Write((float)((maxHeight / 2) + 4 * Math.Sin(j * 0.5f) * Math.Cos(i)));
                writer.Flush();
                file.Position = 0;

                HeightfieldTerrainShape heightterrainShape = new HeightfieldTerrainShape(width, length,
                    file, heightScale, 0, maxHeight, upIndex, scalarType, false);
                heightterrainShape.SetUseDiamondSubdivision(true);

                groundShape = heightterrainShape;
                groundShape.LocalScaling = new Vector3(scale.X, 1, scale.Z);

                tr = Matrix.Translation(new Vector3(-scale.X / 2, scale.Y / 2, -scale.Z / 2));
                vehicleTr = Matrix.Translation(new Vector3(20, 3, -3));

                // Create graphics object

                file.Position = 0;
                BinaryReader reader = new BinaryReader(file);

                int totalTriangles = (width - 1) * (length - 1) * 2;
                int totalVerts = width * length;

                game.groundMesh = new Mesh(game.Device, totalTriangles, totalVerts,
                    MeshFlags.SystemMemory | MeshFlags.Use32Bit, VertexFormat.Position | VertexFormat.Normal);
                SlimDX.DataStream data = game.groundMesh.LockVertexBuffer(LockFlags.None);
                for (i = 0; i < width; i++)
                {
                    for (int j = 0; j < length; j++)
                    {
                        float height;
                        if (scalarType == PhyScalarType.PhyFloat)
                        {
                            // heightScale isn't applied internally for float data
                            height = reader.ReadSingle();
                        }
                        else if (scalarType == PhyScalarType.PhyUChar)
                        {
                            height = file.ReadByte() * heightScale;
                        }
                        else
                        {
                            height = 0.0f;
                        }

                        data.Write((j - length * 0.5f) * scale.X);
                        data.Write(height);
                        data.Write((i - width * 0.5f) * scale.Z);

                        // Normals will be calculated later
                        data.Position += 12;
                    }
                }
                game.groundMesh.UnlockVertexBuffer();
                file.Close();

                data = game.groundMesh.LockIndexBuffer(LockFlags.None);
                for (i = 0; i < width - 1; i++)
                {
                    for (int j = 0; j < length - 1; j++)
                    {
                        // Using diamond subdivision
                        if ((j + i) % 2 == 0)
                        {
                            data.Write(j * width + i);
                            data.Write((j + 1) * width + i + 1);
                            data.Write(j * width + i + 1);

                            data.Write(j * width + i);
                            data.Write((j + 1) * width + i);
                            data.Write((j + 1) * width + i + 1);
                        }
                        else
                        {
                            data.Write(j * width + i);
                            data.Write((j + 1) * width + i);
                            data.Write(j * width + i + 1);

                            data.Write(j * width + i + 1);
                            data.Write((j + 1) * width + i);
                            data.Write((j + 1) * width + i + 1);
                        }

                        /*
                        // Not using diamond subdivision
                        data.Write(j * width + i);
                        data.Write((j + 1) * width + i);
                        data.Write(j * width + i + 1);

                        data.Write(j * width + i + 1);
                        data.Write((j + 1) * width + i);
                        data.Write((j + 1) * width + i + 1);
                        */
                    }
                }
                game.groundMesh.UnlockIndexBuffer();

                game.groundMesh.ComputeNormals();
            }

            CollisionShapes.Add(groundShape);

            //create ground object
            RigidBody ground = LocalCreateRigidBody(0, tr, groundShape);
            ground.UserObject = "Ground";

            CollisionShape chassisShape = new BoxShape(1.0f, 0.5f, 2.0f);
            CollisionShapes.Add(chassisShape);

            CompoundShape compound = new CompoundShape();
            CollisionShapes.Add(compound);

            //localTrans effectively shifts the center of mass with respect to the chassis
            Matrix localTrans = Matrix.Translation(Vector3.UnitY);
            compound.AddChildShape(localTrans, chassisShape);
            RigidBody carChassis = LocalCreateRigidBody(800, Matrix.Identity, compound);
            carChassis.UserObject = "Chassis";
            //carChassis.SetDamping(0.2f, 0.2f);

            //CylinderShapeX wheelShape = new CylinderShapeX(wheelWidth, wheelRadius, wheelRadius);

            // clientResetScene();

            // create vehicle
            RaycastVehicle.VehicleTuning tuning = new RaycastVehicle.VehicleTuning();
            IVehicleRaycaster vehicleRayCaster = new DefaultVehicleRaycaster(World);
            vehicle = new RaycastVehicle(tuning, carChassis, vehicleRayCaster);

            carChassis.ActivationState = ActivationState.DisableDeactivation;
            World.AddAction(vehicle);

            float connectionHeight = 1.2f;
            bool isFrontWheel = true;

            // choose coordinate system
            vehicle.SetCoordinateSystem(rightIndex, upIndex, forwardIndex);

            Vector3 connectionPointCS0 = new Vector3(CUBE_HALF_EXTENTS - (0.3f * wheelWidth), connectionHeight, 2 * CUBE_HALF_EXTENTS - wheelRadius);
            WheelInfo a = vehicle.AddWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, suspensionRestLength, wheelRadius, tuning, isFrontWheel);

            connectionPointCS0 = new Vector3(-CUBE_HALF_EXTENTS + (0.3f * wheelWidth), connectionHeight, 2 * CUBE_HALF_EXTENTS - wheelRadius);
            vehicle.AddWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, suspensionRestLength, wheelRadius, tuning, isFrontWheel);

            isFrontWheel = false;
            connectionPointCS0 = new Vector3(-CUBE_HALF_EXTENTS + (0.3f * wheelWidth), connectionHeight, -2 * CUBE_HALF_EXTENTS + wheelRadius);
            vehicle.AddWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, suspensionRestLength, wheelRadius, tuning, isFrontWheel);

            connectionPointCS0 = new Vector3(CUBE_HALF_EXTENTS - (0.3f * wheelWidth), connectionHeight, -2 * CUBE_HALF_EXTENTS + wheelRadius);
            vehicle.AddWheel(connectionPointCS0, wheelDirectionCS0, wheelAxleCS, suspensionRestLength, wheelRadius, tuning, isFrontWheel);

            for (i = 0; i < vehicle.NumWheels; i++)
            {
                WheelInfo wheel = vehicle.GetWheelInfo(i);
                wheel.SuspensionStiffness = suspensionStiffness;
                wheel.WheelsDampingRelaxation = suspensionDamping;
                wheel.WheelsDampingCompression = suspensionCompression;
                wheel.FrictionSlip = wheelFriction;
                wheel.RollInfluence = rollInfluence;
            }

            vehicle.RigidBody.WorldTransform = vehicleTr;
        }
        /// <summary>
        /// Creates a collision shape for a shape component
        /// </summary>
        private CollisionShape CreateShapeForComponent(ShapeComponent component)
        {
            switch (component.Type) {
                case ThingEnum.Box:
                    return new BoxShape(component.Dimensions);
                case ThingEnum.Cylinder:
                    return new CylinderShape(component.Dimensions);
                case ThingEnum.Cone:
                    var cone = new ConeShape(component.Radius, component.Height);
                    cone.ConeUpIndex = 1;
                    return cone;
                case ThingEnum.Capsule:
                    return new CapsuleShape(component.Radius, component.Height);
                case ThingEnum.Sphere:
                    return new SphereShape(component.Radius);
                case ThingEnum.Hull: {
                        CollisionShape shape;

                        string name = Path.GetFileNameWithoutExtension(component.Mesh);
                        string bulletFilePath = GetBulletFile(name);

                        if (bulletFilePath != null) {
                            // so it has a file
                            shape = ImportCollisionShape(name);
                        }
                        else {
                            /*var sceneMgr = LKernel.GetG<SceneManager>();
                            // get our entity if we have one, create it if we don't
                            Entity ent = sceneMgr.HasEntity(component.Mesh) ? sceneMgr.GetEntity(component.Mesh) : sceneMgr.CreateEntity(component.Mesh, component.Mesh);

                            ConvexHullShape hull = OgreToBulletMesh.ConvertToHull(
                                ent.GetMesh(),
                                component.Transform.GetTrans(),
                                component.Transform.ExtractQuaternion(),
                                Vector3.UNIT_SCALE);
                            shape = hull;

                            // TODO: figure out how to deal with concave triangle mesh shapes since apparently they aren't being exported
                            SerializeShape(shape, name);*/
                            throw new FileNotFoundException("Your \"Mesh\" property did not point to an existing .bullet file!", component.Mesh);
                        }
                        return shape;
                    }
                case ThingEnum.Mesh: {
                        CollisionShape shape;
                        // example
                        // physics/example.bullet
                        string name = Path.GetFileNameWithoutExtension(component.Mesh);
                        string bulletFilePath = GetBulletFile(name);

                        // right, so what we do is test to see if this shape has a .bullet file, and if it doesn't, create one
                        if (bulletFilePath != null) {
                            // so it has a file
                            shape = ImportCollisionShape(name);
                        }
                        else {
                            /*Launch.Log("[CollisionShapeManager] " + bulletFilePath + " does not exist, converting Ogre mesh into physics trimesh and exporting new .bullet file...");

                            // it does not have a file, so we need to convert our ogre mesh
                            var sceneMgr = LKernel.GetG<SceneManager>();
                            Entity ent = sceneMgr.HasEntity(component.Mesh) ? sceneMgr.GetEntity(component.Mesh) : sceneMgr.CreateEntity(component.Mesh, component.Mesh);

                            shape = new BvhTriangleMeshShape(
                                OgreToBulletMesh.Convert(
                                    ent.GetMesh(),
                                    component.Transform.GetTrans(),
                                    component.Transform.ExtractQuaternion(),
                                    Vector3.UNIT_SCALE),
                                true,
                                true);

                            (shape as BvhTriangleMeshShape).BuildOptimizedBvh();

                            // and then export it as a .bullet file
                            SerializeShape(shape, name);*/
                            throw new FileNotFoundException("Your \"Mesh\" property did not point to an existing .bullet file!", component.Mesh);
                        }
                        return shape;
                    }
                case ThingEnum.Heightmap: {
                        string filename = "media/" + component.Mesh;
                        //FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read);
                        Bitmap bitmap = new Bitmap(filename);

                        int width = 256;
                        int length = 256;

                        byte[] terr = new byte[width * length * 4];
                        MemoryStream file = new MemoryStream(terr);
                        BinaryWriter writer = new BinaryWriter(file);
                        for (int i = 0; i < width; i++) {
                            for (int j = 0; j < length; j++) {
                                writer.Write(bitmap.GetPixel((int) (((float) i / width) * bitmap.Width), (int) (((float) j / length) * bitmap.Height)).R / 255f);
                                //writer.Write(bitmap.GetPixel(i, j).R / 255f);
                            }
                        }
                        writer.Flush();
                        file.Position = 0;

                        float heightScale = component.MaxHeight - component.MinHeight / 255f;
                        Vector3 scale = component.Dimensions;

                        var heightfield = new HeightfieldTerrainShape(width, length, file, heightScale,
                            component.MinHeight, component.MaxHeight, 1, PhyScalarType.PhyFloat, false);

                        //heightfield.SetUseDiamondSubdivision(true);
                        //heightfield.LocalScaling = new Vector3(scale.x / width, scale.y, scale.z / length);

                        //Matrix4 trans = new Matrix4();
                        //trans.MakeTransform(new Vector3(-scale.x / 2f, scale.y / 2f, -scale.z / 2f), new Vector3(scale.x, 1, scale.z), Quaternion.IDENTITY);
                        //component.Transform = trans;

                        return heightfield;
                    }
                default:
                    throw new ApplicationException("ShapeComponent's Type was invalid!");
            }
        }
Example #5
0
        public void Load()
        {
            Stream entryStream = new MemoryStream(Resources.GetFile(HeightfieldName));
            if (entryStream  != null)
            {

                // Generate heightfield mesh
                Vector3[] points = new Vector3[Size * Size];
                entryStream.Position = 0;
                byte[] b = new byte[4];
                Vector2[] texturecoords = new Vector2[Size * Size];
                for (long i = 0; i < entryStream.Length; i += 4)
                {
                    entryStream.Read(b, 0, 4);
                    float h = BitConverter.ToSingle(b, 0);
                    points[i / 4] = new Vector3((i / 4) % Size, h, ((i / 4) / Size)) * Scale;
                    texturecoords[i / 4] = new Vector2((i / 4) % Size, ((i / 4) / Size)) * Scale.Xz;
                    texturecoords[i / 4].X /= TextureScale.X;
                    texturecoords[i / 4].Y /= TextureScale.Y;
                    if (h > Maximum) Maximum = h;
                    if (h < Minimum) Minimum = h;
                }
                int[] indicies = new int[(Size - 1) * (Size - 1) * 6];
                int c = 0;
                for (int i = 0; i < points.Length - Size; i++)
                {
                    if ((i % Size) < Size - 1)
                    {
                        indicies[c++] = i;
                        indicies[c++] = i + 1;
                        indicies[c++] = i + 1 + Size;
                        indicies[c++] = i + 1 + Size;
                        indicies[c++] = i + Size;
                        indicies[c++] = i;
                    }
                }
                HeightfieldMesh.Load(points, indicies, TextureName, texturecoords);
                if (!Graphics.StaticView)
                {
                    // Generate rigid body
                    entryStream.Position = 0;
                    float Extreme = (Math.Abs(Minimum) > Math.Abs(Maximum)) ? Math.Abs(Minimum) : Maximum;
                    HeightfieldTerrainShape heightfield = new HeightfieldTerrainShape(Size, Size, entryStream, 1, -Extreme, Extreme, 1, PhyScalarType.PhyFloat, true);
                    heightfield.LocalScaling = Scale;
                    GroundBody = World.CreateRigidBody(0, Matrix4.CreateTranslation(new Vector3(Size / 2, 0, Size / 2)), heightfield);
                    GroundBody.CollisionFlags |= CollisionFlags.DisableVisualizeObject;
                }

                entryStream.Close();
            }
        }