Orbital Camera

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
Gawaboumga
Posts: 11
Joined: Sun Jul 14, 2013 3:06 pm

Orbital Camera

Post by Gawaboumga »

Hi everyone,

I've developed a simple camera which turns free around a target point. This is a mix of the camera FPS & Maya. I hope you will enjoy it.

If you active the comments about inversion, it will conserve the same left & right all along the application. Otherwise, they swap if you pass the tops.

"CSceneNodeAnimatorCameraOrbital.cpp"

Code: Select all

//! This is just a copy of the CSceneNodeAnimatorCameraMaya.h
 
/** Original Copyright is this one !!!!!
//Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
**/
 
#include "CSceneNodeAnimatorCameraOrbital.h"
 
//#include "ICameraSceneNode.h"
//#include "ISceneManager.h"
 
using namespace irr;
 
//! constructor
CSceneNodeAnimatorCameraOrbital::CSceneNodeAnimatorCameraOrbital(
    core::vector3df center, f32 zoom, f32 rotateSpeed, f32 zoomSpeed,
    f32 minimumZoom, SKeyMap* keyMapArray, u32 keyMapSize)
    : OldCamera(0), Center(center), CurrentZoom(zoom), ZoomSpeed(zoomSpeed),
    RotateSpeed(rotateSpeed), RotX(0.0f), RotY(0.0f), MinimumZoom(minimumZoom), firstUpdate(true)
{
    #ifdef _DEBUG
    setDebugName("CSceneNodeAnimatorCameraOrbital");
    #endif
 
    allKeysUp();
 
    // create key map
    if (!keyMapArray || !keyMapSize)
    {
        // create default key map
        KeyMap.push_back(SKeyMap(EKA_MOVE_FORWARD, KEY_UP));
        KeyMap.push_back(SKeyMap(EKA_MOVE_BACKWARD, KEY_DOWN));
        KeyMap.push_back(SKeyMap(EKA_STRAFE_LEFT, KEY_LEFT));
        KeyMap.push_back(SKeyMap(EKA_STRAFE_RIGHT, KEY_RIGHT));
    }
    else
    {
        // create custom key map
        setKeyMap(keyMapArray, keyMapSize);
    }
 
//  inversion = 1.f;
}
 
//! destructor
CSceneNodeAnimatorCameraOrbital::~CSceneNodeAnimatorCameraOrbital(){}
 
//! It is possible to send mouse and key events to the camera. Most cameras
//! may ignore this input, but camera scene nodes which are created for
//! example with scene::ISceneManager::addMayaCameraSceneNode or
//! scene::ISceneManager::addMeshViewerCameraSceneNode, may want to get this input
//! for changing their position, look at target or whatever.
bool CSceneNodeAnimatorCameraOrbital::OnEvent(const SEvent& event)
{
    switch(event.EventType)
    {
    case EET_KEY_INPUT_EVENT:
        for (u32 i=0; i<KeyMap.size(); ++i)
        {
            if (KeyMap[i].KeyCode == event.KeyInput.Key)
            {
                CursorKeys[KeyMap[i].Action] = event.KeyInput.PressedDown;
                return true;
            }
        }
        break;
 
    case EET_MOUSE_INPUT_EVENT:
        if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
        {
            if (event.MouseInput.Wheel > 0 )
            {
                CurrentZoom -= ZoomSpeed;
                if(CurrentZoom < MinimumZoom)
                    CurrentZoom = MinimumZoom;
            }
            else
                CurrentZoom += ZoomSpeed;
 
            return true;
        }
        break;
 
    default:
        break;
    }
    return false;
}
 
