Page 1 of 1

my culling function

Posted: Sat Nov 13, 2010 12:26 pm
by arnir
hello, Iam integrating my own culling function to my AI class.
It avoiding to draw AIs that are behind wall.

first version was:

Code: Select all

void CAI::cull()
{
    line3d<f32> line(m_pCamera->getPosition(), m_pNode->getPosition());

     if(m_pDevice->getSceneManager()->getSceneCollisionManager()->getCollisionPoint(line, m_pMetaSelector,intersection,tri))
     {
         m_pNode->setVisible(false);
     }
     else
     {
         m_pNode->setVisible(true);
     }
}
it work fine but there is blink, because AI is invisible till position(center of BBox) was seen...

then I make antoher version that test all edges of BBox

Code: Select all

bool CAI::canCull()
{
    vector3df *edges = new vector3df[8];
    m_pNode->getTransformedBoundingBox().getEdges(edges);
    
    line3d<f32> line(m_pCamera->getPosition(), vector3df(0,0,0));

    for(int i=0; i<8; i++)
    {
        line.end = edges[i];
        
        if(!m_pDevice->getSceneManager()->getSceneCollisionManager()->getCollisionPoint(line, m_pMetaSelector,intersection,tri))
          return false;
    }
    
    return true;
}


void CAI::cull()
{
     if(canCull())
     {
         m_pNode->setVisible(false);
     }
     else
     {
         m_pNode->setVisible(true);
     }
}
but I don't know why I can't see anything... there's some bug that I pass over?

Posted: Sat Nov 13, 2010 1:16 pm
by mireazma
if( ! m_pDevice->getSceneManager()->getSceneCollisionManager()->getCollisionPoint(line, m_pMetaSelector,intersection,tri))
return false;
So "!" must be the bug.

Posted: Sat Nov 13, 2010 2:24 pm
by arnir
I think no.

Only if we don't see any edge(every line in cycle collide with map) function return true => setVisible(false)
otherwise if we can see at least one edge => setVisible(true)

Posted: Sun Nov 14, 2010 8:33 am
by arnir
but I've tried to remove "!"

and it work better but still not great.
if I see only half of AI(that means some edges) its OK, but if I see whole AI(every edge) AI is again invisible...

I really can't solve this :cry: :oops:

Posted: Sun Nov 14, 2010 12:35 pm
by arnir
I think I solved it :)

Code: Select all

line.end = m_pNode->getPosition() + edges[i];

Posted: Sun Nov 14, 2010 5:58 pm
by arnir
no :cry: it's better but still buggy... any response?

Posted: Mon Nov 15, 2010 4:17 am
by blAaarg
Hi arnir, a few thoughts that might not be enough to completely solve your problem but would seem to me to be some things to consider. I think your conclusion about your first example is completely right so, looking at your second example, with canCull():

The second line...

Code: Select all

m_pNode->getTransformedBoundingBox().getEdges(edges);
doesn't actually transform your bounding box for you, rather it returns a bounding box. If you don't store the return value, you can't do anything with it. It would have to be:

Code: Select all

aabbox3df transformedBB = m_pNode->getTransformedBoundingBox().getEdges(edges);
to be available for usage. Although, I don't think the collision manager would use it unless you adapted the collision manager's code.

Also, the 8 "edges" of the bounding box are actually corners, so when you try to do collisions in your loop using getCollisionPoint() there may be some floating point round-off error that sometimes will miss the box (corners). That's not such a big problem, though, as you could instead use getSceneNodeAndCollisionPointFromRay() [or even getSceneNodeFromCameraBB() ] to find out if your ray hit the bounding box of an AI node. That alone, would do some culling for you, although, iirc it uses an axis-aligned bounding box, not a fully transformed one. :(

Testing collisions against bounding boxes will sometimes produce false positives. That is, your AI nodes should show up when their bounding boxes are not completely blocked or obstructed by another node, but will also sometimes show up if they are almost visible, depending on how much space or volume of their bounding boxes the node's triangles fill up.

