Third-person camera

From Valve Developer Community
Revision as of 22:54, 3 July 2005 by SubKamran (talk | contribs) (Complete third person camera mod)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Overview

This tutorial will teach you how to create a third person camera perspective with the following features:

  • Collision detection
  • Mouse-wheel zooming
  • Transparency when too close

Techniques Used

  • Hiding view model (Gordon's hands) in third person view
  • Hiding weapon in third person (or first) view
  • Hiding crosshair in third person (or first) view
  • Hiding player model when in first person view
  • Adding your own keyboard command

Thank you to the Third Person Camera articles on The Wavelength. This tutorial is a combination of both with a few user friendly modifications.

Step 1: in_camera.cpp

This tutorial assumes you are creating a Half-Life 2 Single Player modification and using Visual Studio .NET 2003.

Open up Game_Sdk.sln in VS.NET.

The first step will be to change the camera code inside in_camera.cpp.

Comment the line:

#define CAM_MIN_DIST			36.0
// #define CAM_MIN_DIST    36.0

Under the line #define YAW_MIN -135.0

Add:

in_camera.cpp

#define CAM_MIN_DIST			16.0 // Don't let the camera get any closer than ...
#define CAM_SWITCH_DIST			96.0 // the default distance the camera will be when switching from 1st to 3rd person
#define CAM_MAX_DIST			96.0 // ... or any farther away than ...
#define CAM_HULL_OFFSET			6.0 // the size of the bounding hull used for collision checking
#define START_TRANS_DIST		40.0       // how close to player when it starts making model translucent
#define TRANS_DELTA			1.9921875       // Set to 255 / START_TRANS_DIST

Replace:

static ConVar cam_idealyaw( "cam_idealyaw", "90", FCVAR_ARCHIVE );	 // thirdperson yaw

With:

static ConVar cam_idealyaw( "cam_idealyaw", "0", FCVAR_ARCHIVE );	 // thirdperson yaw | fix side view bug

Here, all we are doing is change the CAM_MIN_DIST variable and adding our own variables to use later in the code. Instead of commenting out CAM_MIN_DIST you can just delete it. We also fixed a bug that makes the camera view the player from the side and not from behind.

Replace this section (under the function CAM_Think):

if( !m_fCameraInThirdPerson )
      return;

With this:

// Toggle first/3rd person, check every 0.5 seconds
	if(gpGlobals->curtime >= mf_NextSwitch) {
		if(input->KeyState(&in_camchange))
		{
			mf_NextSwitch = gpGlobals->curtime + 0.5; // Check if the key has been pressed every 0.5 seconds
			if(!m_fCameraInThirdPerson)
			{
				CAM_ToThirdPerson();
			} else {
				CAM_ToFirstPerson();
			}
		}
	}

	if( !m_fCameraInThirdPerson )
	{
		// If in FP mode, transparent
		// This is sort of a hack since when the map first loads you ARE transparent...
		// This is for when you switch from 3rd to 1st.
		if(C_BasePlayer::GetLocalPlayer() ) {
			C_BasePlayer::GetLocalPlayer()->SetRenderMode( kRenderTransColor );
			C_BasePlayer::GetLocalPlayer()->SetRenderColorA(0);
		}

		return;
	}

Here we tell the code when to check if the user has pressed the in_camchange button (which we will define later on). We have also put in some code that will turn the player transparent when you switch FROM 3rd person TO 1st person. This is to prevent the player model from getting in the way of the camera.

(NOTE: You can change the 0.5 on this line: mf_NextSwitch = gpGlobals->curtime + 0.5 to a smaller number if you want to check more frequently if a user has pressed the "in_camchange" key.

Within this piece of code:

else if( input->KeyState( &cam_out ) ) {
	dist += CAM_DIST_DELTA;

}

Add right after dist += CAM_DIST_DELTA;:

		// Prevent the cam_out from going any further
		// NOTE: Without this, it _appears_ it's not moving, but
		// the transparency changes so it is... this fixes it.
		if( dist > CAM_MAX_DIST )
			dist = CAM_MAX_DIST;

Replace this:

if( cam_snapto.GetInt() )
	{
		camAngles[ YAW ] = cam_idealyaw.GetFloat() + viewangles[ YAW ];
		camAngles[ PITCH ] = cam_idealpitch.GetFloat() + viewangles[ PITCH ];
		camAngles[ 2 ] = cam_idealdist.GetFloat();
	}
	else
        {
         // code already here
}

With:

    if( cam_snapto.GetInt() )
	{
		camAngles[ YAW ] = cam_idealyaw.GetFloat() + viewangles[ YAW ];
		camAngles[ PITCH ] = cam_idealpitch.GetFloat() + viewangles[ PITCH ];
		camAngles[ 2 ] = cam_idealdist.GetFloat();
	}
	else
    {
        if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw.GetFloat() )
            camAngles[ YAW ] = MoveToward( camAngles[ YAW ], cam_idealyaw.GetFloat() + viewangles[ YAW ], CAM_ANGLE_SPEED );
 
        if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch.GetFloat() )
            camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ], cam_idealpitch.GetFloat() + viewangles[ PITCH ], CAM_ANGLE_SPEED );
 
        if( !C_BasePlayer::GetLocalPlayer() ) {
            // this code can be hit from the main menu, where it will crash
            camAngles[ 2 ] = dist; // if there's no localplayer to calc from
        }
        else {
            trace_t tr;
            float adjDist = dist;
            C_BasePlayer* localPlayer = C_BasePlayer::GetLocalPlayer();

            Vector origin = localPlayer->GetLocalOrigin(); // find our player's origin
            origin += localPlayer->GetViewOffset(); // and from there, his eye position

            AngleVectors( QAngle(camAngles.x, camAngles.y, camAngles.z),
                         &camForward, NULL, NULL ); // get the forward vector

            UTIL_TraceHull( origin, origin - (camForward * dist),
                            CAM_HULL_MIN, CAM_HULL_MAX,
                            MASK_SOLID, NULL, &tr ); // use our previously #defined hull to collision trace

            if( tr.fraction < 1.0 ) {
                adjDist = dist * tr.fraction; // move the camera closer if it hit something
            }
            else {
                adjDist = dist; // no trace hit, use cam_idealdist without adjusting it
            }

			if ( adjDist < START_TRANS_DIST ) {
				localPlayer->SetRenderMode( kRenderTransColor ); // make him translucent
				localPlayer->SetRenderColorA( (byte)(adjDist * TRANS_DELTA) ); // closer = less opacity
			}

            if( adjDist < CAM_MIN_DIST )
                adjDist = CAM_MIN_DIST; // clamp up to minimum

            if( adjDist > CAM_MAX_DIST )
                adjDist = CAM_MAX_DIST; // clamp down to maximum

            camAngles[ 2 ] = adjDist;
        }
    }

