Mesh Instancing

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
korgan00
Posts: 5
Joined: Mon Mar 25, 2013 11:18 pm

Mesh Instancing

Post by korgan00 »

Hi! Im a newbie on 3Dgraphics developing. I learn a lot on tutorials and i am trying to make a simple scene: many cubes and a light flying on circles. I draw lots of cubes (16x16x16) and fps go down so much (4-7 fps). i have good computer: quad core, nvidia gtx570ti, RAM 8GB i think that is enought for rendering 4096 cubes...
I was looking at the forum and many people was speakng about instancing and geting very good fps, drawing thousands of spheres and cubes getting about 30-200fps.
I belive that i understand instancing theory, u have one objet and many projections of the same object.
Can someone explain me how to instancing on irrlicht? can someone linking here an source code simple example?

At the moment i have a custom mesh with 24 vertex and 36 index drawing a cube, (4 vertex per square and 6 index per square (2triangles)) with 2 meshbuffers to get 2 textures.
I tried with smgr->addCubeSceneNode() but performance wasnt so much better (13fps).

this is my code:

Code: Select all

#include <irrlicht.h>
using namespace irr;
 
using namespace scene;
 
#ifndef PRUEBAS_MESHBLOCK
    #define PRUEBAS_MESHBLOCK
 
class meshBlock : public scene::SMesh {
private:
    typedef SMesh super;
 
    SMeshBuffer* getBuffer(u32 bufNum){
 
        SMeshBuffer *buf = 0;
        if (bufNum < this->getMeshBufferCount())
        {
            buf = (SMeshBuffer*)this->getMeshBuffer(bufNum);
        }
        else
        {
            // create new buffer
            buf = new SMeshBuffer();
            this->addMeshBuffer(buf);
            // to simplify things we drop here but continue using buf
            buf->drop();
        }
        return buf;
    }
 
    void clearBuffers(u32 from){
        if (from < this->getMeshBufferCount())
        {
            for (u32 j = from; j < this->getMeshBufferCount(); j++)
                this->getMeshBuffer(j)->drop();
 
            this->MeshBuffers.erase(from, this->getMeshBufferCount()-from);
        }
    }
 
public:
 
