Problem With Making a Camera a Child of a SceneNode.

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post by sudi »

i played around with camera rotation and stuff. dunno what you want but after some minutes of playing i got this.

Code: Select all

#include <irrlicht.h>

struct ship
{
    ship(void)
    {
        Forward = false;
        Backward = false;
        Left = false;
        Right = false;
        Speed = 0.f;
        Camera = 0;
        Node = 0;
    }
    void init(irr::scene::ISceneManager* smgr, irr::scene::ICameraSceneNode* cam)
    {
        Camera = cam;
        Node = smgr->addCubeSceneNode();
        Node->setScale(irr::core::vector3df(2,0.5,5));
        //Node->setMaterialFlag(irr::video::EMF_LIGHTING, false);
    }
    bool Forward;
    bool Backward;
    bool Left;
    bool Right;
    irr::f32 Speed;
    irr::core::vector3df Rotation;

    irr::scene::ISceneNode* Node;
    irr::scene::ICameraSceneNode* Camera;
    irr::core::vector3df CamPos;

    void update(const irr::f32& diff)
    {
        irr::core::vector3df vec(0,0,1);
        irr::core::vector3df up(0,1,0);
        irr::core::matrix4 mat0;
        mat0.setRotationDegrees(irr::core::vector3df(Rotation.X, Rotation.Y, 0.f));
        irr::core::matrix4 mat1;
        mat1.setRotationDegrees(irr::core::vector3df(0, 0, Rotation.Z));
        irr::core::matrix4 mat2 = mat0*mat1;
        mat0.rotateVect(vec);
        mat2.rotateVect(up);

        //printf("Roll: %f\n", Rotation.Z);
        //printf("Up: %f, %f, %f\n", up.X, up.Y, up.Z);

        if (Forward)
        {
            Speed = 100.f;
        }
        else if (Backward)
            Speed = -100.f;
        else
            Speed = 0.f;

        if (Left)
        {
            irr::core::vector3df v(90.f*diff*sin(Rotation.Z/180.f*irr::core::PI), -90.f*diff*cos(Rotation.Z/180.f*irr::core::PI), 0);
            Rotation+=v;
        }
        else if (Right)
        {
            irr::core::vector3df v(-90.f*diff*sin(Rotation.Z/180.f*irr::core::PI), 90.f*diff*cos(Rotation.Z/180.f*irr::core::PI), 0);
            Rotation+=v;
        }

        if (Rotation.X > 360.f)
            Rotation.X -= 360.f;
        if (Rotation.X < -360.f)
            Rotation.X += 360.f;

        if (Rotation.Y > 360.f)
            Rotation.Y -= 360.f;
        if (Rotation.Y < -360.f)
            Rotation.Y += 360.f;

        if (Rotation.Z > 360.f)
            Rotation.Z -= 360.f;
        if (Rotation.Z < -360.f)
            Rotation.Z += 360.f;

        if (up.Y > 0.f)
        {
            irr::core::vector3df rot = vec.getHorizontalAngle();

            if (Rotation.Z < -90 && Rotation.Z > -270)
            {
                Rotation.Z += 180;
                Rotation.X = rot.X;
                Rotation.Y = rot.Y;
            }
            else if (Rotation.Z > 90 && Rotation.Z < 270)
            {
                Rotation.Z -= 180;
                Rotation.X = rot.X;
                Rotation.Y = rot.Y;
            }
        }

        if (Node)
        {
            Node->setPosition(Node->getPosition()+vec*Speed*diff);
            Node->setRotation(mat2.getRotationDegrees());
            if (Camera)
            {
                //Camera->setUpVector(up);
                Camera->setTarget(Node->getPosition());
                CamPos = Node->getPosition()-vec*100+up*20;
                Camera->setPosition(Camera->getPosition()+(CamPos-Camera->getPosition())*diff);
            }
        }
    }
}SpaceShip;