Here we are checking for collision and handling transparency.

In the function void CInput::CAM_ToThirdPerson(void)

Change:

m_vecCameraOffset[ 2 ] = CAM_MIN_DIST;

To:

m_vecCameraOffset[ 2 ] = CAM_SWITCH_DIST; // When switching, move camera to our specified switch distance

Add underneath that:

		// Set model to 'player' because when a map first loads
		// it doesn't set the model... sort of a hack.
		C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
		pPlayer->SetModel("player");

Step 2: c_basecombatweapon.cpp

Open the file c_basecombatweapon.cpp under the client project.

Underneath this:

// check if local player chases owner of this weapon in first person
C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();

Add:

// Get rid of view model, crosshair and weapon in 3rd person
	// Once we actually get weapons working, we'll let it draw only the weapon
	if (localplayer)
	{
		if (input->CAM_IsThirdPerson())
		{
			SetModel( GetWorldModel() );
			localplayer->m_Local.m_iHideHUD |= HIDEHUD_CROSSHAIR; // Hide crosshair, remove this line if you still want to see it.
			return false; // Comment this and uncomment the line underneath if you want to be 
                                      // able to do weapon things (it will display the weapon).
			//return BaseClass:: DrawModel( flags );
		}
	}

Here we have told the code to hide the view model (Gordon's hands) and the crosshair when in third person view. The way the code is written above, the weapon model is also hidden in 3rd person view. If you want your mod to be able to show the weapon in third person view, comment return false; and uncomment return BaseClass:: DrawModel( flags );.

On how to go about positioning weapons and whatnot for 3rd person view, this tutorial does not cover that and assumes you would like to hide the weapon in 3rd person view.

Step 3: in_main.cpp

Open up in_main.cpp in the client project.

Underneath the line kbutton_t in_graph;, add:

kbutton_t	in_camchange;

Underneath:

void IN_ZoomDown(void) {KeyDown(&in_zoom);}
void IN_ZoomUp(void) {KeyUp(&in_zoom);}

Add:

void IN_CamChangeDown(void) {KeyDown(&in_camchange);}
void IN_CamChangeUp(void) {KeyUp(&in_camchange);}

Underneath CalcButtonBits( bits, IN_ZOOM, s_ClearInputState, &in_zoom, bResetState );, add:

CalcButtonBits( bits, IN_CAMCHANGE, s_ClearInputState, &in_camchange, bResetState );

Underneath:

static ConCommand startzoom("+zoom", IN_ZoomDown);
static ConCommand endzoom("-zoom", IN_ZoomUp);

Add:

static ConCommand startcamchange("+camchange", IN_CamChangeDown);
static ConCommand endcamchange("-camchange", IN_CamChangeUp);

Step 4: input.h & in_buttons.h

Open the file in_buttons.h under Header Files under the client project.

Underneath #define IN_BULLRUSH (1 << 22), add:

#define IN_CAMCHANGE	(1 << 23)

NOTE: If you plan on adding more keyboard commands, you can just add:

#define {command} (1 << {int}

Where "{int}" is the next integer (in this case, 24). Note also that {int} cannot go above 32 because Valve set it up that way.

Open the file input.h under Header Files under the client project.

Underneath:

extern kbutton_t in_back;

Add:

extern kbutton_t in_camchange;

Step 5: kb_act.lst

Open up kb_act.lst in your SourceMods/{your_mod}/scripts/ folder. Now, anywhere you want the label to appear, add:

"+camchange"			"Toggle 3rd/1st Person View"

You can add a token in your {mod_name}_english.txt also and refer to that (e.g. "#Mod_CameraToggle").

Conclusion

You should now have a working third person / first person hybrid. If you want to add a default key for "+camchange", refer to The Default Keyboard Layout wiki article.

Reference

Reference code

in_camera.cpp

Your finished in_camera.cpp should now look like:

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Handles 3rd and 1st Person Views
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hud.h"
#include "kbutton.h"
#include "input.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

//-------------------------------------------------- Constants

#define CAM_DIST_DELTA 1.0
#define CAM_ANGLE_DELTA 2.5
#define CAM_ANGLE_SPEED 2.5
#define CAM_ANGLE_MOVE .5
#define MAX_ANGLE_DIFF 10.0
#define PITCH_MAX 90.0
#define PITCH_MIN 0
#define YAW_MAX  135.0
#define YAW_MIN	 -135.0

#define CAM_MIN_DIST			16.0 // Don't let the camera get any closer than ...
#define CAM_SWITCH_DIST			96.0 // the default distance when switching from 1st to 3rd
#define CAM_MAX_DIST			96.0 // ... or any farther away than ...
#define CAM_HULL_OFFSET			6.0 // the size of the bounding hull used for collision checking
#define START_TRANS_DIST		40.0       // how close to player when it starts making model translucent
#define TRANS_DELTA				1.9921875       // Set to 255 / START_TRANS_DIST

static Vector CAM_HULL_MIN(-CAM_HULL_OFFSET,-CAM_HULL_OFFSET,-CAM_HULL_OFFSET);
static Vector CAM_HULL_MAX( CAM_HULL_OFFSET, CAM_HULL_OFFSET, CAM_HULL_OFFSET);

//-------------------------------------------------- Global Variables

static ConVar cam_command( "cam_command", "0", FCVAR_CHEAT | FCVAR_ARCHIVE );	 // tells camera to go to thirdperson
static ConVar cam_snapto( "cam_snapto", "0", FCVAR_ARCHIVE );	 // snap to thirdperson view
static ConVar cam_idealyaw( "cam_idealyaw", "0", FCVAR_ARCHIVE );	 // thirdperson yaw
static ConVar cam_idealpitch( "cam_idealpitch", "0", FCVAR_ARCHIVE );	 // thirperson pitch
static ConVar cam_idealdist( "cam_idealdist", "64", FCVAR_ARCHIVE );	 // thirdperson distance

static ConVar c_maxpitch( "c_maxpitch", "90", FCVAR_ARCHIVE );
static ConVar c_minpitch( "c_minpitch", "0", FCVAR_ARCHIVE );
static ConVar c_maxyaw( "c_maxyaw",   "135", FCVAR_ARCHIVE );
static ConVar c_minyaw( "c_minyaw",   "-135", FCVAR_ARCHIVE );
static ConVar c_maxdistance( "c_maxdistance",   "200", FCVAR_ARCHIVE );
static ConVar c_mindistance( "c_mindistance",   "30", FCVAR_ARCHIVE );
static ConVar c_orthowidth( "c_orthowidth",   "100", FCVAR_ARCHIVE );
static ConVar c_orthoheight( "c_orthoheight",   "100", FCVAR_ARCHIVE );

static kbutton_t cam_pitchup, cam_pitchdown, cam_yawleft, cam_yawright;
static kbutton_t cam_in, cam_out, cam_move;

float mf_NextSwitch;

// API Wrappers

/*
==============================
CAM_ToThirdPerson

==============================
*/
void CAM_ToThirdPerson(void)
{
	input->CAM_ToThirdPerson();
}

/*
==============================
CAM_ToFirstPerson

==============================
*/
void CAM_ToFirstPerson(void) 
{ 
	input->CAM_ToFirstPerson();
}

/*
==============================
CAM_ToOrthographic

==============================
*/
void CAM_ToOrthographic(void) 
{ 
	input->CAM_ToOrthographic();
}

/*
==============================
CAM_StartMouseMove

==============================
*/
void CAM_StartMouseMove( void )
{
	input->CAM_StartMouseMove();
}

/*
==============================
CAM_EndMouseMove

==============================
*/
void CAM_EndMouseMove( void )
{
	input->CAM_EndMouseMove();
}

/*
==============================
CAM_StartDistance

==============================
*/
void CAM_StartDistance( void )
{
	input->CAM_StartDistance();
}

/*
==============================
CAM_EndDistance

==============================
*/
void CAM_EndDistance( void )
{
	input->CAM_EndDistance();
}

/*
==============================
CAM_ToggleSnapto

==============================
*/
void CAM_ToggleSnapto( void )
{ 
	cam_snapto.SetValue( !cam_snapto.GetInt() );
}


/*
==============================
MoveToward

==============================
*/
float MoveToward( float cur, float goal, float maxspeed )
{
	if( cur != goal )
	{
		if( abs( cur - goal ) > 180.0 )
		{
			if( cur < goal )
				cur += 360.0;
			else
				cur -= 360.0;
		}

		if( cur < goal )
		{
			if( cur < goal - 1.0 )
				cur += ( goal - cur ) / 4.0;
			else
				cur = goal;
		}
		else
		{
			if( cur > goal + 1.0 )
				cur -= ( cur - goal ) / 4.0;
			else
				cur = goal;
		}
	}


	// bring cur back into range
	if( cur < 0 )
		cur += 360.0;
	else if( cur >= 360 )
		cur -= 360;

	return cur;
}

/*
==============================
CAM_Think

==============================
*/
void CInput::CAM_Think( void )
{
	Vector origin;
	Vector ext, pnt, camForward, camRight, camUp;
	float dist;
	Vector camAngles;
	float flSensitivity;
	QAngle viewangles;
	
	switch( cam_command.GetInt() )
	{
	case CAM_COMMAND_TOTHIRDPERSON:
		CAM_ToThirdPerson();
		break;
		
	case CAM_COMMAND_TOFIRSTPERSON:
		CAM_ToFirstPerson();
		break;
		
	case CAM_COMMAND_NONE:
	default:
		break;
	}
	
	// Toggle first/3rd person
	if(gpGlobals->curtime >= mf_NextSwitch) {
		if(input->KeyState(&in_camchange))
		{
			mf_NextSwitch = gpGlobals->curtime + 0.5;
			if(!m_fCameraInThirdPerson)
			{
				CAM_ToThirdPerson();
			} else {
				CAM_ToFirstPerson();
			}
		}
	}

	if( !m_fCameraInThirdPerson )
	{
		// If in FP mode, transparent
		// This is sort of a hack since when the map first loads you ARE transparent...
		// This is for when you switch from 3rd to 1st.
		if(C_BasePlayer::GetLocalPlayer() ) {
			C_BasePlayer::GetLocalPlayer()->SetRenderMode( kRenderTransColor );
			C_BasePlayer::GetLocalPlayer()->SetRenderColorA(0);
		}

		return;
	}		
	
	camAngles[ PITCH ] = cam_idealpitch.GetFloat();
	camAngles[ YAW ] = cam_idealyaw.GetFloat();
	dist = cam_idealdist.GetFloat();
	//
	//movement of the camera with the mouse
	//
	if (m_fCameraMovingWithMouse)
	{
		int cpx, cpy;
		
		//get windows cursor position
		GetMousePos (cpx, cpy);
		
		m_nCameraX = cpx;
		m_nCameraY = cpy;
		
		//check for X delta values and adjust accordingly
		//eventually adjust YAW based on amount of movement
		//don't do any movement of the cam using YAW/PITCH if we are zooming in/out the camera	
		if (!m_fCameraDistanceMove)
		{
			int x, y;
			GetWindowCenter( x,  y );
			
			//keep the camera within certain limits around the player (ie avoid certain bad viewing angles)  
			if (m_nCameraX>x)
			{
				//if ((camAngles[YAW]>=225.0)||(camAngles[YAW]<135.0))
				if (camAngles[YAW]<c_maxyaw.GetFloat())
				{
					camAngles[ YAW ] += (CAM_ANGLE_MOVE)*((m_nCameraX-x)/2);
				}
				if (camAngles[YAW]>c_maxyaw.GetFloat())
				{
					
					camAngles[YAW]=c_maxyaw.GetFloat();
				}
			}
			else if (m_nCameraX<x)
			{
				//if ((camAngles[YAW]<=135.0)||(camAngles[YAW]>225.0))
				if (camAngles[YAW]>c_minyaw.GetFloat())
				{
					camAngles[ YAW ] -= (CAM_ANGLE_MOVE)* ((x-m_nCameraX)/2);
					
				}
				if (camAngles[YAW]<c_minyaw.GetFloat())
				{
					camAngles[YAW]=c_minyaw.GetFloat();
					
				}
			}
			
			//check for y delta values and adjust accordingly
			//eventually adjust PITCH based on amount of movement
			//also make sure camera is within bounds
			if (m_nCameraY > y)
			{
				if(camAngles[PITCH]<c_maxpitch.GetFloat())
				{
					camAngles[PITCH] +=(CAM_ANGLE_MOVE)* ((m_nCameraY-y)/2);
				}
				if (camAngles[PITCH]>c_maxpitch.GetFloat())
				{
					camAngles[PITCH]=c_maxpitch.GetFloat();
				}
			}
			else if (m_nCameraY<y)
			{
				if (camAngles[PITCH]>c_minpitch.GetFloat())
				{
					camAngles[PITCH] -= (CAM_ANGLE_MOVE)*((y-m_nCameraY)/2);
				}
				if (camAngles[PITCH]<c_minpitch.GetFloat())
				{
					camAngles[PITCH]=c_minpitch.GetFloat();
				}
			}
			
			//set old mouse coordinates to current mouse coordinates
			//since we are done with the mouse
			
			if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 )
			{
				m_nCameraOldX=m_nCameraX*flSensitivity;
				m_nCameraOldY=m_nCameraY*flSensitivity;
			}
			else
			{
				m_nCameraOldX=m_nCameraX;
				m_nCameraOldY=m_nCameraY;
			}

			ResetMouse();
		}
	}
	
	//Nathan code here
	if( input->KeyState( &cam_pitchup ) )
		camAngles[ PITCH ] += CAM_ANGLE_DELTA;
	else if( input->KeyState( &cam_pitchdown ) )
		camAngles[ PITCH ] -= CAM_ANGLE_DELTA;
	
	if( input->KeyState( &cam_yawleft ) )
		camAngles[ YAW ] -= CAM_ANGLE_DELTA;
	else if( input->KeyState( &cam_yawright ) )
		camAngles[ YAW ] += CAM_ANGLE_DELTA;
	
	if( input->KeyState( &cam_in ) )
	{
		dist -= CAM_DIST_DELTA;
		if( dist < CAM_MIN_DIST )
		{
			// If we go back into first person, reset the angle
			camAngles[ PITCH ] = 0;
			camAngles[ YAW ] = 0;
			dist = CAM_MIN_DIST;
		}
		
	}
	else if( input->KeyState( &cam_out ) ) {
		dist += CAM_DIST_DELTA;

		// Prevent the cam_out from going any further
		// NOTE: Without this, it _appears_ it's not moving, but
		// the transparency changes so it is... this fixes it.
		if( dist > CAM_MAX_DIST )
			dist = CAM_MAX_DIST;
	}

	if (m_fCameraDistanceMove)
	{
		int x, y;
		GetWindowCenter( x, y );

		if (m_nCameraY>y)
		{
			if(dist<c_maxdistance.GetFloat())
			{
				dist +=CAM_DIST_DELTA * ((m_nCameraY-y)/2);
			}
			if (dist>c_maxdistance.GetFloat())
			{
				dist=c_maxdistance.GetFloat();
			}
		}
		else if (m_nCameraY<y)
		{
			if (dist>c_mindistance.GetFloat())
			{
				dist -= (CAM_DIST_DELTA)*((y-m_nCameraY)/2);
			}
			if (dist<c_mindistance.GetFloat())
			{
				dist=c_mindistance.GetFloat();
			}
		}
		//set old mouse coordinates to current mouse coordinates
		//since we are done with the mouse
		m_nCameraOldX=m_nCameraX*gHUD.GetSensitivity();
		m_nCameraOldY=m_nCameraY*gHUD.GetSensitivity();
		ResetMouse();
	}
	
	// update ideal
	cam_idealpitch.SetValue( camAngles[ PITCH ] );
	cam_idealyaw.SetValue( camAngles[ YAW ] );
	cam_idealdist.SetValue( dist );
	
	// Move towards ideal
	VectorCopy( m_vecCameraOffset, camAngles );
	
	engine->GetViewAngles( viewangles );
	
	if( cam_snapto.GetInt() )
	{
		camAngles[ YAW ] = cam_idealyaw.GetFloat() + viewangles[ YAW ];
		camAngles[ PITCH ] = cam_idealpitch.GetFloat() + viewangles[ PITCH ];
		camAngles[ 2 ] = cam_idealdist.GetFloat();
	}
	else
    {
        if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw.GetFloat() )
            camAngles[ YAW ] = MoveToward( camAngles[ YAW ], cam_idealyaw.GetFloat() + viewangles[ YAW ], CAM_ANGLE_SPEED );
 
        if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch.GetFloat() )
            camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ], cam_idealpitch.GetFloat() + viewangles[ PITCH ], CAM_ANGLE_SPEED );
 
        if( !C_BasePlayer::GetLocalPlayer() ) {
            // this code can be hit from the main menu, where it will crash
            camAngles[ 2 ] = dist; // if there's no localplayer to calc from
        }
        else {
            trace_t tr;
            float adjDist = dist;
            C_BasePlayer* localPlayer = C_BasePlayer::GetLocalPlayer();

            Vector origin = localPlayer->GetLocalOrigin(); // find our player's origin
            origin += localPlayer->GetViewOffset(); // and from there, his eye position

            AngleVectors( QAngle(camAngles.x, camAngles.y, camAngles.z),
                         &camForward, NULL, NULL ); // get the forward vector

            UTIL_TraceHull( origin, origin - (camForward * dist),
                            CAM_HULL_MIN, CAM_HULL_MAX,
                            MASK_SOLID, NULL, &tr ); // use our previously #defined hull to collision trace

            if( tr.fraction < 1.0 ) {
                adjDist = dist * tr.fraction; // move the camera closer if it hit something
            }
            else {
                adjDist = dist; // no trace hit, use cam_idealdist without adjusting it
            }

			if ( adjDist < START_TRANS_DIST ) {
				localPlayer->SetRenderMode( kRenderTransColor ); // make him translucent
				localPlayer->SetRenderColorA( (byte)(adjDist * TRANS_DELTA) ); // closer = less opacity
			}

            if( adjDist < CAM_MIN_DIST )
                adjDist = CAM_MIN_DIST; // clamp up to minimum

            if( adjDist > CAM_MAX_DIST )
                adjDist = CAM_MAX_DIST; // clamp down to maximum

            camAngles[ 2 ] = adjDist;
        }
    }

    m_vecCameraOffset[ 0 ] = camAngles[ 0 ];
    m_vecCameraOffset[ 1 ] = camAngles[ 1 ];
    m_vecCameraOffset[ 2 ] = camAngles[ 2 ];
}

