Irrlicht with Bullet Softbody sample sourcecode

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
go
Posts: 28
Joined: Mon Oct 20, 2008 7:53 am

Irrlicht with Bullet Softbody sample sourcecode

Post by go »

Thanks for memoblog !

http://sssiii.seesaa.net/article/109665032.html

and this is sample viedo http://sssiii.seesaa.net/article/108784481.html

This is a sample sourcecode for using irrlicht with bullet softbody

You can use .3ds related resouce, but another resource is not good for use in this phrase.

index number should less than 2000 to use, if you use bigger than this, you may think this simulation is too slow to use.


This sourcecode is good, but may have some not good thing. So if you find it , please give me the position and how to change it.

Thanks!

Code: Select all


#include <iostream>
#include <map>
#include <vector>
#include <list>

#include <btBulletDynamicsCommon.h>
#include "BulletSoftBody/btSoftRigidDynamicsWorld.h"
#include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h"
#include "BulletSoftBody/btSoftBodyHelpers.h"
#include "BulletSoftBody/btSoftBody.h"

#include "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h"
#include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h"
#include "LinearMath/btQuickprof.h"
#include "LinearMath/btIDebugDraw.h"
#include "LinearMath/btConvexHull.h"

#include <irrlicht.h>

#pragma comment (lib, "libbulletdynamics.lib")
#pragma comment (lib, "libbulletcollision.lib")
#pragma comment (lib, "libbulletmath.lib")
#pragma comment (lib, "libbulletsoftbody.lib")
#pragma comment (lib, "Irrlicht.lib")

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

// Vertices
std::map<int, btSoftBody::Node*> vertices;
// Indices
std::vector<int> indices;
// Node->int(index)の一時マップを作成
// Temporary placeholder for nodes
std::map<btSoftBody::Node*, int> node_map;

#define CUBE_HALF_EXTENTS 15

struct MeshData
{
    btScalar *mqo_vertices;
    int *mqo_indices;
    int indexCount, vertexCount;
};

MeshData testMesh;

