- 由上一讲学会了如何使用hud相机,而菜单也刚好是贴在屏幕之上,故可以用hud相机来实现菜单。我们只需要写一个事件接收器,判断鼠标的点击范围即可触发自己想要实现的方法。
//创建hud相机的Menu
osg::Camera* createHudMenu()
{
osg::ref_ptr<osg::Camera>camera = new osg::Camera;
camera->setViewMatrix(osg::Matrix::identity());//相机设置为单位矩阵
camera->setRenderOrder(osg::Camera::POST_RENDER);
camera->setClearMask(GL_DEPTH_BUFFER_BIT);//清除深度缓存
camera->setAllowEventFocus(false);//不接受焦点
camera->setViewport(200, 200, 200, 200);
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);//设置为绝对帧,防止拣选
camera->setProjectionMatrixAsOrtho2D(0, 200, 0, 200);//正视投影的大小
//添加文字
osg::ref_ptr<osg::Geode>geo = new osg::Geode;
geo->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
osg::ref_ptr<osgText::Text> text = new osgText::Text;
geo->addDrawable(text);
text->setFont("fonts/ZhanKuWenYiTi-2.ttf");
text->setCharacterSize(50);//字体大小
text->setText(L"测试");
text->setPosition(osg::Vec3d(0, 50, 0));
camera->addChild(geo);
//添加纹理
osg::Geometry*gm = new osg::Geometry;
//设置顶点坐标
osg::Vec3Array*vertex = new osg::Vec3Array;
vertex->push_back(osg::Vec3d(0, 0, -1.0));
vertex->push_back(osg::Vec3d(100, 0, -1.0));
vertex->push_back(osg::Vec3d(100, 100, -1.0));
vertex->push_back(osg::Vec3d(0, 100, -1.0));
gm->setVertexArray(vertex);
//设置法线
osg::Vec3dArray*norm = new osg::Vec3dArray;
norm->push_back(osg::Vec3(0.0, 0.0, 1.0));
gm->setNormalArray(norm);
gm->setNormalBinding(osg::Geometry::BIND_OVERALL);
osg::Vec4dArray*arr_color = new osg::Vec4dArray;
arr_color->push_back(osg::Vec4d(1.0,0.0,0.0,0.5));
gm->setColorArray(arr_color);
gm->setColorBinding(osg::Geometry::BIND_OVERALL);
gm->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
geo->addDrawable(gm);
return camera.release();
}
class menuEvent:public osgGA::GUIEventHandler
{
public:
menuEvent(osgViewer::Viewer*view_)
{
view = view_;
}
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (!view)
{
return false;
}
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::PUSH:
{
if (ea.getX()>200&&ea.getX()<400&& ea.getY()>200 && ea.getY()<400)//根据菜单的位置触发事件
{
std::cout << "菜单触发";
}
}
break;
default:
break;
}
return false;
}
private:
osgViewer::Viewer*view;
};
我们可以看到,menu的代码和hud相机的实现一模一样,在事件接收器中判断鼠标位置,从而触发事件,前几讲有说到过事件接收器的实现,操作系统把事件给到osg,osg把事件压入队列,然后每一帧遍历事件接收器,触发handle(),如果在handle()中返回true则不再进行下一个事件消息,即如果此处返回true,我们的场景拖动就会无响应,需要返回false则继续下一个事件接收器。