Performance when rendering to texture

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
SpyM
Posts: 9
Joined: Tue Jul 09, 2013 3:29 pm

Performance when rendering to texture

Post by SpyM »

Hello,

I'm developing a 3D football game with Irrlicht 1.7.3 on Ubuntu, and I'm having performance problems when adding jersey numbers on my players textures. The application drops to 5 FPS instead of the usual 60 FPS.

My players share the same mesh, which is a B3D model. The textures I apply on them have the same size 2048*2048 pixels (with PNG type), and they are very similar. Only the colors change, according to the team for which each player competes.
My font for jersey numbers is stored using the XML format, associated with a 1350*250 pixels image representing the 10 digits from 0 to 9. The digits are quite big because they have to be visible from medium range on the back of the players, and also because the texture is also quite big.

To construct my player scene node, I do this :

Code: Select all

 
IAnimatedMesh* mesh = sceneManager->getMesh(mModelPath);
mNode = sceneManager->addAnimatedMeshSceneNode(mesh);
mTexture = driver->getTexture(mTexturePath);
mNode->setMaterialTexture(0, mTexture);
mRenderTexture = driver->addRenderTargetTexture(mTextureSize);
mNode->setMaterialTexture(0, mRenderTexture);
 
Please note I am really using setMaterialTexture two times. It seems stupid when you see it here, but it may not be. Indeed, I gathered all the instructions related to the scene node and textures in the whole class hierarchy to show it to you in just one piece of code.

When it comes to actual rendering, I process each player in the same way.
I get his render texture (RT). I draw his colored texture on this RT. Then I draw his jersey number on this RT.

Here is the code for scene rendering :

Code: Select all

 
mDriver->beginScene(
            true, // clear back-buffer
            true, // clear z-buffer
            mBgColor);
 
for(std::map<int, Player*>::iterator i = players.begin();
        i != players.end(); ++i) {
    Player* p = i->second;
 
    // Virtual surface where to draw
    ITexture* rt = p->getRenderTexture();
    // Actual player texture with its color but without jersey number
    ITexture* texture = p->getTexture();
 
    // Now we draw on texture instead of window
    mDriver->setRenderTarget(rt);
    mDriver->setMaterial(mDriver->getMaterial2D()); // fix OpenGL issue in Irrlicht 1.7.3
    // Draw actual player texture
    mDriver->draw2DImage(texture, vector2di(0, 0));
 
    mDriver->setMaterial(mDriver->getMaterial2D());
    // Draw jersey number over it
    mJerseyFont->draw(p->getJerseyText(),
                      p->getJerseyTextRect(),
                      mJerseyTextColor, true, true);
 
    // We go back to window (necessary to be able to switch, see API)
    mDriver->setRenderTarget(0, true, true, mBgColor);
}
 
mSceneManager->drawAll();
 
mDriver->setMaterial(mDriver->getMaterial2D());
mGui->drawAll();
 
mDriver->endScene();
 
Could you please help me to find what I've done wrong ?

Thanks for your help ;)
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Performance when rendering to texture

Post by mongoose7 »

So you're rendering to texture 22 times per frame? And each RTT is 4*2048*2048 = 16 MB? 22*16MB = 330 MB.

Why don't you just build the textures on the CPU at the beginning. In fact, why don't you have only one texture for the shirt and give the player a rectangle for the number and render the player with the two textures, one for the shirt and the other for the number. You can colour the shirt using vertex colours.
SpyM
Posts: 9
Joined: Tue Jul 09, 2013 3:29 pm

Re: Performance when rendering to texture

Post by SpyM »

I would like to color my players only by changing the texture, since the vertex coloring would be much more complicated to handle when having complex jerseys.

So you think I have to draw the texture with the number only once at the beginning and then save it in a ITexure* member to avoid costly calls to setRT. Is this correct, or do you simply think I need to execute the for iteration only once instead of doing it at each frame ?
However, how can I draw the number on a given texture ? IGUIFont does not provide anything else than draw method, which requires RTT. I also noticed IImage might do the trick, but unfortunately we cannot use IGUIFont on it.
Am I forced to store all the images for each possible number (say from 1 to 100), or can I continue to use my font ?
I might also "hack" the problem by drawing my charset manually without IGUIFont.

What is the best solution ?
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Performance when rendering to texture

Post by mongoose7 »

Your textures are stored in files on the disk? You can also create numbers in, say, Paint. Now load a texture and a number in memory. Write the number over the texture and then save it out (or convert it to a texture).

But, if you use shaders, you could write the number over the texture dynamically. Find where the number needs to go on the texture and create another texture with just the number on it, at the right location. Pass both textures to the shader. Wherever the number colour is white, draw the number, otherwise draw the texture. Just like chromakeying. Also, you should be able to write the colour of the texture in the shader, so you only need one texture for the colour and one texture each for each of the numbers.
SpyM
Posts: 9
Joined: Tue Jul 09, 2013 3:29 pm

Re: Performance when rendering to texture

Post by SpyM »

I gave some memory for performance by executing the "for" iteration only once at the first rendering. I will go for shaders or "completely static" textures later if I need more memory.


Thank you for your answers, I really appreciate your help :D
Adversus
Posts: 128
Joined: Sun Oct 05, 2008 10:58 pm
Contact:

Re: Performance when rendering to texture

Post by Adversus »

Prebuild the shirts for each player as textures once when the match is loading, both colors (although I would simply use a texture per team as anything else will look crap and won't allow for detail) and numbers/names (do a setRenderTarget and call IGuiFont::draw)

btw I've used fonts when rendering to a texture. Works fine.
Post Reply