Manual Objects in Screen Space

A place for users of OGRE to discuss ideas and experiences of utilitising OGRE in their games / demos / applications.
User avatar
CaseyB
OGRE Contributor
OGRE Contributor
Posts: 1335
Joined: Sun Nov 20, 2005 2:42 pm
Location: Columbus, Ohio
x 3

Manual Objects in Screen Space

Post by CaseyB »

I am having a bit of trouble with the new feature that allows you to specify ManualObjects in screen space. I am using it to draw lines on the screen but if I move the camera they seems to come and go randomly. Here are a couple of screenies to show what I mean. In the first one you see the lines as they should be:
Image
Then in the second one I have moved the camera just a little bit and they go away!
Image
Image
Image
User avatar
stoneCold
OGRE Expert User
OGRE Expert User
Posts: 867
Joined: Fri Oct 01, 2004 9:13 pm
Location: Carinthia, Austria
x 1

Post by stoneCold »

Same question like there :wink:

greetings
my tweets | www.fuse-software.com | home of vektrix (Flash GUI for Ogre3D) and caspin (ActionScript 3 Virtual Machine Wrapper)
User avatar
CaseyB
OGRE Contributor
OGRE Contributor
Posts: 1335
Joined: Sun Nov 20, 2005 2:42 pm
Location: Columbus, Ohio
x 3

Post by CaseyB »

Nice! I'll give that a try! Thanks!
Image
Image
User avatar
CaseyB
OGRE Contributor
OGRE Contributor
Posts: 1335
Joined: Sun Nov 20, 2005 2:42 pm
Location: Columbus, Ohio
x 3

Post by CaseyB »

That worked perfectly! I did figure out that you have to place the scene node that these things are attached to in -1 to 1 space as well! Now I am looking for a bit of clarification on the API. I have this code:

Code: Select all

node = sceneMgr->getRootSceneNode()->createChildSceneNode("DefaultOgreNode");
ent = sceneMgr->createEntity("DefaultOgre", "ogrehead.mesh");
node->attachObject(ent);

Ogre::ManualObject *manObj = sceneMgr->createManualObject("DefaultManObj");
node = node->createChildSceneNode("DefaultManObjNode");
node->attachObject(manObj);
manObj->setBoundingBox(aabb);

manObj->setUseIdentityProjection(true);
manObj->setUseIdentityView(true);

manObj->begin("ManualColor",Ogre::RenderOperation::OT_TRIANGLE_FAN);
manObj->position(-0.30, -0.20, 0);
manObj->position(-0.30,  0.20, 0);
manObj->position( 0.30,  0.20, 0);
manObj->position( 0.30, -0.20, 0);
manObj->index(0);
manObj->index(1);
manObj->index(2);
manObj->index(3);
manObj->end();
And it gives me this:
Image
Which is what I expect, the one is the middle is the one in screen space, the other two are in world space. But I am not sure what the difference is between these two calls.

Code: Select all

manObj->setUseIdentityProjection(true);
manObj->setUseIdentityView(true);
I thought I did, but when I try to comment them out one at a time I don't get what I expect.
Image
Image
User avatar
CaseyB
OGRE Contributor
OGRE Contributor
Posts: 1335
Joined: Sun Nov 20, 2005 2:42 pm
Location: Columbus, Ohio
x 3

Post by CaseyB »

I would also like to be able to set it so that the ManualObjects can, optionally, act as billboards. But there is no setIdentityTransform() method or anything like that. Does anyone have any suggestions for that?
Image
Image
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66

Post by sinbad »

To make them behave like billboards, you could use SceneNode::lookAt or SceneNode::setAutoTracking to get the node the manual object is attached to to constantly track the camera position.