int main (void)
{
    // Irrlichtの準備
    IrrlichtDevice *device = createDevice(EDT_OPENGL, dimension2d<s32>(640, 480), 16,
        false, true, false, 0);
    device->setWindowCaption(L"Irrlicht + Bullet : SoftBody Demo");
    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager *smgr = device->getSceneManager();

    // カメラの設定
    ICameraSceneNode *camera = smgr->addCameraSceneNodeFPS(0, 150, 500, -1, 0, 0, false);
    camera->setPosition(core::vector3df(0,400,-300));
    camera->setFarValue(10000);
    camera->setTarget(core::vector3df(0, 300, 0));

    // SoftBodyのメッシュデータをファイルから読み込み(Irrlicht用)

    // you shoud change this object
    IAnimatedMesh *cubeMesh = smgr->getMesh("../media/test.3ds");
    IAnimatedMeshSceneNode *cubeNode = smgr->addAnimatedMeshSceneNode(cubeMesh, 0, -1, vector3df(0, 0, 0), vector3df(0,0,0), vector3df(1,1,1), false);
    cubeNode->setMaterialFlag(video::EMF_LIGHTING, false);

    // 地面の作成(Irrlicht用)
    IAnimatedMesh *planemesh = smgr->addHillPlaneMesh("myHill", dimension2d<f32>(24, 24), dimension2d<u32>(100, 100));
    ISceneNode *q3sn = smgr->addOctTreeSceneNode(planemesh);
    q3sn->setMaterialFlag(video::EMF_LIGHTING, false);

   // you should change this resource
    q3sn->setMaterialTexture(0, driver->getTexture("../media/wall.jpg"));

    // SoftBody用ワールド情報
    btSoftBodyWorldInfo	m_softBodyWorldInfo;

    // ワールドの広さ
    btVector3 worldAabbMin(-10000,-10000,-10000);
    btVector3 worldAabbMax(10000,10000,10000);
    // プロキシの最大数(衝突物体のようなもの)
    int maxProxies = 1024;
    // broadphaseの作成(SAP法)
    btAxisSweep3* broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies);
    m_softBodyWorldInfo.m_broadphase = broadphase;

    // デフォルトの衝突設定とディスパッチャの作成
    //    const btDefaultCollisionConfigurationInfo collisionConfigInfo;
    btDefaultCollisionConfiguration* collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration();
    btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
    m_softBodyWorldInfo.m_dispatcher = dispatcher;

    // 衝突解決ソルバ
    btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;

    // Soft-Rigit動的世界の作成
    btSoftRigidDynamicsWorld* dynamicsWorld = new btSoftRigidDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);

    // 地面の衝突形状の作成
    btCollisionShape* groundShape = new btBoxShape (btVector3(2000,CUBE_HALF_EXTENTS,2000));
    // 地面のMotionStateの設定
    btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,-CUBE_HALF_EXTENTS/2.0,0)));
    // 地面の初期情報を設定
    btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0,groundMotionState,groundShape,btVector3(0,0,0));
    // 地面の剛体の作成
    btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);
    groundRigidBody->setCollisionFlags( groundRigidBody->getCollisionFlags() |  btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK );
    // ワールドに地面の剛体を追加
    dynamicsWorld->addRigidBody(groundRigidBody);

    // 重力の設定
    dynamicsWorld->setGravity(btVector3(0,-10.0,0));
    // softBodyWorldInfoの初期化・設定
    m_softBodyWorldInfo.m_sparsesdf.Initialize();
    m_softBodyWorldInfo.m_gravity.setValue(0,-10.0,0);
    m_softBodyWorldInfo.air_density		=	(btScalar)1.2;
    m_softBodyWorldInfo.water_density	=	0;
    m_softBodyWorldInfo.water_offset	=	0;
    m_softBodyWorldInfo.water_normal	=	btVector3(0,0,0);

    int cMeshBuffer, j;
    IMeshBuffer *mb; 
    video::S3DVertex* mb_vertices;
    u16* mb_indices;

    // getMeshで取得したメッシュ情報の取得
    for (cMeshBuffer=0; cMeshBuffer<cubeMesh->getMesh(0)->getMeshBufferCount(); cMeshBuffer++) 
    {
        // メッシュバッファの取得
        mb = cubeMesh->getMesh(0)->getMeshBuffer(cMeshBuffer); 

        // 頂点情報のポインタを取得。この値を書き換えれば頂点座標を変更できる。
        mb_vertices = (irr::video::S3DVertex*)mb->getVertices(); 
        // 面のインデックスのポインタを取得。この値を書き換えれば面のインデックスを変更できる。
        mb_indices  = mb->getIndices(); 
    } 

    // 読み込んだメッシュデータの最適化
    // 3dsファイル(.objも?)をIrrlichtで読み込むと、(Index数=Vertex数)となり、Indexが一意で、Vertexが重複する。
    // 大量の頂点からSoftBodyを作成しようとするとものすごく時間がかかるので、Vertexの重複をなくす。
    // そのためにまず、重複のないIndexと重複のあるIndexのマップを作成
    std::map<int, int> index_map;
    std::map<int, int> bullet_map;
    std::map<int, S3DVertex> vertex_map;
    int count = 0;
    for (int i=0; i<mb->getIndexCount(); i++)
    {
        int iIndex = mb_indices[i];
        vector3df iVertex = mb_vertices[iIndex].Pos;
        bool isFirst = true;
        for (int j=0; j<i; j++)
        {
            int jIndex = mb_indices[j];
            vector3df jVertex = mb_vertices[jIndex].Pos;
            if (iVertex == jVertex)
            {
                index_map.insert(std::make_pair(i, j));
                isFirst = false;
                break;
            }
        }
        // 初めての場合はBullet用のIndexと頂点を作成
        if (isFirst)
        {
            // IrrlichtのIndex→重複のあるIndex
            index_map.insert(std::make_pair(i, i));
            // とびとびのIndex→連続のIndex
            bullet_map.insert(std::make_pair(i, count));
            // 連続Indexと頂点情報のマップ
            vertex_map.insert(std::make_pair(count, mb_vertices[iIndex]));
            count++;
        }
    }

    // IrrlichtとBulletの間の一時的なIndex-Vertex情報の作成
    testMesh.indexCount = mb->getIndexCount();
    testMesh.mqo_indices = new int[testMesh.indexCount];
    testMesh.vertexCount = vertex_map.size();
    testMesh.mqo_vertices = new btScalar[testMesh.vertexCount*3];

    std::cout << "IndexCount=" << testMesh.indexCount << ", VertexCount=" << testMesh.vertexCount << std::endl;
    // メッシュからポリゴン情報を取得し配列に格納
    for (j=0; j<mb->getIndexCount(); j++) 
    {
        // 重複のないIndex→重複のあるとびとびのIndex
        int index1 = index_map.find(j)->second;
        // 重複のあるとびとびIndex→重複のある順番のIndex
        int index2 = bullet_map.find(index1)->second;
        testMesh.mqo_indices[j]   = index2;
    }
    // SoftBodyを作成するための頂点座標を格納
    for (j=0; j<testMesh.vertexCount; j++)
    {
        testMesh.mqo_vertices[3*j] =   vertex_map[j].Pos.X;
        testMesh.mqo_vertices[3*j+1] = vertex_map[j].Pos.Y;
        testMesh.mqo_vertices[3*j+2] = -vertex_map[j].Pos.Z;
    }

    std::cout << "create softbody" << std::endl;
    // 三角メッシュからSoftBodyを作成(btSoftBodyHelpersを使用)
    btSoftBody* cubeSoftBody = btSoftBodyHelpers::CreateFromTriMesh(
        m_softBodyWorldInfo, testMesh.mqo_vertices, testMesh.mqo_indices, testMesh.indexCount/3);

    std::cout << "create map" << std::endl;
    // 作成されたSoftBodyの面情報をインデックスと関連付ける(node->index)
    for (int i=0; i<cubeSoftBody->m_faces.size(); i++)
    {
        btSoftBody::Face face = cubeSoftBody->m_faces[i];

        for (int j=0; j<3; j++)
        {
            if (node_map.find(face.m_n[j]) == node_map.end())
            {
                node_map.insert(std::make_pair(face.m_n[j], node_map.size()));
            }
        }

        for (int j=0; j<3; j++)
        {
            // Bulletのインデックス
            indices.push_back(node_map.find(face.m_n[j])->second);
        }
    }
    // Reverse node->index to index->node (should be unique on both sides)
    std::map<btSoftBody::Node*, int>::const_iterator node_iter;
    for (node_iter = node_map.begin(); node_iter != node_map.end(); ++node_iter)
    {
        // Bulletの頂点
        vertices.insert(std::make_pair(node_iter->second, node_iter->first));
    }

    // IrrlichtのVertexとBulletのVertexを関連付ける必要がある
    std::cout << "update Irrlicht vertices" << std::endl;
    // 関連付けるためのマップ
    std::map<int, int> testMesh_map;
    // SoftBodyのIndex→Vertexのイテレータ
    std::map<int, btSoftBody::Node*>::const_iterator it;

    // 頂点の数だけ関連付け
    for (int i=0; i<mb->getVertexCount(); i++)
    {
        for (it=vertices.begin(); it != vertices.end(); ++it)
        {
            // 同じ座標を指すIrrlichtの頂点番号とBulletの頂点番号を関連付け
            int v_index = it->first;
            btSoftBody::Node* node = it->second;
            if (node->m_x.x() ==  mb_vertices[i].Pos.X &&
                node->m_x.y() ==  mb_vertices[i].Pos.Y &&
                node->m_x.z() == -mb_vertices[i].Pos.Z)
            {
                // IrrlichtとBulletのマップを作成
                testMesh_map.insert(std::make_pair(i, v_index));
                break;
            }
        }
    }

    // SoftBodyのパラメータ設定
    std::cout << "addSoftBody" << std::endl;
    cubeSoftBody->m_cfg.kDP = 0.0;// Damping coefficient [0,1]
    cubeSoftBody->m_cfg.kDF = 0.2;// Dynamic friction coefficient [0,1]
    cubeSoftBody->m_cfg.kMT = 0.02;// Pose matching coefficient [0,1]
    cubeSoftBody->m_cfg.kCHR = 1.0;// Rigid contacts hardness [0,1]
    cubeSoftBody->m_cfg.kKHR = 0.8;// Kinetic contacts hardness [0,1]
    cubeSoftBody->m_cfg.kSHR = 1.0;// Soft contacts hardness [0,1]
    cubeSoftBody->m_cfg.piterations=2;
    cubeSoftBody->m_materials[0]->m_kLST = 0.8;
    cubeSoftBody->m_materials[0]->m_kAST = 0.8;
    cubeSoftBody->m_materials[0]->m_kVST = 0.8;
    cubeSoftBody->scale(btVector3(10,10,10));
    cubeSoftBody->setPose(true, true);
    cubeSoftBody->generateBendingConstraints(2);
    cubeSoftBody->randomizeConstraints();

    // 初期位置設定、BulletへのSoftBodyの追加
    btMatrix3x3 m;
    m.setIdentity();
    cubeSoftBody->transform(btTransform(m,btVector3(0, 400, 0)));
    dynamicsWorld->addSoftBody(cubeSoftBody);

    std::cout << "start simulation" << std::endl;
    // シミュレーションステップ
    while(device->run())
    {
        // シミュレーションを進める。間隔は60Hz
        dynamicsWorld->stepSimulation(1/60.0f, 1);

        // Irrlichtの頂点情報の更新
        for (int i=0; i<mb->getVertexCount(); i++)
        {
            // Irrlictの頂点番号→Bulletの頂点番号
            int index = testMesh_map.find(i)->second;
            // Bulletの頂点番号からノードを取得し,頂点座標を更新
            btSoftBody::Node* node = vertices.find(index)->second;
            // Irrlicht側はmb_vertices[i]でOK
            mb_vertices[i].Pos.X = node->m_x.x();
            mb_vertices[i].Pos.Y = node->m_x.y();
            mb_vertices[i].Pos.Z = -node->m_x.z();
        }

        if (GetAsyncKeyState(VK_SPACE))
        {
            // 0番目のノードに力を加える
            cubeSoftBody->addForce(btVector3(0, 10, 0), 0);
        }
        else if (GetAsyncKeyState(VK_ESCAPE)) 
        {
            break;
        }

        driver->beginScene(true, true, SColor(0,200,200,200));
        smgr->drawAll();
        driver->endScene();
    }
    device->drop();

    /* Clean up	*/ 
    for(int i=dynamicsWorld->getNumCollisionObjects()-1;i>0;i--)
    {
        btCollisionObject*	obj=dynamicsWorld->getCollisionObjectArray()[i];
        btRigidBody*		body=btRigidBody::upcast(obj);
        if(body&&body->getMotionState())
        {
            delete body->getMotionState();
        }
        while(dynamicsWorld->getNumConstraints())
        {
            btTypedConstraint*	pc=dynamicsWorld->getConstraint(0);
            dynamicsWorld->removeConstraint(pc);
            delete pc;
        }
        btSoftBody* softBody = btSoftBody::upcast(obj);
        if (softBody)
        {
            dynamicsWorld->removeSoftBody(softBody);
        } else
        {
            dynamicsWorld->removeCollisionObject(obj);
        }
        delete obj;
    }

    delete [] testMesh.mqo_indices;
    delete [] testMesh.mqo_vertices;

    // ワールド・ソルバ・その他もろもろの削除
    delete dynamicsWorld;
    delete solver;
    delete collisionConfiguration;
    delete dispatcher;
    delete broadphase;

    return 0;
}
MasterM
Posts: 128
Joined: Sat Oct 20, 2007 2:38 am
Location: netherlands antilles, Curacao

