best way to handle an empty IAnimatedMeshSceneNode?

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
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

best way to handle an empty IAnimatedMeshSceneNode?

Post by Cube_ »

I've run into a slight issue with my optimization, if you recall I store each chunks mesh as an animated mesh scene node, so far so good... except for the slight corner case of an empty one (a chunk without any mesh, either because all blocks are obscured or all blocks are empty), it's sorta a corner case for most of my testing but will be a huge issue later on (as it'll generate a large amount of empty air chunks and obscured land chunks) and I don't really think crashing is the most elegant solution.

I considered adding just one single vertex to the mesh, this does work but feels like a hack; what I'm getting at is, is there a better way to store an empty mesh like this? (the reason I store an empty mesh is because a) users can add blocks there as they please, or blocks could be revealed on a chunk update in which case new block meshes need to be added to fill the void (according to metadata of course).

Or rather, that's what I narrowed down the odd crash to, it could be coincidental as I might be misunderstanding the data but here's the relevant code:

Code: Select all

    byte x = 0, y= 0, z = 0;
    bool vU,vD,vW,vE,vN,vS;
    const int MAX = CHUNKSIZE-1;
    const int MIN = 1;
    
    BlockType BT = BT_grass; //Temporary hack, can't be bothered to add a material selection interface at this point
    scene::SMesh* mesh = new scene::SMesh();
    
    for(x = MIN; x < MAX; x++)
    {
        for(y = MIN; y < MAX; y++)
        {
            for(z = MIN; z < MAX; z++)
            {
                cm = b_blocks[x][y][z].material;
                vU = b_blocks[x][y][z].visUp;
                vD = b_blocks[x][y][z].visDown;
                vE = b_blocks[x][y][z].visEast;
                vW = b_blocks[x][y][z].visWest;
                vN = b_blocks[x][y][z].visNorth;
                vS = b_blocks[x][y][z].visSouth;
 
/*
 * I'll add these comments to annotate the code, makes it easier to follow the logic
 * check current block (within actual block region, excluding border region
 * if air, then check surrounding blocks
 * else do nothing
 * the reason for this is that only blocks next to air (and potentially other nonsolid blocks like glass) 
 * get rendered and thus anything else doesn't need faces
 */
 
                if( b_blocks[x][x][z].isSolid() )
                {
                    continue;
                }
 
/*
 * okay, we've determined that we are an air block
 * proceeding to check the surrounding blocks (including the border region)
 */
 
                else
                {
                    if( b_blocks[x+1][y][z].isSolid()
                     || b_blocks[x-1][y][z].isSolid()
                     || b_blocks[x][y+1][z].isSolid()
                     || b_blocks[x][y-1][z].isSolid()
                     || b_blocks[x][y][z+1].isSolid()
                     || b_blocks[x][y][z-1].isSolid() )
 
/*
 * if we get here then there's a solid block next to us and we should create a mesh
 */
    
                    {
                        createCube(x,y,z,c,mesh,cm, vU, vD, vE, vW, vN, vS);
                    }        
                }
            }
        }
    }
    
/*
 * here I attempt to solve the empty mesh issue by checking if there's a mesh
 * however even an empty mesh seems to follow through here anyway
 * as the else clause I had there never triggered even with chunks specifically
 * (hence why said else clause was removed)
 * designed to be completely empty.
 * it is actually rather strange.
 */
 
    if(mesh)
    {
        scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
        mesh->drop();
        scaleMesh(anim_mesh, scale); 
    
        IMeshSceneNode *Chunk = smgr->addMeshSceneNode(anim_mesh);
        Chunk->setPosition(poteto);
        Chunk->setReadOnlyMaterials(true);
        Chunk->getMesh()->getMeshBuffer(0)->setHardwareMappingHint(scene::EHM_STATIC);
        //Chunk->getMesh()->getMeshBuffer(0)->setDirty();
        nodes.at(p)=Chunk;
        anim_mesh->drop();
    }
This code crashes, as mentioned, I'd wager it's due to trying to use an empty mesh to create an empty animated mesh scene node, until I get this working I can't even begin to think of adding a block selection and addition/removal system (not entirely sure how to do that aside from triangle selectors and rays, I'd wager tutorial 7 and the api could fill me in on the relevant details though).
On that matter, is there an interface for dynamically modifying vertex data in realtime (removing, adding, merging etc) directly from a scene node or does one have to construct a separate mesh buffer, optimize there, delete the mesh from the scene node and then attach the new mesh buffer to the scene node? Or would this be best done in shaders?
"this is not the bottleneck you are looking for"
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: best way to handle an empty IAnimatedMeshSceneNode?

