Manual FPS camera problem, setPosition() changes rotation.

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
Locien
Posts: 25
Joined: Wed Jul 10, 2013 2:43 am

Manual FPS camera problem, setPosition() changes rotation.

Post by Locien »

Hello. A while ago some people on this forum described to me how cameras work in Irrlicht. I have a problem that's related to how cameras adjust the rotation automatically in Irrlicht to look at a coordinate or scene node. I'm making an FPS camera and I've got it working exactly how I want it to except for one little thing. Basically what it does is that it first calculates rotation changes with the mouse, nothing difficult and it works flawlessly. And then it calculates the movement vector based on the rotation.

I'm trying to bypass the system in Irrlicht where cameras automatically look at a specific coordinate or scene node when you change the position since I think it's very confusing and complicated for an FPS camera. So the problem I'm having is that since I call setPosition() and setRotation() once every time the camera is updated, it makes the camera rotate twice in rapid succession. This makes the image jerky/choppy when moving around. Isn't there any way to make it so that setPosition() doesn't rotate the camera at all/change the target? I just want to SET THE POSITION, not SET THE POSITION AND ROTATE THE CAMERA. I understand how it's a really neat feature when you want to pivot around an object, like a third person camera, but it's just unnecessarily confusing when making a first person camera.

I was under the understanding that bindTargetAndRotation(true) would yield the result that I want, but it doesn't. And bindTargetAndRotation(false) makes it impossible to rotate the camera with setRotation() apparently.

Could someone please help me?

tl;dr I'm calling setPosition() and setRotation() once every frame which rotates the camera twice causing jerky movement when moving the camera. Is there some way to disable setPosition() rotating the camera?

Edit: I realize it got a bit convoluted and I don't think I explained it very well. But basically what I want to achieve is to remove any "look at"/Target-function from the setPosition() function so I can handle the updating of rotation myself and just make the camera move from point A to point B, nothing more nothing less.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Manual FPS camera problem, setPosition() changes rotatio

Post by CuteAlien »

setPosition does not change the target. Which is probably your problem. Irrlicht camera internally only works with position, target and upvector. So when the target stays the same and you move the position then it looks like a rotation. Which means if you only work with setRotation you will have to set the rotation new after each setPosition (you can set it to the old value) just to keep the same rotation. And to make it more confusing - you _have_ to call updateAbsolutePosition() in between, because otherwise setRotation still works with the old position.

And yeah - bindTargetAndRotation(false) will just ensure setRotation no longer has any connection to the camera rotation. It still rotates the node, but not the camera - it's something that probably only makes sense if you work with children nodes added to the camera (which in most cases is a bad idea really).

Last thing to note is that the rotation does not affect the up-vector. Just mentioning it (it will be fine in most typical cases).

If you need any changed behavior the easiest solution is usually to copy the CCameraSceneNode code, modify it and just create your own 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
Locien
Posts: 25
Joined: Wed Jul 10, 2013 2:43 am

Re: Manual FPS camera problem, setPosition() changes rotatio

Post by Locien »

Thanks for the answer and the information.
CuteAlien wrote:Which means if you only work with setRotation you will have to set the rotation new after each setPosition (you can set it to the old value) just to keep the same rotation.
That's exactly what I've been doing, but it creates a choppy camera because it makes the camera rotate twice every frame. I guess I'll just abandon this idea and do it the way it's supposed to be done in Irrlicht.

But how exactly are you supposed to do that? I've never done something like this or ever heard of a camera model like this before. The way I do camera movement is to calculate a movement vector in the XZ-plane based on the current rotation. I figured you could add the movement vector once more to the current position to get the right target but it just spins the camera around endlessly, and besides, my movement vector solution doesn't use the Y axis so there would be no way to rotate up and down using target like that then. Can someone give me an example on how to do it? I'd be very grateful.

I also don't understand why it's so needlessly complicated and why there isn't an option to disable the look at-function. This makes the setRotation() function pretty much pointless for any camera that moves unless it's done in a frame without any movement.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Manual FPS camera problem, setPosition() changes rotatio

Post by CuteAlien »

I don't think your problem is that the camera rotates twice per frame. Because a frame is when you draw the scene - so you wouldn't be able to see that as it wouldn't draw it. But hard to tell anything without knowing your code.

