Angle controlled 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
manni63
Posts: 12
Joined: Tue Sep 27, 2016 6:23 am

Angle controlled camera

Post by manni63 »

Because of the recent discussion about camera rotation and up vectors, and because of my own requirements I wrote a camera animator that controls camera movements by angles.
For a demonstration, I implemented this animator to the Sydney example.

The demonstration animator is controlled by the following keys:

left key, right key: camera rotates around the target with vertical image edge as rotation axis.
up key, down key: camera rotates around the target with horizontal image edge as rotation axis.
home key, end key: camera rotates with view direction as axis.
a key, s key: camera rotates around its position with vertical image edge as rotation axis.
w key, y key: camera rotates around its position with horizontal image edge as rotation axis.
d key, f key: camera is shifted along horizontal image edge.
r key, c key: camera is shifted along vertical image edge.
z key, b key: camera is shifted along view direction.

The core of this animator is
the method rotateAroundTarget, which rotates the camera around an arbitrary axis through the target,
the method rotateAroundPosition, which rotates the camera around an arbitrary axis through its own position,
the method shift, which shifts camera position and target along an arbitrary axis.

I think that all these methods can easily be implemented into the camera class, of course, they cannot be mixed with the original methods setPosition, setUpVetor and so on.

This animator is the only test for these methods so far, so I cannot guarantee that they work under all conditions.

Code: Select all

 
 
#include <irrlicht.h>
#include <CCameraSceneNode.h>
 
using namespace irr;
 
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
 
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
 
class CameraRotationsAnimator : public ISceneNodeAnimator
{
public:
 
    CameraRotationsAnimator(ICameraSceneNode *cam, vector3df initPosition, vector3df initTarget)
    {
        rotType=(EKEY_CODE)0;
        camera=cam;
 
        // Initialize camera parameters:
        // The up vector has to be orthogonal to the position - target vector.
        // (position should not be on y axis, because of up vector calculation)
        camera->setPosition(initPosition);
        camera->setTarget (initTarget);
 
        // calculate exact up vector:
        vector3df viewRay= camera->getPosition()-camera->getTarget();
        vector3df orthoHorz (viewRay.Z,0.,-viewRay.X);
        vector3df upVec= viewRay.crossProduct(orthoHorz).normalize();
        camera->setUpVector (upVec);
    }
 
    void rotateAroundTarget (vector3df axis, f32 alpha)
    {
        quaternion q;
        axis.normalize();
        f32 alphaRad=degToRad(alpha);
 
        //Build quaternion from axis and rotation angle:
        q.fromAngleAxis(alphaRad, axis);
 
        // camera position relative to target:vector3df (0.,1.,0.)
        vector3df relPos = camera->getPosition()-camera->getTarget();
 
        // rotate camera relative to target:
        vector3df newRelPos= q*relPos;
 
        // set new absolute position:
        camera->setPosition(newRelPos+camera->getTarget());
 
        // rotate camera up vector:
        vector3df upVec = camera->getUpVector();
        vector3df newUpVec=q*upVec;
 
        // set new up vector:
        camera->setUpVector(newUpVec);
    }
 
    void rotateAroundPosition (vector3df axis, f32 alpha)
    {
        vector3df oldPos = camera->getPosition();
        rotateAroundTarget (axis, alpha);
        vector3df newPos = camera->getPosition();
        // Keep camera position and shift target:
        camera->setPosition(oldPos);
        vector3df oldTarget= camera->getTarget();
        camera->setTarget (oldTarget-(newPos-oldPos));
    }
 
    void shift (vector3df axis, f32 length)
    {
        axis.normalize();
        vector3df oldPos=camera->getPosition();
        vector3df oldTarget=camera->getTarget();
        vector3df newPos=oldPos+length*axis;
        vector3df newTarget=oldTarget+length*axis;
        camera->setPosition(newPos);
        camera->setTarget(newTarget);
    }
 
