getScreenCoordinatesFrom3DPosition trouble

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
Dave
Posts: 25
Joined: Wed Mar 28, 2007 11:00 am

getScreenCoordinatesFrom3DPosition trouble

Post by Dave »

Hi everyone,

Don't know if it's a bug or just me with some wrong code, so I made the thread here.

I use the function 'getScreenCoordinatesFrom3DPosition' to calculate the 2D screen coordinates of each corner of a bounding box. Here's an eplanation of what I'm doing in PSEUDO-code:

Code: Select all

V_3DVECTOR corner[8]; // Corners of the bounding box, trust me that they're in their.
irr::core::position2d<irr::s32> screen[8]; // 2D screen coordinates of the bounding box.
irr::core::aabbox3d<irr::f32> box = node->getTransformedBoundingBox(); // Used for corner calculation.

// Now I fill the 'screen' array variable (for explanation just the first element).
screen[0] = collision->getScreenCoordinatesFrom3DPosition(corner[0]);
Now I'll show the results of both corner and screen vector:
Corner:
[0] {X=0.30330077 Y=19.511070 Z=5.3033009 }
[1] {X=0.30330077 Y=4.5110703 Z=5.3033009 }
[2] {X=0.30330077 Y=19.511070 Z=-15.909903 }
[3] {X=0.30330077 Y=4.5110703 Z=-15.909903 }
[4] {X=0.30330071 Y=19.511070 Z=5.3033009 }
[5] {X=0.30330071 Y=4.5110703 Z=5.3033009 }
[6] {X=0.30330071 Y=19.511070 Z=-15.909903 }
[7] {X=0.30330071 Y=4.5110703 Z=-15.909903 }
Screen:
[0] {X=402 Y=124 }
[1] {X=403 Y=368 }
[2] {X=402 Y=236 }
[3] {X=403 Y=253 }
[4] {X=403 Y=253 }
[5] {X=402 Y=236 }
[6] {X=403 Y=368 }
[7] {X=402 Y=124 }
As you can see, the X element of each corner is the same; that's not the problem. However, the same goes for the screen coordinates.
That's kinda weird, how can all the corners of a cube (with each side of equal length) have the same X-coordinate? This happens when I start rotating the cube, in my case along the Y-axis. Sometimes the X screen coordinates are the same, and sometimes the Y.
Does anyone know what I'm doing wrong?
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

The box returned by getTransformedBoundingBox() is world axis aligned. That means that the X, Y and Z axes of the box are in line with the world coordinate system. Given that, the planes of the box will always be aligned with these axes. That is why you see two distinct sets of values for each axis. There is one set of values for the left [top, front] side of the world aligned box, and one for the right [bottom, back].

The box returned by getTransformedBoundingBox() is not accurate. I've posted sample code to illustrate this problem several times. If you display the transformed box of a rotating cube you'll see the problem. You can use the object bounding box, transformation matrix and transformBoxEx() for a more accurate bounding box. If you want to get the edges of a box in 2d coordinates, the following will give you the most accurate results...

Code: Select all

  // get the object space bounding box
  const core::aabbox3df box = node->getBoundingBox();

  // get the corners of the box in object coordinate system
  core::vector3df edges[8];
  box.getEdges(edges);

  // convert each corner to world coordinates
  u32 e;
  for (e = 0; e < 8; ++e)
  {
    node->getAbsoluteTransformation().transformVect(edges[e]);
  }

  // now the edges are in world coordinates and they represent
  // the corners of the object space bounding box. this gives us
  // the smallest box that encloses the scene node. any other
  // method for calcluating the world space bounding box from
  // the object space bounding box will be less accurate.
If you wanted to display a 2d rectangle that encloses the edges, the following code would do that...

Code: Select all

  // get the corners of the box in screen coordinates
  core::rect<s32> rect;
  rect.UpperLeftCorner =
  rect.LowerRightCorner = smgr->getSceneCollisionManager()->getScreenCoordinatesFrom3DPosition(edges[0]);

  for (e = 1; e < 8; ++e)
  {
    core::position2di edge =
        smgr->getSceneCollisionManager()->getScreenCoordinatesFrom3DPosition(edges[e]);

    rect.UpperLeftCorner.X = core::min_(rect.UpperLeftCorner.X, edge.X);
    rect.UpperLeftCorner.Y = core::min_(rect.UpperLeftCorner.Y, edge.Y);

    rect.LowerRightCorner.X = core::max_(rect.LowerRightCorner.X, edge.X);
    rect.LowerRightCorner.Y = core::max_(rect.LowerRightCorner.Y, edge.Y);
  }

  driver->draw2DRectangle(video::SColor(64, 255, 0, 0), rect);
Travis
Dave
Posts: 25
Joined: Wed Mar 28, 2007 11:00 am

Post by Dave »

Great! I guess is didn't look good enough on the forums for your already posted solution. Nevertheless, it works flawlessly! My solution that didn't even work correctly when rotating object, contained 3x more source lines for nothing :roll:
Thanks again vitek.
Post Reply