//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ HeightfieldCollisionShape::HeightfieldCollisionShape(dSpaceID _spaceId, pTerrainChunk_type _pTerrainChunk) : m_pTerrainChunk(_pTerrainChunk) , CollisionShape(NULL) { m_heightfieldDataId = dGeomHeightfieldDataCreate(); dGeomHeightfieldDataBuildCallback( m_heightfieldDataId, this, getHeightCallback, m_pTerrainChunk->getWorldWidth(), m_pTerrainChunk->getWorldWidth(), m_pTerrainChunk->getWidth(), m_pTerrainChunk->getWidth(), 1.0f, m_pTerrainChunk->getOffset(), m_pTerrainChunk->getSkirtSize(), 0 ); dGeomHeightfieldDataSetBounds( m_heightfieldDataId, m_pTerrainChunk->getMinHeight(), m_pTerrainChunk->getMaxHeight() ); dGeomID geometryId = dCreateHeightfield( _spaceId, m_heightfieldDataId, 1 ); Zen::Math::Vector3& position(m_pTerrainChunk->getPosition()); dGeomSetPosition( geometryId, position.m_x, position.m_y, position.m_z ); /// TODO Set rotation of terrain for cases where it is not /// planar with the X and Z axes. setGeometryId(geometryId); }
WorldPhysics::WorldPhysics() { enable_complex=0; bulldozer_state=1; tmp_scalar=0; tmp_wait=0; qsrand(QTime::currentTime().msec()); dInitODE(); world = dWorldCreate(); space = dHashSpaceCreate (0); contactgroup = dJointGroupCreate (0); dWorldSetGravity (world,0,0,-9.81); //ground_cheat = dCreatePlane (space,0,0,1,0); wall1=dCreatePlane (space,-1,0,0,-100); wall2=dCreatePlane (space,1,0,0,0); wall3=dCreatePlane (space,0,-1,0,-100); wall4=dCreatePlane (space,0,1,0,0); // our heightfield floor dHeightfieldDataID heightid = dGeomHeightfieldDataCreate(); // Create an finite heightfield. dGeomHeightfieldDataBuildCallback( heightid, NULL, near_heightfield_callback, HFIELD_WIDTH, HFIELD_DEPTH, HFIELD_WSTEP, HFIELD_DSTEP, REAL( 1.0 ), REAL( 0.0 ), REAL( 0.0 ), 0 ); // Give some very bounds which, while conservative, // makes AABB computation more accurate than +/-INF. //dGeomHeightfieldDataSetBounds( heightid, REAL( -4.0 ), REAL( +6.0 ) ); gheight = dCreateHeightfield( space, heightid, 1 ); // Rotate so Z is up, not Y (which is the default orientation) dMatrix3 R; dRSetIdentity( R ); dRFromAxisAndAngle( R, 1, 0, 0, DEGTORAD * 90 ); dGeomSetRotation( gheight, R ); dGeomSetPosition( gheight, 50,50,0 ); // for (int i=0;i<MAX_ITEMS;i++) { // items.push_back(generateItem()); //} generateItems(); bulldozer_space = dSimpleSpaceCreate(space); dSpaceSetCleanup (bulldozer_space,0); bulldozer=new BoxItem(world,bulldozer_space,LENGTH,WIDTH,HEIGHT,CMASS); bulldozer->setPosition(STARTX,STARTY,STARTZ); bulldozer_cabin=new BoxItem(world,bulldozer_space,LENGTH/2,WIDTH/2,2*HEIGHT,CMASS/3); bulldozer_cabin->setPosition(-LENGTH/4+STARTX,STARTY,3.0/2.0*HEIGHT+STARTZ); bulldozer_bucket_c=new BoxItem(world,bulldozer_space,BUCKET_LENGTH,BUCKET_WIDTH,BUCKET_HEIGHT,CMASS/10); bulldozer_bucket_c->setPosition(LENGTH/2+BUCKET_LENGTH/2+RADIUS+STARTX,STARTY,STARTZ); bulldozer_bucket_l=new BoxItem(world,bulldozer_space,BUCKET_WIDTH/5,BUCKET_LENGTH,BUCKET_HEIGHT,CMASS/20); bulldozer_bucket_l->setPosition(LENGTH/2+BUCKET_LENGTH+RADIUS+BUCKET_WIDTH/10+STARTX,-BUCKET_WIDTH/2+BUCKET_LENGTH/2+STARTY,STARTZ); bulldozer_bucket_r=new BoxItem(world,bulldozer_space,BUCKET_WIDTH/5,BUCKET_LENGTH,BUCKET_HEIGHT,CMASS/20); bulldozer_bucket_r->setPosition(LENGTH/2+BUCKET_LENGTH+RADIUS+BUCKET_WIDTH/10+STARTX,BUCKET_WIDTH/2-BUCKET_LENGTH/2+STARTY,STARTZ); for (int i=0; i<4; i++) { dQuaternion q; dQFromAxisAndAngle(q,1,0,0,M_PI*0.5); wheels[i] = new WheelItem(world,bulldozer_space,q,RADIUS,WMASS); } dBodySetPosition (wheels[0]->body,0.5*LENGTH+STARTX,WIDTH*0.5+STARTY,STARTZ-HEIGHT*0.5); dBodySetPosition (wheels[1]->body,0.5*LENGTH+STARTX,-WIDTH*0.5+STARTY,STARTZ-HEIGHT*0.5); dBodySetPosition (wheels[2]->body,-0.5*LENGTH+STARTX, WIDTH*0.5+STARTY,STARTZ-HEIGHT*0.5); dBodySetPosition (wheels[3]->body,-0.5*LENGTH+STARTX,-WIDTH*0.5+STARTY,STARTZ-HEIGHT*0.5); cabin_joint=dJointCreateSlider(world,0); dJointAttach(cabin_joint,bulldozer->body,bulldozer_cabin->body); dJointSetSliderAxis(cabin_joint,0,0,1); dJointSetSliderParam(cabin_joint,dParamLoStop,0); dJointSetSliderParam(cabin_joint,dParamHiStop,0); bucket_joint_c=dJointCreateSlider(world,0); dJointAttach(bucket_joint_c,bulldozer->body,bulldozer_bucket_c->body); dJointSetSliderAxis(bucket_joint_c,0,0,1); dJointSetSliderParam(bucket_joint_c,dParamLoStop,0); dJointSetSliderParam(bucket_joint_c,dParamHiStop,0); bucket_joint_l=dJointCreateSlider(world,0); dJointAttach(bucket_joint_l,bulldozer->body,bulldozer_bucket_l->body); dJointSetSliderAxis(bucket_joint_l,0,0,1); dJointSetSliderParam(bucket_joint_l,dParamLoStop,0); dJointSetSliderParam(bucket_joint_l,dParamHiStop,0); bucket_joint_r=dJointCreateSlider(world,0); dJointAttach(bucket_joint_r,bulldozer->body,bulldozer_bucket_r->body); dJointSetSliderAxis(bucket_joint_r,0,0,1); dJointSetSliderParam(bucket_joint_r,dParamLoStop,0); dJointSetSliderParam(bucket_joint_r,dParamHiStop,0); // front and back wheel hinges for (int i=0; i<4; i++) { wheelJoints[i] = dJointCreateHinge2 (world,0); dJointAttach (wheelJoints[i],bulldozer->body,wheels[i]->body); const dReal *a = dBodyGetPosition (wheels[i]->body); dJointSetHinge2Anchor (wheelJoints[i],a[0],a[1],a[2]); dJointSetHinge2Axis1 (wheelJoints[i],0,0,1); dJointSetHinge2Axis2 (wheelJoints[i],0,1,0); } // seeting ERP & CRM for (int i=0; i<4; i++) { dJointSetHinge2Param (wheelJoints[i],dParamSuspensionERP,0.5); dJointSetHinge2Param (wheelJoints[i],dParamSuspensionCFM,0.8); } // block back axis !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! for (int i=0; i<2; i++) { dJointSetHinge2Param (wheelJoints[i],dParamLoStop,0); dJointSetHinge2Param (wheelJoints[i],dParamHiStop,0); } }
int main (int argc, char **argv) { printf("ODE configuration: %s\n", dGetConfiguration()); // Is trimesh support built into this ODE? g_allow_trimesh = dCheckConfiguration( "ODE_EXT_trimesh" ); // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; // create world dInitODE2(0); world = dWorldCreate(); space = dHashSpaceCreate (0); contactgroup = dJointGroupCreate (0); dWorldSetGravity (world,0,0,-0.05); dWorldSetCFM (world,1e-5); dWorldSetAutoDisableFlag (world,1); dWorldSetContactMaxCorrectingVel (world,0.1); dWorldSetContactSurfaceLayer (world,0.001); memset (obj,0,sizeof(obj)); #if 1 dWorldSetAutoDisableAverageSamplesCount( world, 1 ); #endif // base plane to catch overspill dCreatePlane( space, 0, 0, 1, 0 ); // our heightfield floor dHeightfieldDataID heightid = dGeomHeightfieldDataCreate(); // Create an finite heightfield. dGeomHeightfieldDataBuildCallback( heightid, NULL, heightfield_callback, HFIELD_WIDTH, HFIELD_DEPTH, HFIELD_WSTEP, HFIELD_DSTEP, REAL( 1.0 ), REAL( 0.0 ), REAL( 0.0 ), 0 ); // Give some very bounds which, while conservative, // makes AABB computation more accurate than +/-INF. dGeomHeightfieldDataSetBounds( heightid, REAL( -4.0 ), REAL( +6.0 ) ); gheight = dCreateHeightfield( space, heightid, 1 ); dVector3 pos; pos[ 0 ] = 0; pos[ 1 ] = 0; pos[ 2 ] = 0; // Rotate so Z is up, not Y (which is the default orientation) dMatrix3 R; dRSetIdentity( R ); dRFromAxisAndAngle( R, 1, 0, 0, DEGTORAD * 90 ); // Place it. dGeomSetRotation( gheight, R ); dGeomSetPosition( gheight, pos[0], pos[1], pos[2] ); // run simulation dsSimulationLoop (argc,argv,352,288,&fn); dJointGroupDestroy (contactgroup); dSpaceDestroy (space); dWorldDestroy (world); // destroy heightfield data, because _we_ own it not ODE dGeomHeightfieldDataDestroy( heightid ); dCloseODE(); return 0; }
void cPhysicsObject::CreateHeightmap(cWorld* pWorld, const game::cTerrainHeightMap& loader, size_t width, size_t length, const physvec_t& scale, const physvec_t& pos, const physvec_t& rot) { // NOTE: Actual heightmap doesn't seem to be working at the moment so we use a trimesh instead #if 1 // TODO: Shared indices const float fScale = scale.x; std::vector<spitfire::math::cVec3> tempVertices; std::vector<uint32_t> tempIndices; tempVertices.reserve(length * width * 4); tempIndices.reserve(length * width * 6); size_t index = 0; for (size_t y = 0; y < length; y++) { for (size_t x = 0; x < width; x++) { const float fX = float(x) * fScale; const float fY = float(y) * fScale; tempVertices.push_back(spitfire::math::cVec3(fX, fY, loader.GetHeight(fX, fY))); tempVertices.push_back(spitfire::math::cVec3(fX + fScale, fY, loader.GetHeight(fX + fScale, fY))); tempVertices.push_back(spitfire::math::cVec3(fX + fScale, fY + fScale, loader.GetHeight(fX + fScale, fY + fScale))); tempVertices.push_back(spitfire::math::cVec3(fX, fY + fScale, loader.GetHeight(fX, fY + fScale))); tempIndices.push_back(index + 0); tempIndices.push_back(index + 1); tempIndices.push_back(index + 2); tempIndices.push_back(index + 2); tempIndices.push_back(index + 3); tempIndices.push_back(index + 0); index += 4; } } CreateTrimesh(pWorld, tempVertices, tempIndices, pos, rot); #else DestroyHeightfield(); bBody = false; bDynamic = false; // Heightfields are always static v[0] = 0.0f; v[1] = 0.0f; v[2] = 0.0f; fWidth = float(width) * scale.x; fLength = float(length) * scale.y; fHeight = 1.0f * scale.z; const size_t height = length; pHeightfieldData = new float[width * height]; for (size_t y = 0; y < height; y++) { for (size_t x = 0; x < width; x++) { pHeightfieldData[(width * y) + x] = 200.0f * (sinf(float(x)) + cosf(float(y)));// 10.0f * loader.GetHeight(x, y); } } heightfield = dGeomHeightfieldDataCreate(); // TODO: Last parameter, tile indefinitely int copyHeightData = 1; // 0 = we are keeping our own copy (Dynamic), 1 = copy the data to ODE (static) int wrap = 1; // 0 = don't wrap, 1 = wrap indefinitely float fThickness = 10.0f; // The thickness of the "shell" of the heightmap dGeomHeightfieldDataBuildSingle( heightfield, pHeightfieldData, copyHeightData, fWidth, fLength, width, height, scale.z, pos.z, fThickness, wrap ); // Set finite AABB dGeomHeightfieldDataSetBounds(heightfield, 0.0f, 1000.0f); int movable = 1; // 1 = true, 0 = false geom = dCreateHeightfield(pWorld->GetSpaceStatic(), heightfield, movable); ASSERT(geom != 0); InitCommon(pWorld, pos, rot); #endif }