Mesh batching

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
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Mesh batching

Post by B@z »

Hi
Every topic when talking about optimalisation, ppl recommends to batch those nodes what not moving, etc.
Now i wanted to try it out to see how it increases the performance, but couldnt find how to do it.
this is what i tried:

Code: Select all

				IAnimatedMesh* mesh = ((IAnimatedMeshSceneNode*)newObj->getNode())->getMesh();
				if (!batchObj)
				{
					batchObj = device->getSceneManager()->addMeshSceneNode(mesh);
				}
				else
				{
					for (u32 n = 0; n < mesh->getMeshBufferCount(); n++)
					{
						batchObj->getMesh()->getMeshBuffer(0)->append(mesh->getMeshBuffer(n));
					}
				}
I guess its doing its job right, but the problem it isnt saving the positions (of course coz meshes dont have positions :D)
So, how could i batch them, and keep my node positions, rotations, scales?
Image
Image
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

It's often best to batch things that won't move in relation to each other, which removes your problems. Don't make the mistake of "over-optimizing", such as trying to batch things that don't need to be. Batching is best used when you're drawing lots of small items or identical ones. If you need to batch items together and still maintain their positions, rotations, scales, etc., you could use shader batching.
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

no, i just want to set the startup positions.
i have a map editor, where u can place a lot of static objects.
and in game, i want to batch them together, coz they wont move a bit :D

and actually i had a problem with lot of nodes. like trees, there was a huge performance lost, but wasnt so high poly..
Image
Image
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

The coordinates of each mesh vertex are local coordinates. That means that their values only make sense in relation to each other within the mesh. You want to transform the coordinates of each mesh's vertices to their world coordinates before added them to your big batched mesh.
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

yup, and how can i do it? :3
Image
Image
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

Each scene node automatically builds a transform matrix for you (AbsoluteTransformation). If you look at the third tutorial, you'll notice that scene nodes set the world transform to it right before rendering. This is because it transforms the local coordinates of the mesh into the correct world space.

Assuming your meshes are in scene nodes, just take the vertices of the mesh in each scene node and multiply them by the AbsoluteTransformation matrix of that scene node. If you want to save time by not putting your meshes into scene nodes, batching the meshes, then deleting the individual scene nodes, you can use empty scene nodes instead and just delete those when you're done.
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

yeah i got so far but:

Code: Select all

				if (!batchObj)
				{
					batchObj = device->getSceneManager()->addMeshSceneNode(mesh);
				}
				else
				{
					IAnimatedMesh* c = device->getSceneManager()->getMeshManipulator()->createAnimatedMesh(mesh);
					device->getSceneManager()->getMeshManipulator()->transform(c, newObj->getNode()->getAbsoluteTransformation());
					for (u32 n = 0; n < c->getMeshBufferCount(); n++)
					{
						batchObj->getMesh()->getMeshBuffer(0)->append(c->getMeshBuffer(n));
					}
					c->drop();
				}
i found a transform operation in the mesh manipulator, so i thought ill try it out.
but its not working (the mesh is in the same position)
and i think its not only not transformating, but only showing the first mesh what got into it
Image
Image
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

can anyone help me with this please? :3
Image
Image
Bate
Posts: 364
Joined: Sun Nov 01, 2009 11:39 pm
Location: Germany

Post by Bate »

You can use IrrExtensions, it has a batchmesh built-in. However, in reality a batchedMesh is not faster at all as soon as Hardware Buffers are involved. I did a lot of testing some time ago and here are my results for both code snippets rendering the exact same scene:

BatchMesh: 105 FPS AVERAGE

Code: Select all

driver->setMinHardwareBufferVertexCount(0); // always use Hardware Buffers

IBatchMesh* batchtest = smgr->createBatchMesh();
IMesh* hill = smgr->getMesh("hill100c.obj");

