I am trying to use a level in .obj format loaded with Assimp to generate a btBvhTriangleMeshShape
to use with the Bullet physics library. I can successfully load btConvexHullShape
s as well asbtBvhTriangleMeshShape
s and have them collide with each other. However, if I do attempt to generate a btBvhTriangleMeshShape
, the program crashes on deallocating it. Because of this I think my mistake is in my loading function: load_static_collision_shape
. Here's the code:
#include "Physics.hpp"
#include <GLEW/glew.h>
#include "Structs.hpp"
#include <Bullet/btBulletDynamicsCommon.h>
#include <Bullet/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h>
#include <Bullet/BulletCollision/CollisionShapes/btShapeHull.h>
namespace
{
btBroadphaseInterface* m_broadphase;
btDefaultCollisionConfiguration* m_collision_configuration;
btCollisionDispatcher* m_dispatcher;
btSequentialImpulseConstraintSolver* m_solver;
btDiscreteDynamicsWorld* m_dynamics_world;
struct Physics_object
{
bool dynamic;
btConvexHullShape* unoptimized_hull;
btShapeHull* hull_optimizer;
btConvexHullShape* hull;
btTriangleMesh* triangle_mesh;
btBvhTriangleMeshShape* triangle_mesh_shape;
btCollisionShape* collision_shape;
btDefaultMotionState* motion_state;
btScalar mass;
btVector3 inertia;
btRigidBody* object;
Oreg::Model* model;
};
std::vector<Physics_object> m_physics_objects;
void load_dynamic_collision_shape(Physics_object* physics_object, const Oreg::Model& model)
{
physics_object->dynamic = true;
physics_object->triangle_mesh = nullptr;
physics_object->triangle_mesh_shape = nullptr;
physics_object->unoptimized_hull = new btConvexHullShape{};
for(GLuint i : model.indices())
{
btVector3 vertex{model.vertices()[i].position.x,
model.vertices()[i].position.y, model.vertices()[i].position.z};
physics_object->unoptimized_hull->addPoint(vertex);
}
physics_object->hull_optimizer = new btShapeHull{physics_object->unoptimized_hull};
btScalar margin{physics_object->unoptimized_hull->getMargin()};
physics_object->hull_optimizer->buildHull(margin);
physics_object->hull = new btConvexHullShape{
(btScalar*)physics_object->hull_optimizer->getVertexPointer(),
physics_object->hull_optimizer->numVertices()};
physics_object->collision_shape = new btConvexHullShape{*physics_object->hull};
}
void load_static_collision_shape(Physics_object* physics_object, const Oreg::Model& model)
{
physics_object->dynamic = false;
physics_object->unoptimized_hull = nullptr;
physics_object->hull_optimizer = nullptr;
physics_object->hull = nullptr;
physics_object->triangle_mesh = new btTriangleMesh{};
for(unsigned i{0}; i < model.indices().size(); i+=3)
{
btVector3 vertex_1{
model.vertices()[model.indices()[i]].position.x,
model.vertices()[model.indices()[i]].position.y,
model.vertices()[model.indices()[i]].position.z};
btVector3 vertex_2{
model.vertices()[model.indices()[i+1]].position.x,
model.vertices()[model.indices()[i+1]].position.y,
model.vertices()[model.indices()[i+1]].position.z};
btVector3 vertex_3{
model.vertices()[model.indices()[i+2]].position.x,
model.vertices()[model.indices()[i+2]].position.y,
model.vertices()[model.indices()[i+2]].position.z};
physics_object->triangle_mesh->addTriangle(vertex_1, vertex_2, vertex_3);
}
physics_object->triangle_mesh_shape = new btBvhTriangleMeshShape{physics_object->triangle_mesh, true};
physics_object->collision_shape = new btBvhTriangleMeshShape{*physics_object->triangle_mesh_shape};
}
};
void Oreg::Physics::initialize()
{
m_broadphase = new btDbvtBroadphase{};
m_collision_configuration = new btDefaultCollisionConfiguration{};
m_dispatcher = new btCollisionDispatcher{m_collision_configuration};
btGImpactCollisionAlgorithm::registerAlgorithm(m_dispatcher);
m_solver = new btSequentialImpulseConstraintSolver{};
m_dynamics_world = new btDiscreteDynamicsWorld{m_dispatcher, m_broadphase, m_solver, m_collision_configuration};
m_dynamics_world->setGravity(btVector3(0, -10, 0));
}
void Oreg::Physics::add(Model* model, int mass)
{
Physics_object physics_object{};
if(mass) load_dynamic_collision_shape(&physics_object, *model);
else load_static_collision_shape(&physics_object, *model);
physics_object.motion_state = new btDefaultMotionState{btTransform{
btQuaternion{0, 0, 0, 1}, btVector3{model->x(), model->y(), model->z()}}};
physics_object.mass = static_cast<btScalar>(mass);
physics_object.inertia = btVector3{0, 0, 0};
physics_object.collision_shape->calculateLocalInertia(physics_object.mass, physics_object.inertia);
btRigidBody::btRigidBodyConstructionInfo construction_info{physics_object.mass,
physics_object.motion_state, physics_object.collision_shape, physics_object.inertia};
physics_object.object = new btRigidBody{construction_info};
m_dynamics_world->addRigidBody(physics_object.object);
physics_object.model = model;
m_physics_objects.push_back(physics_object);
}
void Oreg::Physics::update()
{
m_dynamics_world->stepSimulation(static_cast<btScalar>(Oreg::Core::get_delta()), 10);
btTransform transform{};
for(Physics_object p : m_physics_objects)
{
if(p.dynamic)
{
p.object->getMotionState()->getWorldTransform(transform);
p.model->set_position(transform.getOrigin().getX(),
transform.getOrigin().getY(), transform.getOrigin().getZ());
}
}
}
void Oreg::Physics::terminate()
{
for(Physics_object p : m_physics_objects)
{
m_dynamics_world->removeRigidBody(p.object);
delete p.object;
delete p.motion_state;
delete p.collision_shape;
if(!p.dynamic)
{
delete p.triangle_mesh_shape;
delete p.triangle_mesh;
}
else
{
delete p.hull_optimizer;
delete p.unoptimized_hull;
delete p.hull;
}
}
delete m_dynamics_world;
delete m_solver;
delete m_dispatcher;
delete m_collision_configuration;
delete m_broadphase;
}