[fixed]Maya camera as child of moving node

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
someguy99
Posts: 38
Joined: Sun Oct 11, 2009 11:20 am

[fixed]Maya camera as child of moving node

Post by someguy99 »

Ill be glad to be proven wrong.
I try to make a Maya camera child of a moving node (moved by user input)

Code: Select all

#include <irrlicht.h>
#include <iostream>

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;


// event reciever
class MyEventReceiver : public IEventReceiver
{
public:
   // This is the one method that we have to implement
   virtual bool OnEvent(const SEvent& event)
   {
      // Remember whether each key is down or up
      if (event.EventType == irr::EET_KEY_INPUT_EVENT)
         KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;

      return false;
   }

   // This is used to check whether a key is being held down
   virtual bool IsKeyDown(EKEY_CODE keyCode) const
   {
      return KeyIsDown[keyCode];
   }
   
   MyEventReceiver()
   {
      for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
         KeyIsDown[i] = false;
   }

private:
   // We use this array to store the current state of each key
   bool KeyIsDown[KEY_KEY_CODES_COUNT];
};


int main()
{   
    // create device
   MyEventReceiver receiver;

   IrrlichtDevice* device = createDevice(EDT_OPENGL,
         dimension2d<s32>(1024, 768), 16, false, false, false, &receiver);

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

   IVideoDriver* driver = device->getVideoDriver();
   ISceneManager* smgr = device->getSceneManager();
   
    // add another object to prove it moves
    IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
   if (!mesh)
      return 1;
   IAnimatedMeshSceneNode* sydney = smgr->addAnimatedMeshSceneNode( mesh );
    if (sydney)
   {
      sydney->setMaterialFlag(EMF_LIGHTING, false);
      sydney->setMD2Animation(EMAT_STAND);
      sydney->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp") );
   }
   
   /*
   Create the node which will be moved with the WSAD keys. We create a
   sphere node, which is a built-in geometry primitive. We place the node
   at (0,0,30) and assign a texture to it to let it look a little bit more
   interesting. Because we have no dynamic lights in this scene we disable
   lighting for each model (otherwise the models would be black).
   */
   scene::ISceneNode * node = smgr->addSphereSceneNode();
   if (node)
   {
      node->setPosition(vector3df(0,0,0));
      node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
      node->setMaterialFlag(EMF_LIGHTING, false);
   }

    // add a camera and attach it to the node
   ICameraSceneNode *camera= smgr->addCameraSceneNodeMaya();
   camera->setPosition(vector3df(0,9,-14));
   
    // move with the node
    camera->setParent(node);
   
   // hide mouse
    device->getCursorControl()->setVisible(false);
   
   int lastFPS = -1;

   // In order to do framerate independent movement, we have to know
   // how long it was since the last frame
   u32 then = device->getTimer()->getTime();

   // This is the movemen speed in units per second.
   const f32 MOVEMENT_SPEED = 5.f;

   while(device->run())
   {
      // Work out a frame delta time.
      const u32 now = device->getTimer()->getTime();
      const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds
      then = now;

      /* Check if keys W, S, A or D are being held down, and move the
      sphere node around respectively. */
      core::vector3df nodePosition = node->getPosition();

      if(receiver.IsKeyDown(KEY_KEY_W))
         nodePosition.Y += MOVEMENT_SPEED * frameDeltaTime;
      else if(receiver.IsKeyDown(KEY_KEY_S))
         nodePosition.Y -= MOVEMENT_SPEED * frameDeltaTime;

      if(receiver.IsKeyDown(KEY_KEY_A))
         nodePosition.X -= MOVEMENT_SPEED * frameDeltaTime;
      else if(receiver.IsKeyDown(KEY_KEY_D))
         nodePosition.X += MOVEMENT_SPEED * frameDeltaTime;

      node->setPosition(nodePosition);
       
       // always look at the node
       camera->setTarget(node->getPosition());
       
      driver->beginScene(true, true, SColor(255,113,113,133));

      smgr->drawAll(); // draw the 3d scene
      device->getGUIEnvironment()->drawAll(); // draw the gui environment (the logo)

      driver->endScene();

      int fps = driver->getFPS();

      if (lastFPS != fps)
      {
         stringw tmp(L"Movement Example - Irrlicht Engine [");
         tmp += driver->getName();
         tmp += L"] fps: ";
         tmp += fps;

         device->setWindowCaption(tmp.c_str());
         lastFPS = fps;
      }
   }

   // In the end, delete the Irrlicht device.
   device->drop();
   
   return 0;
}
Notice the way the orbit of the maya camera turns to elipsoid shape as you move the node? Looks like a bug to me.
Btw, works fine for normal camera. Doesnt work for FPS (doesnt make sence to use it here anyway)
someguy99
Posts: 38
Joined: Sun Oct 11, 2009 11:20 am

