运城网站建设多少钱,丈哥seo博客工具,wordpress分类图片尺寸,宁波seo企业推广目录
1. 需求的提出
2. 具体实现 2.1. 禁止场景跟随鼠标转动 2.2. 矩形框前置绘制
3. 附加说明 3.1. 颜色设置说明 3.2.矩形框显示和隐藏的另一种实现 1. 需求的提出 有时需要在屏幕通过按住键盘上的某个键如Ctrl键且按住鼠标左键#xff0c;拖出一个矩形#xff0c;实现框…目录
1. 需求的提出
2. 具体实现 2.1. 禁止场景跟随鼠标转动 2.2. 矩形框前置绘制
3. 附加说明 3.1. 颜色设置说明 3.2.矩形框显示和隐藏的另一种实现 1. 需求的提出 有时需要在屏幕通过按住键盘上的某个键如Ctrl键且按住鼠标左键拖出一个矩形实现框选三维物体如下效果 现在的问题是:
在osg中拖动鼠标时物体会随鼠标一起转动这样框选是不行的至少是不友好的我们需要的是按住鼠标框选时物体不能随鼠标一起转动。如何根据鼠标拖动的起始点和终止点绘制出这个矩形框矩形框要在所有三维物体的前面而不能被三维物体遮挡且要是透明的能透过它看到背后的三维物体否则框选就失去了意义。按住鼠标右键矩形框消失。
2. 具体实现 2.1. 禁止场景跟随鼠标转动 对第1节中提到的第1个问题默认情况下osgViewer::Viewer事件处理器在鼠标左键按下并拖动时整个场景会随鼠标一起转动。为了不让转动可以通过改写osgViewer::Viewer的 osgGA::GUIEventHandler事件处理器重载如下方法 virtual bool handle(const osgGA::GUIEventAdapter ea, osgGA::GUIActionAdapter aa, osg::Object* obj, osg::NodeVisitor*nv)
当按住键盘上的某个键如Ctrl键且按住鼠标左键让该函数返回true这样后续的流程就不会处理鼠标拖动事件三维物体也就不会跟随鼠标旋转了。 2.2. 矩形框前置绘制 矩形框要绘制在所有三维物体的前面而不能被三维物体遮挡这就要用到三维中的HUD技术Head Up Display。所谓HUD节点说白了就是无论三维场景中的内容怎么改变它都能在屏幕上固定位置显示的节点。实现要点
关闭光照不受场景光照影响所有内容以同一亮度显示。关闭深度测试。调整渲染顺序使它的内容最后绘制。设定参考贴为绝对型setReferenceFrame(osg::Transform:ABSOLUTE_RF)。使其不受父节点变换的影响setMatrix(osg::Matrix::identity())。使用平行投影设定虚拟投影窗口的大小这个窗口的大小决定了后面绘制的图形和文字的尺度比例。 实现代码如下
#includeosgViewer/Viewer
#includeosg/ShapeDrawable
#includeosgDB/readFile
#includeosg/BlendFunc
class selectBoxEventHandler: public osgGA::GUIEventHandler
{
public:selectBoxEventHandler(osg::ref_ptrosg::Camera spHudCamera){m_spHudCamera spHudCamera;}
private:virtual bool handle(const osgGA::GUIEventAdapter ea, osgGA::GUIActionAdapter aa, osg::Object* obj, osg::NodeVisitor*nv){m_pViewer (osgViewer::Viewer*)(aa);if (m_pViewer nullptr){return false;}auto width m_pViewer-getCamera()-getViewport()-width();auto height m_pViewer-getCamera()-getViewport()-height();/* 设置HUD相机为正投影这样绘制的矩形框和鼠标拖动的框选框大小就一样了且要设置正投影的区域和视图窗体一样大小因为鼠标可以在窗体任何位置进行框选*/m_spHudCamera-setProjectionMatrix(osg::Matrix::ortho2D(0, width, 0, height));auto eventType ea.getEventType();switch (eventType){case osgGA::GUIEventAdapter::KEYDOWN:{if ((osgGA::GUIEventAdapter::KEY_Control_L ea.getKey()) || (osgGA::GUIEventAdapter::KEY_Control_R ea.getKey())) // Ctrl键被按下{m_ctrlKeyPressed true;}}break;case osgGA::GUIEventAdapter::KEYUP:{if ((osgGA::GUIEventAdapter::KEY_Control_L ea.getKey())|| (osgGA::GUIEventAdapter::KEY_Control_R ea.getKey())) // Ctrl键被释放{m_ctrlKeyPressed false;}}break;case osgGA::GUIEventAdapter::PUSH: // 鼠标左键按下{auto buttonMask ea.getButtonMask();auto bIsMouseBtn buttonMask osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON;if (bIsMouseBtn){m_fStartPosX ea.getX();m_fStartPosY ea.getY();m_bPush true;}else if (buttonMask osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) // 鼠标右键按下则删除选择框{if (m_spOldNode ! nullptr){m_spHudCamera-removeChild(m_spOldNode);}}}break;case osgGA::GUIEventAdapter::RELEASE: // 释放鼠标左键{m_bPush false;}break;case osgGA::GUIEventAdapter::DRAG: // 拖动鼠标{auto buttonMask ea.getButtonMask();auto bIsMouseBtn buttonMask osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON;if (bIsMouseBtn m_ctrlKeyPressed m_bPush){m_fEndPosX ea.getX();m_fEndPosY ea.getY();auto pSelectBox createSelectBox(m_fStartPosX, m_fStartPosY, m_fEndPosX, m_fEndPosY);if (m_spOldNode ! nullptr){m_spHudCamera-removeChild(m_spOldNode);}m_spHudCamera-addChild(pSelectBox);m_spOldNode pSelectBox;return true;}}} // end swithreturn false;}osg::Geode* createSelectBox(float fStartPosX, float fStartPosY, float fEndPosX, float fEndPosY){osg::Geode* pGeode new osg::Geode();auto pQuardGeomerty new osg::Geometry();pGeode-addChild(pQuardGeomerty);osg::Vec3Array* pVertArray new osg::Vec3Array;pVertArray-push_back(osg::Vec3(fStartPosX, fStartPosY, 0.0));pVertArray-push_back(osg::Vec3(fStartPosX, fEndPosY, 0.0));pVertArray-push_back(osg::Vec3(fEndPosX, fEndPosY, 0.0));pVertArray-push_back(osg::Vec3(fEndPosX, fStartPosY, 0.0));pQuardGeomerty-setVertexArray(pVertArray);osg::Vec4Array* pColorArray new osg::Vec4Array;pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.4));/* pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));*/pQuardGeomerty-setColorArray(pColorArray);//pQuardGeomerty-setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_VERTEX);pQuardGeomerty-setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_PRIMITIVE_SET);pQuardGeomerty-addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));pGeode-getOrCreateStateSet()-setMode(GL_LIGHTING, osg::StateAttribute::OFF); // 关闭光照pGeode-getOrCreateStateSet()-setMode(GL_BLEND, osg::StateAttribute::ON); // 开启透明否则就不能透过选择框看到后面的牛pGeode-addDrawable(pQuardGeomerty);return pGeode;}private:/* 鼠标按下的起始坐标点 */float m_fStartPosX{0.0};float m_fStartPosY{ 0.0 };float m_fEndPosX{ 0.0 };float m_fEndPosY{ 0.0 };bool m_ctrlKeyPressed{false}; // Ctrl键被按下bool m_bPush{false}; // 鼠标左键是否被按下osgViewer::Viewer* m_pViewer{nullptr};osg::ref_ptrosg::Camera m_spHudCamera; // 用于HUD的相机osg::ref_ptrosg::Node m_spOldNode; // 上次鼠标框选绘制出的矩形框};
int main(int argc, char *argv[])
{osgViewer::Viewer viewer;auto cowNode osgDB::readNodeFile(R(E:\osg\OpenSceneGraph-Data\cow.osg));if (nullptr cowNode){OSG_WARN node is null!;return 1;}auto spRoot new osg::Group();osg::ref_ptrosg::Camera spHudCamera new osg::Camera;spHudCamera-setClearMask(GL_DEPTH_BUFFER_BIT); // 关闭深度缓冲// 设置渲染顺序为后渲染即始终在其它绘制物体的上面防止被其它绘制的物体遮挡spHudCamera-setRenderOrder(osg::Camera::RenderOrder::POST_RENDER); spHudCamera-setAllowEventFocus(false); // 不接受任何焦点事件即不响应键盘、鼠标事件spHudCamera-setReferenceFrame(osg::Transform::ReferenceFrame::ABSOLUTE_RF); // 设置参考帧为绝对帧spHudCamera-setViewMatrix(osg::Matrix::identity()); // 设置相机视图矩阵为单位矩阵这样就矩形框选框就不受相机旋转等变换影响spRoot-addChild(cowNode);spRoot-addChild(spHudCamera);viewer.setSceneData(spRoot);viewer.addEventHandler(new selectBoxEventHandler(spHudCamera));return viewer.run();
}3. 附加说明 3.1. 颜色设置说明 2.2节代码对颜色的设置也可以按如下代码一样达到同样的效果 osg::Vec4Array* pColorArray new osg::Vec4Array;pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.4));pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pQuardGeomerty-setColorArray(pColorArray);pQuardGeomerty-setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_VERTEX);
也就是说设置一个顶点的颜色且颜色绑定方式为BIND_PER_PRIMITIVE_SET和分别设置4个顶点颜色颜色绑定方式为BIND_PER_VERTEX效果相同。关于BIND_PER_PRIMITIVE_SET和BIND_PER_VERTEX的具体含义和不同点请参考osg图元绑定方式总结博文。 3.2.矩形框显示和隐藏的另一种实现 上面矩形框的显示和隐藏是通过removeChild和addChild函数来实现的即将新的矩形框节点加入到相机作为其子节点之前删除上次创建的矩形框节点。也可以通过osg::Node的setNodeMask函数来实现如下为更改后的代码
#includeosgViewer/Viewer
#includeosg/ShapeDrawable
#includeosgDB/readFile
#includeosg/BlendFunc#define HIDE_SELECT_BOX 0X0
#define SHOW_SELECT_BOX ~HIDE_SELECT_BOXclass selectBoxEventHandler : public osgGA::GUIEventHandler
{
public:selectBoxEventHandler(osg::ref_ptrosg::Camera spHudCamera){m_spHudCamera spHudCamera;}
private:virtual bool handle(const osgGA::GUIEventAdapter ea, osgGA::GUIActionAdapter aa, osg::Object* obj, osg::NodeVisitor* nv){m_pViewer (osgViewer::Viewer*)(aa);if (m_pViewer nullptr){return false;}auto width m_pViewer-getCamera()-getViewport()-width();auto height m_pViewer-getCamera()-getViewport()-height();/* 设置HuD相机为正投影这样绘制的矩形框和鼠标拖动的框选框大小就一样了且要设置正投影的区域和视图窗体一样大小因为鼠标可以在窗体任何位置进行框选*/m_spHudCamera-setProjectionMatrix(osg::Matrix::ortho2D(0, width, 0, height));auto eventType ea.getEventType();switch (eventType){case osgGA::GUIEventAdapter::KEYDOWN:{if ((osgGA::GUIEventAdapter::KEY_Control_L ea.getKey())|| (osgGA::GUIEventAdapter::KEY_Control_R ea.getKey())) // Ctrl键被按下{m_ctrlKeyPressed true;}}break;case osgGA::GUIEventAdapter::KEYUP:{if ((osgGA::GUIEventAdapter::KEY_Control_L ea.getKey())|| (osgGA::GUIEventAdapter::KEY_Control_R ea.getKey())) // Ctrl键被按下{m_ctrlKeyPressed false;}}break;case osgGA::GUIEventAdapter::PUSH: // 鼠标左键按下{auto buttonMask ea.getButtonMask();auto bIsMouseBtn buttonMask osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON;if (bIsMouseBtn){m_fStartPosX ea.getX();m_fStartPosY ea.getY();m_bPush true;}else if (buttonMask osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) // 鼠标右键按下则删除选择框{if (m_spRectGeometry ! nullptr){m_spRectGeometry-setNodeMask(HIDE_SELECT_BOX);}}}break;case osgGA::GUIEventAdapter::RELEASE: // 释放鼠标左键{m_bPush false;}break;case osgGA::GUIEventAdapter::DRAG: // 拖动鼠标{auto buttonMask ea.getButtonMask();auto bIsMouseBtn buttonMask osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON;if (bIsMouseBtn m_ctrlKeyPressed m_bPush){m_fEndPosX ea.getX();m_fEndPosY ea.getY();if (nullptr ! m_spRectGeometry){auto pVertArray (osg::Vec3Array*)m_spRectGeometry-getVertexArray();(*pVertArray)[0].set(m_fStartPosX, m_fStartPosY, 0.0);(*pVertArray)[1].set(m_fStartPosX, m_fEndPosY, 0.0);(*pVertArray)[2].set(m_fEndPosX, m_fEndPosY, 0.0);(*pVertArray)[3].set(m_fEndPosX, m_fStartPosY, 0.0);// m_spRectGeometry-setVertexArray(pVertArray);m_spRectGeometry-dirtyDisplayList(); // 告知底层外层顶点数据更改了否则不会用新的坐标绘制矩形m_spRectGeometry-setNodeMask(SHOW_SELECT_BOX);}else{auto spSelectBox createSelectBox(m_fStartPosX, m_fStartPosY, m_fEndPosX, m_fEndPosY);m_spRectGeometry spSelectBox-asGeode()-getChild(0)-asGeometry();m_spHudCamera-addChild(spSelectBox);}return true;}}} // end swithreturn false;}osg::Geode* createSelectBox(float fStartPosX, float fStartPosY, float fEndPosX, float fEndPosY){osg::Geode* pGeode new osg::Geode();auto pQuardGeomerty new osg::Geometry();pGeode-addChild(pQuardGeomerty);osg::Vec3Array* pVertArray new osg::Vec3Array;pVertArray-push_back(osg::Vec3(fStartPosX, fStartPosY, 0.0));pVertArray-push_back(osg::Vec3(fStartPosX, fEndPosY, 0.0));pVertArray-push_back(osg::Vec3(fEndPosX, fEndPosY, 0.0));pVertArray-push_back(osg::Vec3(fEndPosX, fStartPosY, 0.0));pQuardGeomerty-setVertexArray(pVertArray);osg::Vec4Array* pColorArray new osg::Vec4Array;pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.4));/* pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));pColorArray-push_back(osg::Vec4(1.0, 1.0, 1.0, 0.40));*/pQuardGeomerty-setColorArray(pColorArray);//pQuardGeomerty-setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_VERTEX);pQuardGeomerty-setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_PRIMITIVE_SET);pQuardGeomerty-addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));pGeode-getOrCreateStateSet()-setMode(GL_LIGHTING, osg::StateAttribute::OFF); // 关闭光照pGeode-getOrCreateStateSet()-setMode(GL_BLEND, osg::StateAttribute::ON); // 开启透明否则就不能透过选择框看到后面的牛pGeode-addDrawable(pQuardGeomerty);return pGeode;}private:/* 鼠标按下的起始坐标点 */float m_fStartPosX{ 0.0 };float m_fStartPosY{ 0.0 };float m_fEndPosX{ 0.0 };float m_fEndPosY{ 0.0 };bool m_ctrlKeyPressed{ false }; // Ctrl键被按下bool m_bPush{ false }; // 鼠标左键是否被按下osgViewer::Viewer* m_pViewer{ nullptr };osg::ref_ptrosg::Camera m_spHudCamera; // 用于HUD的相机osg::ref_ptrosg::Geometry m_spRectGeometry; // 矩形框};int main(int argc, char *argv[])
{osgViewer::Viewer viewer;auto cowNode osgDB::readNodeFile(R(E:\osg\OpenSceneGraph-Data\cow.osg));if (nullptr cowNode){OSG_WARN node is null!;return 1;}auto spRoot new osg::Group();osg::ref_ptrosg::Camera spHudCamera new osg::Camera;spHudCamera-setClearMask(GL_DEPTH_BUFFER_BIT); // 开启深度缓冲// 设置渲染顺序为后渲染即始终在其它绘制物体的上面防止被其它绘制的物体遮挡spHudCamera-setRenderOrder(osg::Camera::RenderOrder::POST_RENDER); spHudCamera-setAllowEventFocus(false); // 不接受任何焦点事件即不响应键盘、鼠标事件spHudCamera-setReferenceFrame(osg::Transform::ReferenceFrame::ABSOLUTE_RF); // 设置参考帧为绝对帧spHudCamera-setViewMatrix(osg::Matrix::identity()); // 设置相机视图矩阵为单位矩阵这样就矩形框选框就不受相机旋转等变换影响spRoot-addChild(cowNode);spRoot-addChild(spHudCamera);viewer.setSceneData(spRoot);viewer.addEventHandler(new selectBoxEventHandler(spHudCamera));return viewer.run();
}说明
在鼠标拖动坐标改变重新设置矩形框坐标时记得调用
// 告知底层外层顶点数据更改了否则不会用新的坐标绘制矩形
m_spRectGeometry-setVertexArray(pVertArray);
或调用 m_spRectGeometry-dirtyDisplayList(); // 告知底层外层顶点数据更改了否则不会用新的坐标绘制矩形
在C中只要把指针指向的内容改了也就是立马改了但在上述代码中如果以为只把顶点数据改了新矩形就会呈现出来是错误的不调用上述代码中的某一种新矩形不会绘制因为只改了顶点数据但osg还没执行重绘。
上述采用节点的setNodeMask函数通过设置节点掩码来实现矩形框的显示或隐藏其实最好的方法是采用osg::Switch来控制矩形框的显示和隐藏在此不再详述列出代码关于这两者的详述参见osg利用setNodeMask和Switch隐藏节点用法说明博文。