Camera Jitter Problem, Please Help

arkos

18-06-2006 01:00:11

Hey guys,

I posted on the ogre in practice forum, but no one could answer my question.

I am tracking a ball that is flying through the air.

Code:
position_tracking_node->setPosition(target_node->getPosition());
cam_node->lookAt(target_node->getPosition(), Node::TS_WORLD);


Basically position_tracking_node is the parent of cam_node which is a SceneNode* that holds the camera. The position_tracking_node sets itself to be at the same position as the target (ball) and then the camera looks at it. The effect is the that camera follows behind the ball as it flys. It follows the ball and looks at it for the most part, but the camera JITTERS like CRAZY!

I have a feeling that the camera is getting positioned and oriented to the LAST frame of the ball's position. I have tried moving my updateCamera function to the frameStarted and the frameEnded functions, but it doesn't change anything. I have also tried calling _update(true, true) on the target node and the camera node and tried rearranging their order. Nothing seems to work!!!!!

If I call
Code:
cam_node->setAutoTracking(true, target_node);
everything seems to work, but I don't want to use autoTracking because I really want to get the current position of the ball for tracking and other functions. I should be able to do it manually so what am I doing wrong.

I am using OgreNewt, which controls the ball. This might cause problems, but I am not sure. Also I took out lookat() and the camera still jitters.

Please Help!

arkos

18-06-2006 07:54:19

I believe that the problem is caused because my app's framelistener is called prior to Newton's framelistener. This means that I am updating the camera to the ball's position, then newton is changing the ball's position. The jitter in the camera is caused by the ball moving at different speeds each frame and therefore appearing at slightly different areas of the camera that is trying to follow it.

I have resolved that if I can get the newton framelistener to get called before my framelistener then I should be set. Does anyone know how to do this?

I have tried adding the newton listener to the root prior to my app's listener and vice versa, but that doesn't seem to do anything. Anyone have any suggestions?

syedhs

18-06-2006 11:20:47

How about you move the camera code into newton frame listener? I think that should solve your problem.

arkos

18-06-2006 19:26:06

Thats a good thought, but I don't have access to that code because AFAIK it is contained within the newton dll. I can see the class declaration within the newton.h, but I can't really touch the implementation of the framelistener.

I think another problem could be that we have newton being called at 60fps while our app runs at around 100. Could this be a problem??

walaber

18-06-2006 21:18:44

yes. i had the same problem with StuntPlayground. i fixed it by only updating the camera in a loop where the physics had also updated.

i advise you stop using the OgreNewt::BasicFrameListener, and just update the OgreNewt::World yourself. you can copy the code from OgreNewt::BasicFrameListener into your own frame listener.

arkos

19-06-2006 17:17:07

Thanks walaber,

I had the same thought myself, but my attempt at calling the camera update function got me the blue screen of death! I don't know if it was something that I did or what. I did something like this:

bool frameStarted(const FrameEvent& evt)
{
bool ret = true;
static float timer = 0;
Universal::get_singleton().camMgr->updateCamera(evt);
timer += evt.timeSinceLastFrame;
if(timer >= 1.0/60.0)
{
timer = 0;
}
return ret;
}


My thoughts behind it were that it would keep a running timer and as soon as it got to be 1/60th of a second (to match newton's 60fps) it would update the camera.

I guess if I used your method of updating OgreNewt::World myself I could just put my camera update in there and the problem would be solved. Where can I get my hands on the code for OgreNewt::BasicFrameListener? I am new to Ogre::Newt. Thanks

HexiDave

19-06-2006 20:45:35

If you just want the code, here:
OgreNewt_BasicFrameListener.h
#include <Ogre.h>
#include <OgreNewt_World.h>


namespace OgreNewt
{


class _OgreNewtExport BasicFrameListener : public Ogre::FrameListener
{
protected:
OgreNewt::World* m_World;

int desired_framerate;
Ogre::Real m_update, m_elapsed;


public:
BasicFrameListener(Ogre::RenderWindow* win, Ogre::SceneManager* mgr, OgreNewt::World* W, int update_framerate = 60);
~BasicFrameListener(void);

bool frameStarted(const Ogre::FrameEvent &evt);

private:

Ogre::InputReader* mInputDevice;

};


OgreNewt_BasicFrameListener.cpp
#include "OgreNewt_BasicFrameListener.h"
#include "OgreNewt_Debugger.h"

namespace OgreNewt
{

BasicFrameListener::BasicFrameListener( Ogre::RenderWindow* win, Ogre::SceneManager* mgr, OgreNewt::World* W, int update_framerate) :
FrameListener()
{
m_World = W;
desired_framerate = update_framerate;

m_update = (Ogre::Real)(1.0f / (Ogre::Real)desired_framerate);
m_elapsed = 0.0f;

// add the standard debug viewer.
Debugger::getSingleton().init( mgr );

mInputDevice = Ogre::PlatformManager::getSingleton().createInputReader();
mInputDevice->initialise(win,true, true);

}

BasicFrameListener::~BasicFrameListener(void)
{
}

bool BasicFrameListener::frameStarted(const Ogre::FrameEvent &evt)
{
m_elapsed += evt.timeSinceLastFrame;
Ogre::LogManager::getSingleton().logMessage(" Newton Frame Listener... m_elapsed: "+Ogre::StringConverter::toString(m_elapsed)+
" m_update:"+Ogre::StringConverter::toString(m_update));

int count = 0;

if ((m_elapsed > m_update) && (m_elapsed < (1.0f)) )
{
while (m_elapsed > m_update)
{
m_World->update( m_update );
m_elapsed -= m_update;
count++;
}
}
else
{
if (m_elapsed < (m_update))
{
// not enough time has passed this loop, so ignore for now.
}
else
{
m_World->update( m_elapsed );
count++;
m_elapsed = 0.0f; // reset the elapsed time so we don't become "eternally behind".
}
}

Ogre::LogManager::getSingleton().logMessage(" Newton updates this loop: "+Ogre::StringConverter::toString(count));

/////////////////////////////////////////////////////////////
// DEBUGGER
mInputDevice->capture();

if (mInputDevice->isKeyDown(Ogre::KC_F3))
{
Debugger::getSingleton().showLines( m_World );
}
else
{
Debugger::getSingleton().hideLines();
}


return true;
}


Basically just gut it and use m_update and m_elapsed with the code from frameStarted.

arkos

20-06-2006 06:30:51

AWESOME!!

Hey thanks a lot guys, that really helped me out!
The camera looks AMAZING! It tracks the ball perfectly!
Thanks again

:D

HexiDave

20-06-2006 06:38:08

Fantastic! Very good news, guess I can scratch another problem off my list :D

Good work :)