extern void KeyDown( kbutton_t *b, bool bIgnoreKey = false );
extern void KeyUp( kbutton_t *b, bool bIgnoreKey = false );

void CAM_PitchUpDown(void) { KeyDown( &cam_pitchup ); }
void CAM_PitchUpUp(void) { KeyUp( &cam_pitchup ); }
void CAM_PitchDownDown(void) { KeyDown( &cam_pitchdown ); }
void CAM_PitchDownUp(void) { KeyUp( &cam_pitchdown ); }
void CAM_YawLeftDown(void) { KeyDown( &cam_yawleft ); }
void CAM_YawLeftUp(void) { KeyUp( &cam_yawleft ); }
void CAM_YawRightDown(void) { KeyDown( &cam_yawright ); }
void CAM_YawRightUp(void) { KeyUp( &cam_yawright ); }
void CAM_InDown(void) { KeyDown( &cam_in ); }
void CAM_InUp(void) { KeyUp( &cam_in ); }
void CAM_OutDown(void) { KeyDown( &cam_out ); }
void CAM_OutUp(void) { KeyUp( &cam_out ); }

/*
==============================
CAM_ToThirdPerson

==============================
*/
void CInput::CAM_ToThirdPerson(void)
{ 
	QAngle viewangles;

// Do allow third person in TF2 for now
#if !defined( TF2_CLIENT_DLL ) && !defined( CSTRIKE_DLL )

#if !defined( _DEBUG )
	if ( gpGlobals->maxClients > 1 )
	{
		// no thirdperson in multiplayer.
		return;
	}
#endif

#endif

	engine->GetViewAngles( viewangles );

	if( !m_fCameraInThirdPerson )
	{		
		m_fCameraInThirdPerson = true;

		
		m_vecCameraOffset[ YAW ] = viewangles[ YAW ]; 
		m_vecCameraOffset[ PITCH ] = viewangles[ PITCH ]; 
		m_vecCameraOffset[ 2 ] = CAM_SWITCH_DIST; 

		// Set model to player because when a map first loads
		// it doesn't set the model... sort of a hack.
		C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
		pPlayer->SetModel("player");
	}

	cam_command.SetValue( 0 );
}