Post by MasterM »

This code looks nice and all but i think its better to post the project file and what font are you using cause my pc cant read some of the comments
C++ is not the Magdalena...it takes patience...shes like the well aged prostitute, it takes years to learn her tricks! she is cruel...laughs at you when you are naked...
Life of a programmer == Const abuse
GameDude
Posts: 498
Joined: Thu May 24, 2007 12:24 am

Post by GameDude »

Code looks good and is good to learn from
go
Posts: 28
Joined: Mon Oct 20, 2008 7:53 am

Post by go »

OK, maybe upload Softbody with Irrlicht project for vc 2008 express...

and sourcecode's comment change for English.
MasterM
Posts: 128
Joined: Sat Oct 20, 2007 2:38 am
Location: netherlands antilles, Curacao

Post by MasterM »

ok cant wait for that cause i have been trying for ages to make irrlicht work with bullet(and actualy now what i'm doing).
C++ is not the Magdalena...it takes patience...shes like the well aged prostitute, it takes years to learn her tricks! she is cruel...laughs at you when you are naked...
Life of a programmer == Const abuse
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

Nice work.

Anyway, I'm still trying to figure how to set the direction and fire a projectile in Bullet. I know how to apply force along the Z-axis. Somehow, setting the rotation doesn't work.

Any idea how I can get it to happen?

Maybe you can add a projectile in your demo program? I would really appreciate that.

Thanks.
Image
punong_bisyonaryo
Posts: 1
Joined: Mon Oct 19, 2009 5:56 am
Contact:

Post by punong_bisyonaryo »

I wrote a short introductory tutorial in the Irrlicht Wiki. It would be nice if you could add some more tutorials since I'm still learning about soft bodies myself.

Check it out at:
http://www.irrlicht3d.org/wiki/index.ph ... WithBullet
jgabrito
Posts: 1
Joined: Sat Nov 12, 2011 3:29 pm

Re: Irrlicht with Bullet Softbody sample sourcecode

Post by jgabrito »

Thanks for the very nice example. Don't forget to call mb->setDirty() after updating the vertex positions in the main loop or, sometimes, Irrlicht won't update the mesh in the rendering pipeline. Also, those vertex position comparisons in the mesh cleanup procedure need more tolerance. I think something round 1.0e-3 as a distance threshold (1.0e-6 as squared distance threshold) is pretty safe.
fmx

Re: Irrlicht with Bullet Softbody sample sourcecode

Post by fmx »

wha Miku! :mrgreen:

I cant believe this piece of code still works since 2008, usually physics engines and other libs evolve immensely over time, and Bullet is one of the most active.
Good stuff
pione
Posts: 1
Joined: Thu Dec 22, 2011 9:29 pm

Re: Irrlicht with Bullet Softbody sample sourcecode

Post by pione »

To dlangdev who asked how to shoot a projectile with Irrlicht and bullet.

It is easy: I wrote this simple function.

Code: Select all

 
// If we have defined Camera, World, and device as global we can call Shoot() without arguments.
void Shoot(btDiscreteDynamicsWorld *World, IrrlichtDevice * device, ICameraSceneNode * Camera) 
{
  ISceneManager *smgr = device->getSceneManager();
  IVideoDriver * driver = device->getVideoDriver();
 
  // Creating the irrlicht scene node of a sphere
  ISceneNode * node = smgr->addSphereSceneNode(1.); 
 
  node->setMaterialFlag(EMF_LIGHTING, false);
  node->setMaterialTexture(0, driver->getTexture("<texture path>")); // You have to specify your texture path
 
 
  // Now we create the bullet rigidbody in the same position of the camera
  btVector3 StartPos(Camera->getPosition().X, Camera->getPosition().Y, Camera->getPosition().Z);
  btCollisionShape * Shape = new btSphereShape(radius);
  btTransform Transform;
  Transform.setIdentity();
  Transform.setOrigin(StartPos);
 
  btVector3 localInertia;
  double mass = 1.;
  Shape->calculateLocalInertia(mass, localInertia);
  btDefaultMotionState *myMotionState = new btDefaultMotionState(Transform);
  btRigidBody::btRigidBodyConstructionInfo constructor(mass, myMotionState, Shape, localInertia);
 
  btRigidBody *body = new btRigidBody(constructor);
 
  // Linking the body to the irrlicht node so that we can update it later as proposed by punong_bisyonaryo's tutorial
  body->setUserPointer((void*)node);
 
  // Now we create a vector ImpulseForce that point to the direction in which the camera is pointing
  btVector3 Target(Camera->getTarget().X, Camera->getTarget().Y, Camera->getTarget().Z);
  btVector3 ImpulseForce(700 *( Target[0] - StartPos[0]), 700* (Target[1] - StartPos[1]), 700 * (Target[2] -StartPos[2]));
  body->applyCentralForce(ImpulseForce);
  World->addRigidBody(body);
 
  /*  Objects is a list of rigidbody that is used to updating the irrlicht nodes. I've defined this as a global variable (out of the main), as we see in  punong_bisyonaryo's tutorial . Otherwise you can pass it as pointer to the  function. */
  Objects.push_back(body);
}
 
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

Re: Irrlicht with Bullet Softbody sample sourcecode

Post by Granyte »

shooting a projectile is not that hard pooling the collision data to know wich object it hit in order to apply a randoom effect of some sort is the fun part
rookie
Posts: 16
Joined: Thu Dec 29, 2011 9:44 pm

Re: Irrlicht with Bullet Softbody sample sourcecode

Post by rookie »

I got the code running but I want to move the sleeves or the model something like this

http://www.youtube.com/watch?v=1jbvnk1T4vQ

This is for a school project. Let me know.
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:

Post by Cube_ »

MasterM wrote:This code looks nice and all but i think its better to post the project file and what font are you using cause my pc cant read some of the comments
a lot of the comments are in japanese. install the japanse language pack.
"this is not the bottleneck you are looking for"
rookie
Posts: 16
Joined: Thu Dec 29, 2011 9:44 pm

Re: Irrlicht with Bullet Softbody sample sourcecode

Post by rookie »

thanks for the code. Can you tell me how to implement keyboard interaction?? I tried the following code. It is ubuntu 11.04. The applicaion exits when I hit ESCAPE but does not apply any force when I press Space.

class MyEventReceiver : public IEventReceiver
{
public:
// This is the one method that we have to implement
virtual bool OnEvent(const SEvent& event)
{
// Remember whether each key is down or up
if (event.EventType == irr::EET_KEY_INPUT_EVENT)
KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;

return false;
}

// This is used to check whether a key is being held down
virtual bool IsKeyDown(EKEY_CODE keyCode) const
{
return KeyIsDown[keyCode];
}

MyEventReceiver()
{
for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
KeyIsDown = false;
}

private:
// We use this array to store the current state of each key
bool KeyIsDown[KEY_KEY_CODES_COUNT];
};
Instead of your GetAsyncKeyState() I have used the following since GetAsyncKeyState() is for Windows only.
if(receiver.IsKeyDown(irr::KEY_SPACE))
cubeSoftBody->addForce(btVector3(10, 0, 0), 10);
else if(receiver.IsKeyDown(irr::KEY_ESCAPE))
break;

I tried applying force in all directions. No changes. Please help me.
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

Re: Irrlicht with Bullet Softbody sample sourcecode

Post by Granyte »

is your controled body a kinematic like the bullet exemple?
or a dynamic body
Post Reply