How to optimise billboard array 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
alko
Posts: 26
Joined: Wed Aug 29, 2018 10:14 am

How to optimise billboard array batching ?

Post by alko »

I need to optimise batching under Pmmx+Voodoo2

1.) Remove artifacts from bike animation
2.) Normalize FPS

https://youtu.be/nl96ZvXI_3Q


Bike animation I made by atlas: 256x80 - 4 frames
Scale/Scroll UV coordinates.

Code: Select all

animtime++;
if(animtime>6)animtime=0;


if(receiver.IsKeyDown(KEY_KEY_A)) {
	playerNode->setSize	(	dimension2df(-32,-40)	)	;
		if(animtime<3)	playerNode->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0.5f,0);	
		else playerNode->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0.75f,0);	

if(dy<40)dy+=4;
}
else if(receiver.IsKeyDown(KEY_KEY_D)) {
		playerNode->setSize	(	dimension2df(32,40)	)	;
		if(animtime<3)	playerNode->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0.5f,0);	
		else playerNode->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0.75f,0);	

if(dy>-40)dy-=4;

}
else {
if(dy>0)dy-=4;
if(dy<0)dy+=4;

if(animtime<3)playerNode->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0,0);
else playerNode->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0.25f,0);
}


objects are selected from atlas: 256x256
each billboard is a unique node.
Terrain ass one polygon and animate by UV scroll

Code: Select all

#ifndef ENVIRONMENT_H_INCLUDED
#define ENVIRONMENT_H_INCLUDED

#include "Globalvar.h"
#include "Player.h"
 #include <cstdlib>
class Environment
{	
public:
	IMeshSceneNode * gndNode;
 IBillboardSceneNode* levelNode[50];

 struct myObjects
 {
	 int type;
	 vector3df Pos;
	 
 };
myObjects objects[50];

 IMesh* gndmesh;

 IMesh* fogPlane;

float scroll,gndScroll;
 IMeshSceneNode* fognode;

ITexture *texObj1;
  
Environment(){

 	
	}
	void initNode(int num, ITexture* tex,vector3df pos ){
	}

 void init(){


texObj1= driver->getTexture("spr/objects.png");


for(int i=0;i<50;i++){
	objects[i].Pos.X=rand()%500;
objects[i].Pos.Z=rand()%1000;
objects[i].type=rand()%5;
levelNode[i]= smgr->addBillboardSceneNode();
levelNode[i]->setMaterialTexture(0, texObj1);

levelNode[i]->setMaterialFlag(EMF_LIGHTING, false);
 levelNode[i]->setMaterialFlag(EMF_FOG_ENABLE,true);
levelNode[i]->setMaterialType(EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
levelNode[i]->setMaterialFlag(EMF_BILINEAR_FILTER, false);
levelNode[i]->setAutomaticCulling(EAC_FRUSTUM_BOX);
levelNode[i]->setMaterialFlag(EMF_FOG_ENABLE,true);

 switch ( objects[i].type )
      {
         case 0:
			 objects[i].Pos.Y=64;
    levelNode[i]->setSize	(	dimension2df(64,128)	)	;
   levelNode[i]->getMaterial(0).getTextureMatrix(0).setScale(vector3df(0.25f,0.5f,0));
 levelNode[i]->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0.75f,0);
            break;
         case 1:
			 objects[i].Pos.Y=64;
levelNode[i]->setSize	(	dimension2df(64,128)	)	;
levelNode[i]->getMaterial(0).getTextureMatrix(0).setScale(vector3df(0.25f,0.5f,0));
 levelNode[i]->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0.75f,0.5f);
      
            break;
		 case 2:
			 		 objects[i].Pos.Y=80;
		levelNode[i]->setSize(	 dimension2df(192,192))		;
levelNode[i]->getMaterial(0).getTextureMatrix(0).setScale(vector3df(0.75f,0.75f,0));
 levelNode[i]->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0,0.33f);
      
            break;
		 case 3:		 objects[i].Pos.Y=32;
levelNode[i]->setSize(	 dimension2df(96,64))		;
levelNode[i]->getMaterial(0).getTextureMatrix(0).setScale(vector3df(0.375f,0.25f,0));
 levelNode[i]->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0,0);
       
