OsgEarth自定义Widget去遮挡异常:背景与图像未隐藏
OsgEarth Declutter 功能:Widget 背景/图像不随文本隐藏的解决方案
问题根源
OsgEarth 的 Declutter 机制默认仅对 osgText::Text 类型的 Drawable 做隐藏处理,普通 Geometry(背景、图像)默认未被纳入遮挡隐藏逻辑,只会因视图缩放规则缩小,不会被隐藏。DEPTH_TEST 参数无效是因为 Declutter 机制本身会接管深度排序和可见性控制,单纯开关深度测试无法改变其默认行为。
解决方案
1. 使用 DeclutterGroup 统一管理 Widget 元素
将原来的 Geode 替换为 osgEarth::DeclutterGroup,该节点会自动管理组内所有 Drawable 的遮挡逻辑,确保重叠时所有元素同步隐藏。
2. 给背景/图像 Drawable 配置 Declutter 属性
对背景和图像的 Geometry 做以下设置:
- 禁用显示列表:
drawable->setUseDisplayList(false),确保 Declutter 能动态修改元素可见性。 - 关闭 DEPTH_TEST 并启用混合模式:Widget 通常为半透明,需设置正确的 BlendFunc 避免渲染异常。
- 设置统一的 Declutter 优先级:让背景、图像和文本使用相同的优先级,确保重叠时整体隐藏。
3. 代码修改示例
// 替换原Geode为DeclutterGroup osg::ref_ptr<osgEarth::DeclutterGroup> declutterGroup = new osgEarth::DeclutterGroup(); // --- 配置背景Geometry --- osg::ref_ptr<osg::Geometry> bgGeom = createBackgroundGeometry(); // 你的背景创建函数 osg::StateSet* bgSS = bgGeom->getOrCreateStateSet(); bgSS->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON); bgSS->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); // 设置与文本一致的优先级(数值越小,优先级越高,越不易被隐藏) bgSS->setAttributeAndModes(new osgEarth::Symbology::DeclutterPriority(50), osg::StateAttribute::ON); bgGeom->setUseDisplayList(false); declutterGroup->addDrawable(bgGeom); // --- 配置图像Geometry --- osg::ref_ptr<osg::Geometry> imgGeom = createImageGeometry(); // 你的图像创建函数 osg::StateSet* imgSS = imgGeom->getOrCreateStateSet(); imgSS->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON); imgSS->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); imgSS->setAttributeAndModes(new osgEarth::Symbology::DeclutterPriority(50), osg::StateAttribute::ON); imgGeom->setUseDisplayList(false); declutterGroup->addDrawable(imgGeom); // --- 配置文本元素 --- for (auto& text : yourTextList) { // yourTextList是你的三个osgText对象集合 osg::StateSet* textSS = text->getOrCreateStateSet(); textSS->setAttributeAndModes(new osgEarth::Symbology::DeclutterPriority(50), osg::StateAttribute::ON); text->setUseDisplayList(false); declutterGroup->addDrawable(text); } // 将DeclutterGroup添加到AnnotationGroup yourAnnotationGroup->addChild(declutterGroup); // yourAnnotationGroup是你的AnnotationGroup对象
4. 额外检查项
- 确保你的 AnnotationGroup 已经正确启用 Declutter 功能:比如通过
osgEarth::AnnotationOptions开启,或者父节点是 DeclutterNode。 - 如果使用自定义的 DeclutterNode,需手动调用
declutterNode->addDrawable()将所有 Widget 元素注册进去,替代 DeclutterGroup 的方式。
内容的提问来源于stack exchange,提问作者Marco Maisano
相关产品推荐
相关产品推荐

