irrlicht + bullet getmesh() not working properly

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
easy163
Posts: 24
Joined: Wed Jul 10, 2013 12:50 pm

irrlicht + bullet getmesh() not working properly

Post by easy163 »

Plugged the bullet physics engine, which created using primitives ISceneNode *Node = smgr->addCubeSceneNode(1.0f); all the clashes were considered normal and physics worked. When drew in MilkShape 3D square and uploaded it using IAnimatedMesh* mailbox_mesh = smgr->getMesh(media/map/box/box.ms3d"); the collision ceased to operate normally.

There is such a line
btVector3 HalfExtents(TScale.X / 2, TScale.Y / 2, TScale.Z / 2);
btCollisionShape* Shape = new btBoxShape(HalfExtents);
Then I understood from the center of the cube are considered to be the border of the object for the collision. When loading a mesh following occurs

Image

Here is how the cube looks like in the editor

Image

Here is how the cube looks if you do the following
btVector3 HalfExtents(TScale.X + 1000, TScale.Y + 1000, TScale.Z + 1000);

Image

The edges were more than he cubic
It turns out that the edges of the mesh are not considered properly, how to properly implement this?
easy163
Posts: 24
Joined: Wed Jul 10, 2013 12:50 pm

Re: irrlicht + bullet getmesh() not working properly

Post by easy163 »

Function to create a mesh

Code: Select all

void CrMailbox(const btVector3 &TPosition, const vector3df &TScale, btScalar TMass) {
    IAnimatedMesh* mailbox_mesh = smgr->getMesh("media/map/box/box.ms3d");
    ISceneNode* mailbox_node = smgr->addMeshSceneNode(mailbox_mesh, 0, -1);
    mailbox_node->setScale(TScale);
    mailbox_node->setMaterialType(EMT_SOLID);
    mailbox_node->setMaterialFlag(EMF_NORMALIZE_NORMALS, true);
 
    btTransform Transform;
    Transform.setIdentity();
    Transform.setOrigin(TPosition);
 
    btDefaultMotionState* MotionState = new btDefaultMotionState(Transform);
 
    btVector3 HalfExtents(TScale.X, TScale.Y, TScale.Z);
    btCollisionShape* Shape = new btBoxShape(HalfExtents);
 
    btVector3 LocalInertia;
    Shape->calculateLocalInertia(TMass, LocalInertia);
 
    btRigidBody* RigidBody = new btRigidBody(TMass, MotionState, Shape, LocalInertia);
 
    RigidBody->setFriction(1000);
 
    //RigidBody->setRestitution(1);
    //RigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
 
    RigidBody->setUserPointer((void *)(mailbox_node));
 
    World->addRigidBody(RigidBody);
    Objects.push_back(RigidBody);
}
serengeor
Posts: 1712
Joined: Tue Jan 13, 2009 7:34 pm
Location: Lithuania

Re: irrlicht + bullet getmesh() not working properly

Post by serengeor »

Mesh center should be at (0,0,0) and from editor screenshot that seams to be the case.
So it might be because youre only taking into account scale of object and not the object size itself. you should get object size and multiply it by scale to get correct bbox extents for bullet I think.

I would recommend implementing debug drawing functions for bullet.
Working on game: Marrbles (Currently stopped).
Otaka
Posts: 17
Joined: Fri Nov 16, 2012 1:47 pm

Re: irrlicht + bullet getmesh() not working properly

Post by Otaka »

I have experienced this issue to. Collision mesh did not work properly. I had no clues how to workaround it until enable debug drawing.
After that I saw that collision mesh(and also ITriangleSelector returned from ISceneCollisionManager) is transformed relative to original mesh(translated, rotated, scaled). After some researching I found that if I export my model from 3ds max with resetXForm, mesh works properly.
If you use 3ds max too, try to apply resetXForm modifier to your model and than merge all modifies into one. It should help.
easy163
Posts: 24
Joined: Wed Jul 10, 2013 12:50 pm

Re: irrlicht + bullet getmesh() not working properly

Post by easy163 »

I looked in the wrappers and saw functions for converting vectors, tried to use them on a clean bullet and put it to work, the functions of the post :)

Code: Select all

 inline static btVector3 irrVectorToBulletVector(const irr::core::vector3df & toConvert)
 {
  return btVector3(toConvert.X,toConvert.Y,toConvert.Z);
 }
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: irrlicht + bullet getmesh() not working properly

Post by Cube_ »

easy163 wrote:I looked in the wrappers and saw functions for converting vectors, tried to use them on a clean bullet and put it to work, the functions of the post :)

Code: Select all

 inline static btVector3 irrVectorToBulletVector(const irr::core::vector3df & toConvert)
 {
  return btVector3(toConvert.X,toConvert.Y,toConvert.Z);
 }
You PM'd me and requested help on using bullet without a wrapper

