Page 1 of 2

Culling with Parents?

Posted: Thu Mar 08, 2007 7:42 pm
by TheC
Hi,

I have a grid of terrain "chunks" which are parented to one object (to easily rotate and position).

When I rotate around the yaw to a value between 0 and 90 (43 in this case), the culling on the chunks becomes very strange.

Below is a screenshot, the chunks appear to disappear in a line.
Does anyone know what might be happening, and how to fix it?

Thanks in Advance!

Image

Posted: Thu Mar 08, 2007 8:34 pm
by vitek
What version of Irrlicht are you using [svn or 1.2]? It looks as if the nodes are being culled. Possibly the bounding boxes of the nodes are wrong, or the function that does the culling has some sort of bug. Are these custom scene nodes, or are they just terrain scene nodes or mesh scene nodes? Do you have your own custom cull method or are you just using the culling provided by Irrlicht?

Travis

Posted: Thu Mar 08, 2007 9:16 pm
by TheC
I'm using irrlicht 1.1, these are "AnimatedMeshSceneNode"'s but they are static.

The green outlines are the bounding boxes, and they are correct. The problem must be with the default culling code. I cannot find out where it is going wrong though.

Posted: Thu Mar 08, 2007 9:32 pm
by vitek
Those bounding boxes don't look right to me. They are much taller than they should be. The bounding box should be the smallest object aligned box that all of the vertices can fit into. Are you loading a model from file? I'm assuming you are loading a model from file, and if so, I would guess that the problem is with your model.

I did some testing with Irrlicht 1.2 and I don't see the problem. I tested with both animated mesh nodes and just plain mesh scene nodes. No problem noticed.

Code: Select all

  core::dimension2df tileSize(100.f, 100.f);
  core::dimension2di tileCount(1, 1);
  f32 hillHeight = 0.f;
  core::dimension2df hillCount(0.f, 0.f);
  core::dimension2df textureRepeat;
  textureRepeat.Height = 1.f; // tileCount.Height / tileSize.Height;
  textureRepeat.Width  = 1.f; // tileCount.Width  / tileSize.Width;

  video::ITexture* textures[8];
  textures[0] = driver->getTexture("../../media/portal1.bmp");
  textures[1] = driver->getTexture("../../media/particlered.bmp");
  textures[2] = driver->getTexture("../../media/portal3.bmp");
  textures[3] = driver->getTexture("../../media/particlewhite.bmp");
  textures[4] = driver->getTexture("../../media/portal5.bmp");
  textures[5] = driver->getTexture("../../media/particlered.bmp");
  textures[6] = driver->getTexture("../../media/portal7.bmp");
  textures[7] = driver->getTexture("../../media/particlewhite.bmp");

  scene::IAnimatedMesh* mesh =
    smgr->addHillPlaneMesh("floor", tileSize, tileCount, 0, hillHeight, hillCount, textureRepeat);
  if (mesh)
  {
    u32 x, z;
    for (x = 0; x < 20; ++x)
    {
      for (z = 0; z < 20; ++z)
      {
        const core::vector3df pos(x * 100.f, -10.f, z * 100.f);

        //scene::IAnimatedMeshSceneNode* floor = smgr->addAnimatedMeshSceneNode(mesh, 0, -1, pos);
        scene::IMeshSceneNode* floor = smgr->addMeshSceneNode(mesh->getMesh(0), 0, -1, pos);
        if (floor)
        {
          floor->setMaterialTexture(0, textures[ rand() & 0x7 ]);
          floor->setMaterialFlag(video::EMF_LIGHTING, false);
          floor->setDebugDataVisible(true);
        }
      }
    }
  }

Posted: Fri Mar 09, 2007 1:53 am
by TheC
This is a custom model.

the reason the boxes are so high is because I added an extra vertex to make them that high, just because it would be difficult to seem them if they are flat.

Even if I removed it, this still happens.

Posted: Fri Mar 09, 2007 2:22 am
by Midnight
I remember seeing this with software drivers or something.


it's the culling in irrlicht.

is your frustum wide? skewed??

I've seen this before somewhere can't place it.

try directx if yer not already.

Posted: Fri Mar 09, 2007 6:06 am
by vitek
I think you're talking about the software driver. It doesn't render triangles that are intersected by the frustrum. You can tell by the screenshot that this is not the case. It does not clip the tris on the left or front, only on the right edge of the screen.

Are you doing anything special with the camera? Can you provide a link to your 'model' so that I can try it out first hand?

Travis

Posted: Fri Mar 09, 2007 4:40 pm
by TheC
I'm not messing with the camera, its how it is by default.

The mesh is custom. Its just 5 verts, and scaled, with the parent rotated.

The driver is DX, but the culling code is in the scene manager, so its device independant.

Posted: Fri Mar 09, 2007 5:01 pm
by BlindSide
I remember having a problem with terrain chunks cliping at weird angles and places. I think playing with the zoom/fov fixed it? not sure...

For a hacky fix zoom in with the fov and move the camera back, that way the things that are clipped are not visible on the screen anymore!

