OGRE框选制作

框选制作

首先,一如既往给出框架程序(运行该框架程序看到一个机器人的矩阵):

 

 #include <CEGUI/CEGUI.h>
   #include <OgreCEGUIRenderer.h>
  
   #include "ExampleApplication.h"
  
   class SelectionRectangle : public ManualObject
   {
   public:
       SelectionRectangle(const String &name)
           : ManualObject(name)
       {
       }
  
      
       void setCorners(float left, float top, float right, float bottom)
       {
       }
  
       void setCorners(const Vector2 &topLeft, const Vector2 &bottomRight)
       {
           setCorners(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
       }
   };
  
   class DemoListener : public ExampleFrameListener, public OIS::MouseListener
   {
   public:
       DemoListener(RenderWindow* win, Camera* cam, SceneManager *sceneManager)
           : ExampleFrameListener(win, cam, false, true), mSceneMgr(sceneManager), mSelecting(false)
       {
           mMouse->setEventCallback(this);
       } // DemoListener
  
       ~DemoListener()
       {
       }
  
      
       bool mouseMoved(const OIS::MouseEvent &arg)
       {
           CEGUI::System::getSingleton().injectMouseMove(arg.state.X.rel, arg.state.Y.rel);
           return true;
       }
  
       bool mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
       {
           return true;
       }
  
       bool mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
       {
           return true;
       }
  
       void performSelection(const Vector2 &first, const Vector2 &second)
       {
       }
  
      void deselectObjects()
      {
          std::list<MovableObject*>::iterator itr;
          for (itr = mSelected.begin(); itr != mSelected.end(); ++itr)
              (*itr)->getParentSceneNode()->showBoundingBox(false);
      }
  
      void selectObject(MovableObject *obj)
      {
          obj->getParentSceneNode()->showBoundingBox(true);
          mSelected.push_back(obj);
      }
  
   private:
       Vector2 mStart, mStop;
       SceneManager *mSceneMgr;
       PlaneBoundedVolumeListSceneQuery *mVolQuery;
       std::list<MovableObject*> mSelected;
       SelectionRectangle *mRect;
       bool mSelecting;
  
  
       static void swap(float &x, float &y)
       {
           float tmp = x;
           x = y;
           y = tmp;
       }
   };
  
   class DemoApplication : public ExampleApplication
   {
   public:
       DemoApplication()
           : mRenderer(0), mSystem(0)
       {
       }
  
       ~DemoApplication()
       {
           if (mSystem)
               delete mSystem;
  
           if (mRenderer)
               delete mRenderer;
       }
  
   protected:
       CEGUI::OgreCEGUIRenderer *mRenderer;
       CEGUI::System *mSystem;
  
       void createScene(void)
       {
           mRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mSceneMgr);
           mSystem = new CEGUI::System(mRenderer);
  
           CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLookSkin.scheme");
           CEGUI::MouseCursor::getSingleton().setImage((CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MouseArrow");
  
           mCamera->setPosition(-60, 100, -60);
           mCamera->lookAt(60, 0, 60);
  
           mSceneMgr->setAmbientLight(ColourValue::White);
           for (int i = 0; i < 10; ++i)
               for (int j = 0; j < 10; ++j)
               {
                   Entity *ent = mSceneMgr->createEntity("Robot" + StringConverter::toString(i + j * 10), "robot.mesh");
                   SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(i * 15, 0, j * 15));
                   node->attachObject(ent);
                   node->setScale(0.1, 0.1, 0.1);
               }
       }
  
       void createFrameListener(void)
       {
           mFrameListener = new DemoListener(mWindow, mCamera, mSceneMgr);
           mFrameListener->showDebugOverlay(true);
           mRoot->addFrameListener(mFrameListener);
       }
   };
  
   #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
   #define WIN32_LEAN_AND_MEAN
   #include "windows.h"
  
   INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT)
   #else
   int main(int argc, char **argv)
   #endif
   {
       // Create application object
       DemoApplication app;
  
       try {
           app.go();
       } catch(Exception& e) {
   #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
           MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occurred!",
               MB_OK | MB_ICONERROR | MB_TASKMODAL);
   #else
           fprintf(stderr, "An exception has occurred: %s/n",
               e.getFullDescription().c_str());
   #endif
       }
  
       return 0;
   }

 

