Irrlicht mesh data in ODE trimesh

Post your questions, suggestions and experiences regarding game design, integration of external libraries here. For irrEdit, irrXML and irrKlang, see the
ambiera forums
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Irrlicht mesh data in ODE trimesh

Post by Tanuva »

Hello,

I'm currently trying to get a TriMesh from Irrlicht also into ODE to do collisions with it. For not having it twice in memory I take the mesh data from Irrlicht and pass it on to ODE, but on creating the trimesh data, ODE fails at this point according to gdb:
[...]
Load track chunk.
Load track chunk.
Load track chunk.
Loaded mesh: mesh/kipper_v4.3ds
createTrimeshGeom: loading mesh/kipper_v4.3ds...

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb65f6990 (LWP 27001)]
0xb7ea3525 in Opcode::AABBTreeOfTrianglesBuilder::ComputeGlobalBox () from /usr/lib/libode.so.0debian1
This is the method that should get the data over to ode: http://pastebin.ca/1352163

Since it works with a dedicated 3ds file loader, this seems not to be a bug in ODE. Do I have to modify the vertex or index data somehow to make it usable by ODE?

Irrlicht 1.5
ODE 0.9-1 (Debian)
3DS mesh saved with 3DSMax 2009
Tanuva
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

One thing that sticks out is your vertex pitch, you should be using:

Code: Select all

inline u32 getVertexPitchFromType(E_VERTEX_TYPE vertexType)
in S3DVertex.h, not 3 * sizeof(float).

Mind you this is just one wrong thing, It's probably some other mistake that's causing the crash (This one will just make the mesh screwed up, unlikely to make it crash.).
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
kh_
Posts: 78
Joined: Fri May 19, 2006 4:29 pm

Post by kh_ »

Not sure, but if what Blindside said doesn't work,see if this works:

Code: Select all

 &(  (meshbuf->getVertices())[0].Pos.X)  //might need a cast
you'd probably need to combine it with what Blindside said.

another problem might be the indices being an array of u16
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

Thanks for your hints :)

Blindside's suggestion is in, but didn't solve the problem.
KH: When I integrate your idea, g++ complains about this:
../src/CGameObject.cpp: In member function ‘void CGameObject::createTrimeshGeom(const char*)’:
../src/CGameObject.cpp:63: error: pointer of type ‘void *’ used in arithmetic
../src/CGameObject.cpp:63: error: ‘void*’ is not a pointer-to-object type
I guess I need to cast that like you already mentioned - how would I do that? Haven't used typecasting in cpp so far...

I found the idea of getting the Irrlicht mesh data over to ODE on the PAL homepage, section "Adding the Terrain" - he does some scaling and is using PAL, so I just "ported" the idea of pulling the mesh data from Irrlicht.
Tanuva
kh_
Posts: 78
Joined: Fri May 19, 2006 4:29 pm

Post by kh_ »

Never mind my idea,it's no different than just using buff->getVertices() , just thought it might be worth a try. It would look like this:
&( ((video::S3DVertex *)mshbuff->getVertices())[0].Pos.X)


Are you using Gimpact?

I tried both ways using Gimpact and got this error:

Code: Select all

 

// GIMPACT only supports stride 12, so we need to catch the error early.
	dUASSERT
	(
	  Data->m_VertexStride == 3*sizeof(float) && Data->m_TriStride == 3*sizeof(int),
          "Gimpact trimesh only supports a stride of 3 float/int\n"
	  "This means that you cannot use dGeomTriMeshDataBuildSimple() with Gimpact.\n"
	  "Change the stride, or use Opcode trimeshes instead.\n"
	);
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

Umm... I'm using the default and since gdb complains about the Opcode::AABBCompute function, I seem to be using opcode. :)
Tanuva
kh_
Posts: 78
Joined: Fri May 19, 2006 4:29 pm

Post by kh_ »

[EDIT: post removed]
Last edited by kh_ on Wed Mar 11, 2009 1:35 am, edited 3 times in total.
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Post by randomMesh »

Here's the code of the implementation of my GameObject class.
It automagically creates an ODE trimesh from an Irrlicht IMesh*.

Have a look at the makeTriMeshData() method.

Code: Select all

#include "GameObject.h"
#include "physics/Physics.h"
#include <SMesh.h>

irr::core::matrix4 GameObject::currentTransformation = irr::core::matrix4();

GameObject::GameObject(
	irr::scene::ISceneNode* node,
	irr::scene::IMesh* mesh,
	const dReal density, const dReal weight,
	const bool createBody = true, const bool gravity = true
) :
	OdeObject(density, weight),
	node(node), mesh(mesh)
{
	init(createBody, gravity);
}

GameObject::~GameObject()
{
	if (this->geom)
		dGeomDestroy(this->geom);

	if (this->body)
		dBodyDestroy(this->body);

	dGeomTriMeshDataDestroy(this->data);

    delete[] this->vertices;
    delete[] this->indices;
}