struct Events : irr::IEventReceiver
{
    Events(irr::gui::ICursorControl* cursor) : MousePos(320, 240)
    {
        Cursor = cursor;
    }
    irr::core::vector2di MousePos;
    irr::gui::ICursorControl* Cursor;
    bool OnEvent(const irr::SEvent& event)
    {
        if (event.EventType == irr::EET_KEY_INPUT_EVENT)
        {
            if (event.KeyInput.Key == irr::KEY_KEY_W)
            {
                SpaceShip.Forward = event.KeyInput.PressedDown;
            }
            else if (event.KeyInput.Key == irr::KEY_KEY_S)
            {
                SpaceShip.Backward = event.KeyInput.PressedDown;
            }
            else if (event.KeyInput.Key == irr::KEY_KEY_A)
            {
                SpaceShip.Left = event.KeyInput.PressedDown;
            }
            else if (event.KeyInput.Key == irr::KEY_KEY_D)
            {
                SpaceShip.Right = event.KeyInput.PressedDown;
            }
        }
        else if (event.EventType == irr::EET_MOUSE_INPUT_EVENT)
        {
            if (event.MouseInput.Event == irr::EMIE_MOUSE_MOVED)
            {
                if (Cursor->getRelativePosition().Y != 0.5f)
                {
                    SpaceShip.Rotation.X -= (Cursor->getRelativePosition().Y-0.5f)*180.f*cos(SpaceShip.Rotation.Z/180.f*irr::core::PI);
                    SpaceShip.Rotation.Y -= (Cursor->getRelativePosition().Y-0.5f)*180.f*sin(SpaceShip.Rotation.Z/180.f*irr::core::PI);
                    Cursor->setPosition(Cursor->getRelativePosition().X, 0.5f);
                }
                if (Cursor->getRelativePosition().X != 0.5f)
                {
                    SpaceShip.Rotation.Z -= (Cursor->getRelativePosition().X-0.5f)*180.f;
                    Cursor->setPosition(0.5f, Cursor->getRelativePosition().Y);
                }
                return true;
            }
        }
        return false;
    }
};

int main()
{
    irr::IrrlichtDevice* device = irr::createDevice(irr::video::EDT_OPENGL);
    irr::scene::ISceneManager* smgr = device->getSceneManager();
    irr::video::IVideoDriver* driver = device->getVideoDriver();

    irr::scene::ICameraSceneNode* camera = smgr->addCameraSceneNode();

    irr::scene::ISceneNode* Node = smgr->addCubeSceneNode();
    Node->setPosition(irr::core::vector3df(15,0,0));

    Node = smgr->addCubeSceneNode();
    Node->setPosition(irr::core::vector3df(0,-10,0));
    Node->setMaterialFlag(irr::video::EMF_LIGHTING, false);
    Node->setScale(irr::core::vector3df(100,1,100));

    SpaceShip.init(smgr, camera);

    device->getCursorControl()->setPosition(320,240);
    Events events(device->getCursorControl());
    device->setEventReceiver(&events);

    irr::u32 LastTime = device->getTimer()->getTime();
    irr::f32 Diff = 0;
    while(device->run())
    {
        irr::u32 Time = device->getTimer()->getTime();
        Diff = 0.f;
        if (LastTime < Time)
        {
            Diff = Time-LastTime;
            Diff /= 1000.f;
        }

        SpaceShip.update(Diff);

        driver->beginScene(true, true, irr::video::SColor(255,0,0,255));
        smgr->drawAll();
        driver->endScene();

        LastTime = Time;
    }
    device->closeDevice();
    device->run();
    device->drop();
    return 0;
}
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
Whirled Peas
Posts: 47
Joined: Mon Jan 10, 2011 8:01 pm
Location: SoCal

Post by Whirled Peas »

thanks for the input Sudi, however the problem for seems to be stemming from the fact that for some reason, my camera refuses to rotate properly along the Z axis. Even if I manually input a specifit value for the Z rotation, it doesn't matter, it just does whatever it wants to.

Any ideas why that would happen?

thanks in advance
Radikalizm
Posts: 1215
Joined: Tue Jan 09, 2007 7:03 pm
Location: Leuven, Belgium

Post by Radikalizm »

So you want to implement a camera roll?
The camera is limited by an up-vector which doesn't directly allow for a rotation around the z-axis, you can however set the up vector yourself
Whirled Peas
Posts: 47
Joined: Mon Jan 10, 2011 8:01 pm
Location: SoCal

Post by Whirled Peas »