本节通过矩形来建立选取,因而必须先介绍一个相应的类。

 

 

创建网格的基本知识:

 

mesh的组成:顶点缓存(Vertex buffer)和索引缓存(Index buffer)。

    顶点缓存在3D空间里定义点集。顶点缓存里的每一个元素由若干你能设置的属性来定义。唯一一个你必须设置的属性就是顶点的坐标。除了这个,你还有设置其它可选的属性,比如顶点颜色、纹理坐标等。你实际需要的属性取决于mesh的用途。

    索引缓存通过从顶点缓存选取顶点,以“把点连起来”。索引缓存里每三个顶点定义了一个由GPU绘制的三角形。你在索引缓存里选取顶点的顺序,告诉了显卡这个三角形的朝向。逆时针绘制的三角形是朝向你的,顺时针绘制的三角形是背向你的。一般情况下只有三角形的正面才被绘制,所以确保你的三角形被正确载入是很重要的。

注意:

1、所有的mesh都有顶点缓存,但不一定都有索引缓存。比如一个空的三角形

2、顶点缓存和索引缓存通常保存在显卡自己的内存里,所以你的软件只要发送一些离散的命令,告诉它使用预定义的缓存来一口气渲染整个3D网格。

    在Ogre里有两种方法来创建你自己的网格。第一种是继承SimpleRenderable,并直接提供给它顶点和索引缓存。这是最直接的创建方式,但也是最不直观的。为了使事情更简单,Ogre提供一个更棒的接口叫做ManualObject,它能让你用一些简单的函数来定义一个网格。你仅仅调用"position"和"colour"函数,而不用往缓存里丢位置、颜色等数据。

 

 

  下面开始添加代码:

一、构建矩形

对创建的矩形的要求:

1、2D的矩形

2、发生重叠是矩形一定要在最上层。

SelectionRectangle的构造器函数中添加代码:

 

         setRenderQueueGroup(RENDER_QUEUE_OVERLAY);//把这个物体的渲染队列设

       //置成重叠队列(Overlay queue)。
       //函数把投影矩阵(projection matrix)和视图矩阵(view matrix)

       //设置成identity,作用就是声明做的东西是2D的
          setUseIdentityProjection(true);
          setUseIdentityView(true);
       //把这个物体的查询标记设置成0
          setQueryFlags(0);

 

 

setCorners里添加代码:


     //坐标转换,构造矩形时,我们通过鼠标坐标(0-1)构建,也就是说这个数字转换成范围[-1,1]的
     left = left * 2 - 1;
    right = right * 2 - 1;
    top = 1 - top * 2;
    bottom = 1 - bottom * 2;
    //开始创建对象
    clear();//重新绘制矩形之前移除上次的矩形
    begin("", RenderOperation::OT_LINE_STRIP);//第一个参数是材质,第二个参数是渲染操作
    //可以使用点、线、三角形来渲染这个网格。如果我们要渲染一个实心的网格,可以用三角形。
    //但我们只需要一个空的矩形,所以我们使用线条(line strip)。
    //定义5个点(第一个和最后一个是相同的,这样才能连接成整个矩形):
       position(left, top, -1);
       position(right, top, -1);//Z参数设成-1,因为我们只定义一个2D对象而不必使用Z轴。
       position(right, bottom, -1);
       position(left, bottom, -1);
       position(left, top, -1);
    end();
    
     AxisAlignedBox box;
     box.setInfinite();
     setBoundingBox(box);

________________________________________试运行程序,保证可以运行,但现在并无效果

 体积选取

创建一个SelectionRectangle类的实例,然后让SceneManager来为我们创建一个体积查询:

DemoListener的构造函数里添加代码:

 

             mRect = new SelectionRectangle("Selection SelectionRectangle");
             mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(mRect);

             mVolQuery = mSceneMgr->createPlaneBoundedVolumeQuery(PlaneBoundedVolumeList());

~DemoListener()里添加代码:
       {
           mSceneMgr->destroyQuery(mVolQuery);
           delete mRect;

       }
  

 

 鼠标处理

 mousePressed函数里添加代码:

 if (id == OIS::MB_Left)
      {
       CEGUI::MouseCursor *mouse = CEGUI::MouseCursor::getSingletonPtr();
       mStart.x = mouse->getPosition().d_x / (float)arg.state.width;
       mStart.y = mouse->getPosition().d_y / (float)arg.state.height;
       mStop = mStart;

       mSelecting = true;
       mRect->clear();
       mRect->setVisible(true);
      }

