View this PageEdit this PageUploads to this PageHistory of this PageHomeRecent ChangesSearchHelp Guide

How to make a "TrackedCamera" Entity

How to make a "TrackedCamera" Entity


Introduction:

Cameras in Mangalore are Entities, which have a CameraProperty attached. This way, the FocusManager can grant Camera Focus and Input Focus to this Entity, which affects the virtual camera.
To enable a camera to be VRPN controlled, we introduce a new Property which can be attached to an Entity. To still be able to control this camera with a mouse (for debugging) this new camera has two modes. The manual one uses the Maya-like mouse control, already implemented in the Mangalore videocameraproperty.


trackedcameraproperty.h
#include "game/property.h"
#include "properties/videocameraproperty.h"

enum CameraMode 
{
   Tracker = 0,
   Manual,
};

//------------------------------------------------------------------------------
namespace Attr
{
    // tracked camera specific attributes
    DeclareInt(TrackerSensorID);
    DeclareInt(CameraMode);
};
//------------------------------------------------------------------------------
namespace Properties
{
class TrackedCameraProperty : public VideoCameraProperty
{
    DeclareRtti;
    DeclareFactory(TrackedCameraProperty);


Entities contain Attributes. These can be declared/defined either in attributes.h/.cc or in properties which actually need them. For out Tracked Camera we declare two Int Attribute, which holds the SensorID of the Tracker Sensor we want to use, and the type of camera mode.

DeclareRtti enables the RTTI (Runtime-Type-Information) mechanism to a class. This is useful for deciding which methods one can invoke on a class.


public:
    /// constructor
    TrackedCameraProperty();
    /// destructor
    virtual ~TrackedCameraProperty();
    /// called from Entity::ActivateProperties()
    virtual void OnActivate();
    /// called before rendering happens
    virtual void OnRender();
    /// setup default entity attributes
    virtual void SetupDefaultAttributes();
    /// listen to message that switches the camera
    virtual bool Accepts(Message::Msg* msg);
    /// handle message that switches the camera
    virtual void HandleMessage(Message::Msg* msg);
private:
    
};
RegisterFactory(TrackerCameraProperty);


The methods which differ from the derived videocameraproperty class, must be overwritten. In our case we have a special behaviour for OnRender(), and OnActivate() as well as the initial Attribute setup.
Since we are using the Attribute mechanism of Mangalore, that means having the attributes stored in the entities, we don't add member attributes to this class. That way, we have a coherent concept, and can access these attributes easily and safely in the application.
The last two methods deal with message handling and are used for to communicate with entities (for example send a message "Hit by weapon")


trackedcameraproperty.cc

namespace Attr
{
    DefineInt(TrackerSensorID);
    DefineInt(CameraMode);
};
namespace Properties
{
ImplementRtti(Properties::TrackedCameraProperty, Properties::VideoCameraProperty);
ImplementFactory(Properties::TrackedCameraProperty);


These are the counterparts of the declarations made in the header file.

//------------------------------------------------------------------------------
/**
*/
void
TrackedCameraProperty::OnActivate()
{
    // set the camera focus on this identity, if it has  CameraFocus Attr true 
    CameraProperty::OnActivate();
		
    // initialize the Maya camera object
    const matrix44 m = GetEntity()->GetMatrix44(Attr::Transform);
    this->mayaCamera.SetDefaultEyePos(m.pos_component());
    this->mayaCamera.SetDefaultUpVec(GetEntity()->GetVector3(Attr::VideoCameraDefaultUpVec));
    this->mayaCamera.SetDefaultCenterOfInterest(GetEntity()->GetVector3(Attr::VideoCameraCenterOfInterest));
    this->mayaCamera.Initialize();
}



The OnActivate() method is called by the entity and initializes the property. Since we are using a manual mode as well, the nMayaCamera is setup as well.


//------------------------------------------------------------------------------
/**
*/
void
TrackedCameraProperty::OnRender()
{	
...
if (FocusManager::Instance()->GetCameraFocusEntity() == GetEntity()) {
    if (GetEntity()->GetInt(Attr::CameraMode) == CameraMode::Tracker)) {
       // Get ViewMatrix for equivalent SensorID from Tracker
       matrix44 viewMat = nTrackerServer::Instance()->GetViewMatrix(GetEntity()->GetInt(Attr::TrackerSensorID)); 
       // update the graphics subsystem's camera transform
       Graphics::CameraEntity* camera = Graphics::Server::Instance()->GetCamera();
       n_assert(camera != 0);
       camera->SetTransform(viewMat);
    }
    else {
       // update the graphics subsystem's camera with maya camera transform
       Graphics::CameraEntity* camera = Graphics::Server::Instance()->GetCamera();
       n_assert(camera != 0);
       camera->SetTransform(this->mayaCamera.GetViewMatrix());
    }
}
...
    // important: call parent class at the end to apply any shake effects
    CameraProperty::OnRender();
}



The OnRender() method is called every frame, and finally alters the graphic's pipeline camera. Either by getting the new view matrix by the tracker server or by the maya camera.


//------------------------------------------------------------------------------
/**
*/
void
TrackedCameraProperty::SetupDefaultAttributes()
{
    CameraProperty::SetupDefaultAttributes();
    vector3 identity;
    GetEntity()->SetVector3(Attr::VideoCameraCenterOfInterest, identity);
    GetEntity()->SetVector3(Attr::VideoCameraDefaultUpVec, vector3(0.0f, 1.0f, 0.0f));
    GetEntity()->SetInt(Attr::TrackerSensorID, 1);
    GetEntity()->SetInt(Attr::CameraMode, CameraMode::Manual);
}


All attributes have to be initialized with a default value, in case they cannot be find in the database

//------------------------------------------------------------------------------
/**
   Accept only specified Messages
*/

bool TrackedCameraProperty::Accepts(Message::Msg* msg)
{
    n_assert(msg);
    if (msg->CheckId(Message::ChangeCameraMode::Id)) 
        return true;
    return Game::Property::Accepts(msg);
}


Any message reveiving property has to implement this method, to tell the communictation system whether it listens to a specific message

//------------------------------------------------------------------------------
/**
   Handle messages, toggle camera tracking
*/
void
TrackedCameraProperty::HandleMessage(Message::Msg* msg)
{
    n_assert(msg);
    if (msg->CheckId(Message::ChangeCameraMode::Id)) {
        GetEntity()->SetInt(Attr::CameraMode, msg->GetCameraMode()); 
    }
}


If a property replies to Accepts() with true, its HandleMessage method is called. Here it reacts to the message and might invoke a new one.


Link to this Page