1.5.5 Blog - SoftBodies half implemented

betajaen

07-06-2009 20:54:57

This is the Blog for NxOgre 1.5.5

betajaen

07-06-2009 21:04:39



Cloth implemented

Cloth has finally been implemented into NxOgre. It took long enough, but it's in, and it's really easy and efficient to use.

ClothDescription desc;
desc.mMesh = NxOgre::MeshManager::getSingleton()->load("media:test.xcl", "testy");
desc.mGlobalPose.identity();
desc.mGlobalPose.set(0, 10, 0);
desc.mFlags |= Enums::ClothFlags_DebugVisualisation;
desc.mFlags |= Enums::ClothFlags_Hardware;

Cloth* cloth = mRenderSystem->createCloth(desc, "WelshFlag");
cloth->attachVertexToGlobalPosition(0, Vec3(1, 10, 0));
cloth->attachVertexToGlobalPosition(16, Vec3(4, 10, 0));
cloth->attachVertexToGlobalPosition(32, Vec3(8, 10, 0));


To make it visible in Ogre. I had to rewrite the Renderable class. It's much more efficient and has better and neater code. I also had to store the texture coordinates of the cloth, so a texture could be applied to it. So I took advantage of the "nxs" file that a normal cloth is in, and added an extra section to contain the texture coordinates. But the best thing is, it's completely compatible with non-NxOgre PhysX implementations.

Unfortunately, Flour doesn't seem to write cloth meshes at the moment. So hopefully if we ask Spacegaier nicely, he will write a short tutorial explaining how to generate cloth sheets for us by hand.

Wheels are in, and we have machines to drive them

The wheels are in. Nothing to special about that, but we now have the "machine" class to drive and display them. The machine class is a class designed to work with many different machine parts such as Wheels or other actors, and periodically tell them to simulate and render.

This is an example car I made;

class Car : public NxOgre::Machine
{
public:

Car(const Vec3& position, Scene* scene, OGRE3DRenderSystem* renderSystem) : Machine(), mScene(scene), mRenderSystem(renderSystem)
{

RigidBodyDescription description;

description.mMass = 1000; // Make it heavy.
description.mWakeUpCounter = 1E8; // Never go to sleep.

NxOgre::Shapes shapes;
mChassisShape = new NxOgre::Box(0.751, 0.275, 3.0);
shapes.insert(mChassisShape);

addWheel(Vec3(-0.5,0,1), true, true, true);
addWheel(Vec3(0.5,0,1), true, true, true);
addWheel(Vec3(-0.5,0,-1), false, false, true);
addWheel(Vec3(0.5,0,-1), false, false, true);

for (unsigned int i=0;i < mWheels.size();i++)
shapes.insert(mWheels[i].mWheel);

mActor = mScene->createActor(shapes, position, description);

mPointRenderable = mRenderSystem->createPointRenderable("photon-frame.mesh");

mScene->registerMachine(this);
}

~Car()
{
mScene->unregisterMachine(this);
}

void addWheel(const Vec3& position, bool driving, bool steering, bool braking)
{
CarWheel w;

// Create the physics wheel, which our rules and point renderable will represent and work with.
WheelBlueprint* blueprint = new WheelBlueprint();
blueprint->mRadius = 0.433f * 0.5f;
blueprint->mLocalPose.set(position);
w.mWheel = new Wheel(blueprint);

// Create our rules about this wheel.
w.mDriving = driving;
w.mSteering = steering;
w.mBraking = braking;

mWheels.insert(w);

// Then create the machine part of that wheel, so rules can be applied to it, and it can be rendered.
createWheelMachinePart(w.mWheel, mRenderSystem->createPointRenderable("photon-wheel.mesh"));
}

void drive(float torque)
{
for (unsigned int i=0;i < mWheels.size();i++)
if (mWheels[i].mDriving)
mWheels[i].mWheel->setMotorTorque(torque);
}

void brake(float torque)
{
for (unsigned int i=0;i < mWheels.size();i++)
if (mWheels[i].mBraking)
mWheels[i].mWheel->setBrakeTorque(torque);
}

void steer(float angle)
{
for (unsigned int i=0;i < mWheels.size();i++)
if (mWheels[i].mSteering)
mWheels[i].mWheel->setSteeringAngle(angle);
}

protected:

struct CarWheel
{
Wheel* mWheel;
bool mDriving;
bool mSteering;
bool mBraking;
};

NxOgre::Array<CarWheel> mWheels;

Scene* mScene;
OGRE3DRenderSystem* mRenderSystem;
NxOgre::Box* mChassisShape;
};


As you can see, it inherits from machine, not only it renders the car and wheels for me. But lets me drive them just as easily.


Conclusion