//! OnAnimate() is called just before rendering the whole scene.
void CSceneNodeAnimatorCameraOrbital::animateNode(scene::ISceneNode *node, u32 timeMs)
{
    if (!node || node->getType() != scene::ESNT_CAMERA)
        return;
 
    scene::ICameraSceneNode* camera = static_cast<scene::ICameraSceneNode*>(node);
 
    // If the camera isn't the active camera, and receiving input, then don't process it.
    if (!camera->isInputReceiverEnabled())
        return;
 
    if (firstUpdate)
    {
        camera->updateAbsolutePosition();
        lastAnimationTime = timeMs;
        firstUpdate = false;
    }
 
    scene::ISceneManager * smgr = camera->getSceneManager();
    if (smgr && smgr->getActiveCamera() != camera)
        return;
 
    // get time
    timeDiff = static_cast<f32>(timeMs - lastAnimationTime) * 0.1f;
    lastAnimationTime = timeMs;
 
    if (OldCamera != camera)
    {
        LastCameraTarget = OldTarget = camera->getTarget();
        OldCamera = camera;
    }
    else
    {
        OldTarget += camera->getTarget() - LastCameraTarget;
    }
 
    // set rot -------------------------------------
 
//    if(RotY > 90.f && RotY < 270.f)
//        inversion = -1.f;
//    else
//        inversion = 1.f;
 
    // adjust camera position based on current key input
    if (CursorKeys[EKA_STRAFE_LEFT])
        RotX += (RotateSpeed * timeDiff);// * inversion;
 
    if (CursorKeys[EKA_STRAFE_RIGHT])
        RotX -= (RotateSpeed * timeDiff);// * inversion;
 
    if (CursorKeys[EKA_MOVE_FORWARD])
        RotY += (RotateSpeed * timeDiff);
 
    if (CursorKeys[EKA_MOVE_BACKWARD])
        RotY -= (RotateSpeed * timeDiff);
 
    modulo360(); //Not really necessary
 
    f32 nRotX = RotX;
    f32 nRotY = RotY;
    f32 nZoom = CurrentZoom;
 
    // Set pos -------------------------------------
 
    core::vector3df pos = OldTarget;
    pos.X += nZoom;
 
    pos.rotateXYBy(nRotY, OldTarget);
    pos.rotateXZBy(-nRotX, OldTarget);
 
    const core::vector3df correctionOfTheError = core::vector3df(0.f,0.f,-100.f); //I don't know why but the camera is originally set on (0.f, 0.f, 100.f)
 
    camera->setPosition(correctionOfTheError + Center + pos);
    camera->setTarget(correctionOfTheError + Center + OldTarget);
 
    // Rotation Error ----------------------------
 
    // jox: fixed bug: jitter when rotating to the top and bottom of y
    pos.set(0.f, 1.f, 0.f);
    pos.rotateXYBy(-nRotY);
    pos.rotateXZBy(-nRotX+180.f);
    camera->setUpVector(pos);
    LastCameraTarget = camera->getTarget();
}
 
//! Sets all keys up
void CSceneNodeAnimatorCameraOrbital::allKeysUp()
{
    for (u32 i=0; i<EKA_COUNT; ++i)
        CursorKeys[i] = false;
}
 
//! Sets the radius
void CSceneNodeAnimatorCameraOrbital::setZoom(f32 zoom)
{
    CurrentZoom = zoom;
}
 
//! Sets the rotation speed
void CSceneNodeAnimatorCameraOrbital::setRotateSpeed(f32 rotateSpeed)
{
    RotateSpeed = rotateSpeed;
}
 
//! Sets the zoom speed
void CSceneNodeAnimatorCameraOrbital::setZoomSpeed(f32 zoomSpeed)
{
    ZoomSpeed = zoomSpeed;
}
 
//! Sets the minimum zoom
void CSceneNodeAnimatorCameraOrbital::setMinimumZoom(f32 minimumZoom)
{
    MinimumZoom = minimumZoom;
}
 
//! Gets the radius
f32 CSceneNodeAnimatorCameraOrbital::getZoom() const
{
    return CurrentZoom;
}
 
//! Gets the rotation speed
f32 CSceneNodeAnimatorCameraOrbital::getRotateSpeed() const
{
    return RotateSpeed;
}
 
//! Gets the zoom speed
f32 CSceneNodeAnimatorCameraOrbital::getZoomSpeed() const
{
    return ZoomSpeed;
}
 
//! Gets the minimum zoom
f32 CSceneNodeAnimatorCameraOrbital::getMinimumZoom() const
{
    return MinimumZoom;
}
 
//! Sets the keyboard mapping for this animator
void CSceneNodeAnimatorCameraOrbital::setKeyMap(SKeyMap *map, u32 count)
{
    // clear the keymap
    KeyMap.clear();
 
    // add actions
    for (u32 i=0; i<count; ++i)
    {
        KeyMap.push_back(map[i]);
    }
}
 