Posted: Fri Mar 09, 2007 5:41 pm
by omaremad
I was reading about multithreading in games and it turns out clipping is a problem since sometimes diffrent parameters are updated ansychronosly(i cant spell :oops: ) they advised to do what blindside did and compensate by making the clipping frutsum larger (he did this using the fov) so no artiffacts occur, till he next chance of proper synch is available.

Posted: Fri Mar 09, 2007 7:59 pm
by TheC
I don't want to mess with the FoV, but, could I scale the frustum within irrlicht? I could scale the bounding box for the frustum.

Posted: Fri Mar 09, 2007 9:05 pm
by vitek
This is not a multithreading problem. The frustum culling code is taking an easy-out and checking against the node bounding box that is incorrectly transformed into world space. When the parent node, or any node for that matter, has a rotation applied, the bounding boxes are wrong.

Here is a simple example that shows the problem using the default camera FOV and a single rotated quad. When the program starts, you won't see the textured quad, but you will see the bounding boxes. If you pan right the quad will appear and if you pan back left it will disappear.

Code: Select all

int main()
{
  // ask user for driver

  video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D8;

  // create device and exit if creation failed

  IrrlichtDevice* device =
    createDevice(driverType, core::dimension2d<s32>(1024, 768));

  if (device == 0)
    return 1; // could not create selected driver.

  video::IVideoDriver* driver = device->getVideoDriver();
  scene::ISceneManager* smgr = device->getSceneManager();

  // load the scene

  const core::vector3df scl(10.f, 10.f, 10.f);
  const core::vector3df rot(0.f, 35.f, 0.f);
  const core::vector3df pos(0, -10.f, 0);

  scene::IAnimatedMesh* mesh =
    smgr->addHillPlaneMesh("floor", core::dimension2df(10.f, 10.f), core::dimension2di(1, 1));

  scene::IMeshSceneNode* floor = smgr->addMeshSceneNode(mesh->getMesh(0), 0, -1, pos, rot, scl);
  floor->setMaterialTexture(0, driver->getTexture("../../media/particlewhite.bmp"));
  floor->setMaterialFlag(video::EMF_LIGHTING, false);

  // setup the camera

  scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
  camera->setPosition(core::vector3df(-90.f, 18.f, 24.f));
  camera->setRotation(core::vector3df(13.f, 37.f, 0.f));

  // create one time materials and matrices

  core::matrix4 identity;
  
  video::SMaterial material;
  material.Lighting = false;

  video::SColor red(255, 255, 0, 0);
  video::SColor grn(255, 0, 255, 0);
  video::SColor blu(255, 0, 0, 255);

  // run the simulation

  while (device->run())
  {
    if (device->isWindowActive())
    {
      if (driver->beginScene(true, true, video::SColor(255,20,20,20)))
      {
        smgr->drawAll();

        // draw boxes

        driver->setTransform(video::ETS_WORLD, identity);
        driver->setMaterial(material);

        core::aabbox3df box;

        //
        // draw the fudged world aligned bounding box. notice it does
        // not enclose all of the vertices of the mesh. this makes it
        // possible for the cull test to cull nodes that are actually
        // in view.
        //

        box = floor->getBoundingBox();
        floor->getAbsoluteTransformation().transformBox(box);
        box.MaxEdge.Y += 10.f; // give the box some height
        driver->draw3DBox(box, red);

        //
        // draw the world aligned bounding box. notice it does include
        // all of the vertices, but in some situations there is a lot
        // of waste, which can cause the frustum culling to not cull
        // something that it should.
        //
        box = floor->getBoundingBox();
        floor->getAbsoluteTransformation().transformBoxEx(box);
        box.MaxEdge.Y += 5.f; // give the box some height
        driver->draw3DBox(box, blu);

        //
        // draw the object space bounding box. notice that this is the
        // smallest enclosing box that is oriented with the object
        // coordinate system. this is the box that should be tested
        // against
        //
        driver->setTransform(video::ETS_WORLD, floor->getAbsoluteTransformation());

        box = floor->getBoundingBox();
        // no box transform needed, the verts will be transformed later
        box.MaxEdge.Y += 5.f; // give the box some height
        driver->draw3DBox(box, grn);

        driver->endScene();
      }   
    }
  }

  device->drop();

  return 0;
}
The solution is to fix CSceneManager::isCulled(). The easy way would be to change transformBox() to transformBoxEx(). Unfortunately that will result in obects not getting culled that should be. This is particularly a problem with slender objects, and is not so much a problem with cube shaped objects.

This is the same exact problem as the one that I ran into here.

Travis

Posted: Fri Mar 09, 2007 9:36 pm
by TheC
TransformBoxEx works great, thanks! :D

I'd rather have "under culling" than "over culling", that way, problems aren't visible :)

Once again, thank you!

Posted: Fri Mar 09, 2007 9:46 pm
by vitek
The SVN version of irrlicht supports culling against the frustum planes which is more accurate. You might give that a try.

Travis

Posted: Fri Mar 09, 2007 9:47 pm
by TheC
I will do, thanks