How can I avoid picking through scene node to another node.

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
Espanol
Posts: 40
Joined: Sun Oct 22, 2006 3:28 am

How can I avoid picking through scene node to another node.

Post by Espanol »

My game is 3d person action and use mouse cursor to shoot some attack skill but my playing character is in front of my victim!

How can I pick through my character to the victim.

I use getSceneNodeFromScreenCoordinatesBB(mousePos, 0x0001);

I think I didn't confuse about <idBitMask> because I set victim scene node ID to 901 and my character is 0x0010 but the result when my mouse cursor lay over my character, -1 is return even my victim stand near behind my charactor.

The picking process cannot pick through my character. Please help. :cry:
Espanol
Posts: 40
Joined: Sun Oct 22, 2006 3:28 am

Post by Espanol »

please help, this problem solution is very nessesary for my project.

Thank you. :cry:
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Assuming that when you wrote 901 as the victim id you didn't mean [0x0901], the player scene node _should_ never be returned from a call to getSceneNodeFromscreenCoordinatesBB(mousePos, 0x0001).

The best thing to do to avoid these problems is to give all victim nodes an id with a single bit set and give other nodes ids with other bits set [never the same bit]. You would have to give all scene nodes explicit IDs to avoid having them turn up in the selection.

Code: Select all

#define VICTIM_BIT (0x0001)
Then when you create a victim, you give it the id VICTIM_BIT. When you want to test for clicking victims only, you call getSceneNodeFromscreenCoordinatesBB(mousePos, VICTIM_BIT).

Travis
Espanol
Posts: 40
Joined: Sun Oct 22, 2006 3:28 am

Post by Espanol »

I assign 0x0001 as a victim scene node ID and assign my player character scene node ID as 0x0010 and then call
getSceneNodeFromScreenCoordinatesBB(mousePos, 0x0001);
but it still cannot pick victim when the victim is behind my player node.
I just want to pick through the node that I don't want to pick to my wanted node but the result is like that when the node which ID is 0x0010 is be reached by the detection line before my wanted node which ID is 0x0001 that stand far behind, the detection line(which is in the process of getSceneNodeFromScreenCoordinatesBB(mousePos, 0x0001) ) cannot avoid the node which ID is 0x0010 and go through it to pick the one which ID 0x0001 where is the far behind.

how can I pick it. Please help again, thank you. :cry:
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

I am very sure that you are doing something wrong. Are you absolutely sure that your player node is getting selected and not the camera or something else?

Here is a testcase that shows the getSceneNodeFromScreenCoordinatesBB() in action and working to select a node that is behind other nodes.

At one position is the camera, and at another position is a sphere. Between the sphere and the camera are 5 flattened cubes. You can select nodes by pressing Shift and then left-clicking the nodes. If you try to select the cubes, you will not be able to. If you click over the sphere, it will get selected, even if there are cubes in the way.

Code: Select all

#include <irrlicht.h>
#pragma comment(lib, "Irrlicht.lib")

using namespace irr;
using namespace scene;

#define NONE_MASK (0x0000)
#define BALL_MASK (0x0001)
#define CUBE_MASK (0x0002)

class MyEventReceiver : public IEventReceiver
{
public:
  MyEventReceiver(ISceneManager* smgr)
    : SceneManager(smgr)
    , Selected(0)
  {
    SceneManager->grab();

    u32 k;
    for (k = 0; k < sizeof(Keys) / sizeof(*Keys); ++k)
      Keys[k] = false;
  }

  virtual ~MyEventReceiver()
  {
    SceneManager->drop();
  }

  virtual bool OnEvent(SEvent event)
  {
    if (event.EventType == EET_KEY_INPUT_EVENT) 
    { 
      Keys[event.KeyInput.Key] = event.KeyInput.PressedDown;
      return false; 
    } 

    // if shift is down and mouse clicked, then do collision test 
    if (Keys[KEY_SHIFT] && 
      event.EventType == EET_MOUSE_INPUT_EVENT && 
      event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) 
    {
      core::position2di pos(event.MouseInput.X, event.MouseInput.Y);

      Selected = 
        SceneManager->getSceneCollisionManager()->getSceneNodeFromScreenCoordinatesBB(pos, BALL_MASK); 

      return true; 
    } 

    return false;
  }

private:
  ISceneManager* SceneManager;
public:
  ISceneNode* Selected;
  bool Keys[KEY_KEY_CODES_COUNT];
};

