my culling function

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
arnir
Competition winner
Posts: 154
Joined: Sat Jan 20, 2007 4:36 pm
Location: Czech Republic

my culling function

Post 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?
programmer is bad designer
designer is bad programmer
mireazma
Posts: 7
Joined: Fri Nov 12, 2010 1:42 pm

Post by mireazma »

if( ! m_pDevice->getSceneManager()->getSceneCollisionManager()->getCollisionPoint(line, m_pMetaSelector,intersection,tri))
return false;
So "!" must be the bug.
arnir
Competition winner
Posts: 154
Joined: Sat Jan 20, 2007 4:36 pm
Location: Czech Republic

Post 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)
programmer is bad designer
designer is bad programmer
arnir
Competition winner
Posts: 154
Joined: Sat Jan 20, 2007 4:36 pm
Location: Czech Republic

Post 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:
programmer is bad designer
designer is bad programmer
arnir
Competition winner
Posts: 154
Joined: Sat Jan 20, 2007 4:36 pm
Location: Czech Republic

Post by arnir »

I think I solved it :)

Code: Select all

line.end = m_pNode->getPosition() + edges[i];
programmer is bad designer
designer is bad programmer
arnir
Competition winner
Posts: 154
Joined: Sat Jan 20, 2007 4:36 pm
Location: Czech Republic

Post by arnir »

no :cry: it's better but still buggy... any response?
programmer is bad designer
designer is bad programmer
blAaarg
Posts: 94
Joined: Tue Mar 02, 2010 9:11 pm
Location: SoCal

Post 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.:)
"Computers don't make mistakes! What they do they do on purpose!!"

-Dale Gribble
arnir
Competition winner
Posts: 154
Joined: Sat Jan 20, 2007 4:36 pm
Location: Czech Republic

Post 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...
programmer is bad designer
designer is bad programmer
blAaarg
Posts: 94
Joined: Tue Mar 02, 2010 9:11 pm
Location: SoCal

Post 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.
"Computers don't make mistakes! What they do they do on purpose!!"

-Dale Gribble
arnir
Competition winner
Posts: 154
Joined: Sat Jan 20, 2007 4:36 pm
Location: Czech Republic

Post 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:
programmer is bad designer
designer is bad programmer
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post 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
Post Reply