Post by hendu »

if mesh && mesh->getMeshBufferCount
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: best way to handle an empty IAnimatedMeshSceneNode?

Post by Cube_ »

okay, so if I run that I get the mesh buffers attached to the mesh, then if that's empty I create a new empty mesh buffer and attach that, and it shouldn't segfault, I think.

I'd assume this would also let me modify the mesh of an animated mesh scene node (not even sure why I used the animated mesh scene node since the meshes are static, they don't deform... are there performance penalties to using the animated mesh scene node for a static mesh?)
"this is not the bottleneck you are looking for"
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: best way to handle an empty IAnimatedMeshSceneNode?

Post by Cube_ »

ah yes, that worked very well, I just do a check for if there are 0 mesh buffers now, if there are none I create a new one and append it with the argument NULL (no vertices or indices) and this seems to work very well.

Now I just need to figure out why my implementation seems to think that any block type is solid, here's an exerpt from my block list

Code: Select all

enum BlockType
{
    BT_NULL = 0,
    BT_empty,
 
    //natural materials
    BT_grass,
    BT_dirt,
    //redacted 
};
here's the function that checks if the blocks are solid or not

Code: Select all

bool block::isSolid()
{   
    if(b_blockType != BT_empty || b_blockType != BT_NULL)
        return true;
    else
        return false;
}
this should work fine, if it isn't either BT_empty or BT_NULL then it should count as solid and be registered as such, but even when I generate a pattern of (row by row)
12121212121212... (each number representing a row of 64 blocks, with the value in question of every block in the row being selected)
block 2 is BT_grass and should by all means register as solid, 1 is BT_empty (i.e air) and should register as nonsolid.
As seen earlier you already know that the block types are properly registered earlier, given that they render fine as their given type, just can't figure out why this dirt simple function isn't cooperating, ah well I'll experiment further.
Anywho, it doesn't crash on generating an empty chunk by accident so that's nice.

Here's a screenshot of what happens http://i.imgur.com/PENONg7.png
I use the same check to assign materials so the binary check itself works.

I'd therefore assume that I'm using the return value wrong, I shall now investigate this.


UPDATE: Okay, that's just weird. it's working now but the code is fundamentally identical, http://i.imgur.com/6MMHNsr.png

Code: Select all

byte block::isSolid()
{   
    if(b_blockType == BT_empty || b_blockType == BT_NULL)
        return 0;
    else
        return 1;
}
what brought this fix:
changed the return type, still same error.
changed the original truth table back to checking if blocks are a certain type instead of if they aren't, mirrored return values.
now working.
the same code didn't work with a boolean return type and a true/false return.
This is very odd but whatever, it's working and my typedef doesn't use any more memory anywho.

here's the old version before I started tinkering with it

Code: Select all

bool block::isSolid()
{   
    if(b_blockType == BT_empty || b_blockType == BT_NULL)
        return false;
    else
        return true;
}
And it doesn't work, as stated.
"this is not the bottleneck you are looking for"
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: best way to handle an empty IAnimatedMeshSceneNode?

Post by hendu »

== || == vs
!= || !=

You might want to work out the truth table for both.
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: best way to handle an empty IAnimatedMeshSceneNode?

Post by chronologicaldot »

hendu's right

This is kinda funny:

Code: Select all

 
if(b_blockType != BT_empty || b_blockType != BT_NULL)
 
I believe it equates to "always true", since the b_blocktype can only be one or the other. Might want to turn || into &&
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: best way to handle an empty IAnimatedMeshSceneNode?

Post by Cube_ »

right, but my original truth table was a boolean return of the
== || == check
however that didn't work, the exact same code with a return type of byte (typecast of char) works fine, meaning for some reason

Code: Select all

if( b_blocks[x][x][z].isSolid() )
doesn't work with a boolean comparison but does work with an integral comparison.
I'd expect (if(functionReturningFalse) to be equivalent to if(false) but it isn't, at least not in this case.
however if(functionReturningZero) is equivalent to if(false) which works for me, a boolean made it slightly more clear what it does (although it's simple and descriptive enough to do that anyway).
"this is not the bottleneck you are looking for"
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: best way to handle an empty IAnimatedMeshSceneNode?

Post by chronologicaldot »

Except that you had:

Code: Select all

 
return true;
else
return false;
 
and switched it around to:

Code: Select all

 
return 0; // technically, return false;
else
return 1; // technically, return true;
 
It had nothing to do with it being integer and everything to do with you switching the return result. Check your original post.
Post Reply