But you can always look at the fps-camera animator in Irrlicht and how that does it. The code is in CSceneNodeAnimatorCameraFPS.cpp and the rotation stuff is documented rather well.
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
Locien
Posts: 25
Joined: Wed Jul 10, 2013 2:43 am

Re: Manual FPS camera problem, setPosition() changes rotatio

Post by Locien »

I'm sorry for reviving an old thread but I've been gone for a long time due to illness. I want to take up programming again though.
CuteAlien wrote:I don't think your problem is that the camera rotates twice per frame. Because a frame is when you draw the scene - so you wouldn't be able to see that as it wouldn't draw it. But hard to tell anything without knowing your code.

But you can always look at the fps-camera animator in Irrlicht and how that does it. The code is in CSceneNodeAnimatorCameraFPS.cpp and the rotation stuff is documented rather well.
That thought crossed my mind too but I honestly have no idea why this is happening. Sometimes the camera just seems to flip into a different direction for no reason whatsoever.

The problem seems to only occur when I "strafe"/move the camera sideways using the A and D keys. I've uploaded a video and hope you can give me an idea of what's wrong.

https://www.youtube.com/watch?v=LZqwXZ6ukdI

Here's the code for the camera:

Code: Select all

    vector2d<irr::f32> CurPos = Cursor->getRelativePosition();
    vector3df CurrentRotation = IrrCam->getRotation();
 
    if(CurPos != LockedCursorPosition)
    {
 
        if(CurPos.X != LockedCursorPosition.X)
        {
                f32 delta = ((CurPos.X - LockedCursorPosition.X) * RotateSpeed);
                for(f32 i = 0; CurrentRotation.Y - (delta + (i*360)) < -180.0f; ++i) delta -= 360;
                for(f32 i = 0; CurrentRotation.Y - (delta + (i*360)) > 180.0f; ++i) delta += 360;
                CurrentRotation.Y -= delta;
        }
 
        if(CurPos.Y != LockedCursorPosition.Y)
        {
                f32 delta = ((CurPos.Y - LockedCursorPosition.Y) * RotateSpeed);
                if(CurrentRotation.X - delta <= -MAX_VERTICAL_ANGLE) CurrentRotation.X = -88.0f;
                else if(CurrentRotation.X - delta >= MAX_VERTICAL_ANGLE) CurrentRotation.X = 88.0f;
                else CurrentRotation.X -= delta;
        }
 
        Cursor->setPosition(LockedCursorPosition);
 
    }
 
    if(Movement_Bits != MOVE_NONE)
    {
        vector3df CurrentPosition = IrrCam->getPosition();
 
        vector3df Target(0,0,1);
 
        matrix4 Matrix;
        Matrix.setRotationDegrees(core::vector3df(CurrentRotation.X, CurrentRotation.Y,0));
        Matrix.transformVect(Target);
 
        vector3df MovementVector = Target;
        //MovementVector.Y = 0.0f;
        MovementVector.normalize();
 
        if(Movement_Bits & MOVE_FORWARD) CurrentPosition += MovementVector * timeMs * 0.01;
        else if(Movement_Bits & MOVE_BACKWARD) CurrentPosition -= MovementVector * timeMs * 0.01;
 
     //The problem starts somewhere around here.
        MovementVector = Target;
        MovementVector = MovementVector.crossProduct(UpVector);
        //MovementVector.Y = 0.0f;
        MovementVector.normalize();
 
        if(Movement_Bits & MOVE_LEFT) CurrentPosition += MovementVector * timeMs * 0.01; //This causes the problem.
        else if(Movement_Bits & MOVE_RIGHT) CurrentPosition -= MovementVector * timeMs * 0.01; //This also causes the problem.
 
        IrrCam->setPosition(CurrentPosition);
 
        //If I put a 100 ms sleep here I can see the camera clearly flipping back and forth between different rotations.
    }
    
    IrrCam->setRotation(CurrentRotation);
And here's the part of code in the main function that renders it if it's relevant:

Code: Select all

            IrrDriver->beginScene(true, true);
 
            updateGUI();
 
            IrrScnMgr->drawAll();
            IrrGui->drawAll();
            IrrDriver->endScene();
 
            getInputs();
            CameraFPS->Update(LastFrameTime, Cursor); //Updates the camera, sends delta time between this frame and last frame.
I'm sorry for being persistent and annoying but I really want to get this to work. I hope someone can enlighten me. Thanks in advance and sorry for the trouble.
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Manual FPS camera problem, setPosition() changes rotatio

