//////////////////////////////////////////////////////////////////////////////// // // TerrainDemo -- private helper methods // //////////////////////////////////////////////////////////////////////////////// /// called whenever key terrain attribute is changed public override void ClientResetScene() { base.ClientResetScene(); // remove old heightfield m_rawHeightfieldData = null; // reset gravity to point in appropriate direction //m_dynamicsWorld.setGravity(getUpVector(m_upAxis, 0.0f, -s_gravity)); m_dynamicsWorld.SetGravity(ref m_defaultGravity); // get new heightfield of appropriate type m_rawHeightfieldData = GetRawHeightfieldData(m_model, m_type, ref m_minHeight, ref m_maxHeight); Debug.Assert(m_rawHeightfieldData != null, "failed to create raw heightfield"); if (m_terrainRigidBody != null) { m_dynamicsWorld.RemoveCollisionObject(m_terrainRigidBody); m_terrainRigidBody = null; m_terrainShape = null; m_collisionShapes.Remove(m_terrainShape); } bool flipQuadEdges = false; m_terrainShape = new HeightfieldTerrainShape(s_gridSize, s_gridSize, m_rawHeightfieldData, s_gridHeightScale, m_minHeight, m_maxHeight, m_upAxis, m_type, flipQuadEdges); Debug.Assert(m_terrainShape != null, "null heightfield"); // scale the shape IndexedVector3 localScaling = GetUpVector(m_upAxis, s_gridSpacing, 1.0f); m_terrainShape.SetLocalScaling(ref localScaling); // stash this shape away m_collisionShapes.Add(m_terrainShape); // set origin to middle of heightfield IndexedMatrix tr = IndexedMatrix.CreateTranslation(new IndexedVector3(0, -20, 0)); // create ground object float mass = 0.0f; m_terrainRigidBody = LocalCreateRigidBody(mass, ref tr, m_terrainShape); CollisionShape sphere = new SphereShape(0.5f); tr = IndexedMatrix.CreateTranslation(new IndexedVector3(0, 0, 0)); LocalCreateRigidBody(1f, ref tr, sphere); }
private HeightfieldTerrainShape _CreateTerrainShape() { 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(row[0, j] * maxHeight); } } writer.Flush(); file.Position = 0; pinnedTerrainData = GCHandle.Alloc(terr, GCHandleType.Pinned); HeightfieldTerrainShape hs = new HeightfieldTerrainShape(width, length, pinnedTerrainData.AddrOfPinnedObject(), 1f, 0f, maxHeight, upIndex, scalarType, false); hs.SetUseDiamondSubdivision(true); hs.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(hs); }
private void CreateHeightfieldTerrain() { const float minHeight = 0; const float maxHeight = 10.0f; const float heightScale = maxHeight / 256.0f; const int width = 64, length = 64; const int dataLength = width * length * sizeof(float); const PhyScalarType scalarType = PhyScalarType.Single; var scale = new Vector3(15.0f, maxHeight, 15.0f); _terrainData = Marshal.AllocHGlobal(dataLength); var terrain = new byte[dataLength]; using (var file = new MemoryStream(terrain)) { using (var writer = new BinaryWriter(file)) { for (int 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))); } } } } Marshal.Copy(terrain, 0, _terrainData, terrain.Length); var groundShape = new HeightfieldTerrainShape(width, length, _terrainData, heightScale, minHeight, maxHeight, upIndex, scalarType, false); groundShape.SetUseDiamondSubdivision(true); groundShape.LocalScaling = new Vector3(scale.X, 1, scale.Z); Matrix transform = Matrix.Translation(-scale.X / 2, scale.Y / 2, -scale.Z / 2); RigidBody ground = PhysicsHelper.CreateStaticBody(transform, groundShape, World); ground.UserObject = "Ground"; Matrix vehicleTransform = Matrix.Translation(new Vector3(20, 3, -3)); CreateVehicle(vehicleTransform); }
private void CreateHeightfieldTerrainFromFile() { const float minHeight = 0; const float maxHeight = 10.0f; const float heightScale = maxHeight / 256.0f; const int width = 128, length = 128; const int dataLength = width * length * sizeof(byte); const PhyScalarType scalarType = PhyScalarType.Byte; var scale = new Vector3(5.0f, maxHeight, 5.0f); string heightfieldFile = Path.Combine("data", "heightfield128x128.raw"); _terrainData = Marshal.AllocHGlobal(dataLength); using (var stream = new FileStream(heightfieldFile, FileMode.Open, FileAccess.Read)) { using (var reader = new BinaryReader(stream)) { while (stream.Position < stream.Length) { int offset = (int)stream.Position; byte height = reader.ReadByte(); Marshal.WriteByte(_terrainData, offset, height); } } } var shape = new HeightfieldTerrainShape(width, length, _terrainData, heightScale, minHeight, maxHeight, upIndex, scalarType, false); shape.SetUseDiamondSubdivision(true); shape.LocalScaling = new Vector3(scale.X, 1, scale.Z); Matrix transform = Matrix.Translation(-scale.X / 2, scale.Y / 2, -scale.Z / 2); RigidBody ground = PhysicsHelper.CreateStaticBody(transform, shape, World); ground.UserObject = "Ground"; Matrix vehicleTransform = Matrix.Translation(new Vector3(20, 3, -3)); CreateVehicle(vehicleTransform); }
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); }
public virtual void LoadHeightField(float[,] heights, float heightRange, uint vertsX, uint vertsZ, Vector3 loc, int metersPerSample) { //if (worldLoaded == false || metersPerSample > 2) // return; loc = loc / scaleFactor; //heightRange = heightRange * 1000; //loc.X += heightFieldOffset; //loc.z += heightFieldOffset; // these axes are out by about 1m? if (heightFields.ContainsKey(loc)) { int oldMetersPerSample = heightFields[loc]; if (oldMetersPerSample == metersPerSample) { return; // no need to update } else { // we need to delete the old one to rebuild this one foreach (CollisionObject a in m_dynamicsWorld.GetCollisionObjectArray()) { if (a.GetCollisionShape() != null && a.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE) { string terrainName = (string)a.GetUserPointer(); if (terrainName == "TestHeightField_" + loc) { a.Cleanup(); heightFields.Remove(loc); System.Console.WriteLine("Removed heightmap at position '{0}' with metersPerSample: '{1}' and old: '{2}'", loc, metersPerSample, oldMetersPerSample); break; } } } } } byte[] terr = new byte[vertsX * vertsZ * 4]; MemoryStream file = new MemoryStream(terr); BinaryWriter writer = new BinaryWriter(file); for (int i = 0; i < vertsX; i++) { for (int j = 0; j < vertsZ; j++) { writer.Write((float)((heightRange / 2) + 4 * Math.Sin(j * 0.5f) * Math.Cos(i))); //writer.Write(0f); } } writer.Flush(); file.Position = 0; float heightScale = heightRange / 32767f / scaleFactor; int upAxis = 1; CollisionShape terrainShape = new HeightfieldTerrainShape((int)vertsX, (int)vertsZ, terr, heightScale, 0, heightRange, upAxis, PHY_ScalarType.PHY_FLOAT, true); IndexedMatrix worldTransform = IndexedMatrix.CreateTranslation(loc); DefaultMotionState objectMotionState = new DefaultMotionState(worldTransform, IndexedMatrix.Identity); //terrainShape = new StaticPlaneShape(Vector3.Up, 0f); //IndexedVector3 halfExtents = new IndexedVector3(50, 50, 50); //terrainShape = new BoxShape(ref halfExtents); RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(0, objectMotionState, terrainShape); RigidBody terrain = new RigidBody(rbInfo); //IndexedMatrix groundTransform = IndexedMatrix.CreateTranslation(new IndexedVector3(0, -50, 0)); IndexedMatrix groundTransform = IndexedMatrix.CreateTranslation(new IndexedVector3(0, -5, 0)); LocalCreateRigidBody(0f, groundTransform, terrainShape); terrain.SetUserPointer("TestHeightField_" + loc.ToString()); //terrain.SetCollisionFlags(CollisionFlags.CF_KINEMATIC_OBJECT); ////m_dynamicsWorld.AddCollisionObject(terrain, CollisionFilterGroups.DefaultFilter, CollisionFilterGroups.AllFilter); //m_dynamicsWorld.AddCollisionObject(terrain); System.Console.WriteLine("Added heightmap at position: '{0}' with metersPerSample: '{1}'", loc, metersPerSample); heightFields.Add(loc, metersPerSample); }
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, PhyScalarType.Int32, PhyScalarType.Single); 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.Single; 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.Single) { // heightScale isn't applied internally for float data height = reader.ReadSingle(); } else if (scalarType == PhyScalarType.Byte) { 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; }
private static Vector3[] CreateHeightFieldTerrainShape(HeightfieldTerrainShape heightfieldTerrainShape, out uint[] indices) { // HeightfieldTerrainShape does not expose its data indices = null; return(new Vector3[1]); }