From 4a078765623b72641164a25291e925bb4e64bcba Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 23 Mar 2009 06:00:21 +0000 Subject: [PATCH] Speedup for bullet physics mesh conversion Was adding each face with a remove doubles option that made conversion increasingly slower for larger meshes, this would often hang blender when starting with the BGE with larger meshes. Replace btTriangleMesh()->addTriangle() with btTriangleIndexVertexArray() YoFrankie level_1_home.blend starts a third faster, level_nut about twice as fast. - previous commit was also incorrect using the original meshes vert locations rather then the vert locations that came from the derived mesh. - Softbody is relying on removing doubles at 0.01 to give stable results, this no longer works but seems a bit dodgy anyway. Maybe some post-processing filter could fix up a mesh for bullet softbody. --- .../Ketsji/KX_ConvertPhysicsObjects.cpp | 3 + .../Physics/Bullet/CcdPhysicsController.cpp | 298 +++++++++++------- .../Physics/Bullet/CcdPhysicsController.h | 5 +- source/gameengine/Rasterizer/RAS_MeshObject.h | 10 + 4 files changed, 198 insertions(+), 118 deletions(-) diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp index 602486e0017..9b2d7403974 100644 --- a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp +++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp @@ -881,6 +881,9 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, { shapeInfo->SetMesh(meshobj, false,false); } + + // Note! since 2.48a bullet mesh conversion has been sped up not to remove doubles + // if softbody needs this there should be some post processing filter for softbody meshes. if (objprop->m_softbody) shapeInfo->setVertexWeldingThreshold(0.01f); //todo: expose this to the UI diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index 61d02847164..35602b4095a 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -16,6 +16,9 @@ subject to the following restrictions: #include "CcdPhysicsController.h" #include "btBulletDynamicsCommon.h" #include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" + +#include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h" + #include "PHY_IMotionState.h" #include "CcdPhysicsEnvironment.h" #include "RAS_MeshObject.h" @@ -1276,150 +1279,212 @@ CcdShapeConstructionInfo* CcdShapeConstructionInfo::FindMesh(RAS_MeshObject* mes bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, bool polytope,bool useGimpact) { + int numpolys; + m_useGimpact = useGimpact; // assume no shape information // no support for dynamic change of shape yet assert(IsUnused()); m_shapeType = PHY_SHAPE_NONE; - m_vertexArray.clear(); - m_polygonIndexArray.clear(); m_meshObject = NULL; - if (!meshobj) - return false; - - // Mesh has no polygons! - int numpolys = meshobj->NumPolygons(); - if (!numpolys) - { + // No mesh object or mesh has no polys + if (!meshobj || meshobj->HasColliderPolygon()==false) { + m_vertexArray.clear(); + m_polygonIndexArray.clear(); + m_triFaceArray.clear(); return false; } - // check that we have at least one colliding polygon - int numvalidpolys = 0; - - for (int p=0; pGetPolygon(p); - - // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { - numvalidpolys++; - break; - } - } - - // No collision polygons - if (numvalidpolys < 1) - return false; + numpolys = meshobj->NumPolygons(); m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH; - numvalidpolys = 0; + /* Convert blender geometry into bullet mesh, need these vars for mapping */ + vector vert_tag_array(meshobj->GetMesh()->totvert, false); + unsigned int tot_bt_verts= 0; + unsigned int orig_index; + int i; if (polytope) { - Mesh *blen_mesh= meshobj->GetMesh(); - vector vuser_array(blen_mesh->totvert, false); - - unsigned int tot_bt_verts= 0; - unsigned int orig_index; - int i; - // Tag verts we're using for (int p2=0; p2GetPolygon(p2); - - // only add polygons that have the collisionflag set + + // only add polygons that have the collision flag set if (poly->IsCollider()) { - for (i=0;iVertexCount();i++) - { + for(i=0; iVertexCount(); i++) { orig_index= poly->GetVertex(i)->getOrigIndex(); - - if (vuser_array[orig_index]==false) + if (vert_tag_array[orig_index]==false) { - vuser_array[orig_index]= true; + vert_tag_array[orig_index]= true; tot_bt_verts++; } } } } - + m_vertexArray.resize(tot_bt_verts); - - // Copy used verts directly from the meshes vert location to the bullet vector array - MVert *mv= blen_mesh->mvert; + btVector3 *bt= &m_vertexArray[0]; - - for (i=0;isetX( mv->co[0] ); - bt->setY( mv->co[1] ); - bt->setZ( mv->co[2] ); - bt++; - } - } - numvalidpolys++; - } - else { + for (int p2=0; p2GetPolygon(p2); + RAS_Polygon* poly= meshobj->GetPolygon(p2); // only add polygons that have the collisionflag set if (poly->IsCollider()) - { - //Bullet can raycast any shape, so - - { - const float* vtx = poly->GetVertex(2)->getXYZ(); - btVector3 vertex0(vtx[0],vtx[1],vtx[2]); + { + for(i=0; iVertexCount(); i++) { + RAS_TexVert *v= poly->GetVertex(i); + orig_index= v->getOrigIndex(); - vtx = poly->GetVertex(1)->getXYZ(); - btVector3 vertex1(vtx[0],vtx[1],vtx[2]); + if (vert_tag_array[orig_index]==true) + { + const float* vtx = v->getXYZ(); + vert_tag_array[orig_index]= false; - vtx = poly->GetVertex(0)->getXYZ(); - btVector3 vertex2(vtx[0],vtx[1],vtx[2]); - - m_vertexArray.push_back(vertex0); - m_vertexArray.push_back(vertex1); - m_vertexArray.push_back(vertex2); - m_polygonIndexArray.push_back(p2); - numvalidpolys++; - } - if (poly->VertexCount() == 4) - { - const float* vtx = poly->GetVertex(3)->getXYZ(); - btVector3 vertex0(vtx[0],vtx[1],vtx[2]); - - vtx = poly->GetVertex(2)->getXYZ(); - btVector3 vertex1(vtx[0],vtx[1],vtx[2]); - - vtx = poly->GetVertex(0)->getXYZ(); - btVector3 vertex2(vtx[0],vtx[1],vtx[2]); - - m_vertexArray.push_back(vertex0); - m_vertexArray.push_back(vertex1); - m_vertexArray.push_back(vertex2); - m_polygonIndexArray.push_back(p2); - numvalidpolys++; + bt->setX(vtx[0]); bt->setY(vtx[1]); bt->setZ(vtx[2]); + bt++; + } } } } } + else { + unsigned int tot_bt_tris= 0; + vector vert_remap_array(meshobj->GetMesh()->totvert, 0); + + // Tag verts we're using + for (int p2=0; p2GetPolygon(p2); - if (!numvalidpolys) + // only add polygons that have the collision flag set + if (poly->IsCollider()) + { + for(i=0; iVertexCount(); i++) { + orig_index= poly->GetVertex(i)->getOrigIndex(); + if (vert_tag_array[orig_index]==false) + { + vert_tag_array[orig_index]= true; + vert_remap_array[orig_index]= tot_bt_verts; + tot_bt_verts++; + } + } + + tot_bt_tris += (i==4 ? 2:1); /* a quad or a tri */ + } + } + + m_vertexArray.resize(tot_bt_verts); + m_polygonIndexArray.resize(tot_bt_tris); + m_triFaceArray.resize(tot_bt_tris*3); + + btVector3 *bt= &m_vertexArray[0]; + int *poly_index_pt= &m_polygonIndexArray[0]; + int *tri_pt= &m_triFaceArray[0]; + + + for (int p2=0; p2GetPolygon(p2); + + // only add polygons that have the collisionflag set + if (poly->IsCollider()) + { + RAS_TexVert *v1= poly->GetVertex(0); + RAS_TexVert *v2= poly->GetVertex(1); + RAS_TexVert *v3= poly->GetVertex(2); + int i1= v1->getOrigIndex(); + int i2= v2->getOrigIndex(); + int i3= v3->getOrigIndex(); + const float* vtx; + + // the face indicies + tri_pt[0]= vert_remap_array[i1]; + tri_pt[1]= vert_remap_array[i2]; + tri_pt[2]= vert_remap_array[i3]; + tri_pt= tri_pt+3; + + // m_polygonIndexArray + *poly_index_pt= p2; + poly_index_pt++; + + // the vertex location + if (vert_tag_array[i1]==true) { /* *** v1 *** */ + vert_tag_array[i1]= false; + vtx = v1->getXYZ(); + bt->setX(vtx[0]); bt->setY( vtx[1]); bt->setZ(vtx[2]); + bt++; + } + if (vert_tag_array[i2]==true) { /* *** v2 *** */ + vert_tag_array[i2]= false; + vtx = v2->getXYZ(); + bt->setX(vtx[0]); bt->setY(vtx[1]); bt->setZ(vtx[2]); + bt++; + } + if (vert_tag_array[i3]==true) { /* *** v3 *** */ + vert_tag_array[i3]= false; + vtx = v3->getXYZ(); + bt->setX(vtx[0]); bt->setY(vtx[1]); bt->setZ(vtx[2]); + bt++; + } + + if (poly->VertexCount()==4) + { + RAS_TexVert *v4= poly->GetVertex(3); + int i4= v4->getOrigIndex(); + + tri_pt[0]= vert_remap_array[i1]; + tri_pt[1]= vert_remap_array[i3]; + tri_pt[2]= vert_remap_array[i4]; + tri_pt= tri_pt+3; + + // m_polygonIndexArray + *poly_index_pt= p2; + poly_index_pt++; + + // the vertex location + if (vert_tag_array[i4]==true) { /* *** v4 *** */ + vert_tag_array[i4]= false; + vtx = v4->getXYZ(); + bt->setX(vtx[0]); bt->setY(vtx[1]); bt->setZ(vtx[2]); + bt++; + } + } + } + } + + + /* If this ever gets confusing, print out an OBJ file for debugging */ +#if 0 + printf("# vert count %d\n", m_vertexArray.size()); + for(i=0; iaddTriangle(m_vertexArray[i+2],m_vertexArray[i+1],m_vertexArray[i],removeDuplicateVertices); - } - - btGImpactMeshShape* gimpactShape = new btGImpactMeshShape(collisionMeshData); + btGImpactMeshShape* gimpactShape = new btGImpactMeshShape(indexVertexArrays); collisionShape = gimpactShape; gimpactShape->updateBound(); @@ -1505,17 +1568,18 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() { if (!m_unscaledShape) { - collisionMeshData = new btTriangleMesh(true,false); - collisionMeshData->m_weldingThreshold = m_weldingThreshold; - - bool removeDuplicateVertices=true; - // m_vertexArray is necessarily a multiple of 3 - for (int i=0;iaddTriangle(m_vertexArray[i+2],m_vertexArray[i+1],m_vertexArray[i],removeDuplicateVertices); - } + + btTriangleIndexVertexArray* indexVertexArrays = new btTriangleIndexVertexArray( + m_polygonIndexArray.size(), + &m_triFaceArray[0], + 3*sizeof(int), + m_vertexArray.size(), + (btScalar*) &m_vertexArray[0].x(), + sizeof(btVector3) + ); + // this shape will be shared and not deleted until shapeInfo is deleted - m_unscaledShape = new btBvhTriangleMeshShape( collisionMeshData, true ); + m_unscaledShape = new btBvhTriangleMeshShape( indexVertexArrays, true ); m_unscaledShape->recalcLocalAabb(); } collisionShape = new btScaledBvhTriangleMeshShape(m_unscaledShape, btVector3(1.0f,1.0f,1.0f)); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index deb3c0880e9..67dd82db5cc 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -167,6 +167,9 @@ public: std::vector m_polygonIndexArray; // Contains the array of polygon index in the // original mesh that correspond to shape triangles. // only set for concave mesh shape. + + std::vector m_triFaceArray; // Contains an array of triplets of face indicies + // quads turn into 2 tris void setVertexWeldingThreshold(float threshold) { @@ -185,7 +188,7 @@ protected: // the actual shape is of type btScaledBvhTriangleMeshShape std::vector m_shapeArray; // for compound shapes bool m_useGimpact; //use gimpact for concave dynamic/moving collision detection - float m_weldingThreshold; //welding closeby vertices together can improve softbody stability etc. + float m_weldingThreshold; //welding closeby vertices together can improve softbody stability etc. // Not used at the moment, maybe remove? CcdShapeConstructionInfo* m_shapeProxy; // only used for PHY_SHAPE_PROXY, pointer to actual shape info }; diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.h b/source/gameengine/Rasterizer/RAS_MeshObject.h index 0d35a2f402b..404b7f16a59 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.h +++ b/source/gameengine/Rasterizer/RAS_MeshObject.h @@ -147,6 +147,16 @@ public: /* polygon sorting by Z for alpha */ void SortPolygons(RAS_MeshSlot& ms, const MT_Transform &transform); + + bool HasColliderPolygon() { + int numpolys= NumPolygons(); + for (int p=0; pIsCollider()) + return true; + + return false; + } + /* for construction to find shared vertices */ struct SharedVertex { RAS_DisplayArray *m_darray;