btIDebugDraw implementation isn't drawing anything

Post Reply
Bicyclette
Posts: 6
Joined: Sat Jan 04, 2020 4:46 pm

btIDebugDraw implementation isn't drawing anything

Post by Bicyclette »

I've recently implemented the btIDebugDraw interface from the bullet engine library, I'm using C++.

When I run the application, nothing is drawn, not a single line. I then inserted some print calls to the standard output to check if the drawLine method was called, and it is strangely never getting called.

The only method called is the draw3dText... and I don't even want to do that for now.

What's wrong with my code ? P.S.: I've tested my drawLine function outside of the class, and it's working.

Here is the code:

btIDebugDraw implementation

Code: Select all

#include "debugDraw.hpp"

DebugDraw::DebugDraw() :
    debug_mode(btIDebugDraw::DBG_DrawWireframe),
    line_shader("../shaders/line/vertex.glsl", "../shaders/line/fragment.glsl", "../shaders/line/geometry.glsl")
{
    // line VAO and VBO
    glGenVertexArrays(1, &line_VAO);
    glBindVertexArray(line_VAO);

    glGenBuffers(1, &line_VBO);
    glBindBuffer(GL_ARRAY_BUFFER, line_VBO);
    glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    std::cout << "debug draw constructor" << std::endl;
}

void DebugDraw::drawLine(const btVector3 & from, const btVector3 & to, const btVector3 & color)
{
    line_shader.use();
    float vertices[] = {from.x(), from.y(), from.z(), to.x(), to.y(), to.z()};

    glBindVertexArray(line_VAO);
    glBindBuffer(GL_ARRAY_BUFFER, line_VBO);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
    glDrawArrays(GL_LINES, 0, 2);
    glBindVertexArray(0);

    std::cout << "draw line" << std::endl;
}

void DebugDraw::drawContactPoint(const btVector3 & PointOnB, const btVector3 & normalOnB, btScalar distance, int lifeTime, const btVector3 & color)
{
    std::cout << "draw contact point" << std::endl;
}

void DebugDraw::reportErrorWarning(const char * warningString)
{
    std::cout << "-=-=-=- Debug Draw ERROR -=-=-=-" << std::endl;
    std::cout << warningString << std::endl;
    std::cout << "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" << std::endl;
}

void DebugDraw::draw3dText(const btVector3 & location, const char * textString)
{
    std::cout << "draw 3d text" << std::endl;
}

void DebugDraw::setDebugMode(int debugMode)
{
    std::cout << "set debug mode" << std::endl;
    debug_mode = debugMode;
}

int DebugDraw::getDebugMode() const { return debug_mode; }
main

Code: Select all

#include <SDL2/SDL.h>
#include <GL/glew.h>
#include "object.hpp"
#include "mesh.hpp"
#include "shader.hpp"
#include "camera.hpp"
#include "debugDraw.hpp"
#include <iostream>
#include <cmath>
#include <omp.h>
#include <string>
#include <btBulletDynamicsCommon.h>
/*
#include <BulletCollision/BroadphaseCollision/btDispatcher.h>
#include <btGImpactCollisionAlgorithm.h>
#include <btGImpactShape.h>
*/
#define SCREEN_W 1560
#define SCREEN_H 780

// -----global-----
struct UserActions user_actions;
bool app = true;

// -----prototypes-----
SDL_Window* createWindow(int w, int h, const std::string & title);
void check_events(SDL_Event& event, const Uint8* keyboardState, Uint32& mouseButtonBitMask, int& mouseX_rel, int& mouseY_rel);
glm::mat4 bullet2glmMatrix(btScalar* matrix);
void draw_line(glm::vec3 from, glm::vec3 to, Shader & shader, GLuint & lineVAO, GLuint & lineVBO);

// -----functions-----
SDL_Window* createWindow(int w, int h, const std::string & title)
{
    SDL_Window* window = nullptr;

    if(SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        std::cerr << SDL_GetError() << std::endl;
        return nullptr;
    }

    // OpenGL Version
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);

    // Double Buffer
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);

    if(window == nullptr)
    {
        std::cerr << SDL_GetError() << std::endl;
        return nullptr;
    }

    return window;
}

