Game Development Community

Fluid Camera

by Jeremy Alessi · 08/03/2005 (3:46 pm) · 43 comments

First open vehicle.h and player.h.

In vehicle.h find:

bool cameraRoll;           ///< Roll the 3rd party camera

After that line copy this:

F32 cameraLag;             ///< Amount of camera lag (lag += car velocity * lag)
F32 cameraDecay;           ///< Rate at which camera returns to target pos.
F32 cameraOffset;          ///< Vertical offset

And then paste it in player.h somewhere after this:

S32 splashEmitterIDList[NUM_SPLASH_EMITTERS];

Next copy this member variable from vehicle.h:

Point3F mCameraOffset; ///< 3rd person camera

Paste it in player.h after this:

S32  mContactTimer;              ///< Ticks since last contact

In vehicle.h find this:

void getCameraTransform(F32* pos, MatrixF* mat);

Paste it under this in player.h:

void getCameraParameters(F32 *min, F32 *max, Point3F *offset, MatrixF *rot);

Next up open your vehicle.cc and player.cc files. You could pretty much transfer the stuff over involving the added variables but here's a walkthrough.

In player.cc after:

groundImpactShakeFalloff = 10.0;

Add:

cameraLag = 0;
cameraDecay = 0;
cameraOffset = 0;

After:

addField("groundImpactShakeFalloff",   TypeF32,       Offset(groundImpactShakeFalloff,    PlayerData));

Add:

addField("cameraLag",      TypeF32,        Offset(cameraLag,      PlayerData));
addField("cameraDecay",  TypeF32,        Offset(cameraDecay,  PlayerData));
addField("cameraOffset",   TypeF32,        Offset(cameraOffset,   PlayerData));

After:

stream->write(groundImpactShakeFalloff);

Add:


stream->write(cameraLag);
stream->write(cameraDecay);
stream->write(cameraOffset);

After:

stream->read(&groundImpactShakeFalloff);

Add:

stream->read(&cameraLag);
stream->read(&cameraDecay);
stream->read(&cameraOffset);

After:

gCamFXMgr.update( dt );
}

Add:

// Update 3rd person camera offset.  Camera update is done
// here as it's a client side only animation.
mCameraOffset -= 
(mCameraOffset * mDataBlock->cameraDecay + 
mVelocity * mDataBlock->cameraLag) * dt;

After this instance of mFalling = false; at ~ line 829 :

mFalling = false;

Add:

mCameraOffset.set(0,0,0);

After:

*max = mDataBlock->cameraMaxDist * scale.y;

Comment out:

off->set(0,0,0);

Add:

off->set(0,0,mDataBlock->cameraOffset);

After this whole function:

void Player::getCameraParameters(F32 *min,F32* max,Point3F* off,MatrixF* rot)
{
   if (!mControlObject.isNull() && mControlObject == getObjectMount()) {
      mControlObject->getCameraParameters(min,max,off,rot);
      return;
   }
   const Point3F& scale = getScale();
   *min = mDataBlock->cameraMinDist * scale.y;
   *max = mDataBlock->cameraMaxDist * scale.y;
   off->set(0,0,mDataBlock->cameraOffset);
   //off->set(0,0,0);
   rot->identity();
}

Add this function:

//----------------------------------------------------------------------------
//Jeremy's Mods Added Camera Function.
void Player::getCameraTransform(F32* pos,MatrixF* mat)
{
   // Returns camera to world space transform
   // Handles first person / third person camera position
   if (isServerObject() && mShapeInstance)
      mShapeInstance->animateNodeSubtrees(true);

   if (*pos == 0) {
      getRenderEyeTransform(mat);
      return;
   }

   // Get the shape's camera parameters.
   F32 min,max;
   MatrixF rot;
   Point3F offset;
   getCameraParameters(&min,&max,&offset,&rot);

   // Start with the current eye position
   MatrixF eye;
   getRenderEyeTransform(&eye);

   // Build a transform that points along the eye axis
   // but where the Z axis is always up.
   MatrixF cam(1);
   VectorF x,y,z(0,0,1);
   eye.getColumn(1, &y);
   mCross(y, z, &x);
   x.normalize();
   mCross(x, y, &z);
   z.normalize();
   cam.setColumn(0,x);
   cam.setColumn(1,y);
   cam.setColumn(2,z);
   mat->mul(cam,rot);


   // Camera is positioned straight back along the eye's -Y axis.
   // A ray is cast to make sure the camera doesn't go through
   // anything solid.
   VectorF vp,vec;
   vp.x = vp.z = 0;
   vp.y = -(max - min) * *pos;
   eye.mulV(vp,&vec);

   // Use the camera node as the starting position if it exists.
   Point3F osp,sp;
   if (mDataBlock->cameraNode != -1) {
      mShapeInstance->mNodeTransforms[mDataBlock->cameraNode].getColumn(3,&osp);
      getRenderTransform().mulP(osp,&sp);
   }
   else
      eye.getColumn(3,&sp);

   // Make sure we don't hit ourself...
   disableCollision();
   if (isMounted())
      getObjectMount()->disableCollision();

   // Cast the ray into the container database to see if we're going
   // to hit anything.
   RayInfo collision;
   Point3F ep = sp + vec + offset + mCameraOffset;
   if (mContainer->castRay(sp, ep,
         ~(WaterObjectType | GameBaseObjectType | DefaultObjectType),
         &collision) == true) {

      // Shift the collision point back a little to try and
      // avoid clipping against the front camera plane.
      F32 t = collision.t - (-mDot(vec, collision.normal) / vec.len()) * 0.1;
      if (t > 0.0f)
         ep = sp + offset + mCameraOffset + (vec * t);
      else
         eye.getColumn(3,&ep);
   }
   mat->setColumn(3,ep);

   // Re-enable our collision.
   if (isMounted())
      getObjectMount()->enableCollision();
   enableCollision();
}


//----------------------------------------------------------------------------

Finally, in your player.cs script files add something like this to the player datablock:

cameraLag = 0.4;
cameraDecay = 3.5;
cameraOffset = 1;
Page «Previous 1 2 3 Last »
#1
08/03/2005 (3:53 pm)
Looks nice; when I get some free time I'll have to check this out to see the difference it makes.

B--
#2
08/03/2005 (4:18 pm)
Looks cool, have to check it out when I get a chance.
#3
08/03/2005 (5:09 pm)
thanks for posting this, it's something that's been on my todo list for a while.

I'm having the oddest problem though.
First I went step by step through your procedure, compiled fine, ran it, the game stopped seemingly, stuck while loading datablocks.

Strange I thought, I'll do a rebuild all.
rebuilt my app, ran again same behavior. Hmm.

Revert files to previous version, build, run, works fine.

Ok I says...lets do this slower. I added a single cameraOffset variable to player's datablock, initialized it in the constructor, added the field for it, and did the stream reading and writing in the proper places. the simplest I could do.

But I get the same behavior, the app seems stuck while loading datablocks. I've debugged a bit but it isn't actually crashed, so each break happens in an odd place. I wonder if it's possible to have too much data in a given datablock and I'm magically there? any ideas would be appreciated.

I'll go double check things.

edit: it's most likely there is some problem with some of my other modifications this is showing up
#4
08/03/2005 (5:27 pm)
ok, definitely my problem, I had done some writing of data a long time ago that didn't have the matching reads!

8O

this explains a few other bugs as well, wonderful. back to the camera I go....
#5
08/03/2005 (5:40 pm)
Let me know if it ends up working. I did this mod like a week ago myself so I just retraced my steps this afternoon ... might have missed something. Though, I'm pretty sure it's all there.
#6
08/03/2005 (5:56 pm)
worked great. I'm so happy to have that bug found. It always surprises me how long a bug that seems so bad can sneak around unnoticed.

I was hoping for a little rotational lag also, have to look into that later. If find that low settings work best for me. something like

cameraLag = 0.10;
cameraDecay = 1.0;
cameraOffset = 0.20;

gives just a little slop but is still responsive enough. also the offset for me isn't very useful, it's just a z offset I believe, I was expecting it to be an offset from the player.

but hey, those are just ideas for improvement, thanks for posting this. simple and quick to add.
#7
08/03/2005 (6:24 pm)
You can already offset the camera from the player normally.

cameraMaxDist = 5;

That pulls the camera away along the players Y axis.

Also if you look at the offset code you could offset the camera easily along any axis just add extra offsets for x and y. I personally love the offset so you can see what's in front of the player instead of looking at the character's back. It was pretty much impossible to shoot anyone in 3rd person before.