使用的是CEGUI::MouseCursor的x和y坐标,而不是OIS的鼠标坐标。这是因为有时OIS反映的坐标与CEGUI实际显示的不一样。为了保证我们与用户所看到的相一致,我们使用CEGUI的鼠标坐标。

mouseReleased函数里添加代码:

     if (id == OIS::MB_Left)
     {
      performSelection(mStart, mStop);
      mSelecting = false;
      mRect->setVisible(false);
     }

mouseMoved函数里添加代码:

      if (mSelecting)
      {
       CEGUI::MouseCursor *mouse = CEGUI::MouseCursor::getSingletonPtr();
       mStop.x = mouse->getPosition().d_x / (float)arg.state.width;
       mStop.y = mouse->getPosition().d_y / (float)arg.state.height;

       mRect->setCorners(mStart, mStop);
      }//鼠标移动时,我们都调整mStop向量,这样我们就能轻松地使用setCorners成员函数了

运行你的程序拖动鼠标左键,看看效果吧!

——————————————————————————————————————————————

performSelection里添加代码:

      float left = first.x, right = second.x,
       top = first.y, bottom = second.y;

      if (left > right)
       swap(left, right);

      if (top > bottom)
       swap(top, bottom);

分别为left、right、top、botton变量赋予向量参数。if语句保证了我们实际的left和top值最小。(如果这个矩形是“反向”画出来的,意味着从右下角到左上角,我们就要进行这种交换。)

 

如果这个矩形小于屏幕的某个百分比,我们只将它返回而不执行这个选取。

      if ((right - left) * (bottom - top) < 0.0001)
        return;

 

PlaneBoundedVolumeQueries使用平面来包围一个区域,所以所有在区域里的物体都被选取。我们将创建一个被五个平面包围的区域,它是朝向里面的。为了创建这些平面,我们建立了4条射线,每一条都是矩形的一个角产生的。

      Ray topLeft = mCamera->getCameraToViewportRay(left, top);
      Ray topRight = mCamera->getCameraToViewportRay(right, top);
      Ray bottomLeft = mCamera->getCameraToViewportRay(left, bottom);
      Ray bottomRight = mCamera->getCameraToViewportRay(right, bottom);

着射线走100个单位抓取一个点。这是随便选择的。在这里唯一重要的是前平面,它在摄像机前面3个单位的位置。

      PlaneBoundedVolume vol;


      vol.planes.push_back(Plane(topLeft.getPoint(3),

                   topRight.getPoint(3), bottomRight.getPoint(3)));         // 前平面
      vol.planes.push_back(Plane(topLeft.getOrigin(),

                   opLeft.getPoint(100), topRight.getPoint(100)));           // 顶平面
      vol.planes.push_back(Plane(topLeft.getOrigin(),

                    bottomLeft.getPoint(100), topLeft.getPoint(100)));       // 左平面
      vol.planes.push_back(Plane(topLeft.getOrigin(),

                    bottomRight.getPoint(100), bottomLeft.getPoint(100)));   // 底平面
      vol.planes.push_back(Plane(topLeft.getOrigin(),

                    topRight.getPoint(100), bottomRight.getPoint(100)));     // 右平面

//定义了一个在摄像机前无限伸展的“开放盒子”。

我们还需要执行这个查询:

   PlaneBoundedVolumeList volList;
      volList.push_back(vol);
      mVolQuery->setVolumes(volList);
      SceneQueryResult result = mVolQuery->execute();
处理查询返回的结果。首先我们要取消所有先前选取的物体,然后选取所有查询得到的物体。
      deselectObjects();
      SceneQueryResultMovableList::iterator itr;
      for (itr = result.movables.begin(); itr != result.movables.end(); ++itr)
          selectObject(*itr);
ok,运行你的程序你已经可以实现框选了。

_____________________________________________________________________________________________

 