Post by someguy99 »

I starve for a reply.
please tell me if i should provide more detail. the above code is a complete irrlicht main.cpp
CuteAlien
Admin
Posts: 9720
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

Hard to tell what the behaviour should be in such a case.
You seem to try mixing an animator behaviour with hardcoded behaviour (like setting the target of the camera yourself) and that is rarely a good idea.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
someguy99
Posts: 38
Joined: Sun Oct 11, 2009 11:20 am

Post by someguy99 »

Say what?
CuteAlien
Admin
Posts: 9720
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

someguy99 wrote:Say what?
The Maya-cam does only what it is designed to do. If you try to use it in another setting where you try to take away some control from it then it will most likely no longer work.

Right now you call setTarget and the animator for the mayacam does call setTarget - such stuff will obviously cause conflicts. It isn't thought to be used that way. If you want a camera behaving different than the mayacam you will have to write it. Or maybe you can even adapt the sources. But you can't mix the automatic behaviour you get from that cam while trying to manually override the controls at the same time.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
someguy99
Posts: 38
Joined: Sun Oct 11, 2009 11:20 am

Post by someguy99 »

I dont think im doing something not ment for Maya cam.
What i want to do:
move Maya camera with the node (setParent).
What do you mean Maya cam already calls setTarget? Do you mean after i do setParent? Because the meshviewer example does that (setTarget).
I tried the code without the setTarget ( assuming setParent will set the target for maya itself) but the camera... Well just remove the "setTarget" line and youll get what i mean
CuteAlien
Admin
Posts: 9720
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

In your mainloop you call setTarget each frame:

Code: Select all

 // always look at the node
camera->setTarget(node->getPosition()); 
And I think that this should conflict with the usual maya behaviour as you are resetting the rotation that way all the time, but internal values will not get updated. And after removing that it looks better to me... not sure if it is correct or not, but the strange jumping camera movement is gone.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
someguy99
Posts: 38
Joined: Sun Oct 11, 2009 11:20 am

Post by someguy99 »

Dont tell me that it works fine after you remove that line?
The camera must move with the sphere accordingly and rotate around it.
It doesnt right?
It moves strangely and the orbit turns elipsoid shape, right?
PS. What jumping camera movement?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

This is *not* an orbiting camera that moves around a sphere center. The camera logic is different and simply does not cope with position and rotation/target changes from the outside as you might need. But this won't be fixed either. You have to code the changes on your own, and you're free to reuse as much of the Maya cam as you want.
CuteAlien
Admin
Posts: 9720
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

OK, I did a few more tests and I think I see the problem, but not sure if it can be fixed.

First of all - using setParent and then setting to node positions is not a good idea. If node is the parent then looking at it would mean you have to look at 0,0,0 and not at getPosition(). Also the animator should care about the distance to the target itself - so any child-parent relation will only confuse it.

But the bigger problem is that you can't change the target once it is set and rendered once as it is currently coded. I check if it that can be changed easily.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
someguy99
Posts: 38
Joined: Sun Oct 11, 2009 11:20 am

Post by someguy99 »

hybrid wrote:This is *not* an orbiting camera that moves around a sphere center. The camera logic is different and simply does not cope with position and rotation/target changes from the outside as you might need. But this won't be fixed either. You have to code the changes on your own, and you're free to reuse as much of the Maya cam as you want.
What? Then what is it? In the meshviewer it rotates around a model, but since you dont move the node in that example it is set to look at a dot in 3d space, and the model is positioned there.
But isnt it ment to rotate around a object? I mean orbiting around a dot in 3d space sounds useless.
And isnt is likely that your will want to move your object too?
someguy99
Posts: 38
Joined: Sun Oct 11, 2009 11:20 am