            break;
		 case 4:		 objects[i].Pos.Y=32;
levelNode[i]->setSize(	 dimension2df(96,64))		;
levelNode[i]->getMaterial(0).getTextureMatrix(0).setScale(vector3df(0.375f,0.25f,0));
 levelNode[i]->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0.375f,0);
       
            break;

      }

 levelNode[i]->setPosition(objects[i].Pos);

}


		gndmesh=smgr->getMesh("spr/plane2.obj");
		gndmesh->setMaterialFlag(EMF_LIGHTING, false);




   gndNode = smgr->addMeshSceneNode(gndmesh);
	gndNode->setMaterialTexture( 0, driver->getTexture("spr/terrain.png") );
	gndNode->setMaterialFlag(EMF_TRILINEAR_FILTER,false);
	 gndNode->setMaterialFlag(EMF_FOG_ENABLE,true);
	 		gndNode->setMaterialFlag(EMF_LIGHTING, false);
	 gndNode->setScale(vector3df(100,0,100));
	 gndNode->setPosition(vector3df(500,0,00));
	 	 gndNode->setRotation(vector3df(180,0,0));
gndNode->getMaterial(0).getTextureMatrix(0).setScale(vector3df(25,25,0));
gndNode->setMaterialFlag(EMF_BACK_FACE_CULLING, false);

	

fogPlane=smgr->getMesh("spr/plane2.obj");
fogPlane->setMaterialFlag(EMF_LIGHTING, false);

   
   fognode = smgr->addMeshSceneNode(fogPlane);
	fognode->setMaterialTexture( 0, driver->getTexture("spr/fog.png") );
	fognode->setMaterialFlag(EMF_TRILINEAR_FILTER,true);
	 fognode->setMaterialFlag(EMF_FOG_ENABLE,true);
	 fognode->setScale(vector3df(100,0,100));
	 fognode->setPosition(vector3df(500,170,00));
	 	 fognode->setRotation(vector3df(180,0,0));
fognode->getMaterial(0).getTextureMatrix(0).setScale(vector3df(10,10,0));


 }

 void update(float speed)
 {
	 


for(int i=0;i<50;i++){

objects[i].Pos.Z+=speed*160;
levelNode[i]->setPosition(objects[i].Pos);

if(objects[i].Pos.Z>1000)objects[i].Pos.Z=0;
}

gndScroll +=speed;
	fognode->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0,gndScroll);
gndNode->getMaterial(0).getTextureMatrix(0).setTextureTranslate(0,gndScroll);

levelNode[1]->setPosition(vector3df(0,80,100));
	 
 }

};

#endif // ENVIRONMENT_H_INCLUDED
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to optimise billboard array batching ?

Post by CuteAlien »

1.) Is that artifact part of the same texture? Then it has wrong uv coordinates for it. Or is it something completely different? Then you likely overwrite texture memory somewhere. Maybe display the whole texture atlas and check if that is still fine (you can use IGUImage with setScaleImage set to true and display the texture-atlas in there to see if it's fine).
2.) Pretty impossible for me to help anyone with optimization without having a full working test-case which I can run myself. As the first step in optimizing is always to run it in a profiler to find out where the bottlenecks are. And you can do that yourself as well - use some tool like VerySleepy on Windows or gprof on Linux and once you see where time is really lost you can maybe ask about that part specifically (and often it's already quite obvious and you don't have to ask anymore).
Or is the problem not that it's slow but that the FPS jumps? In that case you can try to measure the time a frame takes. And then call sleep a bit to wait for the difference to the time you want. Or simpler - you can also enable vsync in the Irrlicht device (when using createDeviceEx that's one of the parameters in there).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
alko
Posts: 26
Joined: Wed Aug 29, 2018 10:14 am

Re: How to optimise billboard array batching ?

Post by alko »

