void VehicleDemo::initPhysics() { #ifdef FORCE_ZAXIS_UP m_cameraUp = btVector3(0,0,1); m_forwardAxis = 1; #endif btCollisionShape* groundShape = new btBoxShape(btVector3(50,3,50)); m_collisionShapes.push_back(groundShape); m_collisionConfiguration = new btDefaultCollisionConfiguration(); m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); btVector3 worldMin(-1000,-1000,-1000); btVector3 worldMax(1000,1000,1000); m_overlappingPairCache = new btAxisSweep3(worldMin,worldMax); m_constraintSolver = new btSequentialImpulseConstraintSolver(); m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration); #ifdef FORCE_ZAXIS_UP m_dynamicsWorld->setGravity(btVector3(0,0,-10)); #endif //m_dynamicsWorld->setGravity(btVector3(0,0,0)); btTransform tr; tr.setIdentity(); //either use heightfield or triangle mesh #define USE_TRIMESH_GROUND 1 #ifdef USE_TRIMESH_GROUND int i; const float TRIANGLE_SIZE=20.f; //create a triangle-mesh ground int vertStride = sizeof(btVector3); 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); m_vertices = new btVector3[totalVerts]; int* gIndices = new int[totalTriangles*3]; for ( i=0; i<NUM_VERTS_X; i++) { for (int j=0; j<NUM_VERTS_Y; j++) { float wl = .2f; //height set to zero, but can also use curved landscape, just uncomment out the code float height = 0.f;//20.f*sinf(float(i)*wl)*cosf(float(j)*wl); #ifdef FORCE_ZAXIS_UP m_vertices[i+j*NUM_VERTS_X].setValue( (i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE, (j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE, height ); #else m_vertices[i+j*NUM_VERTS_X].setValue( (i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE, height, (j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE); #endif } } int index=0; for ( i=0; i<NUM_VERTS_X-1; i++) { for (int j=0; j<NUM_VERTS_Y-1; j++) { gIndices[index++] = j*NUM_VERTS_X+i; gIndices[index++] = j*NUM_VERTS_X+i+1; gIndices[index++] = (j+1)*NUM_VERTS_X+i+1; gIndices[index++] = j*NUM_VERTS_X+i; gIndices[index++] = (j+1)*NUM_VERTS_X+i+1; gIndices[index++] = (j+1)*NUM_VERTS_X+i; } } m_indexVertexArrays = new btTriangleIndexVertexArray(totalTriangles, gIndices, indexStride, totalVerts,(btScalar*) &m_vertices[0].x(),vertStride); bool useQuantizedAabbCompression = true; groundShape = new btBvhTriangleMeshShape(m_indexVertexArrays,useQuantizedAabbCompression); tr.setOrigin(btVector3(0,-4.5f,0)); #else //testing btHeightfieldTerrainShape int width=128; int length=128; unsigned char* heightfieldData = new unsigned char[width*length]; { for (int i=0; i<width*length; i++) { heightfieldData[i]=0; } } char* filename="heightfield128x128.raw"; FILE* heightfieldFile = fopen(filename,"r"); if (!heightfieldFile) { filename="../../heightfield128x128.raw"; heightfieldFile = fopen(filename,"r"); } if (heightfieldFile) { int numBytes =fread(heightfieldData,1,width*length,heightfieldFile); //btAssert(numBytes); if (!numBytes) { printf("couldn't read heightfield at %s\n",filename); } fclose (heightfieldFile); } btScalar maxHeight = 20000.f; bool useFloatDatam=false; bool flipQuadEdges=false; btHeightfieldTerrainShape* heightFieldShape = new btHeightfieldTerrainShape(width,length,heightfieldData,maxHeight,upIndex,useFloatDatam,flipQuadEdges);; groundShape = heightFieldShape; heightFieldShape->setUseDiamondSubdivision(true); btVector3 localScaling(20,20,20); localScaling[upIndex]=1.f; groundShape->setLocalScaling(localScaling); tr.setOrigin(btVector3(0,-64.5f,0)); #endif // m_collisionShapes.push_back(groundShape); //create ground object localCreateRigidBody(0,tr,groundShape); #ifdef FORCE_ZAXIS_UP // indexRightAxis = 0; // indexUpAxis = 2; // indexForwardAxis = 1; btCollisionShape* chassisShape = new btBoxShape(btVector3(1.f,2.f, 0.5f)); btCompoundShape* compound = new btCompoundShape(); btTransform localTrans; localTrans.setIdentity(); //localTrans effectively shifts the center of mass with respect to the chassis localTrans.setOrigin(btVector3(0,0,1)); #else btCollisionShape* chassisShape = new btBoxShape(btVector3(1.f,0.5f,2.f)); m_collisionShapes.push_back(chassisShape); btCompoundShape* compound = new btCompoundShape(); m_collisionShapes.push_back(compound); btTransform localTrans; localTrans.setIdentity(); //localTrans effectively shifts the center of mass with respect to the chassis localTrans.setOrigin(btVector3(0,1,0)); #endif compound->addChildShape(localTrans,chassisShape); tr.setOrigin(btVector3(0,0.f,0)); m_carChassis = localCreateRigidBody(800,tr,compound);//chassisShape); //m_carChassis->setDamping(0.2,0.2); clientResetScene(); /// create vehicle { m_vehicleRayCaster = new btDefaultVehicleRaycaster(m_dynamicsWorld); m_vehicle = new btRaycastVehicle(m_tuning,m_carChassis,m_vehicleRayCaster); ///never deactivate the vehicle m_carChassis->setActivationState(DISABLE_DEACTIVATION); m_dynamicsWorld->addVehicle(m_vehicle); float connectionHeight = 1.2f; bool isFrontWheel=true; //choose coordinate system m_vehicle->setCoordinateSystem(rightIndex,upIndex,forwardIndex); #ifdef FORCE_ZAXIS_UP btVector3 connectionPointCS0(CUBE_HALF_EXTENTS-(0.3*wheelWidth),2*CUBE_HALF_EXTENTS-wheelRadius, connectionHeight); #else btVector3 connectionPointCS0(CUBE_HALF_EXTENTS-(0.3*wheelWidth),connectionHeight,2*CUBE_HALF_EXTENTS-wheelRadius); #endif m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); #ifdef FORCE_ZAXIS_UP connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),2*CUBE_HALF_EXTENTS-wheelRadius, connectionHeight); #else connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),connectionHeight,2*CUBE_HALF_EXTENTS-wheelRadius); #endif m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); #ifdef FORCE_ZAXIS_UP connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),-2*CUBE_HALF_EXTENTS+wheelRadius, connectionHeight); #else connectionPointCS0 = btVector3(-CUBE_HALF_EXTENTS+(0.3*wheelWidth),connectionHeight,-2*CUBE_HALF_EXTENTS+wheelRadius); #endif //FORCE_ZAXIS_UP isFrontWheel = false; m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); #ifdef FORCE_ZAXIS_UP connectionPointCS0 = btVector3(CUBE_HALF_EXTENTS-(0.3*wheelWidth),-2*CUBE_HALF_EXTENTS+wheelRadius, connectionHeight); #else connectionPointCS0 = btVector3(CUBE_HALF_EXTENTS-(0.3*wheelWidth),connectionHeight,-2*CUBE_HALF_EXTENTS+wheelRadius); #endif m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxleCS,suspensionRestLength,wheelRadius,m_tuning,isFrontWheel); for (int i=0; i<m_vehicle->getNumWheels(); i++) { btWheelInfo& wheel = m_vehicle->getWheelInfo(i); wheel.m_suspensionStiffness = suspensionStiffness; wheel.m_wheelsDampingRelaxation = suspensionDamping; wheel.m_wheelsDampingCompression = suspensionCompression; wheel.m_frictionSlip = wheelFriction; wheel.m_rollInfluence = rollInfluence; } } setCameraDistance(26.f); }
virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult\n"); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroids[numObjects] = SimdVector3(0,0,0); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; centroids[numObjects] += vertex0; centroids[numObjects]+= vertex1; centroids[numObjects]+= vertex2; } } centroids[numObjects] *= 1.f/(float(result.mHullTcount) * 3); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroids[numObjects]; vertex1 -= centroids[numObjects]; vertex2 -= centroids[numObjects]; trimesh->AddTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } shapeIndex[numObjects] = numObjects; shapePtr[numObjects++] = new ConvexTriangleMeshShape(trimesh); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } }
void TinyRenderer::renderObject(TinyRenderObjectData& renderData) { B3_PROFILE("renderObject"); int width = renderData.m_rgbColorBuffer.get_width(); int height = renderData.m_rgbColorBuffer.get_height(); Vec3f light_dir_local = Vec3f(renderData.m_lightDirWorld[0],renderData.m_lightDirWorld[1],renderData.m_lightDirWorld[2]); Vec3f light_color = Vec3f(renderData.m_lightColor[0],renderData.m_lightColor[1],renderData.m_lightColor[2]); float light_distance = renderData.m_lightDistance; Model* model = renderData.m_model; if (0==model) return; //discard invisible objects (zero alpha) if (model->getColorRGBA()[3]==0) return; renderData.m_viewportMatrix = viewport(0,0,width, height); b3AlignedObjectArray<float>& zbuffer = renderData.m_depthBuffer; b3AlignedObjectArray<float>* shadowBufferPtr = renderData.m_shadowBuffer; int* segmentationMaskBufferPtr = (renderData.m_segmentationMaskBufferPtr && renderData.m_segmentationMaskBufferPtr->size())?&renderData.m_segmentationMaskBufferPtr->at(0):0; TGAImage& frame = renderData.m_rgbColorBuffer; { // light target is set to be the origin, and the up direction is set to be vertical up. Matrix lightViewMatrix = lookat(light_dir_local*light_distance, Vec3f(0.0,0.0,0.0), Vec3f(0.0,0.0,1.0)); Matrix lightModelViewMatrix = lightViewMatrix*renderData.m_modelMatrix; Matrix modelViewMatrix = renderData.m_viewMatrix*renderData.m_modelMatrix; Vec3f localScaling(renderData.m_localScaling[0],renderData.m_localScaling[1],renderData.m_localScaling[2]); Matrix viewMatrixInv = renderData.m_viewMatrix.invert(); btVector3 P(viewMatrixInv[0][3], viewMatrixInv[1][3], viewMatrixInv[2][3]); Shader shader(model, light_dir_local, light_color, modelViewMatrix, lightModelViewMatrix, renderData.m_projectionMatrix,renderData.m_modelMatrix, renderData.m_viewportMatrix, localScaling, model->getColorRGBA(), width, height, shadowBufferPtr, renderData.m_lightAmbientCoeff, renderData.m_lightDiffuseCoeff, renderData.m_lightSpecularCoeff); { B3_PROFILE("face"); for (int i=0; i<model->nfaces(); i++) { for (int j=0; j<3; j++) { shader.vertex(i, j); } // backface culling btVector3 v0(shader.world_tri.col(0)[0], shader.world_tri.col(0)[1], shader.world_tri.col(0)[2]); btVector3 v1(shader.world_tri.col(1)[0], shader.world_tri.col(1)[1], shader.world_tri.col(1)[2]); btVector3 v2(shader.world_tri.col(2)[0], shader.world_tri.col(2)[1], shader.world_tri.col(2)[2]); btVector3 N = (v1-v0).cross(v2-v0); if ((v0-P).dot(N) >= 0) continue; mat<4,3,float> stackTris[3]; b3AlignedObjectArray< mat<4,3,float> > clippedTriangles; clippedTriangles.initializeFromBuffer(stackTris,0,3); bool hasClipped = clipTriangleAgainstNearplane(shader.varying_tri,clippedTriangles); if (hasClipped) { for (int t=0;t<clippedTriangles.size();t++) { triangleClipped(clippedTriangles[t], shader.varying_tri, shader, frame, &zbuffer[0], segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex); } } else { triangle(shader.varying_tri, shader, frame, &zbuffer[0], segmentationMaskBufferPtr, renderData.m_viewportMatrix, renderData.m_objectIndex); } } } } }
//-------------------------------------------------------------- void ofxBulletConvexShape::init( ofMesh& aMesh, ofVec3f a_localScaling, bool a_bUseConvexHull ) { _centroid.zero(); btVector3 centroid = btVector3(0, 0, 0); btVector3 localScaling( a_localScaling.x, a_localScaling.y, a_localScaling.z ); vector <ofIndexType> indicies = aMesh.getIndices(); vector <ofVec3f> verticies = aMesh.getVertices(); if(!a_bUseConvexHull) { for(int i = 0; i < verticies.size(); i++) { btVector3 tempVec = btVector3(verticies[i].x, verticies[i].y, verticies[i].z); tempVec *= localScaling; centroid += tempVec; } centroid /= (float)verticies.size(); vector<btVector3> newVerts; for ( int i = 0; i < indicies.size(); i++) { btVector3 vertex( verticies[indicies[i]].x, verticies[indicies[i]].y, verticies[indicies[i]].z); vertex *= localScaling; vertex -= centroid; newVerts.push_back(vertex); } btConvexHullShape* convexShape = new btConvexHullShape(&(newVerts[0].getX()), newVerts.size()); convexShape->setMargin( 0.01f ); _shape = convexShape; _centroid = ofVec3f(centroid.getX(), centroid.getY(), centroid.getZ() ); } else { // HULL Building code from example ConvexDecompositionDemo.cpp // btTriangleMesh* trimesh = new btTriangleMesh(); for ( int i = 0; i < indicies.size()/3; i++) { int index0 = indicies[i*3]; int index1 = indicies[i*3+1]; int index2 = indicies[i*3+2]; btVector3 vertex0( verticies[index0].x, verticies[index0].y, verticies[index0].z ); btVector3 vertex1( verticies[index1].x, verticies[index1].y, verticies[index1].z ); btVector3 vertex2( verticies[index2].x, verticies[index2].y, verticies[index2].z ); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->addTriangle(vertex0, vertex1, vertex2); } btConvexShape* tmpConvexShape = new btConvexTriangleMeshShape(trimesh); //create a hull approximation btShapeHull* hull = new btShapeHull(tmpConvexShape); btScalar margin = tmpConvexShape->getMargin(); hull->buildHull(margin); tmpConvexShape->setUserPointer(hull); centroid = btVector3(0., 0., 0.); for (int i = 0; i < hull->numVertices(); i++) { centroid += hull->getVertexPointer()[i]; } centroid /= (float)hull->numVertices(); btConvexHullShape* convexShape = new btConvexHullShape(); for (int i=0;i<hull->numVertices();i++) { convexShape->addPoint(hull->getVertexPointer()[i] - centroid); } delete tmpConvexShape; delete hull; _shape = convexShape; _centroid = ofVec3f(centroid.getX(), centroid.getY(), centroid.getZ() ); } _bInited = true; }
int main(int argc,char** argv) { int i; for (i=0;i<numObjects;i++) { if (i>0) { shapePtr[i] = prebuildShapePtr[1]; shapeIndex[i] = 1;//sphere } else { shapeIndex[i] = 0; shapePtr[i] = prebuildShapePtr[0]; } } ConvexDecomposition::WavefrontObj wo; char* filename = "file.obj"; tcount = wo.loadObj(filename); class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface { public: MyConvexDecomposition (FILE* outputFile) :mBaseCount(0), mHullCount(0), mOutputFile(outputFile) { } virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult\n"); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroids[numObjects] = SimdVector3(0,0,0); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; centroids[numObjects] += vertex0; centroids[numObjects]+= vertex1; centroids[numObjects]+= vertex2; } } centroids[numObjects] *= 1.f/(float(result.mHullTcount) * 3); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroids[numObjects]; vertex1 -= centroids[numObjects]; vertex2 -= centroids[numObjects]; trimesh->AddTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } shapeIndex[numObjects] = numObjects; shapePtr[numObjects++] = new ConvexTriangleMeshShape(trimesh); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } } int mBaseCount; int mHullCount; FILE* mOutputFile; }; if (tcount) { numObjects = 1; //always have the ground object first TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); for (int i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; SimdVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); SimdVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); SimdVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->AddTriangle(vertex0,vertex1,vertex2); } shapePtr[numObjects++] = new ConvexTriangleMeshShape(trimesh); } if (tcount) { char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); unsigned int depth = 7; float cpercent = 5; float ppercent = 15; unsigned int maxv = 16; float skinWidth = 0.01; printf("WavefrontObj num triangles read %i",tcount); ConvexDecomposition::DecompDesc desc; desc.mVcount = wo.mVertexCount; desc.mVertices = wo.mVertices; desc.mTcount = wo.mTriCount; desc.mIndices = (unsigned int *)wo.mIndices; desc.mDepth = depth; desc.mCpercent = cpercent; desc.mPpercent = ppercent; desc.mMaxVertices = maxv; desc.mSkinWidth = skinWidth; MyConvexDecomposition convexDecomposition(outputFile); desc.mCallback = &convexDecomposition; //convexDecomposition.performConvexDecomposition(desc); ConvexBuilder cb(desc.mCallback); int ret = cb.process(desc); if (outputFile) fclose(outputFile); } CollisionDispatcher* dispatcher = new CollisionDispatcher(); SimdVector3 worldAabbMin(-10000,-10000,-10000); SimdVector3 worldAabbMax(10000,10000,10000); OverlappingPairCache* broadphase = new AxisSweep3(worldAabbMin,worldAabbMax); //OverlappingPairCache* broadphase = new SimpleBroadphase(); physicsEnvironmentPtr = new CcdPhysicsEnvironment(dispatcher,broadphase); physicsEnvironmentPtr->setDeactivationTime(2.f); physicsEnvironmentPtr->setGravity(0,-10,0); PHY_ShapeProps shapeProps; shapeProps.m_do_anisotropic = false; shapeProps.m_do_fh = false; shapeProps.m_do_rot_fh = false; shapeProps.m_friction_scaling[0] = 1.; shapeProps.m_friction_scaling[1] = 1.; shapeProps.m_friction_scaling[2] = 1.; shapeProps.m_inertia = 1.f; shapeProps.m_lin_drag = 0.2f; shapeProps.m_ang_drag = 0.1f; shapeProps.m_mass = 10.0f; PHY_MaterialProps materialProps; materialProps.m_friction = 10.5f; materialProps.m_restitution = 0.0f; CcdConstructionInfo ccdObjectCi; ccdObjectCi.m_friction = 0.5f; ccdObjectCi.m_linearDamping = shapeProps.m_lin_drag; ccdObjectCi.m_angularDamping = shapeProps.m_ang_drag; SimdTransform tr; tr.setIdentity(); for (i=0;i<numObjects;i++) { shapeProps.m_shape = shapePtr[shapeIndex[i]]; shapeProps.m_shape->SetMargin(0.05f); bool isDyna = i>0; //if (i==1) // isDyna=false; if (0)//i==1) { SimdQuaternion orn(0,0,0.1*SIMD_HALF_PI); ms[i].setWorldOrientation(orn.x(),orn.y(),orn.z(),orn[3]); } if (i>0) { switch (i) { case 1: { ms[i].setWorldPosition(0,10,0); //for testing, rotate the ground cube so the stack has to recover a bit break; } case 2: { ms[i].setWorldPosition(0,8,2); break; } default: ms[i].setWorldPosition(0,i*CUBE_HALF_EXTENTS*2 - CUBE_HALF_EXTENTS,0); } float quatIma0,quatIma1,quatIma2,quatReal; SimdQuaternion quat; SimdVector3 axis(0,0,1); SimdScalar angle=0.5f; quat.setRotation(axis,angle); ms[i].setWorldOrientation(quat.getX(),quat.getY(),quat.getZ(),quat[3]); } else { ms[i].setWorldPosition(0,-10+EXTRA_HEIGHT,0); } ccdObjectCi.m_MotionState = &ms[i]; ccdObjectCi.m_gravity = SimdVector3(0,0,0); ccdObjectCi.m_localInertiaTensor =SimdVector3(0,0,0); if (!isDyna) { shapeProps.m_mass = 0.f; ccdObjectCi.m_mass = shapeProps.m_mass; ccdObjectCi.m_collisionFlags = CollisionObject::isStatic; } else { shapeProps.m_mass = 1.f; ccdObjectCi.m_mass = shapeProps.m_mass; ccdObjectCi.m_collisionFlags = 0; } SimdVector3 localInertia; if (shapePtr[shapeIndex[i]]->GetShapeType() == EMPTY_SHAPE_PROXYTYPE) { //take inertia from first shape shapePtr[1]->CalculateLocalInertia(shapeProps.m_mass,localInertia); } else { shapePtr[shapeIndex[i]]->CalculateLocalInertia(shapeProps.m_mass,localInertia); } ccdObjectCi.m_localInertiaTensor = localInertia; ccdObjectCi.m_collisionShape = shapePtr[shapeIndex[i]]; physObjects[i]= new CcdPhysicsController( ccdObjectCi); // Only do CCD if motion in one timestep (1.f/60.f) exceeds CUBE_HALF_EXTENTS physObjects[i]->GetRigidBody()->m_ccdSquareMotionTreshold = CUBE_HALF_EXTENTS; //Experimental: better estimation of CCD Time of Impact: //physObjects[i]->GetRigidBody()->m_ccdSweptShereRadius = 0.5*CUBE_HALF_EXTENTS; physicsEnvironmentPtr->addCcdPhysicsController( physObjects[i]); if (i==1) { //physObjects[i]->SetAngularVelocity(0,0,-2,true); } physicsEnvironmentPtr->setDebugDrawer(&debugDrawer); } //create a constraint if (createConstraint) { //physObjects[i]->SetAngularVelocity(0,0,-2,true); int constraintId; float pivotX=CUBE_HALF_EXTENTS, pivotY=-CUBE_HALF_EXTENTS, pivotZ=CUBE_HALF_EXTENTS; float axisX=1,axisY=0,axisZ=0; HingeConstraint* hinge = 0; SimdVector3 pivotInA(CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS); SimdVector3 pivotInB(-CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS); SimdVector3 axisInA(0,1,0); SimdVector3 axisInB(0,-1,0); RigidBody* rb0 = physObjects[1]->GetRigidBody(); RigidBody* rb1 = physObjects[2]->GetRigidBody(); hinge = new HingeConstraint( *rb0, *rb1,pivotInA,pivotInB,axisInA,axisInB); physicsEnvironmentPtr->m_constraints.push_back(hinge); hinge->SetUserConstraintId(100); hinge->SetUserConstraintType(PHY_LINEHINGE_CONSTRAINT); } clientResetScene(); setCameraDistance(26.f); return glutmain(argc, argv,640,480,"Bullet Physics Demo. http://www.continuousphysics.com/Bullet/phpBB2/"); }
int Test_mindot(void) { // Init an array flanked by guard pages btSimdFloat4 *data = (btSimdFloat4 *)GuardCalloc(1, MAX_SIZE * sizeof(btSimdFloat4), NULL); float *fp = (float *)data; long correct, test; btVector3 localScaling(0.1f, 0.2f, 0.3f); size_t size; // Init the data size_t i; for (i = 0; i < MAX_SIZE; i++) { fp[4 * i] = (int32_t)RANDF_16; fp[4 * i + 1] = (int32_t)RANDF_16; fp[4 * i + 2] = (int32_t)RANDF_16; fp[4 * i + 3] = BT_NAN; // w channel NaN } float correctDot, testDot; fp = (float *)localScaling; float maxRelativeError = 0.f; for (size = 1; size <= MAX_SIZE; size++) { float *in = (float *)(data + MAX_SIZE - size); size_t position; for (position = 0; position < size; position++) { float *biggest = in + position * 4; float old[4] = {biggest[0], biggest[1], biggest[2], biggest[3]}; biggest[0] -= LARGE_FLOAT17; biggest[1] -= LARGE_FLOAT17; biggest[2] -= LARGE_FLOAT17; biggest[3] -= LARGE_FLOAT17; correctDot = BT_NAN; testDot = BT_NAN; correct = mindot_ref((btSimdFloat4 *)in, (float *)&localScaling, size, &correctDot); test = localScaling.minDot((btVector3 *)in, size, testDot); if (test < 0 || test >= size) { vlog("Error @ %ld: index out of bounds! *%ld vs %ld \n", size, correct, test); continue; } if (correct != test) { vlog("Error @ %ld: index misreported! *%ld vs %ld (*%f, %f)\n", size, correct, test, fp[0] * in[4 * correct] + fp[1] * in[4 * correct + 1] + fp[2] * in[4 * correct + 2], fp[0] * in[4 * test] + fp[1] * in[4 * test + 1] + fp[2] * in[4 * test + 2]); return 1; } if (test != position) { vlog("Biggest not found where it is supposed to be: *%ld vs %ld (*%f, %f)\n", position, test, fp[0] * in[4 * test] + fp[1] * in[4 * test + 1] + fp[2] * in[4 * test + 2], fp[0] * in[4 * position] + fp[1] * in[4 * position + 1] + fp[2] * in[4 * position + 2]); return 1; } if (correctDot != testDot) { float relativeError = btFabs((testDot - correctDot) / correctDot); if (relativeError > 1e6) { vlog("Error @ %ld: dotpr misreported! *%f vs %f (*%f, %f)\n", size, correctDot, testDot, fp[0] * in[4 * correct] + fp[1] * in[4 * correct + 1] + fp[2] * in[4 * correct + 2], fp[0] * in[4 * test] + fp[1] * in[4 * test + 1] + fp[2] * in[4 * test + 2]); return 1; } else { if (maxRelativeError < relativeError) { maxRelativeError = relativeError; } } } memcpy(biggest, old, 16); } } if (maxRelativeError) { printf("Warning: relative error = %e\n", maxRelativeError); } uint64_t scalarTimes[33 + (MAX_LOG2_SIZE - 5)]; uint64_t vectorTimes[33 + (MAX_LOG2_SIZE - 5)]; size_t j, k; float *in = (float *)data; for (size = 1; size <= 32; size++) { uint64_t startTime, bestTime, currentTime; bestTime = -1LL; scalarTimes[size] = 0; for (j = 0; j < 100; j++) { startTime = ReadTicks(); for (k = 0; k < LOOPCOUNT; k++) correct += mindot_ref((btSimdFloat4 *)in, (float *)&localScaling, size, &correctDot); currentTime = ReadTicks() - startTime; scalarTimes[size] += currentTime; if (currentTime < bestTime) bestTime = currentTime; } if (0 == gReportAverageTimes) scalarTimes[size] = bestTime; else scalarTimes[size] /= 100; } uint64_t *timep = &scalarTimes[33]; for (size = 64; size <= MAX_SIZE; size *= 2) { uint64_t startTime, bestTime, currentTime; bestTime = -1LL; timep[0] = 0; for (j = 0; j < 100; j++) { startTime = ReadTicks(); for (k = 0; k < LOOPCOUNT; k++) correct += mindot_ref((btSimdFloat4 *)in, (float *)&localScaling, size, &correctDot); currentTime = ReadTicks() - startTime; timep[0] += currentTime; if (currentTime < bestTime) bestTime = currentTime; } if (0 == gReportAverageTimes) timep[0] = bestTime; else timep[0] /= 100; timep++; } for (size = 1; size <= 32; size++) { uint64_t startTime, bestTime, currentTime; bestTime = -1LL; vectorTimes[size] = 0; for (j = 0; j < 100; j++) { startTime = ReadTicks(); for (k = 0; k < LOOPCOUNT; k++) test += localScaling.minDot((btVector3 *)in, size, testDot); currentTime = ReadTicks() - startTime; vectorTimes[size] += currentTime; if (currentTime < bestTime) bestTime = currentTime; } if (0 == gReportAverageTimes) vectorTimes[size] = bestTime; else vectorTimes[size] /= 100; } timep = &vectorTimes[33]; for (size = 64; size <= MAX_SIZE; size *= 2) { uint64_t startTime, bestTime, currentTime; bestTime = -1LL; timep[0] = 0; for (j = 0; j < 100; j++) { startTime = ReadTicks(); for (k = 0; k < LOOPCOUNT; k++) test += localScaling.minDot((btVector3 *)in, size, testDot); currentTime = ReadTicks() - startTime; timep[0] += currentTime; if (currentTime < bestTime) bestTime = currentTime; } if (0 == gReportAverageTimes) timep[0] = bestTime; else timep[0] /= 100; timep++; } vlog("Timing:\n"); vlog(" size\t scalar\t vector\n"); for (size = 1; size <= 32; size++) vlog("%5lu\t%10.2f\t%10.2f\n", size, TicksToCycles(scalarTimes[size]) / LOOPCOUNT, TicksToCycles(vectorTimes[size]) / LOOPCOUNT); size_t index = 33; for (size = 64; size <= MAX_SIZE; size *= 2) { vlog("%5lu\t%10.2f\t%10.2f\n", size, TicksToCycles(scalarTimes[index]) / LOOPCOUNT, TicksToCycles(vectorTimes[index]) / LOOPCOUNT); index++; } // Useless check to make sure that the timing loops are not optimized away if (test != correct) vlog("Error: Test != correct: *%ld vs. %ld\n", correct, test); GuardFree(data); return 0; }
//-------------------------------------------------------------- bool ofxBulletCustomShape::addMesh( ofMesh a_mesh, ofVec3f a_localScaling, bool a_bUseConvexHull ) { if(a_mesh.getMode() != OF_PRIMITIVE_TRIANGLES) { ofLog( OF_LOG_ERROR, "ofxBulletCustomShape :: addMesh : mesh must be set to OF_PRIMITIVE_TRIANGLES!! aborting"); return false; } if(_bAdded == true) { ofLog( OF_LOG_ERROR, "ofxBulletCustomShape :: addMesh : can not call after calling add()" ); return false; } btVector3 localScaling( a_localScaling.x, a_localScaling.y, a_localScaling.z ); vector <ofIndexType> indicies = a_mesh.getIndices(); vector <ofVec3f> verticies = a_mesh.getVertices(); btVector3 centroid = btVector3(0, 0, 0); if(!a_bUseConvexHull) { for(int i = 0; i < verticies.size(); i++) { btVector3 tempVec = btVector3(verticies[i].x, verticies[i].y, verticies[i].z); tempVec *= localScaling; centroid += tempVec; } centroid /= (float)verticies.size(); vector<btVector3> newVerts; for ( int i = 0; i < indicies.size(); i++) { btVector3 vertex( verticies[indicies[i]].x, verticies[indicies[i]].y, verticies[indicies[i]].z); vertex *= localScaling; vertex -= centroid; newVerts.push_back(vertex); } btConvexHullShape* convexShape = new btConvexHullShape(&(newVerts[0].getX()), newVerts.size()); convexShape->setMargin( 0.01f ); shapes.push_back( convexShape ); centroids.push_back( ofVec3f(centroid.getX(), centroid.getY(), centroid.getZ()) ); } else { // HULL Building code from example ConvexDecompositionDemo.cpp // btTriangleMesh* trimesh = new btTriangleMesh(); for ( int i = 0; i < indicies.size()/3; i++) { int index0 = indicies[i*3]; int index1 = indicies[i*3+1]; int index2 = indicies[i*3+2]; btVector3 vertex0( verticies[index0].x, verticies[index0].y, verticies[index0].z ); btVector3 vertex1( verticies[index1].x, verticies[index1].y, verticies[index1].z ); btVector3 vertex2( verticies[index2].x, verticies[index2].y, verticies[index2].z ); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->addTriangle(vertex0, vertex1, vertex2); } //cout << "ofxBulletCustomShape :: addMesh : input triangles = " << trimesh->getNumTriangles() << endl; //cout << "ofxBulletCustomShape :: addMesh : input indicies = " << indicies.size() << endl; //cout << "ofxBulletCustomShape :: addMesh : input verticies = " << verticies.size() << endl; btConvexShape* tmpConvexShape = new btConvexTriangleMeshShape(trimesh); //create a hull approximation btShapeHull* hull = new btShapeHull(tmpConvexShape); btScalar margin = tmpConvexShape->getMargin(); hull->buildHull(margin); tmpConvexShape->setUserPointer(hull); centroid = btVector3(0., 0., 0.); for (int i = 0; i < hull->numVertices(); i++) { centroid += hull->getVertexPointer()[i]; } centroid /= (float)hull->numVertices(); //printf("ofxBulletCustomShape :: addMesh : new hull numTriangles = %d\n", hull->numTriangles()); //printf("ofxBulletCustomShape :: addMesh : new hull numIndices = %d\n", hull->numIndices()); //printf("ofxBulletCustomShape :: addMesh : new hull numVertices = %d\n", hull->numVertices()); btConvexHullShape* convexShape = new btConvexHullShape(); for (int i=0;i<hull->numVertices();i++) { convexShape->addPoint(hull->getVertexPointer()[i] - centroid); } delete tmpConvexShape; delete hull; shapes.push_back( convexShape ); centroids.push_back( ofVec3f(centroid.getX(), centroid.getY(), centroid.getZ()) ); } return true; }
virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { btTriangleMesh* trimesh = new btTriangleMesh(); m_convexDemo->m_trimeshes.push_back(trimesh); btVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult. "); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroid.setValue(0,0,0); btAlignedObjectArray<btVector3> vertices; if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; centroid += vertex; } } centroid *= 1.f/(float(result.mHullVcount) ); if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; vertex -= centroid ; vertices.push_back(vertex); } } if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; btVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); btVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); btVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->addTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } // float mass = 1.f; //this is a tools issue: due to collision margin, convex objects overlap, compensate for it here: //#define SHRINK_OBJECT_INWARDS 1 #ifdef SHRINK_OBJECT_INWARDS float collisionMargin = 0.01f; btAlignedObjectArray<btVector3> planeEquations; btGeometryUtil::getPlaneEquationsFromVertices(vertices,planeEquations); btAlignedObjectArray<btVector3> shiftedPlaneEquations; for (int p=0;p<planeEquations.size();p++) { btVector3 plane = planeEquations[p]; plane[3] += collisionMargin; shiftedPlaneEquations.push_back(plane); } btAlignedObjectArray<btVector3> shiftedVertices; btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,shiftedVertices); btConvexHullShape* convexShape = new btConvexHullShape(&(shiftedVertices[0].getX()),shiftedVertices.size()); #else //SHRINK_OBJECT_INWARDS btConvexHullShape* convexShape = new btConvexHullShape(&(vertices[0].getX()),vertices.size()); #endif convexShape->setMargin(0.01f); m_convexShapes.push_back(convexShape); m_convexCentroids.push_back(centroid); m_convexDemo->m_collisionShapes.push_back(convexShape); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } }
// --------------------------------------------------------- PhysBody3D* ModulePhysics3D::AddHeighField(const char* filename, int width, int length) { unsigned char* heightfieldData = new unsigned char[width*length]; { for(int i = 0; i<width*length; i++) heightfieldData[i] = 0; } FILE* heightfieldFile; fopen_s(&heightfieldFile, filename, "r"); if(heightfieldFile) { int numBytes = fread(heightfieldData, 1, width*length, heightfieldFile); //btAssert(numBytes); if(!numBytes) { printf("couldn't read heightfield at %s\n", filename); } fclose(heightfieldFile); } //btScalar maxHeight = 20000.f;//exposes a bug btScalar maxHeight = 100; bool useFloatDatam = false; bool flipQuadEdges = false; int upIndex = 1; btHeightfieldTerrainShape* heightFieldShape = new btHeightfieldTerrainShape(width, length, heightfieldData, maxHeight, upIndex, useFloatDatam, flipQuadEdges); btVector3 mmin, mmax; heightFieldShape->getAabb(btTransform::getIdentity(), mmin, mmax); btCollisionShape* groundShape = heightFieldShape; heightFieldShape->setUseDiamondSubdivision(true); btVector3 localScaling(10, 1, 10); localScaling[upIndex] = 1.f; groundShape->setLocalScaling(localScaling); shapes.add(groundShape); //create ground object btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0, 49.4, 0)); btVector3 localInertia(0, 0, 0); btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); btRigidBody::btRigidBodyConstructionInfo rbInfo(0.0f, myMotionState, groundShape, localInertia); btRigidBody* body = new btRigidBody(rbInfo); PhysBody3D* pbody = new PhysBody3D(body); body->setUserPointer(pbody); world->addRigidBody(body); bodies.add(pbody); return pbody; }
void ConvexDecompositionDemo::initPhysics(const char* filename) { gContactAddedCallback = &MyContactCallback; setupEmptyDynamicsWorld(); setTexturing(true); setShadows(true); setCameraDistance(26.f); #ifndef NO_OBJ_TO_BULLET ConvexDecomposition::WavefrontObj wo; tcount = wo.loadObj(filename); if (!tcount) { //when running this app from visual studio, the default starting folder is different, so make a second attempt... tcount = wo.loadObj("../../file.obj"); } if (!tcount) { //cmake generated msvc files need 4 levels deep back... so make a 3rd attempt... tcount = wo.loadObj("../../../../file.obj"); } btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,-4.5,0)); btCollisionShape* boxShape = new btBoxShape(btVector3(30,2,30)); m_collisionShapes.push_back(boxShape); localCreateRigidBody(0.f,startTransform,boxShape); class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface { ConvexDecompositionDemo* m_convexDemo; public: btAlignedObjectArray<btConvexHullShape*> m_convexShapes; btAlignedObjectArray<btVector3> m_convexCentroids; MyConvexDecomposition (FILE* outputFile,ConvexDecompositionDemo* demo) :m_convexDemo(demo), mBaseCount(0), mHullCount(0), mOutputFile(outputFile) { } virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { btTriangleMesh* trimesh = new btTriangleMesh(); m_convexDemo->m_trimeshes.push_back(trimesh); btVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult. "); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroid.setValue(0,0,0); btAlignedObjectArray<btVector3> vertices; if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; centroid += vertex; } } centroid *= 1.f/(float(result.mHullVcount) ); if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; vertex -= centroid ; vertices.push_back(vertex); } } if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; btVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); btVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); btVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->addTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } // float mass = 1.f; //this is a tools issue: due to collision margin, convex objects overlap, compensate for it here: //#define SHRINK_OBJECT_INWARDS 1 #ifdef SHRINK_OBJECT_INWARDS float collisionMargin = 0.01f; btAlignedObjectArray<btVector3> planeEquations; btGeometryUtil::getPlaneEquationsFromVertices(vertices,planeEquations); btAlignedObjectArray<btVector3> shiftedPlaneEquations; for (int p=0;p<planeEquations.size();p++) { btVector3 plane = planeEquations[p]; plane[3] += collisionMargin; shiftedPlaneEquations.push_back(plane); } btAlignedObjectArray<btVector3> shiftedVertices; btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,shiftedVertices); btConvexHullShape* convexShape = new btConvexHullShape(&(shiftedVertices[0].getX()),shiftedVertices.size()); #else //SHRINK_OBJECT_INWARDS btConvexHullShape* convexShape = new btConvexHullShape(&(vertices[0].getX()),vertices.size()); #endif convexShape->setMargin(0.01f); m_convexShapes.push_back(convexShape); m_convexCentroids.push_back(centroid); m_convexDemo->m_collisionShapes.push_back(convexShape); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } } int mBaseCount; int mHullCount; FILE* mOutputFile; }; if (tcount) { btTriangleMesh* trimesh = new btTriangleMesh(); m_trimeshes.push_back(trimesh); btVector3 localScaling(6.f,6.f,6.f); int i; for ( i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; btVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); btVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); btVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->addTriangle(vertex0,vertex1,vertex2); } btConvexShape* tmpConvexShape = new btConvexTriangleMeshShape(trimesh); printf("old numTriangles= %d\n",wo.mTriCount); printf("old numIndices = %d\n",wo.mTriCount*3); printf("old numVertices = %d\n",wo.mVertexCount); printf("reducing vertices by creating a convex hull\n"); //create a hull approximation btShapeHull* hull = new btShapeHull(tmpConvexShape); btScalar margin = tmpConvexShape->getMargin(); hull->buildHull(margin); tmpConvexShape->setUserPointer(hull); printf("new numTriangles = %d\n", hull->numTriangles ()); printf("new numIndices = %d\n", hull->numIndices ()); printf("new numVertices = %d\n", hull->numVertices ()); btConvexHullShape* convexShape = new btConvexHullShape(); for (i=0;i<hull->numVertices();i++) { convexShape->addPoint(hull->getVertexPointer()[i]); } delete tmpConvexShape; delete hull; m_collisionShapes.push_back(convexShape); float mass = 1.f; btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,2,14)); localCreateRigidBody(mass, startTransform,convexShape); bool useQuantization = true; btCollisionShape* concaveShape = new btBvhTriangleMeshShape(trimesh,useQuantization); startTransform.setOrigin(convexDecompositionObjectOffset); localCreateRigidBody(0.f,startTransform,concaveShape); m_collisionShapes.push_back (concaveShape); } if (tcount) { char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); unsigned int depth = 5; float cpercent = 5; float ppercent = 15; unsigned int maxv = 16; float skinWidth = 0.0; printf("WavefrontObj num triangles read %i\n",tcount); ConvexDecomposition::DecompDesc desc; desc.mVcount = wo.mVertexCount; desc.mVertices = wo.mVertices; desc.mTcount = wo.mTriCount; desc.mIndices = (unsigned int *)wo.mIndices; desc.mDepth = depth; desc.mCpercent = cpercent; desc.mPpercent = ppercent; desc.mMaxVertices = maxv; desc.mSkinWidth = skinWidth; MyConvexDecomposition convexDecomposition(outputFile,this); desc.mCallback = &convexDecomposition; //convexDecomposition.performConvexDecomposition(desc); ConvexBuilder cb(desc.mCallback); cb.process(desc); //now create some bodies if (1) { btCompoundShape* compound = new btCompoundShape(); m_collisionShapes.push_back (compound); btTransform trans; trans.setIdentity(); for (int i=0;i<convexDecomposition.m_convexShapes.size();i++) { btVector3 centroid = convexDecomposition.m_convexCentroids[i]; trans.setOrigin(centroid); btConvexHullShape* convexShape = convexDecomposition.m_convexShapes[i]; compound->addChildShape(trans,convexShape); btRigidBody* body; body = localCreateRigidBody( 1.0, trans,convexShape); } #if 1 btScalar mass=10.f; trans.setOrigin(-convexDecompositionObjectOffset); btRigidBody* body = localCreateRigidBody( mass, trans,compound); body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); convexDecompositionObjectOffset.setZ(6); trans.setOrigin(-convexDecompositionObjectOffset); body = localCreateRigidBody( mass, trans,compound); body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); convexDecompositionObjectOffset.setZ(-6); trans.setOrigin(-convexDecompositionObjectOffset); body = localCreateRigidBody( mass, trans,compound); body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); #endif } if (outputFile) fclose(outputFile); } #ifdef TEST_SERIALIZATION //test serializing this int maxSerializeBufferSize = 1024*1024*5; btDefaultSerializer* serializer = new btDefaultSerializer(maxSerializeBufferSize); m_dynamicsWorld->serialize(serializer); FILE* f2 = fopen("testFile.bullet","wb"); fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1,f2); fclose(f2); exitPhysics(); //now try again from the loaded file setupEmptyDynamicsWorld(); #endif //TEST_SERIALIZATION #endif //NO_OBJ_TO_BULLET #ifdef TEST_SERIALIZATION btBulletWorldImporter* fileLoader = new btBulletWorldImporter(m_dynamicsWorld); //fileLoader->setVerboseMode(true); fileLoader->loadFile("testFile.bullet"); //fileLoader->loadFile("testFile64Double.bullet"); //fileLoader->loadFile("testFile64Single.bullet"); //fileLoader->loadFile("testFile32Single.bullet"); #endif //TEST_SERIALIZATION }
void ConvexDecompositionDemo::initPhysics(const char* filename) { ConvexDecomposition::WavefrontObj wo; tcount = wo.loadObj(filename); CollisionDispatcher* dispatcher = new CollisionDispatcher(); SimdVector3 worldAabbMin(-10000,-10000,-10000); SimdVector3 worldAabbMax(10000,10000,10000); OverlappingPairCache* broadphase = new AxisSweep3(worldAabbMin,worldAabbMax); //OverlappingPairCache* broadphase = new SimpleBroadphase(); m_physicsEnvironmentPtr = new CcdPhysicsEnvironment(dispatcher,broadphase); m_physicsEnvironmentPtr->setDeactivationTime(2.f); m_physicsEnvironmentPtr->setGravity(0,-10,0); SimdTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(SimdVector3(0,-4,0)); LocalCreatePhysicsObject(false,0,startTransform,new BoxShape(SimdVector3(30,2,30))); class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface { ConvexDecompositionDemo* m_convexDemo; public: MyConvexDecomposition (FILE* outputFile,ConvexDecompositionDemo* demo) :m_convexDemo(demo), mBaseCount(0), mHullCount(0), mOutputFile(outputFile) { } virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult\n"); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroid.setValue(0,0,0); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; centroid += vertex0; centroid += vertex1; centroid += vertex2; } } centroid *= 1.f/(float(result.mHullTcount) * 3); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->AddTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } bool isDynamic = true; float mass = 1.f; CollisionShape* convexShape = new ConvexTriangleMeshShape(trimesh); SimdTransform trans; trans.setIdentity(); trans.setOrigin(centroid); m_convexDemo->LocalCreatePhysicsObject(isDynamic, mass, trans,convexShape); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } } int mBaseCount; int mHullCount; FILE* mOutputFile; }; if (tcount) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); for (int i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; SimdVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); SimdVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); SimdVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->AddTriangle(vertex0,vertex1,vertex2); } CollisionShape* convexShape = new ConvexTriangleMeshShape(trimesh); bool isDynamic = true; float mass = 1.f; SimdTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(SimdVector3(20,2,0)); LocalCreatePhysicsObject(isDynamic, mass, startTransform,convexShape); } if (tcount) { char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); unsigned int depth = 7; float cpercent = 5; float ppercent = 15; unsigned int maxv = 16; float skinWidth = 0.01; printf("WavefrontObj num triangles read %i",tcount); ConvexDecomposition::DecompDesc desc; desc.mVcount = wo.mVertexCount; desc.mVertices = wo.mVertices; desc.mTcount = wo.mTriCount; desc.mIndices = (unsigned int *)wo.mIndices; desc.mDepth = depth; desc.mCpercent = cpercent; desc.mPpercent = ppercent; desc.mMaxVertices = maxv; desc.mSkinWidth = skinWidth; MyConvexDecomposition convexDecomposition(outputFile,this); desc.mCallback = &convexDecomposition; //convexDecomposition.performConvexDecomposition(desc); ConvexBuilder cb(desc.mCallback); cb.process(desc); if (outputFile) fclose(outputFile); } m_physicsEnvironmentPtr->setDebugDrawer(&debugDrawer); }
virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult\n"); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroid.setValue(0,0,0); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; centroid += vertex0; centroid += vertex1; centroid += vertex2; } } centroid *= 1.f/(float(result.mHullTcount) * 3); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->AddTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } bool isDynamic = true; float mass = 1.f; CollisionShape* convexShape = new ConvexTriangleMeshShape(trimesh); SimdTransform trans; trans.setIdentity(); trans.setOrigin(centroid); m_convexDemo->LocalCreatePhysicsObject(isDynamic, mass, trans,convexShape); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } }
//----------------------------------------------------------------------- // C o n v e x D e c o m p R e s u l t //----------------------------------------------------------------------- void TMeshShape::ConvexDecompResult(ConvexResult &result) { btTriangleMesh* trimesh = new btTriangleMesh(); m_triMeshes.push_back(trimesh); btVector3 localScaling(1.f,1.f,1.f); btVector3 centroid(0,0,0); btVector3 convexDecompositionObjectOffset(0,0,0); btAlignedObjectArray<btVector3> vertices; //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; centroid += vertex; } centroid *= 1.f/(float(result.mHullVcount) ); //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; vertex -= centroid ; vertices.push_back(vertex); } const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; btVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); btVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); btVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->addTriangle(vertex0,vertex1,vertex2); index0+=m_baseCount; index1+=m_baseCount; index2+=m_baseCount; } btConvexHullShape* convexShape = new btConvexHullShape(&(vertices[0].getX()),vertices.size()); convexShape->setMargin(0.01f); m_convexShapes.push_back(convexShape); m_convexCentroids.push_back(centroid); m_baseCount+=result.mHullVcount; // advance the 'base index' counter. /* btConvexHullShape* chShape = new btConvexHullShape(); unsigned int vidx=0; getApplication()->logMessage(LOG_INFO, "ConvexDecompResult() mHullVcount: %d, " "mHullTcount: %d ", result.mHullVcount, result.mHullTcount); while (vidx < result.mHullVcount) { btVector3 v; v.setX(result.mHullVertices[vidx]); vidx++; v.setY(result.mHullVertices[vidx]); vidx++; v.setZ(result.mHullVertices[vidx]); vidx++; chShape->addPoint(v); } m_compound->addChildShape(m_localTransform, chShape); */ }
/* ----------------------------------------------------------------------- | build bullet height field shape and generate ogre mesh from grayscale image | | @param in : | @param out: raw data of height field terrain | ToDo: adjest grid scale, grid height, local scale, max/min height ----------------------------------------------------------------------- */ bool buildHeightFieldTerrainFromImage(const Ogre::String& filename, btDynamicsWorld* dynamicsWorld, btAlignedObjectArray<btCollisionShape*>& collisionShapes, void* &data) { Ogre::Image img; try { img.load(filename, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); } catch(Ogre::Exception err) { LOG(err.what()); return false; } size_t grid_w = 65, grid_h = 65; // must be (2^N) + 1 size_t grid_max_w = 129, grid_max_h = 129; // must be (2^N) + 1 size_t img_w = img.getWidth(); size_t img_h = img.getHeight(); // validate image size is (2^N) + 1 if ((img_w-1) & (img_w-2)) img_w = grid_w; if ((img_h-1) & (img_h-2)) img_h = grid_h; //if (img_w > grid_max_w) img_w = grid_max_w; //if (img_h > grid_max_h) img_h = grid_max_h; LOG("LoadImage name=%s, width=%d, height=%d, width^2+1=%d, height^2+1=%d", filename.c_str(), img.getWidth(), img.getHeight(), img_w, img_h); img.resize(img_w, img_h); size_t pixelSize = Ogre::PixelUtil::getNumElemBytes(img.getFormat()); size_t bufSize = img.getSize() / pixelSize; data = new Ogre::Real[ bufSize ]; Ogre::Real* dest = static_cast<Ogre::Real*>(data); memset(dest, 0, bufSize); /* | @ Notice the alignment problem | - uchar to float alignment | - pixel format in bytes as rawdata type, also affects alignment */ Ogre::uchar* src = img.getData(); for (size_t i=0;i<bufSize;++i) { dest[i] = ((Ogre::Real)src[i * pixelSize] - 127.0f)/16.0f; } // parameter int upAxis = 1; btScalar gridSpacing = 5.0f; btScalar gridHeightScale = 0.2f; btScalar minHeight = -10.0f; btScalar maxHeight = 10.0f; btScalar defaultContactProcessingThreshold = BT_LARGE_FLOAT; btHeightfieldTerrainShape *heightfieldShape = new btHeightfieldTerrainShape(img_w, img_h, dest, gridHeightScale, minHeight, maxHeight, upAxis, PHY_FLOAT, false); btAssert(heightfieldShape && "null heightfield"); // shape btVector3 localScaling(1.0f, 1.0f, 1.0f); heightfieldShape->setLocalScaling(localScaling); collisionShapes.push_back(heightfieldShape); // rigidBody btDefaultMotionState* motionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,0,0))); btRigidBody::btRigidBodyConstructionInfo cInfo(0, motionState, heightfieldShape, btVector3(0,0,0)); btRigidBody* rigidBody = new btRigidBody(cInfo); rigidBody->setContactProcessingThreshold(defaultContactProcessingThreshold); int flags = rigidBody->getCollisionFlags(); rigidBody->setCollisionFlags(flags | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT); dynamicsWorld->addRigidBody(rigidBody); // add ogre height field mesh Ogre::SceneManager* sceneMgr = Ogre::Root::getSingletonPtr()->getSceneManager("DefaultSceneManager"); btAssert(sceneMgr); Ogre::ManualObject* obj = sceneMgr->createManualObject("btHeightFieldEntity"); btVector3 aabbMin, aabbMax; heightfieldShape->getAabb(btTransform(btQuaternion(0,0,0,1),btVector3(0,0,0)), aabbMin, aabbMax); btHeightFieldProcessor callback(obj, "DefaultPlane"); heightfieldShape->processAllTriangles(&callback, aabbMin, aabbMax); sceneMgr->getRootSceneNode()->attachObject(obj); return true; }