Really Easy Mesh Clicking!

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
tdkr80
Posts: 18
Joined: Thu Aug 18, 2016 10:15 am

Really Easy Mesh Clicking!

Post by tdkr80 »

I stumbled upon a simple way to click on a mesh (C#, IrrlichtLime... But I'm sure it's easy to convert!)

Firstly, here's the way to get 3D world coordinates:

Code: Select all

 
// sceneManager is SceneManager
// device is IrrlichtDevice
// meta is MetaTriangleSelector
// here we go
 
public Vector3Df Get3DCursorPosition()
{
            Vector3Df result;
            Triangle3Df triangle;
            Line3Df ray;
 
            ray = sceneManager.SceneCollisionManager.GetRayFromScreenCoordinates(device.CursorControl.Position, sceneManager.ActiveCamera);
            sceneManager.SceneCollisionManager.GetCollisionPoint(ray, meta, out result, out triangle);
 
            return result;
}
 
This will return the 3D mouse position (x,y,z) as a Vector3Df. Now we just have to set up a method to check if a mesh has been clicked

Code: Select all

 
// node is SceneNode
// game is just my game class, where I stored the Get3DCursorPosition method
// here we go
 
        public bool IsClicked(float range)
        {
            if (node.Position.GetDistanceFrom(game.Get3DCursorPosition()) < range)
            {
                Console.WriteLine(node.Position.GetDistanceFrom(game.Get3DCursorPosition()));
                return true;
            }
 
            return false;
        }
 
and just to clarify, this is how it would be used

Code: Select all

 
// check to see if a button has been clicked, then do this
if(mesh.IsClicked())
{
 // do what ever you want here
}
 
I REALLY hope this helps someone!
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Really Easy Mesh Clicking!

Post by Vectrotek »

Cooooool! :wink:
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Re: Really Easy Mesh Clicking!

Post by Mel »

You could try to implement a sort of "node pick up" cache. I heard of the concept somewhere, and could really use a try. The idea isn't that odd, as many times when you click on something, is very likely you're going to click on it again. So, you just keep a list of nodes updated on a FIFO basis, whose position on screen you update every frame, and when you have your 2D coordinates, you pick-up a node from those first, if it is not there, then you may perform the scene node pick up as always. Just throwing in an idea :)
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
tdkr80
Posts: 18
Joined: Thu Aug 18, 2016 10:15 am

Re: Really Easy Mesh Clicking!

Post by tdkr80 »

That sounds like a good idea but finding a fast way to do this could be difficult, using lists could be extremely slow when there's multiple meshes in the scene. Arrays could work I suppose. I think I might give it a try.

First though, I'm trying to figure out a way to get the actually size of the mesh so that setting the "radius" can be eliminated, otherwise resizing meshes will be annoying because you'll have to change the radius as well.
tdkr80
Posts: 18
Joined: Thu Aug 18, 2016 10:15 am

Re: Really Easy Mesh Clicking!

Post by tdkr80 »

I've tried a few different things but still haven't figured it out yet.

Here's what I've got so far:

Code: Select all

 
        public bool MouseIsOver(Camera camera, float range)
        {
            if (node.Position.GetDistanceFrom(camera.GetCursorPosition3D()) < node.BoundingBoxTransformed.Radius)
                return true;
 
            return false;
        }
 
I know I'm heading in the right direction but for some reason the radius of the bounding box isn't the same size as the mesh, I've also tried using area instead of radius but still no luck.

Any ideas?
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Really Easy Mesh Clicking!

Post by mongoose7 »

The code seems to be asking:

"Is the camera inside the node bounding sphere?"

I guess the answer is:

"No!"
Seven
Posts: 1030
Joined: Mon Nov 14, 2005 2:03 pm

Re: Really Easy Mesh Clicking!

Post by Seven »

Ive been watching this string of threads and am niot sure exactly what you are trying to do, but if all you are doing is selecting a node with the mouse you can do this...

//! Returns the scene node, which is currently visible at the given
//! screen coordinates, viewed from the currently active camera.
ISceneNode* CSceneCollisionManager::getSceneNodeFromScreenCoordinatesBB(
const core::position2d<s32>& pos, s32 idBitMask, bool noDebugObjects, scene::ISceneNode* root)
{
const core::line3d<f32> ln = getRayFromScreenCoordinates(pos, 0);

if ( ln.start == ln.end )
return 0;

return getSceneNodeFromRayBB(ln, idBitMask, noDebugObjects, root);
}
Seven
Posts: 1030
Joined: Mon Nov 14, 2005 2:03 pm

Re: Really Easy Mesh Clicking!

Post by Seven »

here is a full blown application that picks nodes and allows you to manipulate them. Maybe it will help.
just create a new console app and copy / paste this into it.

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_TRANSLATE;
float               RotateSpeed         = 0.01f;
float               ScaleSpeed         = 0.01f;
 
#define ID_QUIT         101
#define ID_TRANSLATE   102
#define ID_ROTATE      103
#define ID_SCALE      104
 
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;
                          } 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 :
                {
                  // 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);
                   }
 
                   // we used this message?
                   return (SelectedNode != 0);
                } break;
 
               case EMIE_LMOUSE_LEFT_UP :
                {
                  LMouseButtonDown = false;
                  return false;
                } 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<s32>(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");
 
   // 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->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));
   camera->setIsDebugObject(true);
 
   // 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;
} 
 
ppsychrite
Posts: 6
Joined: Tue Mar 21, 2017 12:05 am

Re: Really Easy Mesh Clicking!

Post by ppsychrite »

Thanks, this is going to really help my projects! :wink:
Post Reply