Problems with target tracking
by Patrick Webber · in Torque 3D Professional · 02/04/2014 (8:06 pm) · 11 replies
Hi all,
I'm trying to create a target tracking system for a project of mine and I've been having some issues. I've gotten it to mostly work... I copied out the camera object's code for tracking objects. When I lock onto a target, it seems to work flawlessly while the target moves only horizontally. However, when the target jumps (or falls) or slides down a hill, the aimer will jitter after him.
I'm not sure what is causing this. While the code seems to lock the mouse from moving in a left or right position I seem to still be able to jerk it up and down to mess with the camera (in addition to its wonky vertical tracking).
The code was stripped from the interpolateTick and processTick methods from the camera.cpp class. I also added in some network stuff into the pack/unpack updates so that targets are passed from client to server.
I guess my question would be, are interpolateTick and processTick fast enough to do this? Could the jittering be caused because I need this "trackTarget" code in an "onRender" call? I feel like ticks should be fast enough for this...but something's not right.
Any ideas?
Thanks,
Patrick
Here is what I have currently (I know its not the prettiest thing):
Relevant processTick code:
Relevant interpolateTick code:
I'm trying to create a target tracking system for a project of mine and I've been having some issues. I've gotten it to mostly work... I copied out the camera object's code for tracking objects. When I lock onto a target, it seems to work flawlessly while the target moves only horizontally. However, when the target jumps (or falls) or slides down a hill, the aimer will jitter after him.
I'm not sure what is causing this. While the code seems to lock the mouse from moving in a left or right position I seem to still be able to jerk it up and down to mess with the camera (in addition to its wonky vertical tracking).
The code was stripped from the interpolateTick and processTick methods from the camera.cpp class. I also added in some network stuff into the pack/unpack updates so that targets are passed from client to server.
I guess my question would be, are interpolateTick and processTick fast enough to do this? Could the jittering be caused because I need this "trackTarget" code in an "onRender" call? I feel like ticks should be fast enough for this...but something's not right.
Any ideas?
Thanks,
Patrick
Here is what I have currently (I know its not the prettiest thing):
Relevant processTick code:
// orient the camera to face the object
Point3F vec;
MatrixF ret;
lockOnTarget->getRenderEyeTransform( &ret );
objPos = ret.getPosition();
pos = getPosition();
VectorF rotVec(0, 0, 0);
// If this is a shapebase, use its render eye transform
// to avoid jittering.
ShapeBase *shape = lockOnTarget;
if( shape != NULL )
{
MatrixF ret;
shape->getRenderEyeTransform( &ret );
objPos = ret.getPosition();
}
else
{
lockOnTarget->getWorldBox().getCenter(&objPos);
}
mObjToWorld.getColumn(3,&pos);
vec = objPos - pos;
vec.normalizeSafe();
F32 pitch, yaw;
MathUtils::getAnglesFromVector(vec, yaw, pitch);
rotVec.x = -pitch - mRot.x;
rotVec.z = yaw - mRot.z;
if(rotVec.z > M_PI_F)
rotVec.z -= M_2PI_F;
else if(rotVec.z < -M_PI_F)
rotVec.z += M_2PI_F;
mRot.x += rotVec.x;
mRot.z += rotVec.z;
Move pMove = NullMove;
pMove.yaw = move->yaw;
F32 xDiff = objPos.x - pos.x;
F32 yDiff = objPos.y - pos.y;
F32 vertDist = (objPos.z - 2) - pos.z;
F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff);
F32 newPitch = mAtan2( horzDist, vertDist ) - ( M_PI_F / 2.0f );
if (mFabs(newPitch) > 0.01f)
{
Point3F headRotation = getHeadRotation();
//pMove.pitch = newPitch - headRotation.x;
mHead.x = newPitch;// - headRotation.x;
}Relevant interpolateTick code:
if(lockOnTarget != NULL){
MatrixF ret;
lockOnTarget->getRenderEyeTransform( &ret );
objPos = ret.getPosition();
pos = delta.pos + delta.posVec * dt;
Point3F vec = objPos - pos;
vec.normalizeSafe();
F32 pitch, yaw;
MathUtils::getAnglesFromVector(vec, yaw, pitch);
rot.x = -pitch;
rot.z = yaw;
F32 xDiff = objPos.x - pos.x;
F32 yDiff = objPos.y - pos.y;
F32 vertDist = (objPos.z - 2) - pos.z;
F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff);
F32 newPitch = mAtan2( horzDist, vertDist ) - ( M_PI_F / 2.0f );
if (mFabs(newPitch) > 0.01f)
{
Point3F headRotation = getHeadRotation();
mHead.x = newPitch;// - headRotation.x;
//rot.x = newPitch - headRotation.x;
}
}About the author
I'm a computer science major at Stony Brook University, and have been working with the Torque Game Engine for a number of years.
#2
02/05/2014 (6:45 am)
If you can control the camera then it sounds like you should reassign your control object - so you can't control the camera during the time it's tracking....
#3
@Stefan
The ret variable in interpolateTick() is just a MatrixF, so it doesn't have a getRenderPosition() call (that I know of). The matrix data is gotten from the getRenderEyeTransform though, so I think I'm doing what your suggesting.
@Richard
The player is still the control object while the tracking is taking place. He needs to be able to continue to move. I disabled the yaw and pitch functions in the script and gave it a quick run through, but its still jittery for vertical movement.
02/05/2014 (10:18 am)
Thanks for the reply's guys.@Stefan
The ret variable in interpolateTick() is just a MatrixF, so it doesn't have a getRenderPosition() call (that I know of). The matrix data is gotten from the getRenderEyeTransform though, so I think I'm doing what your suggesting.
@Richard
The player is still the control object while the tracking is taking place. He needs to be able to continue to move. I disabled the yaw and pitch functions in the script and gave it a quick run through, but its still jittery for vertical movement.
#4
02/05/2014 (11:28 am)
Another thing that can cause a jittery camera effect is if the camera process tick is being called before the object it's tracking. You can use SceneObject::processAfter() just like you would if the camera was mounted to the object to ensure the object's transform is updated before the camera.
#5
02/05/2014 (12:59 pm)
That's odd. But if you're using the camera that's attached to the player's eye node then he's still in control of it. Might want to spawn a new camera and render through it instead - not sure how much trouble that is though.
#6
Yup, nevermind that. :)
02/05/2014 (2:57 pm)
Quote:
@Stefan
The ret variable in interpolateTick() is just a MatrixF, so it doesn't have a getRenderPosition() call (that I know of). The matrix data is gotten from the getRenderEyeTransform though, so I think I'm doing what your suggesting.
Yup, nevermind that. :)
#7
That was a good thought. I tried setting it to processAfter in the write and read packet data functions depending on what it's sending, but it hasn't changed the outcome. I can get the jittering from just changing my own vertical position on a stationary target.
@Richard
I'm a little confused on what your suggesting. I need to still have control of my player while locked on. If I were to spawn a new camera (and control through that) wouldn't I have to capture it's input and manually feed it into the player object? Or is the idea to spawn a camera, lock on with that, and make the player its parent object (keeping the player in control but rendering the new locked on camera)?
02/05/2014 (5:05 pm)
@MichaelThat was a good thought. I tried setting it to processAfter in the write and read packet data functions depending on what it's sending, but it hasn't changed the outcome. I can get the jittering from just changing my own vertical position on a stationary target.
@Richard
I'm a little confused on what your suggesting. I need to still have control of my player while locked on. If I were to spawn a new camera (and control through that) wouldn't I have to capture it's input and manually feed it into the player object? Or is the idea to spawn a camera, lock on with that, and make the player its parent object (keeping the player in control but rendering the new locked on camera)?
#8
02/05/2014 (6:44 pm)
Ok, if you still need the player to be able to move then the last part of that might work - I thought it was for some type of cinematic event....
#9
I think the code to generate the angle is the same...so I'm guessing something is weird with the timing of the calculations?
Still not sure what is causing it directly, but it's a step towards figuring it out.
Some of the sample output:
02/06/2014 (4:21 pm)
It seems that my code is generating different values for the head's rotation in interpolateTick and processTick, but this only seems to be noticeable when vertical movement is involved.I think the code to generate the angle is the same...so I'm guessing something is weird with the timing of the calculations?
Still not sure what is causing it directly, but it's a step towards figuring it out.
Some of the sample output:
mHead.x = -0.037230; //During interpolateTick mHead.x = 0.018615; //During interpolateTick mHead.x = 0.018609; //During ProcessTick mHead.x = 0.018615; //During ProcessTick mHead.x = -0.037230; //During interpolateTick mHead.x = 0.018615; //During interpolateTick mHead.x = -0.037230; //During interpolateTick mHead.x = 0.018615; //During interpolateTick mHead.x = -0.037230; //During interpolateTick mHead.x = 0.018609; //During ProcessTick mHead.x = 0.018615; //During ProcessTick mHead.x = -0.037230; //During interpolateTick
#10
Interpolate sets the mHead.x (Head's rotation) to 0 right now.
While processTick actually sets the pitch (based off of how the getAIMove did it)
ProcessTick is definitely setting location correctly (I look right at my target, and have no issues while standing still).
So it seems like, the way I'm updating this in interpolate is wrong? Is there some other way of setting it here that I'm not aware of? The camera used rot.x which is fine for the camera, but not the player (I don't want him leaning forward and backwards while aiming).
Pretty confused here...
By the way here's the output from running it (it's repeated over and over):
--------------------
processTick: 0.665691
processTick: 0.664882
interpolate: 0.000000
interpolate: 0.000000
interpolate: 0.000000
interpolate: 0.000000
interpolate: 0.000000
processTick: 0.665691
processTick: 0.664882
---------------------
So it definitely is setting the variable. It just isn't showing up in game...
02/07/2014 (11:02 pm)
While cleaning up the code, I noticed that mHead.x during interpolateTick is really just being ignored (or at least that's how it seemed).Interpolate sets the mHead.x (Head's rotation) to 0 right now.
if(lockOnTarget != NULL){
// variable setup.
Point3F objPos, vec;
MatrixF ret;
F32 pitch, yaw;
// Face the target.
lockOnTarget->getRenderEyeTransform( &ret );
objPos = ret.getPosition();
pos = delta.pos + delta.posVec * dt;
vec = objPos - pos;
vec.normalizeSafe();
MathUtils::getAnglesFromVector(vec, yaw, pitch);
rot.z = yaw;
mHead.x = 0;//mClampF(mHead.x + pitch + 100, mDataBlock->minLookAngle, mDataBlock->maxLookAngle);
Con::warnf("interpolate: %f", mHead.x);
}While processTick actually sets the pitch (based off of how the getAIMove did it)
// First some variable setup
Point3F vec, pos, objPos;
VectorF rotVec(0, 0, 0);
// We should face the target now. Code from camera trackObject mode.
MatrixF ret;
lockOnTarget->getRenderEyeTransform( &ret );
objPos = ret.getPosition();
mObjToWorld.getColumn(3,&pos);
vec = objPos - pos;
vec.normalizeSafe();
F32 pitch, yaw;
MathUtils::getAnglesFromVector(vec, yaw, pitch);
rotVec.x = -pitch - mRot.x;
rotVec.z = yaw - mRot.z;
if(rotVec.z > M_PI_F)
rotVec.z -= M_2PI_F;
else if(rotVec.z < -M_PI_F)
rotVec.z += M_2PI_F;
//mRot.x += rotVec.x;
mRot.z += rotVec.z;
// Now...we need to set the rot around the x rot (pitch)
// The example for this is taken from getAIMove.
F32 xDiff = objPos.x - pos.x;
F32 yDiff = objPos.y - pos.y;
F32 vertDist = (objPos.z - pos.z) - 2; // -2 is because he kept looking above the head.
F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff);
F32 newPitch = mAtan2( horzDist, vertDist ) - ( M_PI_F / 2.0f );
if (mFabs(newPitch) > 0.01f)
{
Point3F headRotation = getHeadRotation();
// We don't set a *move because its too late here.
// We'll update the look ourselves! Yay hard way?
mHead.x = mClampF(mHead.x + newPitch - headRotation.x,mDataBlock->minLookAngle,
mDataBlock->maxLookAngle);
Con::printf("processTick: %f", mHead.x);
}ProcessTick is definitely setting location correctly (I look right at my target, and have no issues while standing still).
So it seems like, the way I'm updating this in interpolate is wrong? Is there some other way of setting it here that I'm not aware of? The camera used rot.x which is fine for the camera, but not the player (I don't want him leaning forward and backwards while aiming).
Pretty confused here...
By the way here's the output from running it (it's repeated over and over):
--------------------
processTick: 0.665691
processTick: 0.664882
interpolate: 0.000000
interpolate: 0.000000
interpolate: 0.000000
interpolate: 0.000000
interpolate: 0.000000
processTick: 0.665691
processTick: 0.664882
---------------------
So it definitely is setting the variable. It just isn't showing up in game...
#11
02/08/2014 (12:12 pm)
I think I've figured it out. Using the delta.head variable instead of mHead seems to have fixed it. Here's the final interpolateTick method, for anyone who's interested.void Player::interpolateTick(F32 dt)
{
if (mControlObject)
mControlObject->interpolateTick(dt);
// Client side interpolation
Parent::interpolateTick(dt);
Point3F rot, pos;
pos = delta.pos + delta.posVec * dt;
rot = delta.rot + delta.rotVec * dt;
F32 pitch = 0;
if(lockOnTarget != NULL){
// variable setup.
Point3F objPos, vec;
MatrixF ret;
F32 yaw;
// Face the target.
lockOnTarget->getRenderEyeTransform( &ret );
objPos = ret.getPosition();
objPos.z = objPos.z - 2;// -2 is because he kept looking above the head.
vec = objPos - pos;
vec.normalizeSafe();
MathUtils::getAnglesFromVector(vec, yaw, pitch);
rot.z = yaw;
F32 xDiff = objPos.x - pos.x;
F32 yDiff = objPos.y - pos.y;
F32 vertDist = (objPos.z - pos.z);
F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff);
F32 newPitch = mAtan2( horzDist, vertDist ) - ( M_PI_F / 2.0f );
delta.head.x = newPitch;
}
setRenderPosition(pos,rot,dt);
updateLookAnimation(dt);
delta.dt = dt;
}
Torque Owner Stefan Lundmark
Shouldn't you use ret.getRenderPosition() in your interpolateTick() method, though? That probably won't help solve your particular problem since horizontal movement works..