目錄
- 首先祝大家國慶快樂
- 本節內容
- 實作要點
- 以下為全部代碼
首先祝大家國慶快樂
本節內容
本節開始介紹滑鼠選擇的操作,正常情況下我們都會在場景中使用滑鼠框選一些物體,本節我們繪制了框選框,程式啟動后,按住鍵盤上的左CTRL鍵,然后滑鼠在場景中拖動,會出來一個白色的框,符合框選的習慣,如下圖所示:

本節代碼在如下網盤中,根據章節編號有對應附件,請使用瀏覽器打開,平時遇到問題或加群也可以加我微信:13324598743:
鏈接:https://pan.baidu.com/s/13gwJLwo_LbRnN3Bl2NXXXw
提取碼:xrf5
實作要點
要點只有兩個,其它均為正常的繪制和邏輯處理:
- 在點下左CTRL的時候,滑鼠拖動時要在框選的狀態,此時場景的操作器就不起作用了,不能一邊選著,場景隨著滑鼠的拖動還轉著,那就不行,此處只需要在事件中回傳true,后面的事件處理器就不再處理該事件了,場景也就不轉動了 這是個很隱蔽但是又很重要的知識點,具體實作參見MyEvent中的handle,注釋較為詳盡,
- 在螢屏表面繪制一個白色的框要用到HUD,HUD的初始化需要知道當前場景的視窗是多大,而當前的視窗是在viewer.realize之后才創建的,因此需要在viewer.realize之后獲取viewport引數之后,再創建HUD中的相機,設定setProjectionMatrix,
以下為全部代碼
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/Camera>
#include <osgGA/GUIEventHandler>
//結點的掩碼,顯示與隱藏
#define NODE_SHOW ~0x0
#define NODE_HIDE 0x0
//選擇框做為一個全域變數,使用起來方便
osg::Geometry* g_geomSelectBox = new osg::Geometry;
//
osg::Camera* createHUD(osg::Viewport* vp)
{
osg::Camera* camera = new osg::Camera;
//設定投影矩陣為正交投影
camera->setProjectionMatrix(osg::Matrix::ortho2D(0, vp->width(), 0, vp->height()));
//設定其觀察矩陣為單位矩陣,且不改變,該相機永遠顯示,也不用參與揀選
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
camera->setViewMatrix(osg::Matrix::identity());
//只清空深度快取,使得其顯示內容可以以主相機為背景
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
//最后渲染,因為需要以主相機顯示的內容為背景
camera->setRenderOrder(osg::Camera::POST_RENDER);
//不需要回應事件
camera->setAllowEventFocus(false);
//繪制選擇框
osg::Geode* gnode = new osg::Geode;
camera->addChild(gnode);
gnode->addDrawable(g_geomSelectBox);
//設定透明
osg::StateSet* ss = gnode->getOrCreateStateSet();
ss->setMode(GL_BLEND, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
//設定頂點
osg::Vec3Array* vertices = new osg::Vec3Array;
float depth = - 0.1;
vertices->push_back(osg::Vec3(0, 0, depth));
vertices->push_back(osg::Vec3(100, 0, depth));
vertices->push_back(osg::Vec3(100, 100, depth));
vertices->push_back(osg::Vec3(0, 100, depth));
g_geomSelectBox->setVertexArray(vertices);
//設定顏色
osg::Vec4Array* color = new osg::Vec4Array;
color->push_back(osg::Vec4(0.8, 0.8, 0.8, 0.2));
g_geomSelectBox->setColorArray(color, osg::Array::BIND_OVERALL);
//繪制盒子
g_geomSelectBox->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
return camera;
}
class MyEvent : public osgGA::GUIEventHandler
{
public:
MyEvent() :osgGA::GUIEventHandler(),
_xStart(0),
_yStart(0)
{
}
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
//左ctrl按著,又滑鼠點擊,則進入繪制狀態
if (ea.getEventType() == ea.PUSH) //
{
//判斷左CTRL鍵是否按下
if (ea.getModKeyMask() == ea.MODKEY_LEFT_CTRL)
{
_xStart = ea.getX();
_yStart = ea.getY();
//清空之前繪制的結果,這里僅隱藏即可
g_geomSelectBox->setNodeMask(NODE_HIDE);
//回傳真代表后續事件處理器包括操作器不再處理該事件,就實作了拖動時場景不動
return true;
}
}
//左ctrl點下時,進入到選擇狀態,開始繪制選擇框,且操作器不再處理滑鼠拖動事件
if (ea.getEventType() == ea.DRAG) //滑鼠拖動,拖動是滑鼠按鍵按下的時候移動滑鼠
{
//判斷左CTRL鍵是否按下
if (ea.getModKeyMask() == ea.MODKEY_LEFT_CTRL)
{
//開始繪制,調整頂點引數就可以
g_geomSelectBox->setNodeMask(NODE_SHOW);
//獲取頂點、更新頂點
osg::Vec3Array* vertices = (osg::Vec3Array*)g_geomSelectBox->getVertexArray();
int xEnd = ea.getX();
int yEnd = ea.getY();
float depth = -0.1;
vertices->at(0).set(_xStart, _yStart, depth);
vertices->at(1).set(xEnd, _yStart, depth);
vertices->at(2).set(xEnd, yEnd, depth);
vertices->at(3).set(_xStart, yEnd, depth);
//重繪
g_geomSelectBox->dirtyDisplayList();
//回傳真代表后續事件處理器包括操作器不再處理該事件,就實作了拖動時場景不動
return true;
}
}
return false;
}
int _xStart, _yStart;
};
int main()
{
osgViewer::Viewer viewer;
osg::Group* root = new osg::Group;
root->addChild(osgDB::readNodeFile("cow.osg"));
viewer.setSceneData(root);
viewer.realize();
//realize之后,背景關系已經被初始化,可以獲得視口大小
//在此處獲得視口大小是為了創建HUD時使其視口大小與創建的一致
osg::Viewport* vp = viewer.getCamera()->getViewport();
root->addChild(createHUD(vp));
viewer.addEventHandler(new MyEvent);
return viewer.run();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/304582.html
標籤:其他
