Quake3World.com
https://www.quake3world.com/forum/

BFP camera code implementation
https://www.quake3world.com/forum/viewtopic.php?f=16&t=54989
Page 1 of 1

Author:  LegendGuard [ 02-05-2023 06:23 AM ]
Post subject:  BFP camera code implementation

I'm implementing BFP camera view, but it doesn't do the same like original Bid For Power (BFP). But AFAIK, the code uses modified Q3 camera parts, it doesn't do the same as ZEQ2-Lite (nothing to do). The camera does a pretty wild flip when flying upside down, have less zoom/more distance than BFP, ... That's badly implemented. Just asking, what should be correct to be the same as BFP camera view?

Video comparising camera implementation and original BFP camera:
https://streamable.com/4gee0d

Code of the camera implementation in CG_OffsetThirdPersonView:
Code:
/*
===============
CG_OffsetThirdPersonView

===============
*/
#define   FOCUS_DISTANCE   512
static void CG_OffsetThirdPersonView( void ) {
   vec3_t      forward, right, up;
   vec3_t      view;
   vec3_t      focusAngles;
   trace_t      trace;
   static vec3_t   mins = { -4, -4, -4 };
   static vec3_t   maxs = { 4, 4, 4 };
   vec3_t      focusPoint;
   float      focusDist;
   float      forwardScale, sideScale;

   // BFP - TODO: Improve camera, when player looks at the ground, the view should
   // be adjusted where the player position, in the screen, is further down like BFP does.
   // The camera isn't using a fixed view

   cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight;

   VectorCopy( cg.refdefViewAngles, focusAngles );

   // if dead, look at killer
   if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
      focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
      cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
   }

   // if ( focusAngles[PITCH] > 45 ) {
   //    focusAngles[PITCH] = 45;      // don't go too far overhead
   // }
   AngleVectors( focusAngles, forward, NULL, NULL );

   VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );

   VectorCopy( cg.refdef.vieworg, view );

   // view[2] += 8;

   // BFP - Third person camera height
   view[2] += cg_thirdPersonHeight.value + 92;

   // BFP - Keep the looking on the ground at the same main focus position
   // if ( !( cg.predictedPlayerState.pm_flags & PMF_FLYING ) ) {
      cg.refdefViewAngles[PITCH] *= 1.55;
   // }

   AngleVectors( cg.refdefViewAngles, forward, right, up );
   
   forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
   sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
   VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
   VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );

   // trace a ray from the origin to the viewpoint to make sure the view isn't
   // in a solid block.  Use an 8 by 8 block to prevent the view from near clipping anything

   // if (!cg_cameraMode.integer) {
      CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );

      if ( trace.fraction != 1.0 ) {
         VectorCopy( trace.endpos, view );

         view[2] += (1.0 - trace.fraction) * 32;
         // try another trace to this position, because a tunnel may have the ceiling
         // close enogh that this is poking out

         CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
         VectorCopy( trace.endpos, view );
      }
   // }
   

   VectorCopy( view, cg.refdef.vieworg );

   // select pitch to look at focus point from vieword
   VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
   focusDist = sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
   if ( focusDist < 1 ) {
      focusDist = 1;   // should never happen
   }
   // cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist );
   cg.refdefViewAngles[PITCH] = focusAngles[PITCH];
   cg.refdefViewAngles[YAW] -= cg_thirdPersonAngle.value;
   //cg.refdefViewAngles[YAW] = focusAngles[YAW];
}

Author:  LegendGuard [ 02-12-2023 08:34 AM ]
Post subject:  Re: BFP camera code implementation

Finally, BFP third person camera implemented! Wooohoooohoho!!!
https://github.com/LegendaryGuard/BFP/c ... 220067e33d

Author:  LegendGuard [ 02-22-2023 03:47 PM ]
Post subject:  Re: BFP camera code implementation

BFP 3rd person camera matches 100% to original BFP!

Moreover, 1st person vis mode is implemented! Let's goooooo!!

Here the 3rd person camera code:

Code:
#define   FOCUS_DISTANCE   512
static void CG_OffsetThirdPersonView( void ) {
   vec3_t      forward, right, up;
   vec3_t      view;
   vec3_t      focusAngles;
   trace_t      trace;
   static vec3_t   mins = { -4, -4, -4 };
   static vec3_t   maxs = { 4, 4, 4 };
   float      forwardScale, sideScale;
   // BFP - Camera setup variables
   vec3_t      overrideOrg;
   float      camAngle, camHeight, camRange;
   // BFP - Fly tilt
   int         cmdNum;
   usercmd_t   cmd;
   // BFP - Last angled for fly tilt angle to move smoothly similar to BFP vanilla
   static float   lastAngled = 0.0f, lastRightAngled = 0.0f, lastUpAngled = 0.0f;
   float      rightAngled, upAngled;

   // BFP - Camera setup
   camAngle  =  cg_thirdPersonAngle.value;
   camHeight =  cg_thirdPersonHeight.value;
   camRange  =  cg_thirdPersonRange.value;
   if ( cg_fixedThirdPerson.integer >= 1 ) { // BFP - Fixed third person camera
      camAngle  =   0.0f;
      camHeight = -60.0f;
      camRange  = 110.0f;
   }
   VectorCopy( cg.refdef.vieworg, overrideOrg );

   // cg.refdef.vieworg[2] += cg.predictedPlayerState.viewheight; // BFP - BFP camera position doesn't use that to move to player's height

   VectorCopy( cg.refdefViewAngles, focusAngles );

   // if dead, look at killer
   if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
      focusAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
      cg.refdefViewAngles[YAW] = cg.predictedPlayerState.stats[STAT_DEAD_YAW];
   }

   AngleVectors( focusAngles, forward, NULL, NULL );

   VectorCopy( cg.refdef.vieworg, view );

   AngleVectors( cg.refdefViewAngles, forward, right, up );

   // BFP - Camera height setup
   VectorMA( overrideOrg, -camHeight, up, overrideOrg );

   forwardScale = cos( camAngle / 180 * M_PI );
   sideScale = sin( camAngle / 180 * M_PI );

   // trace a ray from the origin to the viewpoint to make sure the view isn't
   // in a solid block.  Use an 8 by 8 block to prevent the view from near clipping anything

   // BFP - cg_cameraMode cvar to detect if it's disabled doesn't exist
   // That traces the camera pivot
   CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
   if ( trace.fraction != 1.0 ) {
      // BFP - Use the vector scale to trace something solid and add endpos
      VectorScale( trace.plane.normal, camRange, view );
      VectorAdd( trace.endpos, view, cg.refdef.vieworg );

      view[2] += (1.0 - trace.fraction) * 32;
      // try another trace to this position, because a tunnel may have the ceiling
      // close enogh that this is poking out

      CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
      VectorCopy( trace.endpos, view );
   }

   // BFP - Camera setup
   focusAngles[YAW] -= camAngle;

   // BFP - Fly tilt
   // Get the pressed keys to move left or right
   cmdNum = trap_GetCurrentCmdNumber();
   trap_GetUserCmd( cmdNum, &cmd );

   focusAngles[ROLL] = LERP( lastAngled, 0.0f, (float)(cg.frametime / 1000.00f) * 20.0f );
   rightAngled = LERP( lastRightAngled, 0.0f, (float)(cg.frametime / 1000.00f) * 20.0f );
   upAngled = LERP( lastUpAngled, 0.0f, (float)(cg.frametime / 1000.00f) * 20.0f );

   if ( cg_flytilt.integer >= 1
   && ( cg.predictedPlayerState.pm_flags & PMF_FLYING )
   && ( cg.predictedPlayerState.eFlags & EF_AURA ) && &cmd ) {
      if ( cmd.rightmove < 0 ) { // Left
         focusAngles[ROLL] = LERP( lastAngled, -20.0f, (float)(cg.frametime / 1000.00f) * 15.0f );
         rightAngled = LERP( lastRightAngled, focusAngles[ROLL] - 0.55f, (float)(cg.frametime / 1000.00f) * 15.0f );
         upAngled = LERP( lastUpAngled, -acos( focusAngles[ROLL] / 180 * M_PI ) - 1.7f, (float)(cg.frametime / 1000.00f) * 15.0f );
      } else if ( cmd.rightmove > 0 ) { // Right
         focusAngles[ROLL] = LERP( lastAngled, 20.0f, (float)(cg.frametime / 1000.00f) * 15.0f );
         rightAngled = LERP( lastRightAngled, focusAngles[ROLL] - 0.55f, (float)(cg.frametime / 1000.00f) * 15.0f );
         upAngled = LERP( lastUpAngled, -acos( focusAngles[ROLL] / 180 * M_PI ) - 1.7f, (float)(cg.frametime / 1000.00f) * 15.0f );
      }
   }
   // Last roll where it was "lerped"
   lastAngled = focusAngles[ROLL];
   lastRightAngled = rightAngled;
   lastUpAngled = upAngled;

   VectorCopy( focusAngles, cg.refdefViewAngles );
   // VectorCopy( focusAngles, cg.predictedPlayerState.viewangles ); // For player model, doesn't make sense though :P

   // BFP - NOTE: Applying angles to height and slide (up and right vectors), while rolling with fly tilt, is an odd case, BFP has something that handles up and right vectors  (· ·') *curiosity sweat*
   VectorMA( overrideOrg, -camRange * sideScale + rightAngled, right, cg.refdef.vieworg );
   VectorMA( cg.refdef.vieworg, -camRange * forwardScale, forward, cg.refdef.vieworg );
   VectorMA( cg.refdef.vieworg, upAngled, up, cg.refdef.vieworg );

   // BFP - Trace the camera position when being near to something solid
   CG_Trace( &trace, view, mins, maxs, cg.refdef.vieworg, cg.predictedPlayerState.clientNum, MASK_SOLID );
   if ( trace.fraction != 1.0f ) {
      VectorCopy( trace.endpos, cg.refdef.vieworg );

      cg.refdef.vieworg[2] += ( 1.0f - trace.fraction ) * 32;

      CG_Trace( &trace, view, mins, maxs, cg.refdef.vieworg, cg.predictedPlayerState.clientNum, MASK_SOLID );
      VectorCopy( trace.endpos, cg.refdef.vieworg );
   }
}