There's more to say about further culling, if necessary/desired, but only if that was helpful. For instance, once you have the bounding box and collision point, you could do some further tests to see if the collision actually hit any of the AI node's triangles that are inside the bounding box. I don't want to confuse the issue, though, if that was of no good to you. :?

Also, like mentioned before, it looks like as soon as any of the corners is missed, getCollision() returns false so (!getCollision())==true, causing the function to "return false;" as you've written. You want it to completely miss the bounding box before the function returns false.:)

Posted: Mon Nov 15, 2010 7:21 pm
by arnir
I think I don't understand everything you said :oops:
is my code ok? I really don't know what to change... If I see at least one corner of BBox a call setVisible(true)... I don't understand why it work so bad... I also call:

Code: Select all

m_pNode->setDebugDataVisible(EDS_BBOX);
to see bounding boxes, but sometimes my cull() draw AI behind the wall, sometimes don't draw AI in front of me...

Posted: Tue Nov 16, 2010 4:47 am
by blAaarg
Okay, sorry I made that confusing. Also, I wanted to say use getTransformedBoundingBoxEx() instead of getTransformedBoundingBox() [it's more accurate] but I removed that from my post to simplify and said something confusing and inaccurate instead. :oops: However, that won't solve these problems.

To simplify further:

Irrlicht will cull your objects for rendering. If you also want to cull objects so they don't update their AI methods, you can loop through an array of all AI objects, and use smgr->isCulled() to avoid updating their AI methods. This will give you some 'false positives'. In other words, sometimes something won't get culled when it could be. But it should still reduce the load [the amount of work done by the computer].

Using lines is probably not the best way to cull nodes.

If the program still runs slow, there are more complicated ways of culling, and you might have other problems, but this should, at least, help to cull a lot of AI nodes.
If I see at least one corner of BBox a call setVisible(true)
Actually, canCull() tests all 8 corners and returns false unless "line" hits all 8 corners. Use smgr->isCulled() in a loop instead. But I think this is closer to what you were trying to do:

Code: Select all

bool CAI::canCull()
{
    vector3df *edges = new vector3df[8];
    m_pNode->getTransformedBoundingBox().getEdges(edges);
   
    line3d<f32> line(m_pCamera->getPosition(), vector3df(0,0,0));

    for(int i=0; i<8; i++)
    {
        line.end = edges[i];

// if we hit a corner, return true, leave the loop and the function
if(m_pDevice->getSceneManager()->getSceneCollisionManager()->getCollisionPoint(line, m_pMetaSelector,intersection,tri))
          return true;
    }
   
    // otherwise, we must have finished the loop without hitting any corners at all
    return false;
} 

IIRC, setDebugDataVisible() uses axis aligned bounding boxes, not transformed ones.

Posted: Tue Nov 16, 2010 4:22 pm
by arnir
I finally got it 8)
It works perfect!

Code: Select all

bool CAI::canCull()
{
    vector3df pos = m_pNode->getPosition();
    
    line3d<f32> line(m_pCamera->getPosition(), pos);
      
    vector3df *edges = new vector3df[8];
    m_pNode->getTransformedBoundingBox().getEdges(edges);

    for(int i=0; i<8; i++)
    {
        line.end = edges[i];
        
        if(!m_pDevice->getSceneManager()->getSceneCollisionManager()->getCollisionPoint(line, m_pMetaSelector,intersection,tri))
        {
            delete [] edges;
            return false;
        }
    }
    
    delete [] edges;
    return true;
}
but it's little bit confusing... I think its the same code as in my first post...
anyway thanks :wink:

Posted: Sun Nov 21, 2010 1:35 am
by vitek
arnir wrote:

Code: Select all

    vector3df *edges = new vector3df[8];

    // snip...
    
    delete [] edges;
IMO, you should allocate the edges array on the stack for efficiency and safety. Something like this...

Code: Select all

vector3df edges[8];
Travis