//! Sets the keyboard mapping for this animator
void CSceneNodeAnimatorCameraOrbital::setKeyMap(const core::array<SKeyMap>& keymap)
{
    KeyMap = keymap;
}
 
//! Gets the keyboard mapping for this animator
const core::array<SKeyMap>& CSceneNodeAnimatorCameraOrbital::getKeyMap() const
{
    return KeyMap;
}
 
void CSceneNodeAnimatorCameraOrbital::modulo360()
{
    if(RotX < 0.f)
        RotX = 360.f;
    if(RotX > 360.f)
        RotX = 0.f;
    if(RotY < 0.f)
        RotY = 360.f;
    if(RotY > 360.f)
        RotY = 0.f;
}
 
scene::ISceneNodeAnimator* CSceneNodeAnimatorCameraOrbital::createClone(scene::ISceneNode* node, scene::ISceneManager* newManager)
{
    CSceneNodeAnimatorCameraOrbital * newAnimator =
        new CSceneNodeAnimatorCameraOrbital(Center, CurrentZoom, RotateSpeed, ZoomSpeed, MinimumZoom, 0, 0);
    newAnimator->setKeyMap(KeyMap);
    return newAnimator;
}
"CSceneNodeAnimatorCameraOrbital.h"

Code: Select all

//! This is just a copy of the CSceneNodeAnimatorCameraMaya.h
 
/** Original Copyright is this one !!!!!
//Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
**/
 
#ifndef __C_SCENE_NODE_ANIMATOR_CAMERA_ORBITAL_H_INCLUDED__
#define __C_SCENE_NODE_ANIMATOR_CAMERA_ORBITAL_H_INCLUDED__
 
#include <irr/irrlicht.h>
 
//#include "ICameraSceneNode.h"
//#include "SKeyMap.h"
//#include "irrArray.h"
 
namespace irr
{
 
//! Special scene node animator for Orbital cameras
class CSceneNodeAnimatorCameraOrbital : public scene::ISceneNodeAnimator
{
public:
 
    //! Constructor
    CSceneNodeAnimatorCameraOrbital(core::vector3df center = core::vector3df(0.f,0.f,0.f), f32 zoom = 10.f,
        f32 rotateSpeed = 1.f, f32 zoomSpeed = 1.f, f32 minimumZoom = 1.f, SKeyMap* keyMapArray = 0, u32 keyMapSize = 0);
 
    //! Destructor
    virtual ~CSceneNodeAnimatorCameraOrbital();
 
    //! Animates the scene node, currently only works on cameras
    virtual void animateNode(scene::ISceneNode* node, u32 timeMs);
 
    //! Event receiver
    virtual bool OnEvent(const SEvent& event);
 
    //! Set the radius
    virtual void setZoom(f32 zoom);
 
    //! Set the rotation speed
    virtual void setRotateSpeed(f32 rotateSpeed);
 
    //! Set the zoom speed
    virtual void setZoomSpeed(f32 zoomSpeed);
 
    //! Set the minimum zoom
    virtual void setMinimumZoom(f32 minimumZoom);
 
    //! Returns the radius
    virtual f32 getZoom() const;
 
    //! Returns the rotation speed
    virtual f32 getRotateSpeed() const;
 
    //! Returns the zoom speed
    virtual f32 getZoomSpeed() const;
 
    //! Returns the minimum speed
    virtual f32 getMinimumZoom() const;
 
    //! Sets the keyboard mapping for this animator (old style)
    //! \param keymap: an array of keyboard mappings, see SKeyMap
    //! \param count: the size of the keyboard map array
    virtual void setKeyMap(SKeyMap *map, u32 count);
 
    //! Sets the keyboard mapping for this animator
    //! \param keymap The new keymap array
    virtual void setKeyMap(const core::array<SKeyMap>& keymap);
 
    //! Gets the keyboard mapping for this animator
    virtual const core::array<SKeyMap>& getKeyMap() const;
 
    //! This animator will receive events when attached to the active camera
    virtual bool isEventReceiverEnabled() const
    {
        return true;
    }
 
    //! Returns type of the scene node
    virtual scene::ESCENE_NODE_ANIMATOR_TYPE getType() const
    {
        return scene::ESNAT_CAMERA_MAYA;
    }
 
    //! Creates a clone of this animator.
    /** Please note that you will have to drop
    (IReferenceCounted::drop()) the returned pointer after calling
    this. */
    virtual ISceneNodeAnimator* createClone(scene::ISceneNode* node, scene::ISceneManager* newManager=0);
 
private:
 