Apart from the new vector, quaternion and math classes. Cloth and Wheels are the big thing of 1.5.5. When it's out is another story, I still need to wrap the many functions of NxCloth into the Cloth class, implement cloth raycasting and support metal cloth for deformable bodies. But it'll be out soon.

almondega

08-06-2009 13:27:31

amazing cloth !!!! finally !!
tks betajaen
i'll use it in my college final project :wink:

Karan

08-06-2009 16:20:24

That's really cool! I want to add Cloth to my game relatively soon and now I don't have to implement everything myself :)

mcaden

09-06-2009 07:54:38

rock on :)

Karan

09-06-2009 14:52:41

Will you also do Soft Bodies soon as they're relatively similar to Cloth? I'm not sure if I can do everything I want with Cloth, maybe I need Soft Bodies as well.

betajaen

09-06-2009 16:27:51

I expect so. The only difference is that they use tetrahedra (quads) to aid in Rendering it. Once I read the documentation on it, and understand it, I could implement it in. But I didn't have much luck in the past in previous versions. But the new rendering system is more robust, powerfull and easier to use, so who knows. ;)

But for now, you could use closed meshes with cloth and inflate them. ;)

Karan

09-06-2009 20:27:59

Well, I want to try out both inflated cloth and soft bodies for my deformable objects, because I don't understand the practical difference between them (though I've read the PhysX SDK Guide about them).

betajaen

25-06-2009 00:53:24

Soft Bodies Half Implemented

I just wrote the easy part of the SoftBody code. Generating them using the manual mesh, reading them in, and the related SoftBody and SoftBodyDescription classes.

SoftBodyDescription desc;
desc.mMesh = NxOgre::MeshManager::getSingleton()->load("media:cube.xsb");
desc.mGlobalPose = Vec3(0, 5, 0);
desc.mParticleRadius = 0.2f;
desc.mVolumeStiffness = 0.2f;
desc.mStretchingStiffness = 0.2f;
desc.mFriction = 1.0f;
desc.mSolverIterations = 5;
desc.mFlags = 0;
desc.mFlags |= Enums::SoftBodyFlags_Gravity;
desc.mFlags |= Enums::SoftBodyFlags_Hardware;

mScene->createSoftBody(desc, 0);


No rendering as of yet, because that is the difficult part. However; I know it works through the remote debugger. So tommorow or the day after, I'll have a good stab at it.

Benjiro

29-06-2009 03:50:18

Soft Bodies Half Implemented
I just wrote the easy part of the SoftBody code. Generating them using the manual mesh, reading them in, and the related SoftBody and SoftBodyDescription classes.


Awesome work betajaen! as always!

Indecom

29-06-2009 17:58:15

Fantastic job, i can't wait to start playing around with this. That cloth stuff will definitely add a whole new dimension my space combat as a deformable metal surface!

cjlm007

25-09-2009 11:52:31

How can I rotate the mesh of the machine part?

denizkin

13-05-2010 09:25:08

Please help me with vehicle.

phyxcar.h
#include "ExampleApplication.h"

#include "NxOgre.h"
#include "NxOgreOGRE3D.h"
#include "NxOgreMachine.h"
#include "NxOgreWheel.h"

class Car : public NxOgre::Machine
{
public:

Car(const NxOgre::Vec3& position, NxOgre::Scene* scene, OGRE3DRenderSystem* renderSystem) : Machine(), mScene(scene), mRenderSystem(renderSystem)
{

NxOgre::RigidBodyDescription description;

description.mMass = 1000; // Make it heavy.
description.mWakeUpCounter = 1E8; // Never go to sleep.

NxOgre::Shapes shapes;
mChassisShape = new NxOgre::Box(1, 1, 1);
shapes.insert(mChassisShape);

addWheel(NxOgre::Vec3(-0.5,0,1), true, true, true);
addWheel(NxOgre::Vec3(0.5,0,1), true, true, true);
addWheel(NxOgre::Vec3(-0.5,0,-1), false, false, true);
addWheel(NxOgre::Vec3(0.5,0,-1), false, false, true);

for (unsigned int i=0;i < mWheels.size();i++)
shapes.insert(mWheels[i].mWheel);

mActor = mScene->createActor(shapes, position, description);

mPointRenderable = mRenderSystem->createPointRenderable("chassis.mesh");

mScene->registerMachine(this);
}

~Car()
{
mScene->unregisterMachine(this);
}

void addWheel(const NxOgre::Vec3& position, bool driving, bool steering, bool braking)
{
CarWheel w;

// Create the physics wheel, which our rules and point renderable will represent and work with.
NxOgre::WheelBlueprint* blueprint = new NxOgre::WheelBlueprint();
blueprint->mRadius = 0.433f * 0.5f;
blueprint->mLocalPose.set(position);
w.mWheel = new NxOgre::Wheel(blueprint);

// Create our rules about this wheel.
w.mDriving = driving;
w.mSteering = steering;
w.mBraking = braking;

mWheels.insert(w);

// Then create the machine part of that wheel, so rules can be applied to it, and it can be rendered.
createWheelMachinePart(w.mWheel, mRenderSystem->createPointRenderable("wheel.mesh"));
}

void drive(float torque)
{
for (unsigned int i=0;i < mWheels.size();i++)
if (mWheels[i].mDriving)
mWheels[i].mWheel->setMotorTorque(torque);
}

void brake(float torque)
{
for (unsigned int i=0;i < mWheels.size();i++)
if (mWheels[i].mBraking)
mWheels[i].mWheel->setBrakeTorque(torque);
}

void steer(float angle)
{
for (unsigned int i=0;i < mWheels.size();i++)
if (mWheels[i].mSteering)
mWheels[i].mWheel->setSteeringAngle(angle);
}
protected:

struct CarWheel
{
NxOgre::Wheel* mWheel;
bool mDriving;
bool mSteering;
bool mBraking;
};

NxOgre::Array<CarWheel> mWheels;

NxOgre::Scene* mScene;
OGRE3DRenderSystem* mRenderSystem;
NxOgre::Box* mChassisShape;
};