The view space transform what takes an object from world space to a space where the camera is at the origin, facing down the -Z axis. The projection matrix converts the wedge-shaped frustum to a homogenous cube {-1, +1} in all directions (well, actually it's {0,1} for Z in freaky D3D), which clearly squashes objects at the far end of the frustum. Setting each of these to identity clear does different things - an identity view means that it doesn't matter where the camera is, and an identity projection means that objects must already be scaled within that homogenous cube to be visible.
daves
Goblin
Posts: 214
Joined: Fri Jan 20, 2006 3:35 pm

Post by daves »

sinbad wrote:To make them behave like billboards, you could use SceneNode::lookAt or SceneNode::setAutoTracking to get the node the manual object is attached to to constantly track the camera position.
Interesting option. Will give that a crank. Can you comment on the cost of such an operation given that we may have thousands of such banners looking at the camera. Presumably the lookAt function needs to be called with each frame update (assuming that the camera is moved during a frame update) for each banner that must look at the camera in this fashion.
The view space transform what takes an object from world space to a space where the camera is at the origin, facing down the -Z axis. The projection matrix converts the wedge-shaped frustum to a homogenous cube {-1, +1} in all directions (well, actually it's {0,1} for Z in freaky D3D), which clearly squashes objects at the far end of the frustum. Setting each of these to identity clear does different things - an identity view means that it doesn't matter where the camera is, and an identity projection means that objects must already be scaled within that homogenous cube to be visible.
Thanks for that description.
daves
Goblin
Posts: 214
Joined: Fri Jan 20, 2006 3:35 pm

Post by daves »

We've tried two techniques. With the first technique we tried using autotracking. The results are not quite what we anticipated since the banner (though facing the camera) takes on a different orientation depending on where we are looking at it from.

Image
Image

Here we had the node that the manual object is attached to autotrack the node that the camera is attached to:

Code: Select all


	Ogre::SceneNode *camNode = sceneMgr->getRootSceneNode()->createChildSceneNode("CameraNode");
	camNode->setPosition(0, 100, 100);
	Ogre::SceneNode *pitchNode = camNode->createChildSceneNode("PitchNode");
	pitchNode->attachObject(camera);
	pitchNode->pitch(Ogre::Degree(-30));

	Ogre::AxisAlignedBox aabb;
	aabb.setInfinite();

	/*
	** Create three copies of the same setup to test different settings
	** This one will not have anything other than defualt settings
	*/
	node = sceneMgr->getRootSceneNode()->createChildSceneNode("DefaultOgreNode", Ogre::Vector3(0, 50, 0));
	ent = sceneMgr->createEntity("DefaultOgre", "ogrehead.mesh");
	node->attachObject(ent);

	Ogre::Vector3 offset = Ogre::Vector3(0,50,0);
	Ogre::ManualObject *manObj = sceneMgr->createManualObject("DefaultManObj");
	node = sceneMgr->getRootSceneNode()->createChildSceneNode("DefaultManObjNode");
	node->setPosition(offset);
	node->attachObject(manObj);
	node->setAutoTracking(true, camNode, Ogre::Vector3::NEGATIVE_UNIT_Z, Ogre::Vector3(0, 0, 0));
	manObj->setBoundingBox(aabb);
Is there something simple that we can do to ensure that the "cone" is always pointing up?


The technique that seemed to work for us uses setUseIdentityView but is a bit more complex than simply using setAutoTracking, since it requires that we "back out" the camera orientation each frame.


Frame Started Method:

Code: Select all

bool DeviceListener::frameStarted(const Ogre::FrameEvent& evt)
{
	/*
	** Capture from Devices
	*/
	mMouse->capture();
	mKeyboard->capture();

	/*
	** Move the mmCamera based on input
	*/
    mCamNode->yaw(mMouseYaw * evt.timeSinceLastFrame);
    mPitchNode->pitch(mMousePitch * evt.timeSinceLastFrame);
	mCamNode->translate(mPitchNode->getWorldOrientation() * mDirection * evt.timeSinceLastFrame);
	mMouseYaw = mMousePitch = 0;

	mCamNode->_update(true, false);

	Ogre::SceneNode *node = mSceneMgr->getSceneNode("DefaultOgreNode");
	Ogre::Vector3 offset = mCamera->getWorldOrientation().Inverse() * (node->getWorldPosition() - mCamera->getWorldPosition());
	offset += Ogre::Vector3(0,50,0);
	node = mSceneMgr->getSceneNode("DefaultManObjNode");
	node->setPosition(offset);

	return  mContinue;
}
Scene Construction (uses setUseIdentityView)

Code: Select all

	node = sceneMgr->getRootSceneNode()->createChildSceneNode("CameraNode");
	node->setPosition(0, 100, 100);
	node = node->createChildSceneNode("PitchNode");
	node->attachObject(camera);
	node->pitch(Ogre::Degree(-30));

	Ogre::AxisAlignedBox aabb;
	aabb.setInfinite();

	/*
	** Create three copies of the same setup to test different settings
	** This one will not have anything other than defualt settings
	*/
	node = sceneMgr->getRootSceneNode()->createChildSceneNode("DefaultOgreNode", Ogre::Vector3(0, 50, 0));
	ent = sceneMgr->createEntity("DefaultOgre", "ogrehead.mesh");
	node->attachObject(ent);

	float diff = node->getWorldPosition().z - camera->getWorldPosition().z;
	Ogre::Vector3 offset = Ogre::Vector3(0,50,diff);
	Ogre::ManualObject *manObj = sceneMgr->createManualObject("DefaultManObj");
	node = sceneMgr->getRootSceneNode()->createChildSceneNode("DefaultManObjNode");
	node->setPosition(offset);
	node->attachObject(manObj);
	manObj->setBoundingBox(aabb);

	manObj->begin("Cone",Ogre::RenderOperation::OT_TRIANGLE_FAN);
	manObj->position(-20.0, -20.0, 0);
	manObj->textureCoord(0, 0, 0);
	manObj->position(-20.0,  20.0, 0);
	manObj->textureCoord(0, -1, 0);
	manObj->position( 20.0,  20.0, 0);
	manObj->textureCoord(1, -1, 0);
	manObj->position( 20.0, -20.0, 0);
	manObj->textureCoord(1, 0, 0);
	manObj->index(3);
	manObj->index(2);
	manObj->index(1);
	manObj->index(0);
	manObj->end();
//	manObj->setUseIdentityProjection(true);
	manObj->setUseIdentityView(true);
This approach works, but it seems costly in that it is doing a matrix inverse with each frame update, for each banner.
Image
Image
Image
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66

Post by sinbad »

Is there something simple that we can do to ensure that the "cone" is always pointing up?
Yes, use setFixedYaw(true, Vector3::UNIT_Y) on the SceneNode - this works the same way as the same method on camera to stop rolls being introduced through local yaws.
User avatar
CaseyB
OGRE Contributor
OGRE Contributor
Posts: 1335
Joined: Sun Nov 20, 2005 2:42 pm
Location: Columbus, Ohio
x 3

Post by CaseyB »

Hmm, looks like setFixedYawAxis() isn't quite what we're looking for either. We are going to have text on these objects and want that to always be right side up. Here is what we got with that method:
Image

Image

This is what we get from backing out the camera changes each frame and is what we're looking for. I guess we're just trying to get a feel for how costly this is to do each frame, or if there is a way to short-circuit somehow.
Image

Image

Image
Image
Image
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66

Post by sinbad »

Yes, fixed yaw is mostly for keeping the object itself aligned (like a turret). In that case don't use auto tracking. You'll need to just calculate the orientation yourself based on the camera's own up/right vectors and the vector from camera to object. Doing it like that doesn't require a matrix inverse.