Page 1 of 1

Bullet and ITerrainSceneNode

Posted: Sat Sep 05, 2009 9:52 pm
by yamashi
Hello !
I used to use Irrlicht for my paged terrain system but it would just crash randomly so I decided to go for bullet and I couldn't find a code to cook a Terrain to a Bullet triangle mesh, so I made one and decided to post it for people who will need it in the future !
Here it is :

Code: Select all

void createHeightField(scene::ITerrainSceneNode* node)
{
	btVector3 vertices[3];
	s32 j,k;
	btTriangleMesh *  mTriMesh = new btTriangleMesh();

	irr::scene::CDynamicMeshBuffer* buffer = 0;

	buffer = new irr::scene::CDynamicMeshBuffer(irr::video::EVT_2TCOORDS, irr::video::EIT_16BIT);
	node->getMeshBufferForLOD(*buffer, 0);

	const irr::u32 vertexCount = buffer->getVertexCount();
	const irr::u32 indexCount = buffer->getIndexCount();


	irr::video::S3DVertex2TCoords* mb_vertices = (irr::video::S3DVertex2TCoords*)buffer->getVertexBuffer().getData();
	
	u16* mb_indices = buffer->getIndices();

	for(j=0;j<indexCount;j+=3)
	{ 
		for (k=0;k<3;k++) 
		{
			s32 index = mb_indices[j+k];
			vertices[k] = btVector3(
				mb_vertices[index].Pos.X*node->getScale().X,
				mb_vertices[index].Pos.Y*node->getScale().Y,
				mb_vertices[index].Pos.Z*node->getScale().Z);	
		}
		mTriMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
	}

	buffer->drop();

	btCollisionShape* mShape = new btBvhTriangleMeshShape(mTriMesh, true);

	btDefaultMotionState* state =	new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),
		btVector3(node->getPosition().X,node->getPosition().Y,node->getPosition().Z)));

	btRigidBody* mRigidBody = new btRigidBody(0, state, mShape, btVector3(0, 0, 0));
	mRigidBody->setCollisionFlags(mRigidBody->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);
	mDynamicsWorld->addRigidBody(mRigidBody);
}

Posted: Sun Sep 27, 2009 2:03 pm
by gbox
thanks~ :)

How to get the total number of vertices.

Posted: Sun Nov 15, 2009 5:43 pm
by enif
Hi!

The code above looks promissing - I need to test it. :-) I have one question about it, resp. this line of code is not particulary perfect :-) :

Code: Select all

 buffer = new irr::scene::CDynamicMeshBuffer(irr::video::EVT_2TCOORDS, irr::video::EIT_16BIT); 
The problem is, that this works for small terrains only (256x256 max.). Reason for that is the EIT_16BIT, which creates a 16bit buffer. With a bigger terrain it causes a crash, because terrain vertices does not fit into this buffer.

So, for bigger terrains (with more than 64k vertexes) you should use this:

Code: Select all

 buffer = new irr::scene::CDynamicMeshBuffer(irr::video::EVT_2TCOORDS, irr::video::EIT_32BIT); 
If you look into the sources of the ITerrainSceneNode, you can see a code like this:

Code: Select all

const u32 numVertices = TerrainData.Size * TerrainData.Size;
if (numVertices <= 65536)
{
	//small enough for 16bit buffers
	mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
			RenderBuffer->getIndexBuffer().setType(video::EIT_16BIT);
}
else
{
	//we need 32bit buffers
	mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_32BIT);
			RenderBuffer->getIndexBuffer().setType(video::EIT_32BIT);
}
This code decides, how big mesh buffer we really need.

The "TerrainData.Size" is private, so you can not use it for getting the total number of vertices in terrain scene node.

But, how to do it?

I am using this:

Code: Select all

const u32 numVertices = node->getMesh()->getMeshBuffer(0)->getVertexCount();
But is this a correct way?

Thanks for any ideas and happy codding!

