Game Development Community

over the shoulder camp(GOW) is it possible in script or alter source?

by Kory Imaginism · in Torque 3D Professional · 03/18/2010 (5:00 pm) · 7 replies

ok im trying to change the third person camera to an over the shoulder cam as seen in gow and many others.

i have located in source where the camera is actually being offset (i think) my c++ is not great. if i can accoplish the same thing in script, with model rotation and everything with out modifing fp or 3rdp camera in source would be great, all i need is a starting point to functions and where to insert them in my code. but heres the cpp code i found. in shapebase.cpp
void ShapeBase::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)
   {
      F32 min,max;
      Point3F offset;
      MatrixF eye,rot;
      getCameraParameters(&min,&max,&offset,&rot);
      getRenderEyeTransform(&eye);
      mat->mul(eye,rot);

      // Use the eye transform to orient the camera
      VectorF vp,vec;
      vp.x = vp.z = 0;
      vp.y = -(max - min) * *pos;
      eye.mulV(vp,&vec);

      // Use the camera node's pos.
      Point3F osp,sp;
      if (mDataBlock->cameraNode != -1) {
         mShapeInstance->mNodeTransforms[mDataBlock->cameraNode].getColumn(3,&osp);

         // Scale the camera position before applying the transform
         const Point3F& scale = getScale();
         osp.convolve( scale );

         getRenderTransform().mulP(osp,&sp);
      }
      else
         getRenderTransform().getColumn(3,&sp);

      // Make sure we don't extend the camera into anything solid
      Point3F ep = sp + vec + offset;
      disableCollision();
      if (isMounted())
         getObjectMount()->disableCollision();
      RayInfo collision;
      if( mContainer && mContainer->castRay(sp, ep,
                              (0xFFFFFFFF & ~(WaterObjectType      |
                                              GameBaseObjectType   |
                                              TriggerObjectType    |
                                              DefaultObjectType)),
                              &collision) == true) {
         F32 vecLenSq = vec.lenSquared();
         F32 adj = (-mDot(vec, collision.normal) / vecLenSq) * 0.1;
         F32 newPos = getMax(0.0f, collision.t - adj);
         if (newPos == 0.0f)
            eye.getColumn(3,&ep);
         else
            ep = sp + offset + (vec * newPos);
      }
      mat->setColumn(3,ep);
      if (isMounted())
         getObjectMount()->enableCollision();
      enableCollision();
   }
   else
   {
      getRenderEyeTransform(mat);
   }

   // Apply Camera FX.
   mat->mul( gCamFXMgr.getTrans() );
}

any help will be greatly appreciated. maybe we can actually make different default camera views.

#1
03/18/2010 (5:04 pm)
sorry for double post, browser really messed up there ha
#2
03/18/2010 (7:22 pm)
Make a model with an eye-node over the shoulder.
#3
03/19/2010 (1:00 am)
That'll work fine as long as you don't need to be able to toggle to first person. Definitely the easiest way, as there's already code in place to fix the aim offset.

Just make sure to set correctMuzzleVector = true in your image datablocks. That code looks like it should be working fine, but it seems to only cast the ray 500 units from the eye-node. If you need to adjust this for longer-ranged guns, it's in ShapeBase::getCorrectedAim.

From the getCameraTransform code, it looks like the cam-node is still supported for 3rd person, so you could place it at the appropriate offset in your model. In this case you'll need to make some additional changes to fix the aim offset.

Doesn't look like it would be difficult to modify ShapeBase::getCorrectedAim to correctly determine whether to use the eye or camera position depending on the view state (then need to alter ShapeBase::getMuzzleVector to allow it to call getCorrectedAim in 3rd person). Like so:

void ShapeBase::getMuzzleVector(U32 imageSlot,VectorF* vec)
{
   MatrixF mat;
   getMuzzleTransform(imageSlot,&mat);

   MountedImage& image = mMountedImageList[imageSlot];
   if (image.dataBlock->correctMuzzleVector)
      if (GameConnection * gc = getControllingClient())
         if (/*Remove/Comment:*//*gc->isFirstPerson() && */!gc->isAIControlled())
            if (getCorrectedAim(mat, vec))
               return;

   mat.getColumn(1,vec);
}

and then, the changes are just up at the top:

bool ShapeBase::getCorrectedAim(const MatrixF& muzzleMat, VectorF* result)
{
   const F32 pullInD = 6.0;
   const F32 maxAdjD = 500;

   VectorF  aheadVec(0, maxAdjD, 0);

   MatrixF  eyeMat;
   Point3F  eyePos;
   getEyeTransform(&eyeMat);
   // [EDIT]: Use third person camera transform.
   if (isFirstPerson())
      getEyeTransform(&eyeMat);
   else
   {
      F32 tempPos = 1.0; // related to the push-back effect (?), may cause aiming issues if the camera is being pushed by collision.
      getCameraTransform(&tempPos, &eyeMat);
   }
   // [/EDIT]
   eyeMat.getColumn(3, &eyePos);
   eyeMat.mulV(aheadVec);
   Point3F  aheadPoint = (eyePos + aheadVec);

   !(Truncated function, no edits beyond this point)!

getCameraTransform seems to take a value between 0 and 1 which I believe is connected to the pushback effect. I think this effect is client-side only, so forcing it to 1 is probably the best bet. Totally untested code; this is just what I would do to try to get this working.

If that seems too difficult, you could also do this calculation in script during the onFire event (scripts/server/weapon.cs). Just get the 3rd person camera position and vector and do the raycast (should be plenty of examples in the scripts for doing this), subtract the muzzle position from the raycast hit position, normalize, and plug that into the firing calculations instead of the muzzleVector. The only issue here is that I don't see any script function to get the 3rd person camera position on a server object (because the code which pushes the camera forward towards the player is only executed client-side?).
#4
03/19/2010 (7:11 am)
thanks for the break down, what I'm actually wanting to do is add the over the shoulder to the default 3rd person camera. Also to keep the default 1st person camera in as well. Pat said to make an eye node but will that only work for a 3rd person, or will it also allow for the default 1st person camera also! Any help would be appreciated!

Thanks
#5
03/19/2010 (9:28 am)
I got a GOW-like camera with very little changes, by having the player in 3rd person mode and adding a cameraOffset value to the datablock and adding it to the camera position returned by Player::getCameraTransform()
#6
03/19/2010 (9:32 am)
@Manoel
Thanks cool, I'm having problems with it (of course I'm not the best programmer) but I was wondering if you would be willing to share your code? If not then are you willing to sell it? If you want to you can contact me at jstanleynwo@yahoo.com.

Thanks in advance...
#7
03/20/2010 (11:12 am)
My problem is, without changing the the default 1st person camera, how do I add over the shoulder view to the default 3rd person camera? I tried to do some of the suggestion but it effects both. If someone can help me keep the default 1st person camera but change the 3rd person camera it would help me solve my problem. Any suggestion would be appreciated!
Thanks in advance

KJ