CuteAlien wrote: Mon Feb 07, 2022 11:39 pm Then it has wrong uv coordinates for it.
UV are correct. These artifacts appear when it start on old-machine with voodoo.
On modern machine all is ok.
enable vsync in the Irrlicht device
vsync are enabled. yet again, on modern machine stable 60 fps. But on retro computer slowdowns. however there are not so many objects as for a 225MHz. In games like NFSs III fps are good, there are more polygons.

Link to download project:
https://www.dropbox.com/s/j0dpdikagnao1 ... j.rar?dl=0
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to optimise billboard array batching ?

Post by CuteAlien »

Sorry, I do not have experience with that card. But it might not support non-power-of-two textures. So your 256x80 texture should maybe be 256x256 instead. As IBillboardSceneNode doesn't allow access to UV coordinates (uh oh, gotta do that TODO some day...), you have to workk with texture-scale for now. So increase size of texture (just adding empty space) and in your player init then do:

Code: Select all

playerNode->getMaterial(0).getTextureMatrix(0).setTextureScale(0.25f,0.3125);
If that works then that's the problem.

Sorry, still can't help with slowdowns. You seem to be on Windows, so I hope VerySleepy profiler (http://www.codersnotes.com/sleepy) works on your system. It's free and easy to use - give it a shot.

Otherwise start adding/removing stuff and check what makes a big difference. This can at least give you a hint where the bottleneck is coming from.

And for other people to read your code a bit easier, maybe check a bit how other people use whitespace in code. General rule is - use same depth (with tabs) for code on the same scope.

Also - nice graphics, looks fun! And while I don't get why the controls work, they suprisingly do :-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
alko
Posts: 26
Joined: Wed Aug 29, 2018 10:14 am

Re: How to optimise billboard array batching ?

Post by alko »

I changed the array size to 32000 then on a modern machine appeared lags too.
its just ~32000 polys on intel core i5-3470 + GTX1660 OC.

Here "Very Sleepy" log:
https://www.dropbox.com/s/13s6z78ss8k6x ... e.csv?dl=0
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to optimise billboard array batching ?

Post by CuteAlien »

The problem with 32000 nodes is not the polygons, but amount of nodes. Each node has a pretty high cost itself as it causes a lot of state changes for the OpenGL driver. I noticed you still use Irrlicht 1.7 which was even worse there (svn trunk got a bit better with this).
So easy speed-up would likely be to hide nodes which are not visible in the current frame (for example because they are behind the camera).
Irrlicht does this for MeshSceneNodes, but not for BillboardSceneNodes.

Yeah.. very sleepy log not useful like this. Sorry, I'm so used to compiling Irrlicht myself that I sometimes forget other people don't do that. You need the debug-informations (even in release) to have some useful information in the sleepy log.

Btw also something you might check - if you are in debug or release. Release code will be a lot faster.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
alko
Posts: 26
Joined: Wed Aug 29, 2018 10:14 am

Re: How to optimise billboard array batching ?

Post by alko »

I noticed you still use Irrlicht 1.7
Its last version which works under Win98SE
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to optimise billboard array batching ?

Post by CuteAlien »

Oh? I didn't know Irrlicht no longer works there. Guess I'll have to de-dust my Window98 computer some day (got one under my table - but haven't turned it on in years).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to optimise billboard array batching ?

Post by CuteAlien »

Btw, thinking a bit more about it - it's not just state-switches (like material changes) which are expensive with so many nodes. It's also the pure amount of draw-calls you get. Each billboardscenenode only has 2 polygons - but each one needs it's own drawcall. And those cost. So drawing 1000 nodes is way more expensive than drawing 2000 polygons at once.

Which is kinda the way to optimize this. It's likely cheaper to build a few more polygons on PC side and send those together to the graphic-card. But you have to write your own custom scene node class for that. Or alternatively create your own meshbuffer and do the drawCalls directly (scenenodes are just a nice wrapper around doing that). But that is a bit complicated as it gets pretty low-level. You have to calculate vertex-positions and uv-coordinates yourself for this (thought at least for your case you can ignore camera rotations I guess as it's always from the front).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply