If you haven't done so already, be sure to visit the Wiki Portal to read about how the wiki works. Especially the Ogre Wiki Overview page.
One way to have HUD Elements like targeting indicators or playernames positioned on 3D objects is projecting the 3D position to 2D and positioning the HUD Elements there. The following code can be used to do that.
Table of contents
Projecting position
using namespace Ogre; /// returns true if in front of the cam, and fills x,y with clamped screencoords in [-1;1] // cam->getProjectionMatrix() is cached inside ogre bool ProjectPos (Camera* cam,const Ogre::Vector3& pos,Ogre::Real& x,Ogre::Real& y) { Vector3 eyeSpacePos = cam->getViewMatrix(true) * pos; // z < 0 means in front of cam if (eyeSpacePos.z < 0) { // calculate projected pos Vector3 screenSpacePos = cam->getProjectionMatrix() * eyeSpacePos; x = screenSpacePos.x; y = screenSpacePos.y; return true; } else { x = (-eyeSpacePos.x > 0) ? -1 : 1; y = (-eyeSpacePos.y > 0) ? -1 : 1; return false; } }
Projecting position and radius
using namespace Ogre; /// returns true if in front of the cam, and fills x,y with clamped screencoords in [-1;1] /// and fills cx,cy with projected size on screen in [0;1] // cam->getProjectionMatrix() is cached inside ogre bool ProjectSizeAndPos (Camera* cam,const Ogre::Vector3& pos,const Ogre::Real rad,Ogre::Real& x,Ogre::Real& y,Ogre::Real& cx,Ogre::Real& cy) { Camera* cam = mCamera; Vector3 eyeSpacePos = cam->getViewMatrix(true) * pos; // z < 0 means in front of cam if (eyeSpacePos.z < 0) { // calculate projected pos Vector3 screenSpacePos = cam->getProjectionMatrix() * eyeSpacePos; x = screenSpacePos.x; y = screenSpacePos.y; // calculate projected size Vector3 spheresize(rad, rad, eyeSpacePos.z); spheresize = cam->getProjectionMatrix() * spheresize; cx = spheresize.x; cy = spheresize.y; return true; } else { cx = 0; cy = 0; x = (-eyeSpacePos.x > 0) ? -1 : 1; y = (-eyeSpacePos.y > 0) ? -1 : 1; return false; } }
Notes
- a return value of true just means in front of the cam, not visible on screen (e.g. it might be too far on left)
- to check if the object is visible, check if the projected x,y are in [-1;1]
- to check if the object is partially visible, check if the projected x is in [-1-cx/2;1+cx/2] (y analogue with cy)
Tracking a hierarchical position
When tracking the position of a scenenode pMyChildNode that is the child of another scenenode pMyParentNode,
probably SceneNode::getWorldPosition() should be used to get an absolute position.
When only the position of pMyParentNode is updated,
the pMyChildNode->getWorldPosition() will normally only be update after rendering a frame,
this leads to the projected position lagging behind one frame.
This can be prevented by either :
- calling pMyChildNode->needUpdate() right before calculating the projected position
- calling pMyParentNode->_update(/*bool updateChildren=*/true,/*bool parentHasChanged=*/false) when moving the parent
- also pMyChildNode->setListener() can be used to install a listener that is called at a time where getWorldPosition() will return the correct position, so that could be a good place to recalculate the projected position, but it also depends on the camera position, it would also have to be updated every time the camera moves, so pCamera->setListener() will also be needed. The problem is that this way, the position will be recalculated twice if the cam and the parent change, if that happens every frame, it might be better to recalculate right before rendering a frame and using _update() or needUpdate() instead of the listeners.
Alias: Projecting_3D_position_and_size_to_2D
Contributors to this page: JustBoo
,
OgreWikiBot
and
jacmoe
.
Page last modified on Wednesday 30 of June, 2010 21:03:38 UTC by JustBoo.
The content on this page is licensed under the terms of the Creative Commons Attribution-ShareAlike License.
As an exception, any source code contributed within the content is released into the Public Domain.