int main()
{
  // create device and exit if creation failed

  IrrlichtDevice* device =
    createDevice(video::EDT_DIRECT3D9, core::dimension2d<s32>(800, 600));
  if (device == 0)
    return 1; // could not create selected driver.

  video::IVideoDriver* driver = device->getVideoDriver();
  scene::ISceneManager* smgr = device->getSceneManager();
  
  // need a light to make things visible
  ILightSceneNode* light =
    smgr->addLightSceneNode(0, core::vector3df(0, 50, 0), video::SColorf(1.f, .5f, .5f, 1.f));
  light->setID(NONE_MASK);

  IBillboardSceneNode* bill =
    smgr->addBillboardSceneNode(light);
  bill->setID(NONE_MASK);
  bill->setMaterialFlag(video::EMF_LIGHTING, false);
  bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
  bill->setMaterialTexture(0, driver->getTexture("../../media/particlewhite.bmp"));

  // make the camera
  ICameraSceneNode* camera =
    smgr->addCameraSceneNodeMaya(0, -1500.f, 200.f, 1500.f, NONE_MASK);
  camera->setPosition(core::vector3df(0.f, 0.f, -10.f));

  // make a few cubes
  core::vector3df pos(0.f, 0.f, 5.f);
  core::vector3df rot(0.f, 0.f, 0.f);
  core::vector3df scl(10.f, 10.f, 1.f);

  u32 c;
  for (c = 0; c < 5; ++c)
  {
    smgr->addCubeSceneNode(1.f, 0, CUBE_MASK, pos, rot, scl);
    pos.Z += 5.f;
  }

  // make a ball 
  smgr->addSphereSceneNode(5.f, 8, 0, BALL_MASK, core::vector3df(0, 0, 50));

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

  while (device->run())
  {
    if (device->isWindowActive())
    {
      if (driver->beginScene(true, true, video::SColor(255, 100, 100, 100)))
      {
        smgr->drawAll();

        // draw the bounding box for the selected node
        if (receiver.Selected)
        {
          video::SMaterial m;
          m.Lighting = false;
          m.ZBuffer  = false;
          driver->setMaterial(m);

          driver->setTransform(video::ETS_WORLD,
            receiver.Selected->getAbsoluteTransformation());

          driver->draw3DBox(receiver.Selected->getBoundingBox());
        }

        driver->endScene();
      }
    }
  }

  device->drop();
  
  return 0;
}
Travis
Espanol
Posts: 40
Joined: Sun Oct 22, 2006 3:28 am

Post by Espanol »

Thank you very much for your kindness.
It's my fault, I forgot to set debugTextNode ID to be 0x0000 which attach above my playing character.
Thank you :idea:
ming9899
Posts: 2
Joined: Wed Dec 20, 2006 6:18 pm

Post by ming9899 »

I have some problem about getSceneNodeFromScreenCoordinatesBB(). I try to add 1 more SphereSceneNode and I set the ID to be BALL2_MASK. And then I set getSceneNodeFromScreenCoordinatesBB(pos, BALL2_MASK). From this following code, I should select only on the new Sphere but I can select every node. And I also want to know how to set the id. When I change the id of some node for the example 0x0001 to 0x0007, the result will be different. I very confuse about that.
Please help me to solve this problem. Thank you very much

Code: Select all

#include <irrlicht.h> 
#pragma comment(lib, "Irrlicht.lib") 

using namespace irr; 
using namespace scene; 

#define NONE_MASK (0x0000)
#define BALL_MASK (0x0001) 
#define CUBE_MASK (0x0002) 
#define BALL2_MASK (0x0003) 
 

class MyEventReceiver : public IEventReceiver 
{ 
public: 
  MyEventReceiver(ISceneManager* smgr) 
    : SceneManager(smgr) 
    , Selected(0) 
  { 
    SceneManager->grab(); 

    u32 k; 
    for (k = 0; k < sizeof(Keys) / sizeof(*Keys); ++k) 
      Keys[k] = false; 
  } 

  virtual ~MyEventReceiver() 
  { 
    SceneManager->drop(); 
  } 

