OgreOde Camera

From Ogre Wiki

Jump to: navigation, search

I spent some time to make my Camera collide correctly with the environment in OgreOde, like its known from any commercial computer game. My first thought was to give the camera a geometry and a body in OgreOde, so it collides with any object. After I made it not to move other objects but instead glide along them, I spent really a lot of time finding the right parameters for the cameras body and movement, and after all I gave it up. If anyone of you has this idea, I suggest you drop it :)

The conclusion came, when I began to play World of Warcraft. We are about to implement a camera, that behaves just like this one, except some minor changes. Its pretty much of the GuildWars camera, too.

As I developed this camera while I was working on a bigger project, you will not be able to adapt it completely, but I expect you to work around that on your own ;) It is developed with OgreOde, but it should be no problem to use it with ode or another physics engine. I expect you have worked with OgreOde and cameras in Ogre before, so I will focus the new elements.

Contents

Concept

Its pretty easy.

        - Take a ray, throw it from the point of the camera to the center, the players head or similiar.
        - Check for collisions between the ray and every object that is to move the camera
        -If there is a collision, move the camera along the ray to the point of collision + some distance 

Additional Features: Load and save Settings, chasing if wanted, x rotation bounds

Class Declaration

Declare your cameras class and derive it from OgreOde::CollisionListener as its going to handle the collisions of the ray. You can not work with CollidingObject, because its part of my project. I use it to derive all objects that will have a collision callback by OgreOde.


        class Camera : public virtual CollidingObject, public OgreOde::CollisionListener
        {

We will need the following members:

        private:
        
        typedef CollidingObject inherited;
        protected:
        
        bool CollisionInThisFrame;
        
        Ogre::Camera* MyCamera; //the ogre camera
        
        Ogre::SceneNode* LookAtNode; //the node we are really looking at
        
        Ogre::SceneNode* RotationCenterNode; //the center of rotation, this node will be given by the user on creation
        Ogre::SceneNode* TargetPositionNode; //the position we want to be at, but maybe are not yet (chasing)
        Ogre::SceneNode* TargetLookAtNode; //the point we look at, but maybe dont yet
        
        
        double TightnessPos; //how fast does the camera reach target position
        double TightnessLook; //how fast does the camera look at the target position
        
        double MaxDistance; //how much can you zoom out
        double MinDistance; //how much can you zoom in
        double Distance; //whats the current distance between rotation center and camera
        double TargetDistance; //whats the target distance (chasing)
        
        double MinCamRot; //the bounds for x rotation
        double MaxCamRot;
        
        OgreOde::RayGeometry* Ray; //the ray we use for the collision detection
        
        ObjectManager* ObjManager; //this is part of my engine, you cant use it, more on that later
        Ogre::Vector3 Scale; //the scale vector of the parent node, so the camera will work same on all sizes you set for your player


and we have these functions:

        public:
        Camera(Ogre::SceneNode* CenterParentNode, OgreOde::Space* Space, ObjectManager* Objects);
        ~Camera(void);
        
        bool virtual FrameStarted(double TimePassed);
        bool virtual FrameEnded(double TimePassed);
        void virtual Zoom(const double Value); //Move the camera relative along the ray
        
        bool virtual WriteToIni(IniFile& Ini)	const {return true;} //save the camera to a file
        bool virtual LoadFromIni(const std::basic_string<wchar_t>& ObjectID, IniFile& Ini); //load from a file
        
        
        bool virtual collision(OgreOde::Contact *Contact); //collision callback
        
        void RotateX(double Value); //rotate the camera along x axis, use this instead of rotating the
        //rotation center if you dont want the player to rotate
        
        inline Ogre::Camera* GetCamera(void) {return MyCamera;} //maybe you need the original Ogre object sometime
        
        
        private:
        bool MoveChase(const double TimePassed);
        bool MoveFixed(const double TimePassed);
        
        void InitBase(void);
        void InitNodes(Ogre::Vector3 CamCenter, Ogre::Vector3 LookAtPosition);
        bool InitCamera(void);
        bool InitViewport(void);
        
        void CollideRay(void);
        };

Constructor

