screen coordinates, from the camera point of view

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
mvalle
Posts: 18
Joined: Tue Oct 02, 2007 4:58 am
Location: Brazil

screen coordinates, from the camera point of view

Post by mvalle »

I would like to animate an object from the top of the screen to the bottom of the screen. How can I get the coordinates of a 3d point in the top of the screen and the coordinates of a 3d point in the bottom?
Thanks in advance
[]s
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

You'll also need to decide a depth / distance at which to place your 3d point, since there's no direct mapping between a 2d point and a 3d point.

I'd suggest something like:

Code: Select all

enum { DRAW_DISTANCE = 100.f /* adjust empirically based on the desired model size on screen */ };

core::position2di topScreenPosition(/* set the desired top screen position */);

core::position2di bottomScreenPosition(/* set the desired bottom screen position */);


core::line3df topRay = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
			topScreenPosition, smgr->getActiveCamera());

core::line3df bottomRay = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
			bottomScreenPosition, smgr->getActiveCamera());

core::vector3df top3DPosition = topRay.start + (topRay.getVector().normalize() * DRAW_DISTANCE);

core::vector3df bottom3DPosition = bottomRay.start + (bottomRay.getVector().normalize() * DRAW_DISTANCE);
You'll need to initialise topScreenPosition and bottomScreenPosition with appropriate 2d positions. Apologies if it doesn't doesn't compile cleanly; I'm in lazy Sunday morning mode.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
mvalle
Posts: 18
Joined: Tue Oct 02, 2007 4:58 am
Location: Brazil

Post by mvalle »

rogerborg,


Thanks a lot for replying my message. I tried what you suggested, but it didn't work... Could I have done something wrong?
I have a screen resolution of 720 x 480. I have used the following piece of code:

{
smgr->setActiveCamera(camera);
enum { DRAW_DISTANCE = 100 /* adjust empirically based on the desired model size on screen */ };
core::position2di topScreenPosition(0, 0/* set the desired top screen position */);
core::position2di bottomScreenPosition(700,400/* set the desired bottom screen position */);
core::line3df topRay = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
topScreenPosition, smgr->getActiveCamera());
core::line3df bottomRay = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
bottomScreenPosition, smgr->getActiveCamera());
core::vector3df top3DPosition = topRay.start + (topRay.getVector().normalize() * DRAW_DISTANCE);
core::vector3df bottom3DPosition = bottomRay.start + (bottomRay.getVector().normalize() * DRAW_DISTANCE);

printf("%.2f %.2f %.2f <-> %.2f %.2f %.2f \n",
top3DPosition.X, top3DPosition.Y, top3DPosition.Z,
bottom3DPosition.X, bottom3DPosition.Y, bottom3DPosition.Z);
fflush(stdout);
myNode->anim2 = smgr->createFlyStraightAnimator(
core::vector3df(0, 100, 50), core::vector3df(0, -100, 50),
//top3DPosition, bottom3DPosition,
4000, true);
myNode->addAnimator(myNode->anim2);
myNode->anim2->drop();
}


My camera is at (0,0,-300) pointing to (0,0,0):
camera = smgr->addCameraSceneNode(0, core::vector3df(0, 0, -300), core::vector3df(0, 0, 0));

I was expecting my node to animate from (0,0) to (700,400), in screen coordinates, but take a look at the values of top and bottom position, after code is executed:
bottom: -0.33 0.33 -200.00
top: 0.31 -0.22 -200.00


The Z coordinate seems correct, but X and Y are too small... The object just stay stopped at screen center.
It seems it lacks the multiplication for some factor, but I am a bit confused, because Z coordinate is right... Any idea?
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Ah, excuse me, I forgot that the camera won't have the correct matrices until after it's been updated. This is a gotcha that catches a lot of people out.

The trick is to force an update before you use it to calculate the ray. It's a but esoteric, but I know that all the necessary calculations are called in OnRegisterSceneNode(), so we can just call that:

Code: Select all

	ICameraSceneNode * camera = smgr->addCameraSceneNode(0, core::vector3df(0,-40,0), core::vector3df(0,0,0));
	camera->OnRegisterSceneNode();
Complete sample app:

Code: Select all

#include <irrlicht.h>

using namespace irr;

#pragma comment(lib, "Irrlicht.lib")

int main()
{
    IrrlichtDevice *device =
        createDevice(video::EDT_OPENGL, core::dimension2d<s32>(640, 480), 32, false);

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

    scene::ICameraSceneNode * camera = smgr->addCameraSceneNode(0, core::vector3df(0,-40,0), core::vector3df(0,0,0));
    camera->OnRegisterSceneNode();

    scene::IBillboardSceneNode * node = smgr->addBillboardSceneNode();
    node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR );
    node->setMaterialTexture(0, driver->getTexture("../../media/particle.bmp"));
    node->setMaterialFlag(video::EMF_LIGHTING, false);

    enum { DRAW_DISTANCE = 100 };
    core::position2di topScreenPosition(driver->getScreenSize().Width / 2, 0);
    core::position2di bottomScreenPosition(driver->getScreenSize().Width / 2,
                                            driver->getScreenSize().Height);

    core::line3df topRay = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
        topScreenPosition, smgr->getActiveCamera());
    core::line3df bottomRay = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
        bottomScreenPosition, smgr->getActiveCamera());
    core::vector3df top3DPosition = topRay.start + (topRay.getVector().normalize() * DRAW_DISTANCE);
    core::vector3df bottom3DPosition = bottomRay.start + (bottomRay.getVector().normalize() * DRAW_DISTANCE);

    scene::ISceneNodeAnimator * anim = smgr->createFlyStraightAnimator(top3DPosition,
                                                                       bottom3DPosition,
                                                                       4000, true);

    node->addAnimator(anim);
    anim->drop();

    while(device->run())
    {
        driver->beginScene(true, true, video::SColor(0,100,100,100));
        smgr->drawAll();
        driver->endScene();
    }

    device->drop();
    
    return 0;
}
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
mvalle
Posts: 18
Joined: Tue Oct 02, 2007 4:58 am
Location: Brazil

Post by mvalle »

Now it worked fine! Thanks a lot!!

Just to understand a little better what I am doing, may you tell me what exactly this line means?


core::line3df topRay = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
topScreenPosition, smgr->getActiveCamera());

Is it getting an horizontal line that passes by screen coordinate topScreenPosition? Or is it a ray trace, from camera's position to screen coordinates?
Would I be able to use the same trick to perform an animation from the left of the screen to the right?
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

mvalle wrote: core::line3df topRay = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(
topScreenPosition, smgr->getActiveCamera());

Is it getting an horizontal line that passes by screen coordinate topScreenPosition? Or is it a ray trace, from camera's position to screen coordinates?
Are you familiar with view frustums?

Image

That (particular) calculation creates a ray that goes from the camera position, out along the centre of the top plane of the view frustum. Any point along that ray will appear to be at the top of the screen.

Similarly, the ray from bottomScreenPosition goes out along the bottom plane of the view frustum.

mvalle wrote:Would I be able to use the same trick to perform an animation from the left of the screen to the right?
Sure, just change the co-ordinates of the two points. Notice that rather than hardwiring them, I've used driver->getScreenSize(), so to go from the centre of the left side to the centre of the right side, your two points would be:

Code: Select all

    core::position2di startPosition(0, driver->getScreenSize().Height / 2);
    core::position2di endPosition(driver->getScreenSize().Width,                                            driver->getScreenSize().Height / 2);
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
mvalle
Posts: 18
Joined: Tue Oct 02, 2007 4:58 am
Location: Brazil

Post by mvalle »

No, I had not been formally presented to this concept yet ;-)
Thanks a lot for all your help rogerborg, your explanation was awesome. If I can be of help for something anytime, just tell me please.
Post Reply