/*
==============================
CAM_ToFirstPerson

==============================
*/
void CInput::CAM_ToFirstPerson(void)
{
	m_fCameraInThirdPerson = false;
	cam_command.SetValue( 0 );
}

/*
==============================
CAM_ToFirstPerson

==============================
*/
bool CInput::CAM_IsOrthographic(void) const
{
	return m_CameraIsOrthographic;
}


/*
==============================
CAM_ToFirstPerson

==============================
*/
void CInput::CAM_OrthographicSize(float& w, float& h) const
{
	w = c_orthowidth.GetFloat(); h = c_orthoheight.GetFloat();
}


/*
==============================
CAM_ToFirstPerson

==============================
*/
void CInput::CAM_ToOrthographic(void)
{	
	m_fCameraInThirdPerson = false;
	m_CameraIsOrthographic = true;
	cam_command.SetValue( 0 );
}

/*
==============================
CAM_StartMouseMove

==============================
*/
void CInput::CAM_StartMouseMove(void)
{
	float flSensitivity;
		
	//only move the cam with mouse if we are in third person.
	if ( m_fCameraInThirdPerson )
	{
		//set appropriate flags and initialize the old mouse position
		//variables for mouse camera movement
		if (!m_fCameraMovingWithMouse)
		{
			int cpx, cpy;

			m_fCameraMovingWithMouse=true;
			m_fCameraInterceptingMouse=true;
			
			GetMousePos(cpx, cpy);

			m_nCameraX = cpx;
			m_nCameraY = cpy;

			if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 )
			{
				m_nCameraOldX=m_nCameraX*flSensitivity;
				m_nCameraOldY=m_nCameraY*flSensitivity;
			}
			else
			{
				m_nCameraOldX=m_nCameraX;
				m_nCameraOldY=m_nCameraY;
			}
		}
	}
	//we are not in 3rd person view..therefore do not allow camera movement
	else
	{   
		m_fCameraMovingWithMouse=false;
		m_fCameraInterceptingMouse=false;
	}
}