  virtual bool OnEvent(SEvent event) 
  { 
	  
    if (event.EventType == EET_KEY_INPUT_EVENT) 
    { 
      Keys[event.KeyInput.Key] = event.KeyInput.PressedDown; 
      return false; 
    } 

    // if shift is down and mouse clicked, then do collision test 
    if (Keys[KEY_SHIFT] && 
      event.EventType == EET_MOUSE_INPUT_EVENT && 
      event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) 
    { 
      core::position2di pos(event.MouseInput.X, event.MouseInput.Y); 

      Selected = 
        SceneManager->getSceneCollisionManager()->getSceneNodeFromScreenCoordinatesBB(pos, BALL2_MASK); 
	
      return true; 
    } 

    return false; 
  } 

private: 
  ISceneManager* SceneManager; 
public: 
  ISceneNode* Selected; 
  bool Keys[KEY_KEY_CODES_COUNT]; 
}; 

int main() 
{ 
  // create device and exit if creation failed 

  IrrlichtDevice* device = 
    createDevice(video::EDT_DIRECT3D9, core::dimension2d<s32>(800, 600)); 
  if (device == 0) 
    return 1; // could not create selected driver. 

  video::IVideoDriver* driver = device->getVideoDriver(); 
  scene::ISceneManager* smgr = device->getSceneManager(); 
  
  // need a light to make things visible 
  ILightSceneNode* light = 
    smgr->addLightSceneNode(0, core::vector3df(0, 50, 0), video::SColorf(1.f, .5f, .5f, 1.f)); 
  light->setID(NONE_MASK); 

  IBillboardSceneNode* bill = 
    smgr->addBillboardSceneNode(light); 
  bill->setID(NONE_MASK); 
  bill->setMaterialFlag(video::EMF_LIGHTING, false); 
  bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); 
  bill->setMaterialTexture(0, driver->getTexture("../../media/particlewhite.bmp")); 

  // make the camera 
  ICameraSceneNode* camera = 
    smgr->addCameraSceneNodeMaya(0, -1500.f, 200.f, 1500.f, NONE_MASK); 
  camera->setPosition(core::vector3df(0.f, 0.f, -10.f)); 

  // make a few cubes 
  core::vector3df pos(0.f, 0.f, 5.f); 
  core::vector3df rot(0.f, 0.f, 0.f); 
  core::vector3df scl(10.f, 10.f, 1.f); 

  u32 c; 
  for (c = 0; c < 5; ++c) 
  { 
    smgr->addCubeSceneNode(1.f, 0, CUBE_MASK, pos, rot, scl); 
    pos.Z += 5.f; 
  } 

  // make a ball 
  smgr->addSphereSceneNode(5.f, 8, 0, BALL_MASK, core::vector3df(0, 0, 50)); 
  smgr->addSphereSceneNode(5.f, 8, 0, BALL2_MASK, core::vector3df(100, 0, 50)); 

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

  while (device->run()) 
  { 
    if (device->isWindowActive()) 
    { 
      if (driver->beginScene(true, true, video::SColor(255, 100, 100, 100))) 
      { 
        smgr->drawAll(); 

        // draw the bounding box for the selected node 
        if (receiver.Selected) 
        { 
          video::SMaterial m; 
          m.Lighting = false; 
          m.ZBuffer  = false; 
          driver->setMaterial(m); 

          driver->setTransform(video::ETS_WORLD, 
            receiver.Selected->getAbsoluteTransformation()); 

          driver->draw3DBox(receiver.Selected->getBoundingBox()); 
        } 

        driver->endScene(); 
      } 
    } 
  } 

  device->drop(); 
  
  return 0; 
} 
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

The problem is your understanding of the masking concept. Given the following definitions...

Code: Select all

#define NONE_MASK (0x0000) // binary 0000
#define BALL_MASK (0x0001)  // binary 0001
#define CUBE_MASK (0x0002) // binary 0010
#define BALL2_MASK (0x0003) // binary 0011
A bit-mask is something that is done in binary. Each bit in a binary number is combined with the same bit in another number. That is what bit-masking [masking] is.

Say you give a scene node the id BALL_MASK (or 0001b). When you ask the scene collision manager to find the node with ids matching BALL_MASK (0001b) it looks for nodes that have an id which, when anded with 0001b returns some non-zero value. If it sees a node with an id 0001b and it is searching for nodes that match the mask 0001b, you get 0001b & 0001b = 0001b. So this is a hit. If the node has a mask 0010b, then you get 0010b & 0001b = 0000b, which is not a hit.