void check_events(SDL_Event& event, const Uint8* keyboardState, Uint32& mouseButtonBitMask, int& mouseX_rel, int& mouseY_rel)
{
    keyboardState = SDL_GetKeyboardState(nullptr);
    mouseButtonBitMask = SDL_GetRelativeMouseState(&mouseX_rel, &mouseY_rel);

    while(SDL_PollEvent(&event))
    {
        if(event.type == SDL_QUIT)
        {
           app = false; 
        }
        if(event.type == SDL_MOUSEWHEEL)
        {
            user_actions.mouse_scroll = true;
            user_actions.scroll_direction = event.wheel.y;
        }
        else
        {
            user_actions.mouse_scroll = false;
            user_actions.scroll_direction = 0;
        }
        if(event.type == SDL_MOUSEMOTION)
        {
            user_actions.mouseX = event.motion.x;
            user_actions.mouseY = event.motion.y;
        }
    }

    if(SDL_BUTTON(mouseButtonBitMask) == SDL_BUTTON_MIDDLE)
    {
        user_actions.xRel = mouseX_rel;
        user_actions.yRel = mouseY_rel;
        user_actions.mouse_middle = true;
    }
    else
    {
        user_actions.xRel = 0;
        user_actions.yRel = 0;
        user_actions.mouse_middle = false;
    }
    if(SDL_BUTTON(mouseButtonBitMask) == SDL_BUTTON_LEFT)
        user_actions.mouse_left = true;
    else
        user_actions.mouse_left = false;

    if(keyboardState[SDL_SCANCODE_LSHIFT])
        user_actions.key_shift = true;
    else
        user_actions.key_shift = false;
    if(keyboardState[SDL_SCANCODE_DOWN])
        user_actions.key_down = true;
    else
        user_actions.key_down = false;
    if(keyboardState[SDL_SCANCODE_UP])
        user_actions.key_up = true;
    else
        user_actions.key_up = false;
    if(keyboardState[SDL_SCANCODE_LEFT])
        user_actions.key_left = true;
    else
        user_actions.key_left = false;
    if(keyboardState[SDL_SCANCODE_RIGHT])
        user_actions.key_right = true;
    else
        user_actions.key_right = false;
}

glm::mat4 bullet2glmMatrix(btScalar* matrix)
{
    return glm::mat4(
            matrix[0], matrix[1], matrix[2], matrix[3],
            matrix[4], matrix[5], matrix[6], matrix[7],
            matrix[8], matrix[9], matrix[10], matrix[11],
            matrix[12], matrix[13], matrix[14], matrix[15]);
}

void draw_line(glm::vec3 from, glm::vec3 to, Shader & shader, GLuint & lineVAO, GLuint & lineVBO)
{
    shader.use();
    float vertices[] = {from.x, from.y, from.z, to.x, to.y, to.z};

    glBindVertexArray(lineVAO);
    glBindBuffer(GL_ARRAY_BUFFER, lineVBO);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
    glDrawArrays(GL_LINES, 0, 2);
    glBindVertexArray(0);
}

// -----main-----