/*
==============================
CAM_EndMouseMove

the key has been released for camera movement
tell the engine that mouse camera movement is off
==============================
*/
void CInput::CAM_EndMouseMove(void)
{
   m_fCameraMovingWithMouse=false;
   m_fCameraInterceptingMouse=false;
}

/*
==============================
CAM_StartDistance

routines to start the process of moving the cam in or out 
using the mouse
==============================
*/
void CInput::CAM_StartDistance(void)
{
	//only move the cam with mouse if we are in third person.
	if ( m_fCameraInThirdPerson )
	{
	  //set appropriate flags and initialize the old mouse position
	  //variables for mouse camera movement
	  if (!m_fCameraDistanceMove)
	  {
		  int cpx, cpy;

		  m_fCameraDistanceMove=true;
		  m_fCameraMovingWithMouse=true;
		  m_fCameraInterceptingMouse=true;
		  GetMousePos(cpx, cpy);

		  m_nCameraX = cpx;
		  m_nCameraY = cpy;

		  m_nCameraOldX=m_nCameraX*gHUD.GetSensitivity();
		  m_nCameraOldY=m_nCameraY*gHUD.GetSensitivity();
	  }
	}
	//we are not in 3rd person view..therefore do not allow camera movement
	else
	{   
		m_fCameraDistanceMove=false;
		m_fCameraMovingWithMouse=false;
		m_fCameraInterceptingMouse=false;
	}
}

