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;
}
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__
"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;
}