Posted: Tue Nov 17, 2009 2:28 pm
by yamashi
I don't need this because I use 33x33 terrains and I made a paged terrain system (see my Paged Terrain system video).
So if I can skip a few lines of code and optimize the system even by a few instructions it's always better for realtime loading.

Posted: Tue Nov 17, 2009 4:59 pm
by enif
yamashi: Hi! Your code is gread, no doubt about it! :-) May bye I sound, like I am trying to fix something, thats needs no fixing. I am sorry for that! I am trying to make it better and more universal. And my English is a crap... :-)

I discovered one week point in the code - the indices.

If numVertices <= 65536, indices are 16bit. If not, indices are 32bit! You can (and should) test for the indices format by calling:

Code: Select all

video::E_INDEX_TYPE indicesType = buffer->getIndexType();
... on your CDynamicMeshBuffer.

For video::EIT_16BIT type you are OK. For video::EIT_32BIT you are getting u32* array pointer. So you should do something like this:

Code: Select all

u32* mb_indices32 = (u32*)buffer->getIndices();
... and continue with that.

For us, the big-terrain-lowers, this should help. :-)

Thanks!

Posted: Tue Nov 17, 2009 6:04 pm
by yamashi
You might be a big terrain lover but mine is infinite ^^ and I still use 16bits array... It's all about the way you chose to implement it.
Of course if you use the basic irrlicht system, you need a huge height-map which is not the best imo (loads of memory and slow), my system is able to load infinite terrains and in real time with little performance hit. But of course it takes time and work...
See a demo : http://www.youtube.com/watch?v=ETOOCZ0Hpxc

heightfield

Posted: Wed May 05, 2010 1:52 am
by kamikaze942
been working on this for a little bit. i get access violations, and i'm curious as to what im doing wrong. is this code correct? the bolded part is where im getting the access violation.

Code: Select all

First-chance exception at 0x00475222 in Trials of the Gods.exe: 0xC0000005: Access violation reading location 0x35852c54.
Unhandled exception at 0x00475222 in Trials of the Gods.exe: 0xC0000005: Access violation reading location 0x35852c54.
The program '[4772] Trials of the Gods.exe: Native' has exited with code -1073741819 (0xc0000005).

Code: Select all

void createHeightField(scene::ITerrainSceneNode* node)
{
   
   btVector3 vertices[3];
   s32 j,k;
   btTriangleMesh *  mTriMesh = new btTriangleMesh();

   irr::scene::CDynamicMeshBuffer* buffer = 0;

   buffer = new irr::scene::CDynamicMeshBuffer(irr::video::EVT_2TCOORDS, irr::video::EIT_32BIT);
   node->getMeshBufferForLOD(*buffer, 0);

   const irr::u32 vertexCount = buffer->getVertexCount();
   const irr::u32 indexCount = buffer->getIndexCount();


   irr::video::S3DVertex2TCoords* mb_vertices = (irr::video::S3DVertex2TCoords*)buffer->getVertexBuffer().getData();
   
   u32* mb_indices = (u32*)buffer->getIndices();

   for(j=0;j<indexCount;j+=3)
   {
      for (k=0;k<3;k++)
      {
         s32 index = mb_indices[j+k];
         vertices[k] = btVector3(
            mb_vertices[index].Pos.X*node->getScale().X,
            mb_vertices[index].Pos.Y*node->getScale().Y,
          [b]  mb_vertices[index].Pos.Z*node->getScale().Z);   [/b]
      }
      mTriMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
   }

   buffer->drop();

   btCollisionShape* mShape = new btBvhTriangleMeshShape(mTriMesh, true);
   btTransform T;
   T.setIdentity();
   T.setOrigin(btVector3(node->getPosition().X, node->getPosition().Y, node->getPosition().Z));
   btDefaultMotionState* state =   new btDefaultMotionState(T);
   btVector3 Inertia;
   mShape->calculateLocalInertia(0, Inertia);
   btRigidBody* mRigidBody = new btRigidBody(0, state, mShape,Inertia);
   mRigidBody->setCollisionFlags(mRigidBody->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);
   World->addRigidBody(mRigidBody);
}