Camera is always 1 frame behind, what can I do about it? | 2024 edition

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
SomeGuyWithAComputer
Posts: 13
Joined: Wed Jun 26, 2024 12:28 am

Camera is always 1 frame behind, what can I do about it? | 2024 edition

Post by SomeGuyWithAComputer »

I am having a problem where I'm trying to get the camera to chase an object. For some reason, it actually works when following a node at the root level. If I want to get it to follow a node that is a child of another node, it's always 1 frame behind. Using getAbsolutePosition() only returns the position of that node from 1 frame ago. This means that the faster the parent object moves, the further behind the camera lags when chasing the child object.

In my update loop I run everything in this order:

Code: Select all

irrDriver->beginScene(true, true, SColor(255,0,0,0));
physicsTick();		//tick the reactphysics3d physics engine
updateAllObjects();	//set the position of all the node objects to whatever the physics engine says they should be
cameraChase();	//whatever camera following code i'm currently testing
irrsmgr->drawAll();//scene manager
guienv->drawAll();//IGUIEnvironment
irrDriver->endScene();//IVideoDriver
I've experimented with all kinds of other combinations but I'd love to hear someone else's reasoning for why this should be a different way. The obvious thing of putting cameraChase() before beginScene() doesn't fix the camera lag even if I also put updateAllObjects() before beginScene() too.

I know about the updateAbsolutePosition() function but i'm not sure if its broken or if im not using it right. The following code performs exactly the same regardless of if the lines containing updateAbsolutePosition() are commented out or not.

Code: Select all

core::vector3df forward = thingToChase->getNode()->getRotation().rotationToDirection();
core::vector3df up = thingToChase->getNode()->getRotation().rotationToDirection(core::vector3df(0,1,0));
core::vector3df thingPosition = thingToChase->getNode()->getPosition();

thingToChase->getParentThing()->getNode()->updateAbsolutePosition();
thingToChase->getNode()->updateAbsolutePosition();
theCamera->updateAbsolutePosition();
theCamera->setPosition(thingPosition - forward);
theCamera->updateAbsolutePosition();
theCamera->setTarget(thingPosition + forward);
theCamera->setUpVector(up);
The following modification of that same code results in also the exact same behavior

Code: Select all

thingToChase->getParentThing()->getNode()->updateAbsolutePosition();
thingToChase->getNode()->updateAbsolutePosition();

core::vector3df forward = thingToChase->getNode()->getRotation().rotationToDirection();
core::vector3df up = thingToChase->getNode()->getRotation().rotationToDirection(core::vector3df(0,1,0));
core::vector3df thingPosition = thingToChase->getNode()->getPosition();

theCamera->setPosition(thingPosition - forward);
theCamera->setTarget(thingPosition + forward);
theCamera->setUpVector(up);
Literally all it takes to allow the camera to follow a root node without lagging behind at high speeds is this:

Code: Select all

core::vector3df forward = thingToChase->getNode()->getRotation().rotationToDirection();
core::vector3df up = thingToChase->getNode()->getRotation().rotationToDirection(core::vector3df(0,1,0));
core::vector3df shipPosition = thingToChase->getNode()->getPosition();

theCamera->setPosition(shipPosition + (forward * -64.0f) + (up * 10.0f));
theCamera->setTarget(shipPosition);
So.. besides trying to make something that calculates how fast objects are going and proactively sets the camera forward based on velocity to sort of balance out the to-me unfixable camera lag, what are some other things I can try? When updateAbsolutePosition() gets called, when do those changes, if any, become valid instead of being set to the previous frame's values?

Edit: well, darn. calculating velocities and moving the camera to where it should be 1 frame from "now" can't work if the parent object is rotating and the child object is moving because of the way pivoting changes the position. That's some really complicated math.
CuteAlien
Admin
Posts: 9716
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Camera is always 1 frame behind, what can I do about it? | 2024 edition

Post by CuteAlien »

About the edit - you can go over matrices with thingToChase->getAbsoluteTransformation() (after calling updateAbsolutePosition for it). Then get position, rotation from that matrix. It will give you the absolute rotation/position for your child.

Order of operations looks correct otherwise. Calling updateAbsolutePosition for parent before child.

And I think you won't need updateAbsolutePosition for the camera unless TargetAndRotationAreBound is set to true for it.

But maybe I'm missing something as well. But I need a working example then. For example make sure you don't have additional animators for the camera trying to control positions as well (seen people do that a few times...).
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
SomeGuyWithAComputer
Posts: 13
Joined: Wed Jun 26, 2024 12:28 am

Re: Camera is always 1 frame behind, what can I do about it? | 2024 edition

Post by SomeGuyWithAComputer »

it turned out that I wasn't quite running updateAbsolutePosition() often enough I guess. For some reason, when I added updateAbsolutePosition() into a loop within updateAllObjects() so that it updated the absolute position for every object when it copies the values from the physics engine to the scene node, it started working as expected all of a sudden. I don't know exactly why doing it there made it work, but my positions are no longer 1 frame behind.
CuteAlien
Admin
Posts: 9716
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Camera is always 1 frame behind, what can I do about it? | 2024 edition

Post by CuteAlien »

You have to be careful if you have parent-child objects in Irrlicht that parents always have to be updated before childs. If you work with a physics engine it's sometimes simpler to only have those parent-child relations in the physics engine - and not use any parent-child relations inside Irrlicht. Otherwise you may start calculating the full matrices twice. Or only use parent-child in Irrlicht for sub-nodes which don't need their own physics (like effects around your ship).
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
SomeGuyWithAComputer
Posts: 13
Joined: Wed Jun 26, 2024 12:28 am

Re: Camera is always 1 frame behind, what can I do about it? | 2024 edition

Post by SomeGuyWithAComputer »

welp, false alarm. I thought I had my position lag bugs fixed but I don't. My changes made it so that I can have an object on a moving ship and still be able to get the position of the object that is a child object in the ship and have it be accurate but I can't have an object be a child of that object without it still being 1 frame behind. I strategically tried calling updateAbsolutePosition() even more often and on even more objects like I did before but that's not fixing it this time. I'm trying to attach a gun to a hand bone.

I don't think updateAbsolutePosition() takes effect as soon as it gets run. Maybe it doesn't apply any of the position changes until the next frame. I wish I understood why it doesn't appear to take immediate effect sometimes. I am aware that you're supposed to update a parent node before a child node but i'm updating every parent object as far as I know.

I am running the following code several times per frame and the gun i'm trying to attach to the hand bone is still always 1 frame behind. I tried updating the absolute position on more objects like I did last time but the gun is still a frame behind.

Code: Select all

m_parentThing->getNode()->updateAbsolutePosition();
m_node->updateAbsolutePosition();
getBoneNamed("root_bone")->getParent()->updateAbsolutePosition();//IBoneSceneNode
getBoneNamed("root_bone")->updateAbsolutePosition();
getBoneNamed("root_bone")->updateAbsolutePositionOfAllChildren();
getRightHandBone()->updateAbsolutePosition();
getRightHandBone()->updateAbsolutePositionOfAllChildren();	//an already saved IBoneSceneNode pointer - try to make it update

if (getEquippedWeapon() != nullptr)
{
	getEquippedWeapon()->updateNodeObject();
}
Edit: ok I made that video and accidentally solved my problem (for now) along the way. I'll post the video anyway just so there's a demo of what I'm working on. Note that the rotation controls are awful because I haven't yet figured out relative rotational velocities so I have to use reactphysics3d's angular dampening instead of simulated pids which isn't as good.
https://www.youtube.com/watch?v=B9cNA79kxS4
Post Reply