physx.cpp
#include "ExampleApplication.h"

#include "NxOgre.h"
#include "NxOgreOGRE3D.h"
#include "physxcar.h"
class BloodyMessTutorial2Listener : public ExampleFrameListener
{
public:
BloodyMessTutorial2Listener(RenderWindow *win, Camera *cam)
: ExampleFrameListener(win, cam)
{
mTimeController = NxOgre::TimeController::getSingleton();
}

bool frameStarted(const FrameEvent& evt)
{
mTimeController->advance(evt.timeSinceLastFrame);
return ExampleFrameListener::frameStarted(evt);
}

protected:
NxOgre::TimeController* mTimeController;
};

class BloodyMessTutorial2 : public ExampleApplication
{
protected:
NxOgre::World* mWorld2;
NxOgre::Scene* mScene2;
OGRE3DRenderSystem* mRenderSystem2;

OGRE3DBody* mCube2;
OGRE3DBody* mCubeTwo2;

void createScene()
{
// Set ambient light
mSceneMgr->setAmbientLight(ColourValue(0.5f, 0.5f, 0.5f));

// Create a light
Light* l = mSceneMgr->createLight("MainLight");
l->setPosition(20, 80, 50);

// Position the camera
mCamera->setPosition(0, 20, 80);
mCamera->lookAt(0, 20, 0);

// Create the world
mWorld2 = NxOgre::World::createWorld();

// Create scene description
NxOgre::SceneDescription sceneDesc;
sceneDesc.mGravity = NxOgre::Vec3(0, -9.8f, 0);
sceneDesc.mName = "DemoScene";

// Create scene
mScene2 = mWorld2->createScene(sceneDesc);

// Set some physical scene values
mScene2->getMaterial(0)->setStaticFriction(0.5);
mScene2->getMaterial(0)->setDynamicFriction(0.5);
mScene2->getMaterial(0)->setRestitution(0.1);

// Create render system
mRenderSystem2 = new OGRE3DRenderSystem(mScene2);

// Car
Car(NxOgre::Vec3(50,50,50),mScene2,mRenderSystem2);

// Create floor plane (BloodyMess)
mScene2->createSceneGeometry(new NxOgre::PlaneGeometry(0, NxOgre::Vec3(0, 1, 0)), Matrix44_Identity);

// Create floor plane (Ogre)
MovablePlane *plane = new MovablePlane("Plane");
plane->d = 0;
plane->normal = Vector3::UNIT_Y;
Ogre::MeshManager::getSingleton().createPlane("PlaneMesh",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
*plane, 120, 120, 1, 1, true, 1, 3, 3, Vector3::UNIT_Z);
Entity *planeEnt = mSceneMgr->createEntity("PlaneEntity", "PlaneMesh");
planeEnt->setMaterialName("Examples/GrassFloor");

Ogre::SceneNode* mPlaneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
mPlaneNode->attachObject(planeEnt);
}

// Create a new frame listener
void createFrameListener()
{
mFrameListener = new BloodyMessTutorial2Listener(mWindow, mCamera);
mRoot->addFrameListener(mFrameListener);
}
};

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT)
#else
int main(int argc, char **argv)
#endif
{
// Create application object
BloodyMessTutorial2 app;

try {
app.go();
} catch(Exception& e) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBoxA(NULL, e.getFullDescription().c_str(),
"An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "An exception has occurred: " << e.getFullDescription();
#endif
}

return 0;
}

#ifdef __cplusplus
}
#endif

Sorry,for my English. The car is constantly appears in the coordinates 0,0,0. What is the problem?

denizkin

14-05-2010 17:38:42

Please,somebody help me.