在OSG场景中,采用HUD抬头显示来显示模型的运动参数,但是运行的时候发现HUD出现重复投射的现象,如图中红线框中所示。
抬头显示的CreateHUDText函数如下:
// 创建HUD抬头显示文字
osg::Projection* cOSG::CreateHUDText(void)
{
// 获取屏幕尺寸
RECT rect;
int rect_width,rect_height;
// Get the current window size
::GetWindowRect(m_hWnd, &rect);
rect_width = rect.right - rect.left;
rect_height = rect.bottom - rect.top;
// 投影节点用于定义HUD的视景体(view frustrum)
osg::Projection* HUDProjectionMatrix = new osg::Projection;
// 投影矩阵的水平和垂直范围与屏幕尺寸相同,
// 因此该节点子树中的位置坐标将等同于像素坐标
HUDProjectionMatrix->setMatrix(osg::Matrix::ortho2D(0,rect_width,0,rect_height));
// HUD模型观察矩阵应使用单位矩阵
osg::MatrixTransform* HUDModelViewMatrix = new osg::MatrixTransform;
HUDModelViewMatrix->setMatrix(osg::Matrix::identity());
// 确保模型观察矩阵不会被场景图形的位置变换影响
HUDModelViewMatrix->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
// 添加HUD模型观察矩阵到HUD投影矩阵
HUDProjectionMatrix->addChild(HUDModelViewMatrix);
// 添加文字套Geode叶节点中
HUDModelViewMatrix->addChild(HUDGeode);
osg::StateSet* HUDStateset = new osg::StateSet();
HUDGeode->setStateSet(HUDStateset);
HUDStateset->setMode(GL_BLEND,osg::StateAttribute::ON);
//关闭光照
HUDStateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
// 关闭深度测试
HUDStateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
// 透明渲染
//HUDStateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
//osgUtil::RenderBin* HUDBin =
//new osgUtil::RenderBin(osgUtil::RenderBin::SORT_BACK_TO_FRONT);
// 确认背景板几何体在最后进行绘制。渲染元(RenderBin)按照数字顺序进行渲染
// 因此我们设置一个比较大的数字值
HUDStateset->setRenderBinDetails(11,"DepthSortedBin");
//////////////////////////////////////////////////////////////////////////
// 为创建抬头显示信息(HUD)文字显示做准备
white = osg::Vec4(1.0f,0.0f,0.0f,1.0f);
// 用来显示汉字
font_China = osgText::readFontFile("fonts/simhei.ttf");
text_China = new osgText::Text;
text_China->setFont(font_China.get());
text_China->setColor(white);
text_China->setCharacterSize(20.0);
text_China->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
text_China->setPosition(osg::Vec3(0.857*rect_width,0.955*rect_height,0.0f));
text_China->setDrawMode(osgText::Text::TEXT /*| osgText::Text::BOUNDINGBOX*/);
font = osgText::readFontFile("Fonts/arial.ttf");
text_heading = new osgText::Text;
text_heading->setFont(font.get());
text_heading->setColor(white);
text_heading->setCharacterSize(20.f);
// 制定字符在屏幕上显示的大小,Text可以根据视角,适当缩放文字几何体
// 以保持它在屏幕上的恒定尺寸
text_heading->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
text_heading->setPosition(osg::Vec3(0.892*rect_width,0.955*rect_height,0.0f));
text_heading->setDrawMode(osgText::Text::TEXT /*| osgText::Text::BOUNDINGBOX*/);
HUDGeode->addDrawable(text_heading.get());
HUDGeode->addDrawable(text_China.get());
return HUDProjectionMatrix;
}
//将HUD作为group节点的子节点
group_SpecialEffects->addChild(CreateHUDText());
//将group节点作为root根节点的子节点
root->addChild(group_SpecialEffects.get());
//创建视口
view1 = CreateView(&m_compositeViewer,root,gc,NULL,0,0,traits->width,traits->height);
上述代码即为HUD显示的结构。出现重复投射的问题后,一开始以为是场景中添加阴影效果、天空盒之后和HUD不兼容或者有冲突的问题,随即把阴影效果模块、天空盒模块都删掉,还是不行。
最后把HUD显示都删掉,发现依然有异常的投射。
这个时候,就有点头绪了,那应该不是其他模块的影响,有可能是重复的加载了HUD显示模块中的文字信息。果然,在 PreFrameUpdate函数中,有这么一行代码:
view1->getCamera()->addChild(HUDGeode.get());
HUDGeode正是CreateHUDText函数中的叶节点对象,是绘制这些的文字的父节点,即相当于把HUD显示的信息重新加载了一遍。把这行代码删除,重复投射的问题就解决了。
通过上述问题,有以下两点的体会:
1、写代码的时候一定要仔细、严谨,否则会付出更多的经历和时间去找BUG;
2、找BUG的时候,需要一步步的排查,逐步缩小范围,排除所有的可疑点后,问题一般就会水落石出了。