框选制作(手札24 终级代码)

 #include <CEGUI/CEGUI.h>
   #include <OgreCEGUIRenderer.h>
  
   #include "ExampleApplication.h"
  
   class SelectionRectangle : public ManualObject
   {
   public:
       SelectionRectangle(const String &name)
           : ManualObject(name)
       {
           setRenderQueueGroup(RENDER_QUEUE_OVERLAY);//把这个物体的渲染队列设置成重叠队列(Overlay queue)。
     //函数把投影矩阵(projection matrix)和视图矩阵(view matrix)设置成identity,作用就是声明做的东西是2D的
                 setUseIdentityProjection(true);
                 setUseIdentityView(true);
     //把这个物体的查询标记设置成0
     setQueryFlags(0);
    

       }
  
      
       void setCorners(float left, float top, float right, float bottom)
       {
     //坐标转换,构造矩形时,我们通过鼠标坐标(0-1)构建,也就是说这个数字转换成范围[-1,1]的
     left = left * 2 - 1;
    right = right * 2 - 1;
    top = 1 - top * 2;
    bottom = 1 - bottom * 2;
    //开始创建对象
    clear();//重新绘制矩形之前移除上次的矩形
    begin("", RenderOperation::OT_LINE_STRIP);//第一个参数是材质,第二个参数是渲染操作
    //可以使用点、线、三角形来渲染这个网格。如果我们要渲染一个实心的网格,可以用三角形。
    //但我们只需要一个空的矩形,所以我们使用线条(line strip)。
    //定义5个点(第一个和最后一个是相同的,这样才能连接成整个矩形):
       position(left, top, -1);
       position(right, top, -1);//Z参数设成-1,因为我们只定义一个2D对象而不必使用Z轴。
       position(right, bottom, -1);
       position(left, bottom, -1);
       position(left, top, -1);
    end();
    
     AxisAlignedBox box;
     box.setInfinite();
     setBoundingBox(box);

 


       }
  
       void setCorners(const Vector2 &topLeft, const Vector2 &bottomRight)
       {
           setCorners(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
       }
   };
  
   class DemoListener : public ExampleFrameListener, public OIS::MouseListener
   {
   public:
       DemoListener(RenderWindow* win, Camera* cam, SceneManager *sceneManager)
           : ExampleFrameListener(win, cam, false, true), mSceneMgr(sceneManager), mSelecting(false)
       {
           mMouse->setEventCallback(this);

      mRect = new SelectionRectangle("Selection SelectionRectangle");
             mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(mRect);

             mVolQuery = mSceneMgr->createPlaneBoundedVolumeQuery(PlaneBoundedVolumeList());
       } // DemoListener
  
       ~DemoListener()
       {
     mSceneMgr->destroyQuery(mVolQuery);
           delete mRect;

       }
  
      
       bool mouseMoved(const OIS::MouseEvent &arg)
       {
           CEGUI::System::getSingleton().injectMouseMove(arg.state.X.rel, arg.state.Y.rel);
           if (mSelecting)
      {
       CEGUI::MouseCursor *mouse = CEGUI::MouseCursor::getSingletonPtr();
       mStop.x = mouse->getPosition().d_x / (float)arg.state.width;
       mStop.y = mouse->getPosition().d_y / (float)arg.state.height;

       mRect->setCorners(mStart, mStop);
      }

           return true;
       }
  
       bool mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
       {
           if (id == OIS::MB_Left)
      {
       CEGUI::MouseCursor *mouse = CEGUI::MouseCursor::getSingletonPtr();
       mStart.x = mouse->getPosition().d_x / (float)arg.state.width;
       mStart.y = mouse->getPosition().d_y / (float)arg.state.height;
       mStop = mStart;

       mSelecting = true;
       mRect->clear();
       mRect->setVisible(true);
      }
           return true;
       }
  
       bool mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
       {
     if (id == OIS::MB_Left)
     {
      performSelection(mStart, mStop);
      mSelecting = false;
      mRect->setVisible(false);
     }

           return true;
       }
  
       void performSelection(const Vector2 &first, const Vector2 &second)
       {
           float left = first.x, right = second.x,
       top = first.y, bottom = second.y;

      if (left > right)
       swap(left, right);

      if (top > bottom)
       swap(top, bottom);
      if ((right - left) * (bottom - top) < 0.0001)
        return;

      Ray topLeft = mCamera->getCameraToViewportRay(left, top);
      Ray topRight = mCamera->getCameraToViewportRay(right, top);
      Ray bottomLeft = mCamera->getCameraToViewportRay(left, bottom);
      Ray bottomRight = mCamera->getCameraToViewportRay(right, bottom);
 


      PlaneBoundedVolume vol;
      vol.planes.push_back(Plane(topLeft.getPoint(3), topRight.getPoint(3), bottomRight.getPoint(3)));         // 前平面
      vol.planes.push_back(Plane(topLeft.getOrigin(), topLeft.getPoint(100), topRight.getPoint(100)));         // 顶平面
      vol.planes.push_back(Plane(topLeft.getOrigin(), bottomLeft.getPoint(100), topLeft.getPoint(100)));       // 左平面
      vol.planes.push_back(Plane(topLeft.getOrigin(), bottomRight.getPoint(100), bottomLeft.getPoint(100)));   // 底平面
      vol.planes.push_back(Plane(topLeft.getOrigin(), topRight.getPoint(100), bottomRight.getPoint(100)));     // 右平面
     
   PlaneBoundedVolumeList volList;
      volList.push_back(vol);

      mVolQuery->setVolumes(volList);
      SceneQueryResult result = mVolQuery->execute();
      deselectObjects();
      SceneQueryResultMovableList::iterator itr;
      for (itr = result.movables.begin(); itr != result.movables.end(); ++itr)
          selectObject(*itr);

       }
  
      void deselectObjects()
      {
          std::list<MovableObject*>::iterator itr;
          for (itr = mSelected.begin(); itr != mSelected.end(); ++itr)
              (*itr)->getParentSceneNode()->showBoundingBox(false);
      }
  
      void selectObject(MovableObject *obj)
      {
          obj->getParentSceneNode()->showBoundingBox(true);
          mSelected.push_back(obj);
      }
  
   private:
       Vector2 mStart, mStop;
       SceneManager *mSceneMgr;
       PlaneBoundedVolumeListSceneQuery *mVolQuery;
       std::list<MovableObject*> mSelected;
       SelectionRectangle *mRect;
       bool mSelecting;
  
  
       static void swap(float &x, float &y)
       {
           float tmp = x;
           x = y;
           y = tmp;
       }
   };
  
   class DemoApplication : public ExampleApplication
   {
   public:
       DemoApplication()
           : mRenderer(0), mSystem(0)
       {
       }
  
       ~DemoApplication()
       {
           if (mSystem)
               delete mSystem;
  
           if (mRenderer)
               delete mRenderer;
       }
  
   protected:
       CEGUI::OgreCEGUIRenderer *mRenderer;
       CEGUI::System *mSystem;
  
       void createScene(void)
       {
           mRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mSceneMgr);
           mSystem = new CEGUI::System(mRenderer);
  
           CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLookSkin.scheme");
           CEGUI::MouseCursor::getSingleton().setImage((CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MouseArrow");
  
           mCamera->setPosition(-60, 100, -60);
           mCamera->lookAt(60, 0, 60);
  
           mSceneMgr->setAmbientLight(ColourValue::White);
           for (int i = 0; i < 10; ++i)
               for (int j = 0; j < 10; ++j)
               {
                   Entity *ent = mSceneMgr->createEntity("Robot" + StringConverter::toString(i + j * 10), "robot.mesh");
                   SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(i * 15, 0, j * 15));
                   node->attachObject(ent);
                   node->setScale(0.1, 0.1, 0.1);
               }


       }
  
       void createFrameListener(void)
       {
           mFrameListener = new DemoListener(mWindow, mCamera, mSceneMgr);
           mFrameListener->showDebugOverlay(true);
           mRoot->addFrameListener(mFrameListener);
       }
   };
  
   #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
   #define WIN32_LEAN_AND_MEAN
   #include "windows.h"
  
   INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT)
   #else
   int main(int argc, char **argv)
   #endif
   {
       // Create application object
       DemoApplication app;
  
       try {
           app.go();
       } catch(Exception& e) {
   #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
           MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occurred!",
               MB_OK | MB_ICONERROR | MB_TASKMODAL);
   #else
           fprintf(stderr, "An exception has occurred: %s/n",
               e.getFullDescription().c_str());
   #endif
       }
  
       return 0;
   }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值