for (u32 i = 0; i < 100; i++)
{
  for (u32 j = 0; j < 100; j++)
  {
    batchtest->addMesh(hill, vector3df(i, 0, j));
  }
}

batchtest->finalize();

IMeshSceneNode* MergedNode = smgr->addMeshSceneNode(batchtest);
MergedNode->setMaterialFlag(EMF_LIGHTING, false);

batchtest->drop();

for (u32 i = 0; i < MergedNode->getMesh()->getMeshBufferCount(); i++)
{
  MergedNode->getMesh()->getMeshBuffer(i)->setHardwareMappingHint(EHM_STATIC); // set to static if the mesh never changes
}
Lots of Nodes: 126 FPS AVERAGE

Code: Select all

driver->setMinHardwareBufferVertexCount(0);

IMeshSceneNode* test[10000];
IMesh* temp = smgr->getMesh("hill100c.obj");
temp->setHardwareMappingHint(EHM_STATIC);

u32 tileID = 0;

for (u32 i = 0; i < 100; i++)
{
  for (u32 j = 0; j < 100; j++)
  {
    test[tileID] = smgr->addMeshSceneNode(temp);
    test[tileID]->setPosition( vector3df(i, 0, j) );
    test[tileID]->setMaterialFlag(EMF_LIGHTING, false);
    tileID++;
  }
}
So, in my case a batchedMesh didn't render faster. That's why I ditched it.
Never take advice from someone who likes to give advice, so take my advice and don't take it.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

If your meshes are large enough, then hardware buffers will often help enough. However, for very small meshes, batching will help muh better. However, the batch mesh needs to put all the things into one meshbuffer (not just many buffers into one mesh). Don't know if the referenced batchmesh node does this.
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

thanks for help.
i tried out IrrExtensions' batchMesh, but actually it slowed down the performance..

tried to set the hardware buffer(?) to EHM_STATIC, that didnt improve anything too..

Well actually, i have like 20 or more trees(very lowpoly) on my map, and its pretty slow... so is there any way to improve the performance?
Image
Image
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

I'd guess then, like Hybrid hinted, that the batchMesh doesn't actually combine the mesh buffers themselves, but just the meshes.

Hardware mapping only works well with large numbers of geometry per mesh buffer. In fact, the engine is set to ignore requests to use hardware buffers when a mesh buffer has too few vertices (< 300 IIRC). Your best bet is still to combine the trees into as few mesh buffers as possible.
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

yea it seems like. cant check the source, coz its not available.

and yeah i guess so i should combine the mesh buffers but... as i said append didnt do what it should so what to do?
Image
Image
Frank Dodd
Posts: 208
Joined: Sun Apr 02, 2006 9:20 pm

Post by Frank Dodd »

I utilise the Batching Mesh in my IrrlichtWrapper you can use that as a simple example. When dealing with static objects the CBatchingMesh module can offer really massive frame rate improvements as it gets rid of all of the overhead associated with managing a node and setting up a node for rendering.

There are three simple steps to it: -
  • 1) Create your batching mesh
    2) Add your static meshes to your batching mesh
    3) Finalize your batching mesh
Essentially you just do the following with it (you should use static meshes for this instead of IAnimatedMesh that is a feature of my code where I hide the concept of static meshes):

Code: Select all

	CBatchingMesh* meshBatch = new CBatchingMesh();

	meshBatch->addMesh(	mesh,
						core::vector3df( posX,posY,posZ ),
						core::vector3df( rotX,rotY,rotZ ),
						core::vector3df( scaX,scaY,scaZ ));

	meshBatch->finalize();
	IMeshManipulator * mm = smgr->getMeshManipulator();
	IAnimatedMesh * resultMesh = mm->createAnimatedMesh( meshBatch );
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

well thats just what i did, and it made worse D:
It dropped down from 20 fps to 10 xD
but yeah i didn't use static mesh, i used IAnimatedMesh (coz i dont know how to load static only from b3d...). was that the problem?
Image
Image
Post Reply