Here you go:
config.h

Code: Select all

// <headers>
#include "irrlicht/irrlicht.h"
#include "btBulletDynamicsCommon.h"
#include <string>
#include "stdlib.h"
#include "stdio.h"
// </headers>
// <namespaces!>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
// </namespaces!>
main.cpp

Code: Select all

#include "config.h"
#include "time.h"
 
 
//Global bullet vars
static bool Done = false;
static btDiscreteDynamicsWorld *dynamicsWorld;
static list<btRigidBody *> objects;
 
//Global Irrlicht vars
static IrrlichtDevice *device;
static IVideoDriver *driver;
static ISceneManager *smgr;
static ITimer *timer;
//static IGUIEnvironment *guienv;
//static IFileSystem *filesys;
//static ILogger *logger;
 
//Bullet Related Functions
 
static void createStartScene();
static void createBox(const btVector3 &TPosition, const vector3df &TScale, btScalar TMass);
static void createSphere(const btVector3 &TPosition, btScalar TRadius, btScalar TMass);
void UpdatePhysics(u32 TDeltaTime);
static void UpdateRender(btRigidBody *TObject);
static void ClearObjects();
static int GetRandInt(int TMax) {return rand() % TMax; }
 
class EventReceiverClass : public IEventReceiver
{
    public:
 
            virtual bool OnEvent(const SEvent &TEvent)
            {
 
                if(TEvent.EventType == EET_KEY_INPUT_EVENT && !TEvent.KeyInput.PressedDown)
                {
                    switch(TEvent.KeyInput.Key)
                    {
                        case KEY_ESCAPE:
                        Done=true;
                        break;
 
                        case KEY_KEY_Q:
                        createBox(btVector3(GetRandInt(10) - 5.0f, 7.0f, GetRandInt(10) - 5.0f), vector3df(GetRandInt(3)+0.5f,GetRandInt(3)+0.5f, GetRandInt(3)+0.5f),1.0f);
                        break;
 
                        case KEY_KEY_W:
                        createSphere(btVector3(GetRandInt(10) - 5.0f, 7.0f, GetRandInt(10) - 5.0f), GetRandInt(5) / 5.0f + 0.2f, 1.0f);
                        break;
 
                        case KEY_KEY_E:
                        createStartScene();
                        break;
 
                        default:
                        return false;
                        break;
                    }
                return true;
            }
            return false;
        }
};
 
int main()
{
    srand(time(NULL));
    int screenHeight = 800, screenWidth = 600;
 
    EventReceiverClass receiver;
    device = createDevice(EDT_OPENGL, dimension2d<u32>(screenHeight, screenWidth), 32, false, false, false, &receiver);
 
    if (device == 0)
    {
        return 1;
    }
 
    //guienv = device->getGUIEnvironment();
    timer = device->getTimer();
    driver = device->getVideoDriver();
    smgr = device->getSceneManager();
 
    device->getCursorControl()->setVisible(false);
 
    btBroadphaseInterface *broadPhase = new btAxisSweep3(btVector3(-1000,-1000,-1000), btVector3(1000,1000,1000));
    btDefaultCollisionConfiguration *collisionConfiguration = new btDefaultCollisionConfiguration();
    btCollisionDispatcher *dispatcher = new btCollisionDispatcher(collisionConfiguration);
    btSequentialImpulseConstraintSolver *solver = new btSequentialImpulseConstraintSolver();
    dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadPhase, solver, collisionConfiguration);
 
    ICameraSceneNode *camera = smgr->addCameraSceneNodeFPS(0,100,25);
    camera->setPosition(vector3df(0,5,-5));
    camera->setTarget(vector3df(0,0,0));
 
    /*IGUISkin* skin = guienv->getSkin();
    skin->setColor(EGDC_BUTTON_TEXT, SColor(255,200,200,200));
    guienv->addStaticText(L"Hit Q to spawn a cube, W for a sphere and E to reset or escape to exit.", rect<s32>(0,0,200,100), false);
    IGUIStaticText* versionText = guienv->addStaticText(L"", rect<s32>(0,0,300,200),false);
    versionText->setText(string);*/
 
    smgr->addLightSceneNode(0, vector3df(2, 5, -2), SColorf(4, 4, 4, 1));
    createStartScene();
 
    driver->getTexture("resources/textures/tex.jpg");
    driver->getTexture("resources/textures/tex1.jpg");
 
    u32 timeStamp = timer->getTime(), DeltaTime = 0;
 
    while(Done == false)
    {
        device->run();
        if(device->isWindowActive())
        {
            DeltaTime = timer->getTime() - timeStamp;
            timeStamp = timer->getTime();
 
            UpdatePhysics(DeltaTime);
 
            driver->beginScene(true,true,SColor(255,55,0,155));
            smgr->drawAll();
            //guienv->drawAll();
            driver->endScene();
 
            int FPS = driver->getFPS(), lastFPS = -1;
 
            if(lastFPS != FPS)
            {
                stringw str = L"COLLISION TEST [";
                str += driver->getName();
                str += "] FPS:";
                str += FPS;
                str += " VERSION:";
                str += auto__RC_FILEVERSION_STRING;
 
                device->setWindowCaption(str.c_str());
                lastFPS=FPS;
            }
        }
        device->yield();
    }
    ClearObjects();
    delete dynamicsWorld;
    delete solver;
    delete dispatcher;
    delete broadPhase;
    delete collisionConfiguration;
 
    device->drop();
    getchar();
    return 0;
}
 