    virtual void animateNode(ISceneNode* node, u32 timeMs)
    {
        ICameraSceneNode *cam= (ICameraSceneNode *)node;
         vector3df horzImageEdge;
        switch (rotType)
        {
            case KEY_LEFT:
            // rotate around up vector (vertical image axis):
                rotateAroundTarget(cam->getUpVector(),1.);
                break;
            case KEY_RIGHT:
                // rotate around up vector (vertical image axis):
                rotateAroundTarget(cam->getUpVector(),-1);
                break;
            case KEY_UP:
                // rotate around horizontal image edge:
                horzImageEdge= (cam->getPosition()-cam->getTarget()).crossProduct(cam->getUpVector());
                rotateAroundTarget (horzImageEdge,1.);
                break;
            case KEY_DOWN:
                // rotate around horizontal image edge:
                horzImageEdge= (cam->getPosition()-cam->getTarget()).crossProduct(cam->getUpVector());
                rotateAroundTarget (horzImageEdge,-1.);
                break;
            case KEY_HOME:
                //  rotate around view direction
                rotateAroundTarget (cam->getPosition()-cam->getTarget(),1.);
                break;
            case KEY_END:
                //  rotate around view direction
                rotateAroundTarget (cam->getPosition()-cam->getTarget(),-1.);
                break;
            case KEY_KEY_S:
                // rotate around up vector (vertical image axis):
                rotateAroundPosition(cam->getUpVector(),1.);
                break;
            case KEY_KEY_A:
                // rotate around up vector (vertical image axis):
                rotateAroundPosition(cam->getUpVector(),-1);
                break;
            case KEY_KEY_Y:
                // rotate around up vector (vertical image axis):
                horzImageEdge= (cam->getPosition()-cam->getTarget()).crossProduct(cam->getUpVector());
                rotateAroundPosition(horzImageEdge,1.);
                break;
            case KEY_KEY_W:
                // rotate around up vector (vertical image axis):
                horzImageEdge= (cam->getPosition()-cam->getTarget()).crossProduct(cam->getUpVector());
                rotateAroundPosition(horzImageEdge,-1);
                break;
            case KEY_KEY_F:
                // shift camera along horzontal image edge:
                horzImageEdge= (cam->getPosition()-cam->getTarget()).crossProduct(cam->getUpVector());
                shift (horzImageEdge,0.1);
                break;
            case KEY_KEY_D:
                // shift camera along horzontal image edge:
                horzImageEdge= (cam->getPosition()-cam->getTarget()).crossProduct(cam->getUpVector());
                shift (horzImageEdge,-0.1);
                break;
            case KEY_KEY_R:
                // shift camera along vertical image edge:
                shift (cam->getUpVector(),0.1);
                break;
            case KEY_KEY_C:
                // shift camera along vertical image edge:
                shift (cam->getUpVector(),-0.1);
                break;
            case KEY_KEY_Z:
                // shift camera along view vector:
                shift (cam->getTarget()-cam->getPosition(),0.1);
                break;
            case KEY_KEY_B:
                // shift camera along view vector:
                shift (cam->getTarget()-cam->getPosition(),-0.1);
                break;
        }
    }
 
    virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0)
    {
 
    }
 
    virtual bool isEventReceiverEnabled() const
    {
        return true;
    }
 
    virtual bool OnEvent(const SEvent& event)
    {
        if (event.EventType == EET_KEY_INPUT_EVENT)
         {
             if( event.KeyInput.PressedDown && rotType==(EKEY_CODE)0)
                    rotType=event.KeyInput.Key;
             if( !event.KeyInput.PressedDown)
                 rotType=(EKEY_CODE)0;
        }
    }
 
    ICameraSceneNode *camera;
    EKEY_CODE rotType;
};
 
int main()
{
    IrrlichtDevice *device =
        createDevice( video::EDT_SOFTWARE, dimension2d<u32>(640, 480), 16,
            false, false, false, 0);
 
    if (!device)
        return 1;
 
    device->setWindowCaption(L"Hello World! - Irrlicht Engine VerticalDemo");
 
    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager* smgr = device->getSceneManager();
    IGUIEnvironment* guienv = device->getGUIEnvironment();
 
    guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!",
        rect<s32>(10,10,260,22), true);
 
    IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
    if (!mesh)
    {
        device->drop();
        return 1;
    }
    IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
 
    if (node)
    {
        node->setMaterialFlag(EMF_LIGHTING, false);
        node->setMD2Animation(scene::EMAT_STAND);
        node->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp"));
    }
 
    // Parameters are irrelevant
    ICameraSceneNode *cam=smgr->addCameraSceneNode(0, vector3df(0,0,0), vector3df(0,0,0));
    // Camera initialization is done here!
    CameraRotationsAnimator *camrot=new CameraRotationsAnimator(cam, vector3df(0.,0.,-60.),vector3df (0.,0.,0.));
    cam->addAnimator(camrot);
 
    while(device->run())
    {
        driver->beginScene(true, true, SColor(255,100,101,140));
 
        smgr->drawAll();
        guienv->drawAll();
        driver->endScene();
    }
    device->drop();
    return 0;
}
 
 
 
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Angle controlled camera

Post by chronologicaldot »

Thanks! :)
Always nice to have this sort of code around.
Post Reply