I consciously kept the var keyword in there so that it is clear that the Object will be changed. Maybe I should explicitly define it as an out parameter, but I am unsure if FreePascal supports that keyword.

Thanks to Sly and co for all their input on the Vector class.

Following is the proposed camera class....

[pascal]
unit camera;

interface

uses
vector;

type
TCamera = class
private
CalcVector : TVector; // A sort of cached dummry vector used in Update methods.
protected
// these are used for moving and changing camera orientation
// through the MoveTo/LookTo methods
initPosition, finalPosition : TVector;
initLookAt, finalLookAt : TVector;

LookAtVelocity : TVector; // velocity for looking at objects
LookAtAcceleration : TVector; // acceleration for looking at objects

procedure UpdateLookAt;
procedure UpdateMoveTo;
public
CameraPosition : TVector; // position of camera
CameraVelocity : TVector; // velocity of camera
CameraAcceleration : TVector; // acceleration of camera
CameraLookAt : TVector; // lookat vector

// up, forward, right vectors
CameraUp : TVector;
CameraForward : TVector;
CameraRight : TVector;

// yaw and pitch angles
CameraYaw : TScalar;
CameraPitch : TScalar;

ScreenWidth, ScreenHeight : integer;
ScreenCenterX, ScreenCenterY : integer;

constructor Create; overload;
constructor Create( aLook : TVector ); overload;
constructor Create( aPosition : TVector; aLook : TVector ); overload;
destructor Destroy; override;

procedure LookAt( aX : TScalar; aY : TScalar; aZ : TScalar ); overload;
procedure LookAt( aLook : TVector ); overload;
procedure MoveTo( aX : TScalar; aY : TScalar; aZ : TScalar ); overload;
procedure MoveTo( aPosition : TVector ); overload;

// right rotation along y-axis (yaw)
procedure RotateYaw( aRadians : TScalar );
procedure RotatePitch( aRadians : TScalar );
procedure RotateRoll( aRadians : TScalar );
end;

implementation

{ TCamera }

constructor TCamera.Create;
begin
inherited;
CameraPosition := TVector.Create( 0.0, 0.0, 0.0 );
CameraLookAt := TVector.Create( 0.0, 0.0, 1.0 );

CameraForward := CameraLookAt;
CameraUp := TVector.Create( 0.0, 1.0, 0.0 );
CameraRight := TVector.Create( 1.0, 0.0, 0.0 );

CameraVelocity := TVector.Create( 0.0, 0.0, 0.0 );
CameraAcceleration := TVector.Create( 0.0, 0.0, 0.0 );

CameraYaw := 0.0;
CameraPitch := 0.0;

CalcVector := TVector.Create( 0.0, 0.0, 0.0 );
end;

constructor TCamera.Create( aPosition, aLook : TVector );
begin
inherited Create;
CameraPosition := aPosition;
CameraLookAt := aLook.UnitVector;

CameraForward := CameraLookAt;
CameraUp := TVector.Create( 0.0, 1.0, 0.0 );
CameraRight := TVector.Create( 1.0, 0.0, 0.0 );

CameraVelocity := TVector.Create( 0.0, 0.0, 0.0 );
CameraAcceleration := TVector.Create( 0.0, 0.0, 0.0 );

CameraYaw := 0.0;
CameraPitch := 0.0;

CalcVector := TVector.Create( 0.0, 0.0, 0.0 );
end;

constructor TCamera.Create( aLook : TVector );
begin
inherited Create;
CameraPosition := TVector.Create( 0.0, 0.0, 0.0 );
CameraLookAt := aLook.UnitVector;

CameraForward := CameralookAt;
CameraUp := TVector.Create( 0.0, 1.0, 0.0 );
CameraForward.CrossProduct( CameraUp, CameraRight );

CameraVelocity := TVector.Create( 0.0, 0.0, 0.0 );
CameraAcceleration := TVector.Create( 0.0, 0.0, 0.0 );

CameraYaw := 0.0;
CameraPitch := 0.0;

CalcVector := TVector.Create( 0.0, 0.0, 0.0 );
end;

destructor TCamera.Destroy;
begin
if CameraPosition <> nil then
CameraPosition.Free;
if CameraLookAt <> nil then
CameraLookAt.Free;

if CameraForward <> nil then
CameraForward.Free;
if CameraUp <> nil then
CameraUp.Free;
if CameraRight <> nil then
CameraRight.Free;

if CameraVelocity <> nil then
CameraVelocity.Free;
if CameraAcceleration <> nil then
CameraAcceleration.Free;

if CalcVector <> nil then
CalcVector.Free;
inherited;
end;

procedure TCamera.LookAt( aX, aY, aZ : TScalar );
begin
CameraLookAt.x := aX;
CameraLookAt.y := aY;
CameraLookAt.y := aZ;
end;

procedure TCamera.LookAt( aLook : TVector );
begin
CameraLookAt.Assign( aLook );
end;

procedure TCamera.MoveTo( aX, aY, aZ : TScalar );
begin
CameraPosition.x := aX;
CameraPosition.y := aY;
CameraPosition.z := aZ;
end;

procedure TCamera.MoveTo( aPosition : TVector );
begin
CameraPosition.Assign( aPosition );
end;

procedure TCamera.RotatePitch( aRadians : TScalar );
var
sine, cosine : TScalar;
begin
sine := sin( aRadians );
cosine := cos( aRadians );

CameraUp.y := cosine * CameraUp.Length;
CameraUp.z := sine * CameraUp.Length;

CameraForward.y := -sine * CameraForward.Length;
CameraForward.z := cosine * CameraForward.Length;
{* x y z p
| 1 0 0 0 |
M = | 0 cos(A) -sin(A) 0 |
| 0 sin(A) cos(A) 0 |
| 0 0 0 1 |
*}
end;

procedure TCamera.RotateRoll( aRadians : TScalar );
var
sine, cosine : TScalar;
begin
sine := sin( aRadians );
cosine := cos( aRadians );

CameraRight.x := cosine * CameraRight.Length;
CameraRight.y := sine * CameraRight.Length;

CameraUp.x := -sine * CameraForward.Length;
CameraUp.y := cosine * CameraForward.Length;
{*
| cos(A) -sin(A) 0 0 |
M = | sin(A) cos(A) 0 0 |
| 0 0 1 0 |
| 0 0 0 1 |
*}
end;

procedure TCamera.RotateYaw( aRadians : TScalar );
var
sine, cosine : TScalar;
begin
sine := sin( aRadians );
cosine := cos( aRadians );

CameraRight.x := cosine * CameraRight.Length;
CameraRight.z := sine * CameraRight.Length;

CameraForward.x := -sine * CameraForward.Length;
CameraForward.z := cosine * CameraForward.Length;

{* x y z p
| cos(A) 0 -sin(A) 0 |
M = | 0 1 0 0 |
| sin(A) 0 cos(A) 0 |
| 0 0 0 1 |
*}
end;

procedure TCamera.UpdateLookAt;
begin
CalcVector.Assign( finalLookAt.x - CameralookAt.x,
finalLookAt.y - CameralookAt.y,
finalLookAt.z - CameralookAt.z );

LookAtVelocity.Assign( CalcVector.Scale( 0.5 ) );
end;

procedure TCamera.UpdateMoveTo;
begin
CalcVector.Assign( finalPosition.x - Cameraposition.x,
finalPosition.y - Cameraposition.y,
finalPosition.z - Cameraposition.z );

CameraVelocity.Assign( CalcVector.Scale( 0.5 ) );
end;

end.
[/pascal]

The Sine and Cosine operations should probably be a look-up table to speed things up, if you are so inclined .