    meshBlock(f32 x, f32 y, f32 z, video::ITexture* tex1, video::ITexture* tex2): scene::SMesh(){
        
        /* inicializacion de constantes de configuracion del cubo */
        const f32 n = 10;//Cube Lenght
 
        const video::SColor marron(255,255,255,255);
        
        const u16 indices[] =   {   0,3,1,
                                    1,3,2,
                                    4,5,7,
                                    5,6,7,
                                    8,11,9,
                                    9,11,10,
                                    12,13,15,
                                    13,14,15,
                                    16,17,18,
                                    16,18,19,
                                    20,22,21,
                                    20,23,22
                                };
        
        /* Buffers */
        
 
        scene::SMeshBuffer* bufferTop = getBuffer(0);
        scene::SMeshBuffer* bufferRest = getBuffer(1);
 
        /* Indices de la tapa */
        bufferTop->Indices.set_used(6);
        for(int i = 0; i < 6; i++)
            bufferTop->Indices[i] = indices[i];
        
        /* Indices del resto del objeto */
        bufferRest->Indices.set_used(30);
        for(int i = 6; i < 36; i++)
            bufferRest->Indices[i-6] = indices[i]-4;
 
 
        /* Vertices 4 por cara */
        bufferTop->Vertices.set_used(4);
        bufferRest->Vertices.set_used(20);
        int i=0;
        //                                          (x,y,z)     normal      color       Texture Coordinates
        //////////////////////  TAPA
        bufferTop->Vertices[i] = video::S3DVertex   (0,n,0,     0,1,0,      marron,     0, 0);i++;
        bufferTop->Vertices[i] = video::S3DVertex   (n,n,0,     0,1,0,      marron,     1, 0);i++;
        bufferTop->Vertices[i] = video::S3DVertex   (n,n,n,     0,1,0,      marron,     1, 1);i++;
        bufferTop->Vertices[i] = video::S3DVertex   (0,n,n,     0,1,0,      marron,     0, 1);i=0;//*/i++;
        //////////////////////  FONDO
        bufferRest->Vertices[i] = video::S3DVertex  (0,0,0,     0,-1,0,     marron,     0, 0);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (n,0,0,     0,-1,0,     marron,     1, 0);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (n,0,n,     0,-1,0,     marron,     1, 1);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (0,0,n,     0,-1,0,     marron,     0, 1);i++;
        //////////////////////  CARA Z,Y en X=0
        bufferRest->Vertices[i] = video::S3DVertex  (0,0,0,     -1,0,0,     marron,     0, 1);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (0,n,0,     -1,0,0,     marron,     0, 0);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (0,n,n,     -1,0,0,     marron,     1, 0);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (0,0,n,     -1,0,0,     marron,     1, 1);i++;
        //////////////////////  CARA Z,Y en X=n
        bufferRest->Vertices[i] = video::S3DVertex  (n,0,0,     1,0,0,      marron,     0, 1);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (n,n,0,     1,0,0,      marron,     0, 0);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (n,n,n,     1,0,0,      marron,     1, 0);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (n,0,n,     1,0,0,      marron,     1, 1);i++;
        //////////////////////  CARA X,Y en Z=0
        bufferRest->Vertices[i] = video::S3DVertex  (0,0,0,     0,0,-1,     marron,     1, 1);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (0,n,0,     0,0,-1,     marron,     1, 0);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (n,n,0,     0,0,-1,     marron,     0, 0);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (n,0,0,     0,0,-1,     marron,     0, 1);i++;
        //////////////////////  CARA X,Y en Z=n
        bufferRest->Vertices[i] = video::S3DVertex  (0,0,n,     0,0,1,      marron,     0, 1);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (0,n,n,     0,0,1,      marron,     0, 0);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (n,n,n,     0,0,1,      marron,     1, 0);i++;
        bufferRest->Vertices[i] = video::S3DVertex  (n,0,n,     0,0,1,      marron,     1, 1);
        
        bufferTop->getMaterial().setTexture(0,tex1);
        //bufferTop->getMaterial().MaterialType = video::EMT_SOLID;
        //bufferTop->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, true);
        //bufferTop->setHardwareMappingHint(EHM_STATIC);
        //bufferTop->getMaterial().setFlag(video::EMF_POLYGON_OFFSET, true);
        bufferRest->getMaterial().setTexture(0,tex2);
        //bufferRest->getMaterial().MaterialType = video::EMT_SOLID;
        //bufferRest->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, true);
        //bufferRest->setHardwareMappingHint(EHM_STATIC);
        //bufferRest->getMaterial().setFlag(video::EMF_POLYGON_OFFSET, true);
        
        /*
        for(int i = 0; i < 4; i++){
            bufferTop->Vertices[i].Pos.X += x*n;
            bufferTop->Vertices[i].Pos.Y += y*n;
            bufferTop->Vertices[i].Pos.Z += z*n;
        }
 
        for(int i = 0; i < 20; i++){
            bufferRest->Vertices[i].Pos.X += x*n;
            bufferRest->Vertices[i].Pos.Y += y*n;
            bufferRest->Vertices[i].Pos.Z += z*n;
        }//*/
        
        /* Eliminamos el resto de buffers */
        clearBuffers(2);
 
        /* Recalculamos las cajas de colision */
        bufferRest->setDirty();
        bufferTop->setDirty();
 
        bufferTop->recalculateBoundingBox();
        bufferRest->recalculateBoundingBox();
        this->recalculateBoundingBox();
 
    }
 
    ISceneNode* addNodeToScene(ISceneManager* smgr){
        return smgr->addMeshSceneNode(this);
    }
 
};
 
#endif
and an extract of main.

Code: Select all

 
const f32 MAX_X = 16;
    const f32 MAX_Y = 16;
    const f32 MAX_Z = 16;
 
    meshBlock* myNode = new meshBlock(0,0,0, grass, dirt);
    //myNode->setHardwareMappingHint(scene::EHM_STATIC);
 
    for(f32 x = 0; x < MAX_X; x++){
        for(f32 y = 0; y < MAX_Y; y++){
            for(f32 z = 0; z < MAX_Z; z++){
 
                ISceneNode* n = myNode->addNodeToScene(smgr);
                n->setPosition(core::vector3df(x*10,y*10,z*10));
 
            }
        }
    }
 
Some variables are spanish words sorry about that and about my poor english.
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Re: Mesh Instancing

Post by Mel »

There are already patches to use instancing with Irrlicht, look for them also.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
korgan00
Posts: 5
Joined: Mon Mar 25, 2013 11:18 pm

Re: Mesh Instancing

Post by korgan00 »

can u tell me where are them?
mikkis
Posts: 64
Joined: Mon Jan 28, 2013 2:38 pm
Location: Fi

Re: Mesh Instancing

Post by mikkis »

Here is something:
http://irrlicht.sourceforge.net/forum/v ... 0&start=15

But if you dont like to patch your codes / if your scene is static, you can use MeshCombiner
http://irrlicht.sourceforge.net/forum/v ... =6&t=39598
korgan00
Posts: 5
Joined: Mon Mar 25, 2013 11:18 pm

Re: Mesh Instancing

Post by korgan00 »

Thx I was testing the example code and seems good. Thanks for helping.

Could it be done in another way, without patching? The nodes cant be full static, then, meshCombiner is not my solution.
I read about hardware buffer, but dont understand it at all. if i draw a mesh and set hardware hint to static, the hardware keep it on memory 20sec right?
if i dont draw it in the next cicle, it disappear? Is there any way to use this feature?
I need individual nodes but it will not change a lot. I want it to be selected only.
Post Reply