setrotation doesn't override the upvector?

even with bindTargetAndRotation set to true?
Radikalizm
Posts: 1215
Joined: Tue Jan 09, 2007 7:03 pm
Location: Leuven, Belgium

Post by Radikalizm »

Whirled Peas wrote:setrotation doesn't override the upvector?

even with bindTargetAndRotation set to true?
As far as I know, it doesn't
Whirled Peas
Posts: 47
Joined: Mon Jan 10, 2011 8:01 pm
Location: SoCal

Post by Whirled Peas »

ok, so I set the camera to use an upvector which is another object that is also a child of the main mesh object, yet the camera now seems to roll independently whatever the main object does
Mikhail9
Posts: 54
Joined: Mon Jun 29, 2009 8:41 am

Post by Mikhail9 »

This may help you:

http://irrlicht.sourceforge.net/phpBB2/ ... ht=#241485

Perform the numbered steps, then add the camera scene node plus children as a child of your mesh. During updates, after you rotate the mesh, do the updateAbsolutePosition(), setTarget(), setUpVector() stuff. This should ensure the camera is oriented as you intend.

This is how I do "fixed" cameras on moving objects, and they behave as expected.
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post by sudi »

Ok i seriously don't get what the f your problem is then. maybe post code, screenshots and/or a video. bc right now i have no clue what you want
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
Whirled Peas
Posts: 47
Joined: Mon Jan 10, 2011 8:01 pm
Location: SoCal

Post by Whirled Peas »

Mikhail9 wrote:This may help you:

http://irrlicht.sourceforge.net/phpBB2/ ... ht=#241485

Perform the numbered steps, then add the camera scene node plus children as a child of your mesh. During updates, after you rotate the mesh, do the updateAbsolutePosition(), setTarget(), setUpVector() stuff. This should ensure the camera is oriented as you intend.

This is how I do "fixed" cameras on moving objects, and they behave as expected.
Mikhail I could kiss you. It FREAKING WORKED!!!!

I was really starting to get hopeless there, even after the first time I tried it and it didn't work right, but after a little trial and error I figured out that you gotta put those lines of code:

Code: Select all

        cam->updateAbsolutePosition();
        Tnode->updateAbsolutePosition();
        Unode->updateAbsolutePosition();

        cam->setTarget(Tnode->getAbsolutePosition());
        cam->setUpVector(Unode->getAbsolutePosition() - cam->getAbsolutePosition());
inside the main game loop rather than before it.

Anyway, it works just like I had intended now, thank you so much.

here is the code for the program for those that are curious.

Code: Select all

#include <irrlicht.h>
#include <irrBullet.h>
#include <trianglemeshshape.h>
#include <ICameraSceneNode.h>
#include <iostream>

#include <strsafe.h>




using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
using namespace std;