Post by someguy99 »

CuteAlien wrote:OK, I did a few more tests and I think I see the problem, but not sure if it can be fixed.

First of all - using setParent and then setting to node positions is not a good idea. If node is the parent then looking at it would mean you have to look at 0,0,0 and not at getPosition(). Also the animator should care about the distance to the target itself - so any child-parent relation will only confuse it.
:( i tried to understand that
But the bigger problem is that you can't change the target once it is set and rendered once as it is currently coded. I check if it that can be changed easily.
i think i got this one
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

As was mentioned many times already, the cameras available in Irrlicht SDK are not meant for general purpose usage. You're best off to write your own camera animators, based on the existing ones or not. However, the Maya cam is very special, and is not meant to be moved along. It's an editor cam which tries to mimic a certain behavior, but it's by no means possible to use it as a follower cam in a game.
CuteAlien
Admin
Posts: 9720
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

I guess a real orbiting-cam would be nice, but anyway.. I wrote a small patch which would allow you to get close to what you need.

Code: Select all

Index: source/Irrlicht/CSceneNodeAnimatorCameraMaya.cpp
===================================================================
--- source/Irrlicht/CSceneNodeAnimatorCameraMaya.cpp	(revision 2769)
+++ source/Irrlicht/CSceneNodeAnimatorCameraMaya.cpp	(working copy)
@@ -110,7 +110,12 @@
 	{
 		OldTarget = camera->getTarget();
 		OldCamera = camera;
+		LastCameraTarget = OldTarget;
 	}
+	else
+	{
+		OldTarget += camera->getTarget() - LastCameraTarget; // translation is still lost
+	}
 
 	core::vector3df target = camera->getTarget();
 
@@ -227,6 +232,7 @@
 	camera->setPosition(Pos);
 	camera->setTarget(target);
 	camera->setUpVector(upVector);
+	LastCameraTarget = camera->getTarget();
 }
 
 
Index: source/Irrlicht/CSceneNodeAnimatorCameraMaya.h
===================================================================
--- source/Irrlicht/CSceneNodeAnimatorCameraMaya.h	(revision 2769)
+++ source/Irrlicht/CSceneNodeAnimatorCameraMaya.h	(working copy)
@@ -99,6 +99,7 @@
 		f32 CurrentZoom;
 		f32 RotX, RotY;
 		core::vector3df OldTarget;
+		core::vector3df LastCameraTarget;	// to find out if the camera target was moved outside this animator
 		scene::ICameraSceneNode* OldCamera;
 
 		core::position2df MousePos;
When you patch Irrlicht with this and do a few changes in your example you can use it to rotate around a target-node, but the translation will still be lost as soon as you move your node.

So your example should look like this afterwards:

Code: Select all

#include <irrlicht.h>
#include <iostream>

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;


// event reciever
class MyEventReceiver : public IEventReceiver
{
public:
   // This is the one method that we have to implement
   virtual bool OnEvent(const SEvent& event)
   {
      // Remember whether each key is down or up
      if (event.EventType == irr::EET_KEY_INPUT_EVENT)
         KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;

      return false;
   }

   // This is used to check whether a key is being held down
   virtual bool IsKeyDown(EKEY_CODE keyCode) const
   {
      return KeyIsDown[keyCode];
   }
   
   MyEventReceiver()
   {
      for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
         KeyIsDown[i] = false;
   }

private:
   // We use this array to store the current state of each key
   bool KeyIsDown[KEY_KEY_CODES_COUNT];
};


int main()
{   
    // create device
   MyEventReceiver receiver;

   IrrlichtDevice* device = createDevice(EDT_OPENGL,
         dimension2d<u32>(1024, 768), 16, false, false, false, &receiver);

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

   IVideoDriver* driver = device->getVideoDriver();
   ISceneManager* smgr = device->getSceneManager();
   
    // add another object to prove it moves
    IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
   if (!mesh)
      return 1;
   IAnimatedMeshSceneNode* sydney = smgr->addAnimatedMeshSceneNode( mesh );
    if (sydney)
   {
      sydney->setMaterialFlag(EMF_LIGHTING, false);
      sydney->setMD2Animation(EMAT_STAND);
      sydney->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp") );
   }
   
   /*
   Create the node which will be moved with the WSAD keys. We create a
   sphere node, which is a built-in geometry primitive. We place the node
   at (0,0,30) and assign a texture to it to let it look a little bit more
   interesting. Because we have no dynamic lights in this scene we disable
   lighting for each model (otherwise the models would be black).
   */
   scene::ISceneNode * node = smgr->addSphereSceneNode();
   if (node)
   {
      node->setPosition(vector3df(0,0,0));
      node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
      node->setMaterialFlag(EMF_LIGHTING, false);
   }

    // add a camera and attach it to the node
   ICameraSceneNode *camera= smgr->addCameraSceneNodeMaya();
   camera->setPosition(vector3df(0,9,-14));
	camera->setTarget(vector3df(0,0,0));
   
    // move with the node
	//camera->setParent(node);
   
   // hide mouse
    device->getCursorControl()->setVisible(false);
   
   // In order to do framerate independent movement, we have to know
   // how long it was since the last frame
   u32 then = device->getTimer()->getTime();

   // This is the movemen speed in units per second.
   const f32 MOVEMENT_SPEED = 5.f;

   while(device->run())
   {
      // Work out a frame delta time.
      const u32 now = device->getTimer()->getTime();
      const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds
      then = now;

      /* Check if keys W, S, A or D are being held down, and move the
      sphere node around respectively. */
      core::vector3df nodePosition = node->getPosition();

	   bool moved = false;
      if(receiver.IsKeyDown(KEY_KEY_W))
      {
	      moved = true;
         nodePosition.Y += MOVEMENT_SPEED * frameDeltaTime;
      }
      else if(receiver.IsKeyDown(KEY_KEY_S))
      {
	      moved = true;
         nodePosition.Y -= MOVEMENT_SPEED * frameDeltaTime;
      }

      if(receiver.IsKeyDown(KEY_KEY_A))
      {
	      moved = true;
         nodePosition.X -= MOVEMENT_SPEED * frameDeltaTime;
      }
      else if(receiver.IsKeyDown(KEY_KEY_D))
      {
	      moved = true;
         nodePosition.X += MOVEMENT_SPEED * frameDeltaTime;
      }

      node->setPosition(nodePosition);
	   if ( moved )
	   {
	   	camera->setTarget(nodePosition);	   
	   }
	   
      driver->beginScene(true, true, SColor(255,113,113,133));

      smgr->drawAll(); // draw the 3d scene
      device->getGUIEnvironment()->drawAll(); // draw the gui environment (the logo)

      driver->endScene();
	   
   }

   // In the end, delete the Irrlicht device.
   device->drop();
   
   return 0;
} 
No longer do that parent-child thing. And I only set the target when moving the target-node because the translation (the movement while right-clicking the mouse) is lost as soon as you set the target new. I could probably also fix that somehow, but it's getting more tricky and I miss the time for that currently - and also I'm not really sure what a "correct" solution would be when setting the target. I think this might be a good compromise.

I could add the patch to svn as my few tests didn't show any disadvantages, but maybe Hybrid takes also a look at it and he knows more about how the Maya-cam should behave than me :-)

I think the best solution for you is creating your own animator. You can start with the CSceneNodeAnimatorCameraMaya and apply my patch from above. Then maybe just kick out the movement on mouse right-click and you already should have a nice orbiting camera.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
someguy99
Posts: 38
Joined: Sun Oct 11, 2009 11:20 am

Post by someguy99 »

Thanks CuteAlien, you sure are helpful :)
I actually wanted to get rid of that "rotate only when button pressed" sooner or later.
Now what do i do with that "patch"? Replace it with original and recompile?
Also, i dont understand why this cant be added as feature request if not bug.
PS. Why is setParent evil?
Post Reply