Post by mongoose7 »

Try debugging - print out the rotation every frame and see if you notice anything special when it starts to glitch. Maybe print out 'Target' as well.
Locien
Posts: 25
Joined: Wed Jul 10, 2013 2:43 am

Re: Manual FPS camera problem, setPosition() changes rotatio

Post by Locien »

mongoose7 wrote:Try debugging - print out the rotation every frame and see if you notice anything special when it starts to glitch. Maybe print out 'Target' as well.
Good idea. I tried doing this before setPosition(), between setPosition() and setRotation() and after setRotation(). The rotation of the camera doesn't change at all as long as I don't move the mouse but I can still clearly see the camera twitching and changing angles. The target changes just as it should. I tried setting the rotation to 0,0,0 and when I move in one single direction only a value in one dimension of the target changes just as it should. The target and rotation are changing exactly as they should, but for some reason when I move sideways or sideways while going back or forth the camera starts twitching as in the video.

I'm completely at a loss for what I should do. Does anyone have any ideas?
horvatha4
Posts: 12
Joined: Sun Feb 23, 2014 6:03 am
Location: Rheiland-Pfalz, Germany
Contact:

Re: Manual FPS camera problem, setPosition() changes rotatio

Post by horvatha4 »

Soon it will be a problem for me. It is interesting.
I meet this problem soon ( rapid rotation ) and sometimes the Matrixes may be funny.
I have a few queston Locien:
- At witch direction occurs this? In my program when the object lies the Z axis paralell.
-Have you tried the matrix4->buildCameraLookAtMatrixLH() function?
-Why usefull this two line in your code?
for(f32 i = 0; CurrentRotation.Y - (delta + (i*360)) < -180.0f; ++i) delta -= 360;
for(f32 i = 0; CurrentRotation.Y - (delta + (i*360)) > 180.0f; ++i) delta += 360;

So I build a follow camera.
This cam is orbiting around the active object. Like a cam on a rod's end and the cam look the object allways.
If you change this two - so the cam look always the rod's end and the cam sitting in the origin- this can you help maybe. I will try this firts in my code.
This my code currently:

Code: Select all

 
class TSTrainDriver:public IEventReceiver 
{
private:
    TrainSimLocomotive* ActiveLocomotive;
    ICameraSceneNode*   ActiveCamera, *FollowCamera, *BoardCamera;
    irr::s32 cAlfa, cBeta, mLastX, mLastY, mDeltaX, mDeltaY;// c like camera, m like mouse
    ...
}   
...
bool TSTrainDriver::OnEvent(const irr::SEvent &event)
{
    ...
    
    if( event.EventType == EET_MOUSE_INPUT_EVENT )
    {
        if( event.MouseInput.Event == EMIE_MOUSE_MOVED && event.MouseInput.isRightPressed() )
        {
            cBeta-=((event.MouseInput.X - cLastX)/2); cLastX = event.MouseInput.X;// cBeta = irr::core::clamp( cBeta, 0, 360 );
            cAlfa-=((event.MouseInput.Y - cLastY)/2); cLastY = event.MouseInput.Y;// cAlfa = irr::core::clamp( cAlfa, 0, 180 );
        }
        if( event.MouseInput.Event == EMIE_MOUSE_WHEEL)
        {
                cRadius -= event.MouseInput.Wheel; cRadius = irr::core::clamp( cRadius, 1.0f, 30.0f );// +-1
        }
        if( event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN )
        {
            cLastX = event.MouseInput.X;
            cLastY = event.MouseInput.Y;
        }
    }
    return false;
}
 
void TSTrainDriver::setActiveCameraPosition()
{
    irr::core::vector3df dirvector( 0.0f, cRadius, 0 ), 
        avc = ActiveLocomotive->GetMeshSceneNode()->getAbsolutePosition();
    dirvector.rotateYZBy( cAlfa, irr::core::vector3df(0,0,0) );// rotating around the x-axis
    dirvector.rotateXZBy( cBeta, irr::core::vector3df(0,0,0) );// the the y-axis
    ActiveCamera->setPosition( dirvector );
    ActiveCamera->setTarget( avc );
    ActiveCamera->updateAbsolutePosition();
}   
 
In this code you can orbiting with pressed RightMouseButton!

Arpi
Post Reply