void GameObject::update(const dBodyID body)
{
	irr::scene::ISceneNode* const node = ((GameObject*)dBodyGetData(body))->node;

   	const irr::core::matrix4& mat = getTransformationMatrix(body);
   	node->setRotation(mat.getRotationDegrees());
   	node->setPosition(mat.getTranslation());
}

const irr::core::matrix4& GameObject::getTransformationMatrix(dBodyID const body)
{
	const dReal* const p = dBodyGetPosition(body);
	const dReal* const r = dBodyGetRotation(body);

	irr::f32 m[16];
	m[ 0] = r[ 0]; m[ 1] = r[ 4]; m[ 2] = r[ 8]; m[ 3] = 0;
	m[ 4] = r[ 1]; m[ 5] = r[ 5]; m[ 6] = r[ 9]; m[ 7] = 0;
	m[ 8] = r[ 2]; m[ 9] = r[ 6]; m[10] = r[10]; m[11] = 0;
	m[12] = p[ 0]; m[13] = p[ 1]; m[14] = p[ 2]; m[15] = 1;

	currentTransformation.setM(m);

	return currentTransformation;
}

const void GameObject::init(const bool createBody, const bool gravityMode)
{
	const irr::core::vector3df& pos = this->node->getPosition();
	const irr::core::vector3df& rotationRAD = (this->node->getRotation()*irr::core::DEGTORAD);
	const irr::core::quaternion irrQuat(rotationRAD);
	dQuaternion odeQuat;
	odeQuat[0] = irrQuat.W;
	odeQuat[1] = irrQuat.X;
	odeQuat[2] = irrQuat.Y;
	odeQuat[3] = irrQuat.Z;


	//create geom
	this->internalCreateGeom();
	dGeomSetData(this->geom, this);
	dGeomSetPosition(this->geom, pos.X, pos.Y, pos.Z);
	dGeomSetQuaternion(this->geom, odeQuat);

	if (createBody)
	{
		//create body
		this->body = dBodyCreate(Physics::getWorld());
		dBodySetData(this->body, this);

		//setup mass
		this->internalSetUpMass();

		dBodySetPosition(this->body, pos.X, pos.Y, pos.Z);
		dBodySetQuaternion(this->body, odeQuat);
		dBodySetGravityMode(this->body, gravityMode);
		dBodySetMovedCallback(this->body, &this->update);
	}

	dGeomSetBody(this->geom, this->body);
}

const void GameObject::internalSetUpMass()
{
	dMassSetTrimesh(&this->mass, this->density, this->geom);
	dMassTranslate(&this->mass, -this->mass.c[0], -this->mass.c[1], -this->mass.c[2]);
	dMassAdjust(&this->mass, this->weight);
	dBodySetMass(this->body, &this->mass);
}

const void GameObject::internalCreateGeom()
{
	makeTriMeshData();
	this->geom = dCreateTriMesh(Physics::getSpace(), this->data, 0, 0, 0);
}

void GameObject::makeTriMeshData()
{
	irr::u32 indexcount = 0;
	irr::u32 vertexcount = 0;

	// count vertices and indices
	irr::u32 i;
	for (i = 0; i < mesh->getMeshBufferCount(); i++)
    {
		const irr::scene::IMeshBuffer* mb = mesh->getMeshBuffer(i);

		indexcount += mb->getIndexCount();
		vertexcount += mb->getVertexCount();
	}

	// build structure for ode trimesh geom
	this->vertices = new dVector4[vertexcount];
	this->indices = new dTriIndex[indexcount];

	irr::u32 i_off = 0, i_cnt = 0, v_off = 0;

	const irr::core::vector3df& scale = node->getScale();

	for (irr::u32 i = 0; i < mesh->getMeshBufferCount(); ++i)
    {
		const irr::scene::IMeshBuffer* mb = mesh->getMeshBuffer(i);
		const irr::u16* mb_indices = mb->getIndices();

		for (irr::u32 j = 0; j < mb->getIndexCount(); ++j)
			indices[i_off++] = i_cnt + mb_indices[j];

		i_cnt += mb->getIndexCount();


		if (mb->getVertexType() == irr::video::EVT_STANDARD)
		{
			const irr::video::S3DVertex* mb_vertices = (irr::video::S3DVertex*)mb->getVertices();
			irr::u32 j;
			for(j = 0; j < mb->getVertexCount(); ++j)
			{
				vertices[v_off][0] = mb_vertices[j].Pos.X*scale.X;
				vertices[v_off][1] = mb_vertices[j].Pos.Y*scale.Y;
				vertices[v_off][2] = mb_vertices[j].Pos.Z*scale.Z;
				v_off++;
			}
		}
		else if (mb->getVertexType() == irr::video::EVT_2TCOORDS)
		{
			const irr::video::S3DVertex2TCoords* mb_vertices = (irr::video::S3DVertex2TCoords*)mb->getVertices();
			irr::u32 j;
			for (j = 0; j < mb->getVertexCount(); ++j)
			{
				vertices[v_off][0] = mb_vertices[j].Pos.X*scale.X;
				vertices[v_off][1] = mb_vertices[j].Pos.Y*scale.Y;
				vertices[v_off][2] = mb_vertices[j].Pos.Z*scale.Z;
				v_off++;
			}
		}
    }

	this->data = dGeomTriMeshDataCreate();
	dGeomTriMeshDataBuildSimple(this->data, (const dReal*)this->vertices, vertexcount, (const dTriIndex*)this->indices, indexcount);
}

