1
\$\begingroup\$

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 btConvexHullShapes as well asbtBvhTriangleMeshShapes 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;
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

A solution is to avoid deallocating the btBvhTriangleMeshShape altogether.

Instead of this:

physics_object->triangle_mesh_shape = new btBvhTriangleMeshShape{physics_object->triangle_mesh, true};

physics_object->collision_shape = new btBvhTriangleMeshShape{*physics_object->triangle_mesh_shape};

Use this:

physics_object->collision_shape = new btBvhTriangleMeshShape{physics_object->triangle_mesh, true};
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .