Custom Maya Camera Animator

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.

Custom Maya Camera Animator

Postby Mel » Mon Oct 24, 2016 11:23 am

Ever felt that you wanted to click on something on a scene but suddenly you've started to move the camera because you were using a Maya Camera Animator? Well, this animator solves that issue by forcing also the usage of the control key. That is, to move the camera just like the maya animator, you also have to press the control key, or else, the camera won't move, and the events will slip away further into the events system, perhaps catching up with any click routine you've provided.

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
cpp 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
 


Source
cpp 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;
    }
 


You have to create a new customMayaAnimator and assign it to any camera for it to work, but remember, for the camera animator to work you have to press the CONTROL KEY! or else the camera won't move, and the events will slip away. And you have to create your custom event receiver that passes the events to this animator.
Last edited by Mel on Wed Oct 26, 2016 11:49 pm, edited 2 times in total.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
User avatar
Mel
Competition winner
 
Posts: 2264
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Re: Custom Maya Camera Animator

Postby Vectrotek » Mon Oct 24, 2016 7:37 pm

This is something so cool it should be incorporated in the next major Irrlicht version! :D
I got the code for later!
User avatar
Vectrotek
Competition winner
 
Posts: 1076
Joined: Sat May 02, 2015 5:05 pm
Location: South Africa

Re: Custom Maya Camera Animator

Postby Mel » Wed Oct 26, 2016 11:51 pm

Hmm... i've rectified the part where said it wasn't necesary to have an event receiver for this animator, actually, it is necesary. But the good part is that animators inherit from the event reciever interface themselves, so that part is half done.

You have to create an event receiver that simply passes the event to this animator. If it is processed, it will return true, otherwise, false, and you will be able to process it further... my bad, you need an event receiver, after all... it is fixed in the first post.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
User avatar
Mel
Competition winner
 
Posts: 2264
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Re: Custom Maya Camera Animator

Postby Vectrotek » Thu Nov 03, 2016 8:56 pm

Cool!
User avatar
Vectrotek
Competition winner
 
Posts: 1076
Joined: Sat May 02, 2015 5:05 pm
Location: South Africa


Return to Code Snippets

Who is online

Users browsing this forum: No registered users and 1 guest