int main()
{


    IrrlichtDevice *device = createDevice(EDT_OPENGL, dimension2d<u32>(640, 480), 16, false, false, false, 0);


    device->setWindowCaption(L"Physics & Camera Game Test");

    IVideoDriver *driver = device->getVideoDriver();
    ISceneManager *smgr = device->getSceneManager();
    IGUIEnvironment *GEnv = device->getGUIEnvironment();


    IAnimatedMesh* mesh = smgr->getMesh("c:/gamemedia/b3dtest.b3d");
    IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);

    IAnimatedMesh* ground = smgr->getMesh("c:/gamemedia/terrmesh1.b3d");
    IAnimatedMeshSceneNode* Gnode = smgr->addAnimatedMeshSceneNode(ground);

    node->setMaterialFlag(EMF_LIGHTING, false);
    node->setMaterialTexture(0, driver->getTexture("c:/gamemedia/uv.jpg"));

    Gnode->setPosition(vector3df(0, -5, 0));


    ICameraSceneNode *cam = smgr->addCameraSceneNode();

    ISceneNode* Tnode = smgr->addEmptySceneNode();
    ISceneNode* Unode = smgr->addEmptySceneNode();

    cam->setPosition(vector3df(0, 0, -10));
    Tnode->setPosition(vector3df(0, 0,10));
    Unode->setPosition(vector3df(0, 1, -10));

    Tnode->setParent(cam);
    Unode->setParent(cam);

    //cam->updateAbsolutePosition();
    //Tnode->updateAbsolutePosition();
    //Unode->updateAbsolutePosition();

    //cam->setTarget(Tnode->getAbsolutePosition());
    //cam->setUpVector(Unode->getAbsolutePosition() - cam->getAbsolutePosition());

    cam->setParent(node);



    irrBulletWorld* world = createIrrBulletWorld(device, true);

    world->setGravity(vector3df(0, -5, 0));

    IGImpactMeshShape* thing = new IGImpactMeshShape(node, device->getSceneManager()->getMesh("c:/gamemedia/b3dtest.b3d"), 5.0);
    IGImpactMeshShape* Gthing = new IGImpactMeshShape(Gnode, device->getSceneManager()->getMesh("c:/gamemedia/terrmesh1.b3d"), 0.0);

    IRigidBody *body = world->addRigidBody(thing);
    IRigidBody *Gbody = world->addRigidBody(Gthing);


    u32 TStamp = device->getTimer()->getTime();
    u32 DTime = 0;




    while (device->run())
    {

        driver->beginScene(true, true, SColor(0, 100, 100, 200));

        DTime= device->getTimer()->getTime() - TStamp;
        TStamp = device->getTimer()->getTime();

        world->stepSimulation(DTime*0.001f, 120);

        cam->updateAbsolutePosition();
        Tnode->updateAbsolutePosition();
        Unode->updateAbsolutePosition();

        cam->setTarget(Tnode->getAbsolutePosition());
        cam->setUpVector(Unode->getAbsolutePosition() - cam->getAbsolutePosition());


        smgr->drawAll();
        GEnv->drawAll();

        driver->endScene();

    }


    delete world;

    device->drop();

    return 0;


}


sorry for lack of comments in it, I kinda just rewrote the whole thing from scratch in an effort to clean things up a bit.

And I apologize for getting you frustrated Sudi, my main objective was to have full control over pitch, roll, and yaw of the camera. As the cameras normally presented in Irrlicht seem to be heavily bound by the constraints of the upvector, which of course makes it hard to control the camera roll. In the end the objective was to have the player control an in game mesh which he can fly around in a 3d world, the camera is merely "bolted on" to the model mesh.

My confusion came in because I used to work in Panda3d which didn't have quite such a restriction. I also didn't realize that even the bindTargetAndOrientation only applied to overriding the camera's constraint to the target, but not the upvector. Finally, things were compounded by the fact that in spite of the fact that the upvector for the camera should make the camera rotate the way I wanted, it didn't behave properly and required this specific line of code:

Code: Select all

cam->setUpVector(Unode->getAbsolutePosition() - cam->getAbsolutePosition());
to make it behave, I dunno why.

Again, thanks so much for all the feedback guys, especially from you Mikhail.

~jumps for joy~
Mikhail9
Posts: 54
Joined: Mon Jun 29, 2009 8:41 am

Post by Mikhail9 »

Whirled Peas wrote:Mikhail I could kiss you. It FREAKING WORKED!!!!
Maybe later, but I'm glad it worked for you.

I'll remember next time to say "in your render loop" rather than "during updates" in order to save the next person the frustration.
Whirled Peas
Posts: 47
Joined: Mon Jan 10, 2011 8:01 pm
Location: SoCal

Post by Whirled Peas »

Mikhail9 wrote:
Whirled Peas wrote:Mikhail I could kiss you. It FREAKING WORKED!!!!
Maybe later, but I'm glad it worked for you.

I'll remember next time to say "in your render loop" rather than "during updates" in order to save the next person the frustration.
:D k

Well, the confusion may have been mostly my own fault, as I simply misunderstood when you said
Before drawing the scene, set the up-vector and target-vector easily like this:
as that you should implement the code before the main loop, in retrospect I probably should have guessed that you meant merely that it should be inserted before the "device->drawAll();" function is called. This is probably because I typically will enact just about everything within the main while loop before drawing the scene anyway.

also, as an interesting note, I found that I had to take out the "- cameranode->getAbsolutePosition()" part of the pointer call there to get the camera to orient in the right direction. Mind you, this isn't a complaint, just an observation and a note for future reference.
Post Reply