You can also add rotational lag. Actually, it'll lag when you turn but it's based on the player's movement velocity not rotational velocity. You could of course add any other changes as I mentioned above from here that you want. I'm personally, still tweaking it but with this in place you can do pretty much any 3rd person behavior you want.
#8
08/03/2005 (6:32 pm)
Quote:You can already offset the camera from the player normally.

ah yes, forgot about that, and already using it.

Quote:I personally love the offset so you can see what's in front of the player instead of looking at the character's back. It was pretty much impossible to shoot anyone in 3rd person before.

hmm I think I used the camera node in my player model to position things so it'd be easier to see over the player.

Quote:Actually, it'll lag when you turn but it's based on the player's movement velocity not rotational velocity.


really? I didn't notice any lag, I'll have to run really fast and turn the camera to see :)

Quote:I'm personally, still tweaking it but with this in place you can do pretty much any 3rd person behavior you want.

yep, thanks for posting it.
#9
08/03/2005 (9:01 pm)
Great resource! I really like the perspective this gives. However, my player seems to vibrate an awful lot in this view. Is this expected? Any idea what the problem might be?
#10
08/03/2005 (9:31 pm)
Vibrate huh? I don't have that problem, perhaps it could be the values you used for the lag and decay.
#11
08/03/2005 (9:50 pm)
Jeremy, I used the same values you provided. I will test with some others and see what happens.
#12
08/03/2005 (10:09 pm)
@Robert, there was no vibrating for me...one possible confusion could be this part above:

After:


gCamFXMgr.update( dt );
}



Add:


// Update 3rd person camera offset. Camera update is done
// here as it's a client side only animation.
mCameraOffset -=
(mCameraOffset * mDataBlock->cameraDecay +
mVelocity * mDataBlock->cameraLag) * dt;



I think that you do not want to put that after the closing }, but inside the closing } that might change behavior slightly, I dont' know, I just put it inside the first time as it seemed the right thing to do.
#13
08/03/2005 (10:53 pm)
Mine's outside ... as I put it there. Would be interesting to see a video of the vibration. Could be a lot of things that might cause that.
#14
08/04/2005 (6:13 am)
Mmmmm....I will take a look at the lines Clint suggested and see what I can find. I will see about posting a video as well.
#15
08/04/2005 (4:18 pm)
@robert, given Jeremy's comment those lines I mentioned shouldn't make a difference, must be something else.

I'm upgrading my rating to a 4, as this resource shows you a great and _simple_ way to make a customizable 3rd person camera.
#16
08/05/2005 (3:12 am)
Very cool, thank you posting this Jeremy

EDIT: I've just installed this and I get the same 'vibration' that was mentioned above.
It's actually a movement jitter when walking forward. I tried taking a video with fraps, but
interestingly, the problem went away while recording the video only to return as soon as recording
was stopped.

ANOTHER EDIT: Just discovered the problem. The line: mCameraOffset.set(0,0,0);
was placed in the wrong place as the reference mFalling = false is a little ambiguous in player.cc
the line that it needed to be added after was around line 2571 and I had added it around line
1666 in the running code instead, resulting in jittery running.
#17
08/05/2005 (11:37 am)
Hehe, good find there. The line mFalling = false is pretty generic. I'll post a comment in there.

OK, just went back through my code. The code you're supposed to add after mFalling = false; is about line 829 where you are just initializing.
#18
08/05/2005 (4:28 pm)
Great resource Jeremy! I needed something like this...You're going in the credits if this stays in our project upon release.

Favorite settings are:
cameraLag = 0.5;
cameraDecay = 3.5;
cameraOffset = 0.5;

Anyone have any idea where to look for adjusting the offset along the player's x-axis (left/right)?

Nick
#19
08/05/2005 (4:35 pm)
@Nick, try changing this part:
off->set(0,0,mDataBlock->cameraOffset);

should do it, but try putting something hardcoded in there for the X param to see if it works. like:
off->set(5,0,mDataBlock->cameraOffset);
#20
08/05/2005 (5:32 pm)
Midhir,
Ah, I saw that too (the ambiguity with mFalling....), and was wondering about it, but had not had the chance yet to move the line. Excellent!
Page «Previous 1 2 3 Last »