/*
==============================
CAM_EndDistance

the key has been released for camera movement
tell the engine that mouse camera movement is off
==============================
*/
void CInput::CAM_EndDistance(void)
{
   m_fCameraDistanceMove=false;
   m_fCameraMovingWithMouse=false;
   m_fCameraInterceptingMouse=false;
}

/*
==============================
CAM_IsThirdPerson

==============================
*/
int CInput::CAM_IsThirdPerson( void )
{
	return m_fCameraInThirdPerson;
}

/*
==============================
CAM_GetCameraOffset

==============================
*/
void CInput::CAM_GetCameraOffset( Vector& ofs )
{
	VectorCopy( m_vecCameraOffset, ofs );
}

/*
==============================
CAM_InterceptingMouse

==============================
*/
int CInput::CAM_InterceptingMouse( void )
{
	return m_fCameraInterceptingMouse;
}

static ConCommand startpitchup( "+campitchup", CAM_PitchUpDown );
static ConCommand endpitcup( "-campitchup", CAM_PitchUpUp );
static ConCommand startpitchdown( "+campitchdown", CAM_PitchDownDown );
static ConCommand endpitchdown( "-campitchdown", CAM_PitchDownUp );
static ConCommand startcamyawleft( "+camyawleft", CAM_YawLeftDown );
static ConCommand endcamyawleft( "-camyawleft", CAM_YawLeftUp );
static ConCommand startcamyawright( "+camyawright", CAM_YawRightDown );
static ConCommand endcamyawright( "-camyawright", CAM_YawRightUp );
static ConCommand startcamin( "+camin", CAM_InDown );
static ConCommand endcamin( "-camin", CAM_InUp );
static ConCommand startcamout( "+camout", CAM_OutDown );
static ConCommand camout( "-camout", CAM_OutUp );
static ConCommand thirdperson( "thirdperson", ::CAM_ToThirdPerson, "Switch to thirdperson camera.", FCVAR_CHEAT );
static ConCommand firstperson( "firstperson", ::CAM_ToFirstPerson, "Switch to firstperson camera." );
static ConCommand camortho( "camortho", ::CAM_ToOrthographic, "Switch to orthographic camera.", FCVAR_CHEAT );
static ConCommand startcammousemove( "+cammousemove",::CAM_StartMouseMove);
static ConCommand endcammousemove( "-cammousemove",::CAM_EndMouseMove);
static ConCommand startcamdistance( "+camdistance", ::CAM_StartDistance );
static ConCommand endcamdistance( "-camdistance", ::CAM_EndDistance );
static ConCommand snapto( "snapto", CAM_ToggleSnapto );
/*
==============================
Init_Camera

==============================
*/
void CInput::Init_Camera( void )
{
	m_CameraIsOrthographic = false;
}

