2019-11-05
去年,公司项目在三维交互中提出了一项需求。在QGLWidget上构造的右键菜单中直接删除点选中的对象。对于被选择的普通三维对象,弹出的右键菜单删除它是没有问题的,但是,删除overlay层控件时,却导致OSG内部崩溃。我查看了一下OSG源代码,发现是设计之初没有考虑过这个需求。然而,实现这个功能patch却是很简单的,只需要修改两个文件,并且,需要定制osgWidget::WindowManager,重新实现removeChild(Node *child)。具体修改代码如下:
src/osgWidget/WindowManager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/osgWidget/WindowManager.cpp b/src/osgWidget/WindowManager.cpp index 7bccbd348..d4561f790 100644 --- a/src/osgWidget/WindowManager.cpp +++ b/src/osgWidget/WindowManager.cpp @@ -634,4 +634,14 @@ osg::Camera* WindowManager::createParentOrthoCamera() { return camera; } +void WindowManager::setLastEventNull() +{ + this->_lastEvent = nullptr; +} + +const osgWidget::EventInterface* WindowManager::lastEvent() +{ + return this->_lastEvent ; +} + } include/osgWidget/WindowManager | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/osgWidget/WindowManager b/include/osgWidget/WindowManager index 49b5e6eeb..311d05820 100644 --- a/include/osgWidget/WindowManager +++ b/include/osgWidget/WindowManager @@ -99,7 +99,8 @@ class OSGWIDGET_EXPORT WindowManager: public osg::Switch, public UIObjectParent< bool mouseScroll (float, float); osg::Camera* createParentOrthoCamera(); - + void setLastEventNull(); + const osgWidget::EventInterface* lastEvent(); unsigned int getNodeMask() const { return _nodeMask; } 定制WindowManager: bool WindowManager::removeChild(Node *child) { osgWidget::Window* osgWindow = dynamic_cast<osgWidget::Window*>(child); if (nullptr != osgWindow) { if (this->lastEvent() == osgWindow){ this->setLastEventNull(); } else { // 正常逻辑, } bool ret = osgWidget::WindowManager::removeChild(osgWindow); return ret; } return osgWidget::WindowManager::removeChild(child); }
原因在于,WindowManager依赖于缓存的最后一次交互操作的Widget 对象,若没有清除此缓存,则在下一帧中会使用到已经被删除的对象,造成空指针错误。故需要主动清除此缓存。
不得不说,OSG WindowManager的实现还真是非常简单明了的。就几个文件,层次清晰。但是,osg学习开源的代码,还是非常有必要的。在自己的项目中使用了开源代码,发现了问题也不要怕,直接修改,若有必要,直接提交patch。
如果有任何意见,欢迎留言讨论。
[ 主页 ]