void UpdatePhysics(u32 TDeltaTime)
{
    dynamicsWorld->stepSimulation(TDeltaTime * 0.001f, 60);
 
    for(list<btRigidBody *>::Iterator Iterator = objects.begin(); Iterator != objects.end(); ++Iterator)
    {
        UpdateRender(*Iterator);
    }
}
 
void createStartScene()
{
    ClearObjects();
    createBox(btVector3(0.0f,0.0f,0.0f), vector3df(10.0f,0.5f,10.0f), 0.0f);
}
 
 
 
void createBox(const btVector3 &TPosition, const vector3df &TScale, btScalar TMass)
{
    ISceneNode *node = smgr->addCubeSceneNode(1.0f);
    node->setScale(TScale);
    node->setMaterialFlag(EMF_LIGHTING, 1);
    node->setMaterialFlag(EMF_NORMALIZE_NORMALS, true);
    node->setMaterialTexture(0,driver->getTexture("resources/textures/tex.jpg"));
 
    btTransform bulletTransform;
    bulletTransform.setIdentity();
    bulletTransform.setOrigin(TPosition);
 
    btDefaultMotionState *motionState = new btDefaultMotionState(bulletTransform);
 
    btVector3 halfExtents(TScale.X * 0.5f, TScale.Y * 0.5f, TScale.Z * 0.5f);
    btCollisionShape *shape = new btBoxShape(halfExtents);
 
    btVector3 localInertia;
    shape->calculateLocalInertia(TMass, localInertia);
 
    btRigidBody *rigidBody = new btRigidBody(TMass, motionState, shape, localInertia);
 
    rigidBody->setUserPointer((void*)(node));
 
    dynamicsWorld->addRigidBody(rigidBody);
    objects.push_back(rigidBody);
}
 
void createSphere(const btVector3 &TPosition, btScalar TRadius, btScalar TMass)
{
    ISceneNode *node = smgr->addSphereSceneNode(TRadius, 32);
    node->setMaterialFlag(EMF_LIGHTING, 1);
    node->setMaterialFlag(EMF_NORMALIZE_NORMALS, true);
    node->setMaterialTexture(0,driver->getTexture("resources/textures/tex1.jpg"));
 
    btTransform bulletTransform;
    bulletTransform.setIdentity();
    bulletTransform.setOrigin(TPosition);
 
    btDefaultMotionState *motionState = new btDefaultMotionState(bulletTransform);
 
    btCollisionShape *shape = new btSphereShape(TRadius);
 
    btVector3 localInertia;
    shape->calculateLocalInertia(TMass, localInertia);
 
    btRigidBody *rigidBody = new btRigidBody(TMass,motionState,shape,localInertia);
 
    rigidBody->setUserPointer((void*)(node));
 
    dynamicsWorld->addRigidBody(rigidBody);
    objects.push_back(rigidBody);
}
 
void UpdateRender(btRigidBody *TObject)
{
    ISceneNode *node = static_cast<ISceneNode *>(TObject->getUserPointer());
 
    btVector3 point = TObject->getCenterOfMassPosition();
    node->setPosition(vector3df((f32)point[0], (f32)point[1], (f32)point[2]));
 
    vector3df Euler;
    const btQuaternion& TQuaternion = TObject->getOrientation();
    quaternion q(TQuaternion.getX(), TQuaternion.getY(), TQuaternion.getZ(), TQuaternion.getW());
    q.toEuler(Euler);
    Euler *= RADTODEG;
    node->setRotation(Euler);
}
 
void ClearObjects()
{
    for(list<btRigidBody *>::Iterator Iterator = objects.begin(); Iterator != objects.end(); ++Iterator)
    {
        btRigidBody *object = *Iterator;
 
        ISceneNode *node = static_cast<ISceneNode *>(object->getUserPointer());
        node->remove();
 
        dynamicsWorld->removeRigidBody(object);
 
        delete object->getMotionState();
        delete object->getCollisionShape();
        delete object;
    }
    objects.clear();
}
 

Something along those lines should work, this code isn't commented nor can I guarantee that it is particularly useful, it's mostly written from memory and UNTESTED
"this is not the bottleneck you are looking for"
Post Reply