int main(int argc, char* argv[])
{
    // create an opengl window
    SDL_Window * window = createWindow(SCREEN_W, SCREEN_H, "test bullet-physics");

    // create OpenGL context
    SDL_GLContext glContext = SDL_GL_CreateContext(window);

    // Glew init
    glewExperimental = true;
    GLenum err = glewInit();
    if(err != GLEW_OK)
    {
        std::cerr << glewGetErrorString(err) << std::endl;
        SDL_GL_DeleteContext(glContext);
        SDL_DestroyWindow(window);
        SDL_Quit();
        std::exit(-1);
    }

    // OpenGL states
    glViewport(0, 0, SCREEN_W, SCREEN_H);
    glEnable(GL_DEPTH_TEST);
    glLineWidth(2.5f);
    SDL_GL_SetSwapInterval(1);

    // lineVAO and lineVBO
    GLuint lineVAO, lineVBO;
    glGenVertexArrays(1, &lineVAO);
    glBindVertexArray(lineVAO);

    glGenBuffers(1, &lineVBO);
    glBindBuffer(GL_ARRAY_BUFFER, lineVBO);
    glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // create camera
    Camera* cam = new Camera(60.0f, SCREEN_W, SCREEN_H);

    // sunshine
    glm::vec3 sun_dir(1.0f, -1.0f, 1.0f);
    glm::vec3 sun_color(1.0, 1.0, 1.0);

    // line shader
    Shader* line_shader = new Shader("../shaders/line/vertex.glsl", "../shaders/line/fragment.glsl", "../shaders/line/geometry.glsl");
    line_shader->use();
    line_shader->set_Matrix("model", glm::mat4(1.0f));

    // basic shader
    Shader* basic = new Shader("../shaders/vertex.glsl", "../shaders/fragment.glsl", "../shaders/geometry.glsl");
    basic->use();
    basic->set_Matrix("model", glm::mat4(1.0f));
    basic->set_Matrix("view", cam->get_view());
    basic->set_Matrix("proj", cam->get_projection());
    basic->set_vec3f("sun.dir", sun_dir);
    basic->set_vec3f("sun.color", sun_color);

    // load ground
    Object* ground = new Object("../assets/ground.obj", true);

    // load suzy
    Object* suzy = new Object("../assets/suzanne.obj", true);

    // ----- bullet initialization start -----
    btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
    btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
    btBroadphaseInterface* overlappingPairCache = new btDbvtBroadphase();
    btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver();
    btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);
    dynamicsWorld->setGravity(btVector3(0, -10, 0));

    btIDebugDraw * debug = new DebugDraw();
    dynamicsWorld->setDebugDrawer(debug);

    //btGImpactCollisionAlgorithm::registerAlgorithm(dispatcher);
    // ----- bullet initialization end -----

    // array of rigid bodies
    btAlignedObjectArray<btCollisionShape*> collisionShapes;

    // ----- ground static rigid body
    {
        std::vector<Mesh*> meshes = ground->get_mesh_collection();
        for(int i = 0; i < meshes.size(); i++)
        {
            Mesh* m = meshes.at(i);
            const std::vector<Vertex> & vertices = m->get_vertex_list();
            const std::vector<int> & indices = m->get_index_list();

            btTriangleMesh* striding_interface = new btTriangleMesh();
            for(int j = 0; j < indices.size(); j += 3)
            {
                btVector3 v0(vertices.at(indices.at(j)).position.x, vertices.at(indices.at(j)).position.y, vertices.at(indices.at(j)).position.z);
                btVector3 v1(vertices.at(indices.at(j+1)).position.x, vertices.at(indices.at(j+1)).position.y, vertices.at(indices.at(j+1)).position.z);
                btVector3 v2(vertices.at(indices.at(j+2)).position.x, vertices.at(indices.at(j+2)).position.y, vertices.at(indices.at(j+2)).position.z);

                striding_interface->addTriangle(v0, v1, v2, true);
            }
            //btCollisionShape* groundShape = new btGImpactMeshShape(striding_interface);
            btCollisionShape* groundShape = new btBvhTriangleMeshShape(striding_interface, true);

            collisionShapes.push_back(groundShape);

            btTransform groundTransform;
            groundTransform.setIdentity();
            groundTransform.setOrigin(btVector3(0, 0, 0));

            btScalar mass(0.0);
            btVector3 localInertia(0, 0, 0);
            btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
            btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, groundShape, localInertia);
            btRigidBody* body = new btRigidBody(rbInfo);

            // add the body to the dynamics world
            dynamicsWorld->addRigidBody(body);
        }
    }
    // suzy dynamic rigid body
    {
        std::vector<Mesh*> meshes = suzy->get_mesh_collection();
        for(int i = 0; i < meshes.size(); i++)
        {
            Mesh* m = meshes.at(i);
            const std::vector<Vertex> & vertices = m->get_vertex_list();
            const std::vector<int> & indices = m->get_index_list();

            btTriangleMesh* striding_interface = new btTriangleMesh();
            for(int j = 0; j < indices.size(); j += 3)
            {
                btVector3 v0(vertices.at(indices.at(j)).position.x, vertices.at(indices.at(j)).position.y, vertices.at(indices.at(j)).position.z);
                btVector3 v1(vertices.at(indices.at(j+1)).position.x, vertices.at(indices.at(j+1)).position.y, vertices.at(indices.at(j+1)).position.z);
                btVector3 v2(vertices.at(indices.at(j+2)).position.x, vertices.at(indices.at(j+2)).position.y, vertices.at(indices.at(j+2)).position.z);

                striding_interface->addTriangle(v0, v1, v2, true);
            }
            //btCollisionShape* suzyShape = new btGImpactMeshShape(striding_interface);
            btCollisionShape* suzyShape = new btBvhTriangleMeshShape(striding_interface, true);

            collisionShapes.push_back(suzyShape);

            btTransform suzyTransform;
            suzyTransform.setIdentity();
            suzyTransform.setOrigin(btVector3(0, 0, 0));

            btScalar mass(1.0);
            btVector3 localInertia(0, 0, 0);

            suzyShape->calculateLocalInertia(mass, localInertia);

            btDefaultMotionState* myMotionState = new btDefaultMotionState(suzyTransform);
            btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, suzyShape, localInertia);
            btRigidBody* body = new btRigidBody(rbInfo);

            // add the body to the dynamics world
            dynamicsWorld->addRigidBody(body);
        }

    }

    // main loop
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    SDL_Event event;
    const Uint8 * keyboardState = nullptr;
    Uint32 mouseButtonBitMask;
    int mouseX_rel = 0, mouseY_rel = 0;
    double delta = 0.0;
    double current_time = 0.0;
    double last_time = 0.0;

    while(app)
    {
        // compute delta
        last_time = current_time;
        current_time = omp_get_wtime();
        delta = current_time - last_time;

        // update camera data
        check_events(event, keyboardState, mouseButtonBitMask, mouseX_rel, mouseY_rel);
        cam->update_view(user_actions, delta);

        // clear screen
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // physics simulations
        dynamicsWorld->stepSimulation(1.0f/60.0f, 10);
        btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[1];
        btRigidBody* body = btRigidBody::upcast(obj);
        btTransform trans;
        if(body && body->getMotionState())
            body->getMotionState()->getWorldTransform(trans);
        else
            trans = obj->getWorldTransform();

        btScalar matrix[16];
        trans.getOpenGLMatrix(matrix);
        glm::mat4 bullet_model = bullet2glmMatrix(matrix);

        // draw
        /*
        basic->use();
        basic->set_Matrix("model", glm::mat4(1.0f));
        basic->set_Matrix("view", cam->get_view());
        basic->set_Matrix("proj", cam->get_projection());
        ground->draw(*basic);
        basic->set_Matrix("model", bullet_model);
        suzy->draw(*basic);

        // draw some lines
        line_shader->use();
        line_shader->set_Matrix("view", cam->get_view());
        line_shader->set_Matrix("proj", cam->get_projection());
        draw_line(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 25.0f, 0.0f), *line_shader, lineVAO, lineVBO);
        draw_line(glm::vec3(0.0f, 25.0f, 0.0f), glm::vec3(25.0f, 25.0f, 0.0f), *line_shader, lineVAO, lineVBO);
        draw_line(glm::vec3(25.0f, 25.0f, 0.0f), glm::vec3(25.0f, 0.0f, 0.0f), *line_shader, lineVAO, lineVBO);
        */

        // debug draw
        dynamicsWorld->debugDrawWorld();

        SDL_GL_SwapWindow(window);
    }

    // clean
    SDL_GL_DeleteContext(glContext);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}
Thank you !
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: btIDebugDraw implementation isn't drawing anything

Post by drleviathan »

Check the implementation of btCollisionWorld::debugDrawObject(). AFAICT there is no support there for rendering btBvhTriangleMeshShape. That code has a switch on the ShapeType and in the default case it only handles convex shapes.

Try using convex shapes, or override the debugDrawObject() method and add support for rendering concave mesh.
Bicyclette
Posts: 6
Joined: Sat Jan 04, 2020 4:46 pm

Re: btIDebugDraw implementation isn't drawing anything

Post by Bicyclette »

Alright, thank you very much for that information, I'll check that !
Post Reply