When you made BALL2_MASK a value of 3 (0011b), it matches nodes with BALL_MASK, CUBE_MASK and BALL2_MASK. This is because 0011b & 0010b = 0010b, 0011b & 0001b = 0001b and 0011b & 0011b = 0011b.

If you want BALL2 objects to be selected independently from BALL objects, you should make the mask 0x0004. If you added another type you would make that one 0x0008, and the next would be 0x0010...

If you wanted to make an object selectable as a ball or a cube, you would give it an id of BALL_MASK | CUBE_MASK. If you wanted to allow selection of either balls or cubes, you would pass that same mask to the collision manager selection method.

Travis
ming9899
Posts: 2
Joined: Wed Dec 20, 2006 6:18 pm

Post by ming9899 »

If you added another type you would make that one 0x0008, and the next would be 0x0010...
#define NONE_MASK (0x0000)
#define BALL_MASK (0x0001)
#define CUBE_MASK (0x0008) <------
#define BALL2_MASK (0x0010) <------

Then is set getSceneNodeFromScreenCoordinatesBB(pos, BALL2_MASK);


I have a confusing part about 0x0008 and 0x0010. 1010 & 1000 = 1000
From this calculation, 1000 is not a non-zero value and I should able to select on cube but why I can only select on the BALL2 (0x0010). Thank you very much
Spintz
Posts: 1688
Joined: Thu Nov 04, 2004 3:25 pm

Post by Spintz »

masks should be setup like this -

Code: Select all

#define NONE_MASK (0x0000) 
#define BALL_MASK (0x0001) 
#define CUBE_MASK (0x0002)
#define BALL2_MASK (0x0004)
So none is( in binary ) 0000, ball is 0001, cube is 0010, ball2 is 0100.
Image
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Cant integers be used here?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yes, but hex is a little more intuitive as you have zeros everywhere except for the desired bit which is marked by either 1,2,4, or 8.
Georgian
Posts: 60
Joined: Sat Mar 31, 2007 12:55 pm

a little help please

Post by Georgian »

hello i am making a free game for Georgian kids..
in my game I have 33 texture mapped cubes several of which a kid should select, for test i created one cube with id 0x0001 and picking worked , now when i added second cube it doesn't work:

Code: Select all

#define CUBE_ID 0x0001
#define CUBE_ID2 0x0002
#define CUBE_ID3 0x0004


and then
aBox= sm->addCubeSceneNode();
	    aBox->setID(CUBE_ID);
		aBox->setPosition(core::vector3df(0,0,i));
		i+=30;
		
		
		
		if (aBox)
		{
			aBox->setMaterialTexture(0, driver->getTexture("../../media/data/FontA.jpg"));
			aBox->setMaterialFlag(video::EMF_LIGHTING, true);
			
		}

	// ------------------- 2 --------------------- //
		bBox= sm->addCubeSceneNode();
		bBox->setID(CUBE_ID2);
		bBox->setPosition(core::vector3df(0,0,i));
		i+=10;
		
		
		if (bBox)
		{ 
			bBox->setMaterialTexture(0, driver->getTexture("../../media/data/FontB.jpg"));
			bBox->setMaterialFlag(video::EMF_LIGHTING, true);
			
		}
		// ------------------- 3 --------------------- //
		gBox= sm->addCubeSceneNode();
		gBox->setID(CUBE_ID3);
		gBox->setPosition(core::vector3df(0,0,i));
		i+=10;

and finally pick
if(device->getSceneManager()->getSceneCollisionManager()->getSceneNodeFromCameraBB(camera,CUBE_ID2,false)==aBox )
	{device->closeDevice();  
	
	} 
so if 2nd cube was clicked program should close , it worked vith CUBE_ID :(

if I set CUBE_ID2 as 0x0010 it picks the first cube :(
can anyone tell me what am i doing wrong??
using Visual Studio 2003 , I use 3D Max 7, I love irrlicht its a really good and easy engine
Georgian
Posts: 60
Joined: Sat Mar 31, 2007 12:55 pm

Post by Georgian »

oooops sorry my bad :D i forgot to change aBox to bBox in If() statement of picking :oops:
using Visual Studio 2003 , I use 3D Max 7, I love irrlicht its a really good and easy engine
Post Reply