Can a user modify objects in the camera?

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.
Post Reply
wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Can a user modify objects in the camera?

Post by wsw1231 »

As I am just a beginner of this engine, I am just studying the code in the second tutorial, Quake3Map.

I notice that a camera should be set after the node is established, so that the user can see the scene.

However, if I want to do something within this scene, what should I do?
DarkDepths
Posts: 126
Joined: Sun Apr 02, 2006 1:21 am
Location: Canada

Post by DarkDepths »

First, I have a question for you. What exactly do you mean by "However, if I want to do something within this scene, what should I do?"

I think you mean, for example, how can you make a cube move during the scene?

Well, first let me address your point about the camera. Unless I am horribly mistaken at this very late hour, there should be no reason why you must create a camera after the node.

Your code probably looks something like:

Code: Select all

...

ISceneNode* cube = smgr->addCubeSceneNode(10.0f);
cube->setMaterialFlag(EMF_LIGHTING, false);

smgr->addCameraSceneNodeFPS();

while (device->run())
{
     driver->beginScene(true, true, SColor(255, 255, 255, 255);

     smgr->drawAll();

     driver->endScene();
}
device->drop();
I excluded a large portion, of course, but if I remember correctly, this is basically how the tutorials are structured.

Now, first, there is no reason why I couldn't create my camera before I created the cube, and the reason is pretty simple.

The while-loop is the render loop. Every frame, this loop is executed. So, the actual drawing is occurring at the function call smgr->drawAll();

Look back at how we created the camera and the cube scene node. They are created by the ISceneManager, thus they are also managed by the ISceneManager.

The scene manager keeps track of all your 3D data, and perceives the world from the active camera. So, as long as you set a camera before the render loop, there should be no problem.


About the second part of your question. Again, I'm not very clear on what you meant, but I'm guessing you might want something to move around. For this, remember that the render loop is called every frame. In order to move something around, it's position should be updated every frame.

So, let's just make the cube that I created move in a straight line:

(The only thing changed is in the render loop)

Code: Select all

...

ISceneNode* cube = smgr->addCubeSceneNode(10.0f);
cube->setMaterialFlag(EMF_LIGHTING, false);

smgr->addCameraSceneNodeFPS();

while (device->run())
{
     cube->setPosition(vector3df(cube->getAbsolutePosition().X + 2, 0, 0));

     driver->beginScene(true, true, SColor(255, 255, 255, 255);

     smgr->drawAll();

     driver->endScene();
}
device->drop();
So the idea is to set the position of the cube to the previous position plus the amount that you want to offset it by (in this case 2).

If this didn't answer your question, then feel free to ask!
wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Post by wsw1231 »

Thanks for your reply.
I think you have corrected my concept. Now I know that the order of statements before the while loop are not very important as they are just to setup the things to be displayed.

For the "if I want to do something within this scene, what should I do?", I mean if I create a button for users to click, then after it is clicked, a new objected will be created somewhere in the scene and users are allowed to move that newly created object by drag&drop. Can Irrlicht support this kind of action? or should I use game engine instead?
DarkDepths
Posts: 126
Joined: Sun Apr 02, 2006 1:21 am
Location: Canada

Post by DarkDepths »

Sure, there should be no problem doing this.

I assume you've got a button set up and working. The function I am about to present, you would call when the button is pressed.

Code: Select all

void createCube()
{
    ISceneNode* node = smgr->addCubeSceneNode(10.0f);
    // Do other things... apply textures, set it to a new position etc.
}
Of course, you need to have access to your ISceneManager, so you could declare it outside the scope of the main function, or you could pass it in as an argument:

Code: Select all

void createCube(ISceneManager* sceneManager)
{
    ISceneNode* node = sceneManager->addCubeSceneNode(10.0f);
    node->changeSomeSettings(:P);
}
Remember, the node instance is only available in it's scope. So after you leave the function, you cannot refer to it as node. Instead, you would have to retrieve it from the SceneManager. ISceneManager has functions for retrieving SceneNodes by name or id. If, every time you create a new scene node you also give that node a unique name, you can then access it later simply by using the methods in the SceneManager.

Alternatively, you could also keep track of them yourself (which is probably what i would do). Irrlicht has it's own array class that functions very similarly to an stl vector and is quite easy to use!

Code: Select all

array<ISceneNode*> sceneNodes;

void createCube(ISceneManager* sceneManager)
{
    ISceneNode* node = sceneManager->addCubeSceneNode(10.0f);
    node->changeSomeSettings(:P);
    sceneNodes.push_back(node);
}
Again, of course, the array needs to be accessible to the function. I also haven't actually used it in awhile, but I'm pretty sure you can use the standard array access method, i.e. you could access the 3rd element in the collection by doing sceneNodes[2].



Gah, I hope that's legible :P It keeps on getting later, and I have no idea why I'm still awake!
wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Post by wsw1231 »

Thanks.
I think I know how to add a new object (i.e. node) after clicking a button.
However, how can I drag and drop a node?

p.s. I notice that I must use Maya camera since the FPS camera will have the cursor stuck in the middle of the window, so the button cannot be clicked.

This leads to a new problem. Assume I have created a new node after clicking a button and I want to drag and drop it to somewhere else. As I am using Maya camera, when I click and hold the left mouse on the node and move the mouse, the camera view will change. So, how to fix the background/camera view when doing drag and drop?
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Post by Seven »

the following is a fully functional program. just paste into a new project, compile and run.

select a mode button and then use left mouse to pick node to manipulate
hold left mouse down and move mouse to manipulate node.

right mouse toggle camera able to move

addbox button will add additional boxes to move around, scale etc...

Code: Select all

// IrrEditor.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 
#include <irrlicht.h> 

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

#pragma comment(lib, "Irrlicht.lib") 

IrrlichtDevice			*device       = 0; 
IVideoDriver			*driver       = 0; 
ISceneManager			*smgr         = 0; 
IGUIEnvironment         *guienv       = 0; 
ICameraSceneNode		*camera       = 0; 
ISceneCollisionManager  *CollMan      = 0; 

enum EditorMode 
{ 
   MODE_NONE, 
   MODE_QUIT, 
   MODE_TRANSLATE, 
   MODE_ROTATE, 
   MODE_SCALE, 
}; 

position2di        initialCursorPosition;      // where mouse cursor started 
position2di        initialObjectPosition;      // where ray from camera to object intersected screen 
ISceneNode*        SelectedNode			= 0;   // the selected node 
bool               ShiftIsPressed		= 0;   // is the shift key pressed? 
bool               LMouseButtonDown		= 0;   // is the left mouse button down? 
EditorMode         Mode					= MODE_NONE; 
float              RotateSpeed			= 0.01f; 
float              ScaleSpeed			= 0.01f; 

#define ID_QUIT         101 
#define ID_TRANSLATE	102 
#define ID_ROTATE		103 
#define ID_SCALE		104 
#define ID_ADDBOX		105

class MyEventReceiver : public IEventReceiver 
{ 
public: 
  virtual bool OnEvent(const SEvent& anevent) 
  { 
       switch(anevent.EventType) 
       { 
         case EET_GUI_EVENT : 
         { 
            switch (anevent.GUIEvent.EventType) 
               { 
                  case EGET_BUTTON_CLICKED: 
                     { 
                        switch (anevent.GUIEvent.Caller->getID()) 
                          { 
                             case ID_QUIT		: { Mode = MODE_QUIT;		} break; 
                             case ID_TRANSLATE  : { Mode = MODE_TRANSLATE;  } break; 
                             case ID_ROTATE		: { Mode = MODE_ROTATE;		} break; 
                             case ID_SCALE      : { Mode = MODE_SCALE;		} break; 
                             case ID_ADDBOX      : 
                                { 
									ISceneNode* box = smgr->addCubeSceneNode();
									box->setMaterialTexture(0, driver->getTexture("media/fire.bmp"));
									box->setMaterialFlag(video::EMF_LIGHTING, false);
									box->setMaterialFlag(video::EMF_FOG_ENABLE,false);
                                } break; 
                          } break; 
                     } break; 
               } 
         }  break; 
          
         case EET_KEY_INPUT_EVENT : 
         { 
            if (anevent.KeyInput.Shift) ShiftIsPressed = true; 
            else ShiftIsPressed = false; 
         } break; 

         // if it is a mouse event 
         case EET_MOUSE_INPUT_EVENT : 
         { 
            // based upon the mouse event type 
            switch (anevent.MouseInput.Event) 
            { 
               case EMIE_LMOUSE_PRESSED_DOWN : 
                { 
					if (Mode == MODE_NONE) return false;

                  // what a freakin hack 
                  LMouseButtonDown = true; 

                   // check for a node being selected 
                  SelectedNode = CollMan->getSceneNodeFromScreenCoordinatesBB(device->getCursorControl()->getPosition(),0,true); 

                   // If we selected a node 
                   if(SelectedNode) 
                   { 
		            // Remember where the node and cursor were when it was clicked on 
			        initialCursorPosition = device->getCursorControl()->getPosition(); 
				    initialObjectPosition = CollMan->getScreenCoordinatesFrom3DPosition(SelectedNode->getAbsolutePosition(), camera); 
					SelectedNode->setDebugDataVisible(scene::EDS_BBOX);
                   } 

                   // we used this message? 
                   return (SelectedNode != 0); 
                } break; 

               case EMIE_LMOUSE_LEFT_UP : 
                { 
                  LMouseButtonDown = false;
				  if (SelectedNode) SelectedNode->setDebugDataVisible(scene::EDS_OFF);
				  SelectedNode = 0;
                  return false; 
                } break; 

			   case EMIE_RMOUSE_LEFT_UP : 
                { 
					if (camera)
					{
						camera->setInputReceiverEnabled(!camera->isInputReceiverEnabled());
						device->getCursorControl()->setVisible(!camera->isInputReceiverEnabled());
						if (camera->isInputReceiverEnabled()) Mode = MODE_NONE;
					}					
                } break; 

               case EMIE_MOUSE_MOVED : 
               { 
                  if (!LMouseButtonDown) return false; 

                  if (Mode == MODE_TRANSLATE) 
                  { 
                     if (SelectedNode) 
                     { 
                        vector3df p = SelectedNode->getPosition(); 
                          
                        if (ShiftIsPressed) 
                         { 
                           plane3df const planeXY(SelectedNode->getAbsolutePosition(), vector3df(1.f, 0.f, 0.f)); 
                           position2di currentCursorPosition(device->getCursorControl()->getPosition()); 
                           position2di effectiveObjectPosition = initialObjectPosition + currentCursorPosition - initialCursorPosition; 
                           line3df ray(CollMan->getRayFromScreenCoordinates(effectiveObjectPosition, camera)); 
                           vector3df intersectWithPlane; 
                           vector3df oldPos = SelectedNode->getAbsolutePosition(); 

                           if(planeXY.getIntersectionWithLine(ray.start, ray.getVector(), intersectWithPlane)) 
                           { 
                              intersectWithPlane.X = oldPos.X; 
                              intersectWithPlane.Z = oldPos.Z; 
                              SelectedNode->setPosition(intersectWithPlane); 
                           } 
                         } 
                         else 
                         { 
                           plane3df const planeXZ(SelectedNode->getAbsolutePosition(), vector3df(0.f, 1.f, 0.f)); 
                           position2di currentCursorPosition(device->getCursorControl()->getPosition()); 
                           position2di effectiveObjectPosition = initialObjectPosition + currentCursorPosition - initialCursorPosition; 
                           line3df ray(CollMan->getRayFromScreenCoordinates(effectiveObjectPosition, camera)); 
                           vector3df intersectWithPlane; 
                           if(planeXZ.getIntersectionWithLine(ray.start, ray.getVector(), intersectWithPlane)) 
                           { 
                              SelectedNode->setPosition(intersectWithPlane); 
                           } 
                         } 
                     } 
                  } // end mode translate 
                  else 
                  if (Mode == MODE_ROTATE) 
                  { 
                     if (SelectedNode) 
                     { 
                        vector3df rot = SelectedNode->getRotation(); 
                        position2di currentCursorPosition(device->getCursorControl()->getPosition()); 
                        if (ShiftIsPressed) 
                        { 
                           if (initialObjectPosition.X < currentCursorPosition.X) rot.X -= RotateSpeed; 
                           if (initialObjectPosition.X > currentCursorPosition.X) rot.X += RotateSpeed; 
                        } 
                        else 
                        { 
                           if (initialObjectPosition.X < currentCursorPosition.X) rot.Y -= RotateSpeed; 
                           if (initialObjectPosition.X > currentCursorPosition.X) rot.Y += RotateSpeed; 
                           if (initialObjectPosition.Y < currentCursorPosition.Y) rot.Z -= 1; 
                           if (initialObjectPosition.Y > currentCursorPosition.Y) rot.Z += 1; 
                        } 
                        initialObjectPosition = currentCursorPosition; 
                        SelectedNode->setRotation(rot); 
                     } 
                  } 
                  else 
                  if (Mode == MODE_SCALE) 
                  { 
                     if (SelectedNode) 
                     { 
                        vector3df scale = SelectedNode->getScale(); 
                        position2di currentCursorPosition(device->getCursorControl()->getPosition()); 
                        if (initialObjectPosition.X > currentCursorPosition.X) 
                        { 
                           scale.X -= ScaleSpeed; 
                           scale.Y -= ScaleSpeed; 
                           scale.Z -= ScaleSpeed; 
                        } 
                        if (initialObjectPosition.X < currentCursorPosition.X) 
                        { 
                           scale.X += ScaleSpeed; 
                           scale.Y += ScaleSpeed; 
                           scale.Z += ScaleSpeed; 
                        } 
                        initialObjectPosition = currentCursorPosition; 
                        SelectedNode->setScale(scale); 
                     } 
                  } 

               } break; 
            } 
         } 
      } 
      return 0; 
   } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
   // create the device 
   device =  createDevice( video::EDT_OPENGL, dimension2d<u32>(640, 480), 16, false, false, false, 0); 
   if (!device) return 1; 

   MyEventReceiver receiver; 
   device->setEventReceiver(&receiver); 

   // get a pointer to all of the irr items 
   driver      = device->getVideoDriver(); 
   smgr      = device->getSceneManager(); 
   guienv      = device->getGUIEnvironment(); 
   CollMan      = smgr->getSceneCollisionManager(); 

   // add my little plug 
   int x      = 10; 
   int y      = 10; 
   int width   = 100; 
   int height   = 20; 
   int space   = 5; 

   guienv->addButton(core::rect<s32>(x,y,x+width,y+height),0,ID_QUIT,L"QUIT"); 
   y += height + space; 
   guienv->addButton(core::rect<s32>(x,y,x+width,y+height),0,ID_TRANSLATE,L"Translate"); 
   y += height + space; 
   guienv->addButton(core::rect<s32>(x,y,x+width,y+height),0,ID_ROTATE,L"Rotate"); 
   y += height + space; 
   guienv->addButton(core::rect<s32>(x,y,x+width,y+height),0,ID_SCALE,L"Scale"); 
   y += height + space; 
   guienv->addButton(core::rect<s32>(x,y,x+width,y+height),0,ID_ADDBOX,L"Add A Box"); 

   // load a mesh 
   IAnimatedMesh* mesh = smgr->getMesh("media/sydney.md2"); 
    if (!mesh) return 1; 

   // create a node 
   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") ); 
    } 

	// add a camera 
	camera = smgr->addCameraSceneNodeFPS();
	camera->setPosition(vector3df(0,40,-40));
	camera->setTarget(vector3df(0,0,0));
	camera->setIsDebugObject(true); 
	camera->setInputReceiverEnabled(false);

   // run the scne 
   while(Mode != MODE_QUIT) 
   { 

      device->run(); 
      driver->beginScene(true, true, SColor(255,100,101,140)); 
      smgr->drawAll(); 
      guienv->drawAll(); 
	  driver->endScene(); 
    } 

   // kill the device 
   device->drop(); 

   return 0; 
} 


wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Post by wsw1231 »

Thanks for the code :D
I will study it deeply later.
I have just compiled and run it.

Actually, if there is a map loaded e.g. Quake3 map like tutorial 2, can I move the object to a place where it will not overlap the map? (i.e. the object cannot be moved through the wall of the map, there should be some constraints)

Apart from the above, my university FYP requires using OpenCV to detect hand gestures to control the camera. I think this is the most difficult part.....because I dont know how OpenCV can interact with Irrlicht engine... :cry:
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Post by Seven »

I am trying to help as much as possible, but the topics you ask about are not trivial. The code I provided will function as a small editor and you can pretty easily modify it to add whatever nodes you like. As for the nodes not intersecting, you are talking about adding a physics engine to the mix. There are many good libraries available, all of which do the same basic things. You could get a good 'which is better' discussion going if you like. I wont participate in it though :)

Check out the tutorials. I think there are a few code snippets in that section for adding physics.

if you choose one, feel free to share your successes with the rest of the forum,
Post Reply