Author:  LegendGuard [ 10-02-2023 02:59 AM ]
Post subject:  Re: BFP camera code implementation

Here the part of 1st person vis mode (if you wanna use the code, you will need to use correctly the functions due the difference of the functionality. Look carefully to the implementation in the repository on cg_view.c and cg_players.c):
Code:
void CG_OffsetFirstPersonView( centity_t *cent, refEntity_t *parent, qhandle_t parentModel ) { // BFP - First person setup, originally, Q3 doesn't use these parameters
   float         *origin;
   float         *angles;
   float         bob;
   float         ratio;
   float         delta;
   float         speed;
   float         f;
   vec3_t         predictedVelocity;
   int            timeDelta;
   orientation_t   tagOrient; // BFP - First person vis mode orientation setup
   
   if ( cg.snap->ps.pm_type == PM_INTERMISSION ) {
      return;
   }

   origin = cg.refdef.vieworg;
   angles = cg.refdefViewAngles;

   // if dead, fix the angle and don't add any kick
   if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
      angles[ROLL] = 40;
      angles[PITCH] = -15;
      angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW];
      origin[2] += cg.predictedPlayerState.viewheight;
      return;
   }

   // add angles based on weapon kick
   VectorAdd (angles, cg.kick_angles, angles);

   // add angles based on damage kick
   if ( cg.damageTime ) {
      ratio = cg.time - cg.damageTime;
      if ( ratio < DAMAGE_DEFLECT_TIME ) {
         ratio /= DAMAGE_DEFLECT_TIME;
         angles[PITCH] += ratio * cg.v_dmg_pitch;
         angles[ROLL] += ratio * cg.v_dmg_roll;
      } else {
         ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;
         if ( ratio > 0 ) {
            angles[PITCH] += ratio * cg.v_dmg_pitch;
            angles[ROLL] += ratio * cg.v_dmg_roll;
         }
      }
   }

   // add angles based on velocity
   VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );

   delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]);
   angles[PITCH] += delta * cg_runpitch.value;
   
   delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]);
   angles[ROLL] -= delta * cg_runroll.value;

   // add angles based on bob

   // make sure the bob is visible even at low speeds
   speed = cg.xyspeed > 200 ? cg.xyspeed : 200;

   delta = cg.bobfracsin * cg_bobpitch.value * speed;
   if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
      delta *= 3;      // crouching
   angles[PITCH] += delta;
   delta = cg.bobfracsin * cg_bobroll.value * speed;
   if (cg.predictedPlayerState.pm_flags & PMF_DUCKED)
      delta *= 3;      // crouching accentuates roll
   if (cg.bobcycle & 1)
      delta = -delta;
   angles[ROLL] += delta;

//===================================

   // add view height
   origin[2] += cg.predictedPlayerState.viewheight;

   // smooth out duck height changes
   timeDelta = cg.time - cg.duckTime;
   if ( timeDelta < DUCK_TIME) {
      cg.refdef.vieworg[2] -= cg.duckChange
         * (DUCK_TIME - timeDelta) / DUCK_TIME;
   }

   // add bob height
   bob = cg.bobfracsin * cg.xyspeed * cg_bobup.value;
   if (bob > 6) {
      bob = 6;
   }

   origin[2] += bob;
   
   // BFP - First person vis mode
   // pivot the eye based on a neck length
#if 1
   if ( cg_drawOwnModel.integer >= 1 ) {
#define   NECK_LENGTH      8
      vec3_t         forward, up;

      VectorClear( cg.refdefViewAngles );
      
      if ( CG_GetTagOrientationFromPlayerEntityParentModel( cent, parent, parentModel, "tag_head", &tagOrient ) ) {
         VectorCopy( tagOrient.origin, cg.refdef.vieworg );
         cg.refdef.vieworg[2] -= NECK_LENGTH;
         AngleVectors( cg.refdefViewAngles, forward, NULL, up );
         VectorMA( cg.refdef.vieworg, -1, forward, cg.refdef.vieworg );
         VectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg );
      }
   }
#endif

   // add fall height
   delta = cg.time - cg.landTime;
   if ( delta < LAND_DEFLECT_TIME ) {
      f = delta / LAND_DEFLECT_TIME;
      cg.refdef.vieworg[2] += cg.landChange * f;
   } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
      delta -= LAND_DEFLECT_TIME;
      f = 1.0 - ( delta / LAND_RETURN_TIME );
      cg.refdef.vieworg[2] += cg.landChange * f;
   }

   // add step offset
   CG_StepOffset();

   // add kick offset

   VectorAdd (origin, cg.kick_origin, origin);
}

Page 1 of 1 All times are UTC - 8 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/