"Whoops..."
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

KH: Glad yours works :) - mine doesn't yet though...
randomMesh: Could you give me the lines where the vertices and indices arrays are declared?
corresponding to:

Code: Select all

this->vertices = dVector4[vertexcount];
this->indices = new dTriIndex[indexcount];
Unfortunately, I cannot seem to get a proper array declaration done. :oops:
Hope your code works for me in the end, I already suspected my mesh to be kind of faulty, but with another one ODE shows the same crashy behaviour on calculating the aabb. Strange thing this is...
Tanuva
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Post by randomMesh »

Tanuva wrote:randomMesh: Could you give me the lines where the vertices and indices arrays are declared?
corresponding to:

Code: Select all

this->vertices = dVector4[vertexcount];
this->indices = new dTriIndex[indexcount];
Unfortunately, I cannot seem to get a proper array declaration done.
You missed a 'new'.

Code: Select all

///Vertex array for trimesh geom.
dVector4* vertices;

///Index array for trimesh geom.
dTriIndex* indices;
"Whoops..."
irrFu
Posts: 2
Joined: Sat Mar 14, 2009 1:40 pm

Post by irrFu »

Hi,

I had a look to your makeTriMeshData() method and used it to create my own function (thanks !).

But there is a mistake in this function. Problems can occurs when you use meshes with several mesh buffers.
The mistake is here : i_cnt += mb->getIndexCount();
You have to replace this line with : i_cnt += mb->getVertexCount();

Hope this will help.
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

Okay, it took a while for me to find out that dTriIndex doesn't exist in ODE 0.9 yet, so I had to install 0.11 (which luckily also resides in Debian Sid) - now I'm still getting an error about a bad direction number for dMassSetCylinderTotal which is indeed 3 (for z axis) and therefore NOT bad, but I'll see...
Tanuva
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

The cylinder direction thing was caused by a change from dSINGLE to dDOUBLE in the Debian ODE binary, got it fixed.

Next issue (-.-, can't this simply "work"?):
My trimesh falls down 2 or 3 meters, hits a cylinder standing upright on the groundplane like a wheel. The cylinder gets pushed aside (still upright...) and the trimesh lies flat on the ground. After some 1/2 secs, ODE complains about a normalization error:
ODE INTERNAL ERROR 1: assertion "bNormalizationResult" failed in _dNormalize4 () [../../include/ode/odemath.h]

What might cause this? Do I still have to transform the vertex/index data somehow (I'm using randomMesh's code, see above)?
Also tried with irrFu's suggestion, but that doesn't help.
Tanuva
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Post by randomMesh »

Tanuva wrote:ODE complains about a normalization error:
ODE INTERNAL ERROR 1: assertion "bNormalizationResult" failed in _dNormalize4 () [../../include/ode/odemath.h]
It's very important to compile your program with the same precision settings as the compiled ODE lib.

To know if either single or double precision was used, you can do something like this:

Code: Select all

const char* odeConfiguration = dGetConfiguration();
device->getLogger()->log(irr::core::stringw(odeConfiguration).c_str());
Output on my system is:

Code: Select all

ODE ODE_EXT_no_debug ODE_EXT_trimesh ODE_EXT_opcode ODE_OPC_new_collider ODE_double_precision
You then need to add dDOUBLE or dSINGLE to your compiler settings. (Defined symbols)

Btw:
dTrindex is only a typedef.

Code: Select all

typedef uint32 dTriIndex;
"Whoops..."
Tanuva
Posts: 54
Joined: Tue Oct 10, 2006 6:49 pm
Location: 200 metres behind the moon
Contact:

Post by Tanuva »

It's all running with double precision now, your snipped gives:

Code: Select all

ODE ODE_EXT_trimesh ODE_EXT_opcode ODE_double_precision
I don't have ODE_OPC_new_collider enabled and the code works for you having it.
Might that thing cause my error?
[Seems like I need to compile ODE myself to test that. Would prefer relying on Debian's binaries. :/]
Tanuva
Post Reply