It has an onEvent routine which must be provided to Irrlicht somehow, so it can be part of another event receiver. Also, fixes a limitation of the Maya animator when moving the camera forward, this also moves the target forward, so, it never is really too close to the target to produce odd motions. And adds another completely new feature by allowing to zoom in and out using the wheel. It also doesn't have gimbal lock because the up vector is constantly updated, so the view matrix is always kept orthogonal, allowing for any rotation to take place freely.
Features:
Orbit the camera around the camera target with CTRL+LMB.
Pan the camera with CTRL+RMB
Dolly (Moves forward and backward) the camera with CTRL+MMB or RMB+LMB
Zoom in and out (opens and closes the camera FOV) with CTRL+wheel up or down (ranges from a 120 degrees fov to a 5 degrees fov in 5 degrees steps)
Header
Code: Select all
#ifndef _CUSTOMMAYAANIMATOR_H_
#define _CUSTOMMAYAANIMATOR_H_
#include <irrlicht.h>
class customMayaAnimator : public virtual irr::scene::ISceneNodeAnimator
{
irr::core::vector2di currentMousePos;
irr::core::vector2di lastMousePos;
irr::core::vector2di deltaMousePos;
irr::f32 mouseMotionSensitivity;
irr::f32 mouseRotationSensitivity;
irr::f32 cameraFOV;
bool LMPressed;
bool RMPressed;
bool MBPressed;
irr::f32 wheelMotion;
irr::u32 currentTime;
irr::u32 lastTime;
irr::f32 deltaTime;
public:
customMayaAnimator();
~customMayaAnimator();
bool OnEvent(const irr::SEvent& event);
void animateNode(irr::scene::ISceneNode* node, irr::u32 timeMs);
irr::scene::ISceneNodeAnimator* createClone(irr::scene::ISceneNode* node, irr::scene::ISceneManager* newManager = 0);
};
#endif
Code: Select all
#include "customMayaAnimator.h"
using namespace irr;
customMayaAnimator::customMayaAnimator()
{
LMPressed = RMPressed = MBPressed = false;
currentTime = lastTime = 0;
deltaTime = 0.0f;
mouseMotionSensitivity = 10.0f;
mouseRotationSensitivity = 50.0f;
cameraFOV = 60.0f;
}
customMayaAnimator::~customMayaAnimator()
{
}
bool customMayaAnimator::OnEvent(const SEvent& event)
{
bool result = false;
switch (event.EventType)
{
case EET_MOUSE_INPUT_EVENT:
switch (event.MouseInput.Event)
{
case EMIE_LMOUSE_PRESSED_DOWN:
LMPressed = true & event.MouseInput.Control;
if (LMPressed)
result = true;
break;
case EMIE_RMOUSE_PRESSED_DOWN:
RMPressed = true & event.MouseInput.Control;
if (RMPressed)
result = true;
break;
case EMIE_MMOUSE_PRESSED_DOWN:
MBPressed = true & event.MouseInput.Control;
if (MBPressed)
result = true;
break;
case EMIE_LMOUSE_LEFT_UP:
LMPressed = false & event.MouseInput.Control;
break;
case EMIE_RMOUSE_LEFT_UP:
RMPressed = false & event.MouseInput.Control;
break;
case EMIE_MMOUSE_LEFT_UP:
MBPressed = false & event.MouseInput.Control;
break;
case EMIE_MOUSE_MOVED:
lastMousePos = currentMousePos;
if (event.MouseInput.Control)
{
LMPressed = event.MouseInput.isLeftPressed();
RMPressed = event.MouseInput.isRightPressed();
MBPressed = event.MouseInput.isMiddlePressed();
currentMousePos.X = event.MouseInput.X;
currentMousePos.Y = event.MouseInput.Y;
result = true;
}
deltaMousePos = currentMousePos - lastMousePos;
break;
case EMIE_MOUSE_WHEEL: //Increase or decrease speed sensitivity?
if (event.MouseInput.Control)
wheelMotion = event.MouseInput.Wheel;
break;
case EMIE_LMOUSE_DOUBLE_CLICK:
case EMIE_RMOUSE_DOUBLE_CLICK:
case EMIE_MMOUSE_DOUBLE_CLICK:
case EMIE_LMOUSE_TRIPLE_CLICK:
case EMIE_RMOUSE_TRIPLE_CLICK:
case EMIE_MMOUSE_TRIPLE_CLICK:
break;
}
break;
}
return result;
}
void customMayaAnimator::animateNode(scene::ISceneNode* node, u32 timeMs)
{
if (node->getType() != scene::ESNT_CAMERA)
return;
lastTime = currentTime;
currentTime = timeMs;
deltaTime = (currentTime - lastTime)/1000.0f; //What if we take less than 1 msec to render a new frame? O.o
deltaTime = deltaTime == 0.0f ? 0.001f : deltaTime; //The animator may run out of "time" if the frame speed is just too fast (a low load scene, or an empty scene, for instance)
//A better measurement would be the inverse of the frames per second stat from the video driver, so perhaps it could be wise to resort to that just in case
scene::ICameraSceneNode* camera = (scene::ICameraSceneNode*)node;
core::vector3df up = camera->getUpVector();
core::vector3df view = (camera->getTarget() - camera->getPosition()).normalize();
core::vector3df right = view.crossProduct(up).normalize();
up = right.crossProduct(view).normalize();
if (LMPressed & !RMPressed)//Orbit camera
{
camera->setPosition(camera->getPosition() + (right*deltaMousePos.X + up*deltaMousePos.Y)*deltaTime*mouseRotationSensitivity);
camera->setUpVector(up);
}
if (RMPressed & !LMPressed)//Pan camera
{
camera->setPosition(camera->getPosition() + (right*deltaMousePos.X + up*deltaMousePos.Y)*deltaTime*mouseMotionSensitivity);
camera->setTarget(camera->getTarget() + (right*deltaMousePos.X + up*deltaMousePos.Y)*deltaTime*mouseMotionSensitivity);
}
if (RMPressed & LMPressed || MBPressed) //Dolly Camera
{
camera->setPosition(camera->getPosition() + view*deltaMousePos.X*deltaTime*mouseMotionSensitivity);
camera->setTarget(camera->getTarget() + view*deltaMousePos.X*deltaTime*mouseMotionSensitivity);
}
if (abs(wheelMotion) > 0.0f)//ZOOM Camera
{
cameraFOV -= wheelMotion*5.0f;
cameraFOV = cameraFOV < 5 ? 5 : cameraFOV>120 ? 120 : cameraFOV;
camera->setFOV(cameraFOV*core::DEGTORAD);
}
wheelMotion = 0.0f;
deltaMousePos = core::vector2di();
}
scene::ISceneNodeAnimator* customMayaAnimator::createClone(scene::ISceneNode* node, scene::ISceneManager* newManager)
{
return new customMayaAnimator;
}