Initialize your members. The constructor gets the node of the parent object, like your player, the space including the ode objects that the camera is going to collide with and a pointer to my ObjectManager class. As I said you cant use it, you need to find a way to let the camera access your objects.

        ::Camera::Camera(Ogre::SceneNode* CenterParentNode, OgreOde::Space* Space, ObjectManager* Objects) : inherited(),
        MyCamera(0), LookAtNode(0), TargetLookAtNode(0), TargetPositionNode(0), RotationCenterNode(0),
        TightnessPos(0.0), TightnessLook(0.0), MaxDistance(2.0), MinDistance(0.0), Ray(0), MinCamRot(0.0), MaxCamRot(0.0),
        Distance(1.0), TargetDistance(1.0), CollisionInThisFrame(false), Scale()
        {

Create a child of the parent center node, so it may has its own rotation that does not effect the player

        RotationCenterNode = CenterParentNode->createChildSceneNode("Camera Pos");
        
        //Camera never rotates around the z axis:
        RotationCenterNode->setFixedYawAxis(true);

Our Ray. You see that I cast the camera to CollidingObject and then make it user object of the Ray. I do this with every Geometry and its parent colliding class, so you can make your own collision callback behaviour for every object. To use this camera you somehow have to identify your camera in the ray .

        Ray = new OgreOde::RayGeometry(0, HardwareManager::getSingleton().GetWorld(), Space);
        Ray->setUserObject(static_cast<CollidingObject*>(this));
        Ray->disable();
        

Save a pointer to the class that handles all the objects we are going to collide with.

        ObjManager = Objects;
        
        Scale = CenterParentNode->getScale();
        }

Destructor

Clean up a little bit:

        ::Camera::~Camera(void)
        {
        	delete Ray;
        }

Create Camera and Viewport

These two functions create a camera and a viewport in ogre, I expect you are familiar with that.

        bool ::Camera::InitCamera(void)
        {
        	         // Create the camera
        	if (MyCamera)
        	        HardwareManager::getSingleton().GetScene()->destroyCamera(MyCamera);
        
        	MyCamera = HardwareManager::getSingleton().GetScene()->createCamera("PlayerCam");
        	if (!MyCamera) return false;
        
        	MyCamera->setNearClipDistance(5);
               //note: Position is Ogre::SceneNode* and comes from CollidingObject
        	Position->attachObject(MyCamera);
        	return true;	
        }
        
        bool ::Camera::InitViewport(void)
        {
        	// Create one viewport, entire window
        	static Ogre::Viewport* vp =          HardwareManager::getSingleton().GetWindow()->addViewport(MyCamera);
        	if (!vp) return false;
        
        	//Pink is our background color
        	vp->setBackgroundColour(Ogre::ColourValue(255,0,255));
        
        	// Alter the camera aspect ratio to match the viewport
        	MyCamera->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
        	return true;
        }

Init the SceneNodes

Now we need several scene nodes for our camera. The RotationCenterNode is what it says and is created within the constructor, so we dont need to handle it here. We will only adjust its position to the given vector, so you can set it to the players head e.g. Then we have a TargetLookAtNode and a TargetPositionNode, these are the positions where the camera should be and look at, but maybe is not yet. LookAtNode and Position are the real ones and will be updated later. You will be able to choose, if you want a static or chasing camera.

        void ::Camera::InitNodes(Ogre::Vector3 CamCenter, Ogre::Vector3 LookAtPosition)
        {
        	//set position of camera rotation center:
        	RotationCenterNode->setPosition(CamCenter);
        
        	//Destroy the nodes, if they exist
        	if (LookAtNode)    
                          HardwareManager::getSingleton().GetScene()->destroySceneNode(LookAtNode->getName());
        	if (TargetLookAtNode) 
                       HardwareManager::getSingleton().GetScene()->destroySceneNode(TargetLookAtNode->getName());
        	if (TargetPositionNode) 
                      HardwareManager::getSingleton().GetScene()->destroySceneNode(TargetPositionNode->getName());
        
        	//create LookAtNode
        	LookAtNode = HardwareManager::getSingleton().GetScene()->getRootSceneNode()->createChildSceneNode();
        
                 //the targets are children of the center node and as such always rotated automatically to the correct positions
        	TargetLookAtNode = RotationCenterNode->createChildSceneNode();
        	TargetLookAtNode->setPosition(LookAtPosition);
        	TargetPositionNode = RotationCenterNode->createChildSceneNode();
               
               //note: Position is Ogre::SceneNode* and comes from CollidingObject         
        	//Real PositionNode shall always look at real LookAtNode
        	Position->setAutoTracking(true, LookAtNode);
        	//and it should never rotate around the z axis.
        	Position->setFixedYawAxis(true);
        
        }
Personal tools
administration