An arcball camera is a camera that is around a point like on google earth per example. you can use it to look at an object. By default just click and drag with the mouse and you should see the effect happening.
Still some test to be done and in case you find a bug (and or a fix) you would be welcome to post! I know per example that I haven't try arcball that don't revolve around the origin, and I haven't tried camera that are not on the z-axe.
I tried to make something similar to CameraFPS and CameraMaya so that it is easily plugged in any project.
I suppressed the comments headers for clarity but this code is under BSD license as far as I am concerned.
ISceneNodeAnimatorCameraArcball.h (interface header)
Code: Select all
#ifndef ISCENENODEANIMATORCAMERAARCBALL_H_
#define ISCENENODEANIMATORCAMERAARCBALL_H_
namespace irr {
namespace scene {
class ISceneNodeAnimatorCameraArcball : public ISceneNodeAnimator {
public:
virtual void captureMouse() = 0;
virtual bool isMouseCaptured() const = 0;
virtual void freeMouse() = 0;
virtual void setCaptureMouseEvent(EMOUSE_INPUT_EVENT event) = 0;
virtual EMOUSE_INPUT_EVENT getCaptureMouseEvent() const = 0;
virtual void setFreeMouseEvent(EMOUSE_INPUT_EVENT event) = 0;
virtual EMOUSE_INPUT_EVENT getFreeMouseEvent() const = 0;
};
} // end scene
} // end irr
#endif /* ISCENENODEANIMATORCAMERAARCBALL_H_ */
Code: Select all
#ifndef CSCENENODEANIMATORCAMERAARCBALL_H_
#define CSCENENODEANIMATORCAMERAARCBALL_H_
#include <irrlicht.h>
#include "ISceneNodeAnimatorCameraArcball.h"
namespace irr {
namespace scene {
class CSceneNodeAnimatorCameraArcball : public ISceneNodeAnimatorCameraArcball {
public:
//! Constructor
CSceneNodeAnimatorCameraArcball(
gui::ICursorControl* cursorControl,
ICameraSceneNode* camera,
EMOUSE_INPUT_EVENT captureEvent = EMIE_LMOUSE_PRESSED_DOWN,
EMOUSE_INPUT_EVENT freeEvent = EMIE_LMOUSE_LEFT_UP);
//! Destructor
virtual ~CSceneNodeAnimatorCameraArcball();
//! Capture the mouse
virtual void captureMouse();
//! tell if the mouse is captured
virtual bool isMouseCaptured() const { return mouseDrag; }
//! Free the mouse
virtual void freeMouse();
//! set the capture event for the mouse
virtual void setCaptureMouseEvent(EMOUSE_INPUT_EVENT event)
{ CaptureMouseEvent = event; }
//! get the capture event of the mouse
virtual EMOUSE_INPUT_EVENT getCaptureMouseEvent() const
{ return CaptureMouseEvent; }
//! set the free event for the mouse
virtual void setFreeMouseEvent(EMOUSE_INPUT_EVENT event)
{ FreeMouseEvent = event; }
//! get the free event for the mouse
virtual EMOUSE_INPUT_EVENT getFreeMouseEvent() const
{ return FreeMouseEvent; }
//! Animate the scene node, currently only work on cameras
virtual void animateNode(ISceneNode* node, u32 timeMs);
//! Event receiver
virtual bool OnEvent(const SEvent& event);
//! This animator will receive events when attached to the active camera
virtual bool isEventReceiverEnabled() const
{ return true; }
//! Returns the type of this animator
virtual ESCENE_NODE_ANIMATOR_TYPE getType() const
{ return ESNAT_CAMERA_FPS; }
//! create clone of this animator
virtual ISceneNodeAnimator* createClone(
ISceneNode* node,
ISceneManager* newManager = 0);
private :
core::vector3df position2vector(const core::position2df& pos) const;
gui::ICursorControl* CursorControl;
core::position2df CursorDown;
core::quaternion QuatOri;
core::vector3df CamOri;
core::vector3df CamUp;
ICameraSceneNode* Camera;
bool InvertAxes;
bool mouseDrag;
EMOUSE_INPUT_EVENT CaptureMouseEvent;
EMOUSE_INPUT_EVENT FreeMouseEvent;
};
}
}
#endif /* CSCENENODEANIMATORCAMERAARCBALL_H_ */
Code: Select all
#include "CSceneNodeAnimatorCameraArcball.h"
irr::scene::CSceneNodeAnimatorCameraArcball::CSceneNodeAnimatorCameraArcball(
gui::ICursorControl* cursorControl,
ICameraSceneNode* camera,
EMOUSE_INPUT_EVENT captureEvent,
EMOUSE_INPUT_EVENT freeEvent)
: CursorControl(cursorControl),
Camera(camera),
mouseDrag(false),
CaptureMouseEvent(captureEvent),
FreeMouseEvent(freeEvent)
{
CamOri = Camera->getPosition();
CamUp = Camera->getUpVector();
QuatOri.makeIdentity();
// should solve some camera miss placement effect
core::vector3df begin(0, 0, 1);
InvertAxes = (begin.dotProduct(Camera->getTarget() - CamOri) > 0);
QuatOri.rotationFromTo(begin, CamOri);
}
irr::scene::CSceneNodeAnimatorCameraArcball::~CSceneNodeAnimatorCameraArcball() {}
irr::core::vector3df irr::scene::CSceneNodeAnimatorCameraArcball::position2vector(
const irr::core::position2df& pos) const
{
float fx = -(0.5 - pos.X);
float fy = ((InvertAxes)?1:-1) * (0.5 - pos.Y);
float fz = 0.0f;
float mag = fx*fx + fy*fy;
if( mag > 1.0f)
{
float scale = 1.0f / sqrtf(mag);
fx *= scale;
fy *= scale;
}
else
fz = sqrtf( 1.0f - mag );
return irr::core::vector3df(fx, fy, fz);
}
void irr::scene::CSceneNodeAnimatorCameraArcball::animateNode(ISceneNode *node, u32 timeMs)
{
if (!node || node->getType() != ESNT_CAMERA)
return;
if (!mouseDrag)
return;
if (!Camera->isInputReceiverEnabled())
return;
ISceneManager* smgr = Camera->getSceneManager();
if (smgr && smgr->getActiveCamera() != Camera)
return;
core::vector3df target = Camera->getTarget();
core::vector3df pos = Camera->getPosition() - target;
core::vector3df up = Camera->getUpVector();
core::quaternion quat;
if (CursorControl) {
core::position2df CursorPos = CursorControl->getRelativePosition();
core::vector3df from = position2vector(CursorDown);
core::vector3df to = position2vector(CursorPos);
quat.rotationFromTo(from, to);
CursorDown = CursorPos;
}
QuatOri = quat * QuatOri;
pos = QuatOri * CamOri;
up = QuatOri * CamUp;
Camera->setPosition(pos + target);
Camera->setUpVector(up);
}
void irr::scene::CSceneNodeAnimatorCameraArcball::captureMouse() {
CursorDown = CursorControl->getRelativePosition();
mouseDrag = true;
}
void irr::scene::CSceneNodeAnimatorCameraArcball::freeMouse() {
mouseDrag = false;
}
bool irr::scene::CSceneNodeAnimatorCameraArcball::OnEvent(const irr::SEvent & event)
{
if (event.EventType == EET_MOUSE_INPUT_EVENT) {
if (event.MouseInput.Event == CaptureMouseEvent) {
captureMouse();
return true;
}
if (event.MouseInput.Event == FreeMouseEvent) {
freeMouse();
return true;
}
}
return false;
}
irr::scene::ISceneNodeAnimator* irr::scene::CSceneNodeAnimatorCameraArcball::createClone(
ISceneNode *node,
ISceneManager *newManager)
{
CSceneNodeAnimatorCameraArcball* newAnimator =
new CSceneNodeAnimatorCameraArcball(CursorControl, Camera);
return newAnimator;
}