    void allKeysUp();
    void modulo360();
    bool isMouseKeyDown(s32 key) const;
 
    core::array<SKeyMap> KeyMap;          // Array KeyMap
    bool CursorKeys[EKA_COUNT];
 
    scene::ICameraSceneNode* OldCamera;
    core::vector3df Center;
    core::vector3df OldTarget;
    core::vector3df LastCameraTarget;   // to find out if the camera target was moved outside this animator
    f32 CurrentZoom;
    f32 ZoomSpeed;
    f32 RotateSpeed;
    f32 TranslateSpeed;
    f32 RotX, RotY;
    f32 MinimumZoom;
    f32 timeDiff;
    f32 inversion;
    u32 lastAnimationTime;
    bool firstUpdate;
};
 
} // end namespace irr
 
#endif // __C_SCENE_NODE_ANIMATOR_CAMERA_ORBITAL_H_INCLUDED__
And this is how we use it:

"main.cpp"

Code: Select all

#include <irr/irrlicht.h>
#include "CSceneNodeAnimatorCameraOrbital.h"
 
using namespace irr;
 
int main()
{
    SIrrlichtCreationParameters params;
    params.DriverType = video::EDT_OPENGL;
    params.WindowSize = core::dimension2d<u32>(640, 480);
    IrrlichtDevice* device = createDeviceEx(params);
 
    if (device == 0)
        return 1;
 
    // disable mouse cursor
    device->getCursorControl()->setVisible(false);
 
    video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();
 
    core::vector3df center = core::vector3df(0.f, 0.f, 0.f);
 
//    SKeyMap keyMap[4];
//    keyMap[0].Action = EKA_MOVE_FORWARD;
//    keyMap[0].KeyCode = KEY_KEY_W;
//    keyMap[1].Action = EKA_MOVE_BACKWARD;
//    keyMap[1].KeyCode = KEY_KEY_S;
//    keyMap[2].Action = EKA_STRAFE_LEFT;
//    keyMap[2].KeyCode = KEY_KEY_A;
//    keyMap[3].Action = EKA_STRAFE_RIGHT;
//    keyMap[3].KeyCode = KEY_KEY_D;
 
    // add camera
    scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(smgr->getRootSceneNode());
    CSceneNodeAnimatorCameraOrbital* animator = new CSceneNodeAnimatorCameraOrbital(center, 5.f, 1.f, 1.f, 2.f); //, keyMap, 4);
 
    camera->addAnimator(animator);
    animator->drop();
 
    scene::ISceneNode* earth = smgr->addSphereSceneNode(1.f, 256, 0, -1, center);
 
    if (earth)
    {
        earth->setMaterialTexture(0, driver->getTexture("../../media/earth.jpg"));
        earth->setMaterialFlag(video::EMF_LIGHTING, false);
    }
 
    smgr->addSkyBoxSceneNode(
        driver->getTexture("../../media/irrlicht2_up.jpg"),
        driver->getTexture("../../media/irrlicht2_dn.jpg"),
        driver->getTexture("../../media/irrlicht2_lf.jpg"),
        driver->getTexture("../../media/irrlicht2_rt.jpg"),
        driver->getTexture("../../media/irrlicht2_ft.jpg"),
        driver->getTexture("../../media/irrlicht2_bk.jpg"));
 
    s32 lastFPS = -1;
 
    while(device->run())
    if (device->isWindowActive())
    {
        driver->beginScene(true, true, 0 );
 
        smgr->drawAll();
 
        driver->endScene();
 
        // display frames per second in window title
        s32 fps = driver->getFPS();
        if (lastFPS != fps)
        {
            core::stringw str = L"Orbital Camera [";
            str += driver->getName();
            str += "] FPS:";
            str += fps;
 
            device->setWindowCaption(str.c_str());
            lastFPS = fps;
        }
    }
 
    device->drop();
 
    return 0;
}
Hope you'll enjoy it.
Mars_999
Posts: 136
Joined: Sat Dec 08, 2012 7:59 pm

Re: Orbital Camera

Post by Mars_999 »

Ah how do I move this camera to a new nodes position to rotate around that selected node? I can't get it to move the position...

thanks!
Post Reply