c_basecombatweapon.cpp

The DrawModel function should now look like:

//-----------------------------------------------------------------------------
// Purpose: Render the weapon. Draw the Viewmodel if the weapon's being carried
//			by this player, otherwise draw the worldmodel.
//-----------------------------------------------------------------------------
int C_BaseCombatWeapon::DrawModel( int flags )
{
	VPROF_BUDGET( "C_BaseCombatWeapon::DrawModel", VPROF_BUDGETGROUP_MODEL_RENDERING );
	if ( !m_bReadyToDraw )
		return 0;

	if ( !IsVisible() )
		return 0;

	// check if local player chases owner of this weapon in first person
	C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();

	// Get rid of view model, crosshair and weapon in 3rd person
	// Once we actually get weapons working, we'll let it draw only the weapon
	if (localplayer)
	{
		if (input->CAM_IsThirdPerson())
		{
			SetModel( GetWorldModel() );
			localplayer->m_Local.m_iHideHUD |= HIDEHUD_CROSSHAIR;
			return false;
			//return BaseClass:: DrawModel( flags ); // Uncomment this if you want to be able to 
                        //do weapon things (it will display the weapon).
		}
	} 

	if ( localplayer && localplayer->IsObserver() && GetOwner() )
	{
		// don't draw weapon if chasing this guy as spectator
		// we don't check that in ShouldDraw() since this may change
		// without notification 
		
		if ( localplayer->GetObserverMode() == OBS_MODE_IN_EYE &&
			 localplayer->GetObserverTarget() == GetOwner() ) 
			return false;
	}

	return BaseClass::DrawModel( flags );
}