查看: 1980|回复: 11

求助:关于求交计算的问题

[复制链接]

该用户从未签到

发表于 2010-4-30 11:00:30 | 显示全部楼层 |阅读模式
      大家好!
      我建了一个MFC的OSG应用程序,基本上就是实现了osgViewerMFC例子中的模型查看的功能,尚未添加其他任何功能。
      现在我想在场景中实现求交判断,目的是想实现对象选取。参考了《OpenSceneGraph三维渲染引擎编程指南》这本书中8.3.3例子的代码。
      但是,鼠标点击场景中的模型后,会出现堆内存损坏的错误提示。下面是具体的代码和错误提示截图:
////pickhandler
CPickHandler::CPickHandler()
{
}
CPickHandler::~CPickHandler()
{
}
bool CPickHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
{
    switch(ea.getEventType())
    {
        case(osgGA::GUIEventAdapter:USH):
        {
            osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
            if (view)
           {
                pick(view,ea);
           }
               return false;
        }   
         default:
             return false;
    }
}
void CPickHandler::pick(osgViewer::View* view, const osgGA::GUIEventAdapter& ea)
{
    osgUtil:ineSegmentIntersector::Intersections intersections;
  
    float x = ea.getX();
float y = ea.getY();
    if (view->computeIntersections(x,y,intersections))
    {
}
}


//////初始化

void CMFCOSG::InitSceneGraph(void)
{
//初始化组
Root=new osg::Group;
  
//读取模型
Model=osgDB::readNodeFile(ModelName);


//优化模型
osgUtil::Optimizer optimizer;
optimizer.optimize( Model.get());
optimizer.reset();
    Root->addChild(Model.get());
}

void CMFCOSG::InitCameraConfig(void)
{

RECT rect;

Viewer = new osgViewer::Viewer;
  
::GetWindowRect(HWnd,&rect);

osg::ref_ptr<osg::GraphicsContext::Traits>traits = new   osg::GraphicsContext::Traits;
//初始化窗口变量
osg::ref_ptr<osg::Referenced>windata = new osgViewer::GraphicsWindowWin32::WindowData(HWnd);

  traits->x=0;
traits->y=0;
traits->width=rect.right-rect.left;
traits->height=rect.bottom-rect.top;
traits->windowDecoration=false;
traits->doubleBuffer=true;
traits->sharedContext=0;
traits->setInheritedWindowPixelFormat=true;
traits->inheritedWindowData=windata;

//创建图形上下文
osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits.get());


//初始化一个相机
osg::ref_ptr<osg::Camera>camera=new osg::Camera;

//将相机绑定到窗口设备
camera->setGraphicsContext(gc);
//相机视口设置
camera->setViewport(new osg::Viewport(traits->x,traits->y,traits->width,traits->height));
//添加相机到VIEWER
Viewer->addSlave(camera.get());
Viewer->setCameraManipulator(KeyswitchManipulator.get());

CPickHandler* pickHandler = new CPickHandler();
  Viewer->addEventHandler(pickHandler);

//设置数据
Viewer->setSceneData(Root.get());

//实现VIEWER
Viewer->realize();
double fovy,aspectRatio,z1,z2;
Viewer->getCamera()->getProjectionMatrixAsPerspective(fovy,aspectRatio,z1,z2);
aspectRatio=double(traits->width)/double(traits->height);
Viewer->getCamera()->setProjectionMatrixAsPerspective(fovy,aspectRatio,z1,z2);
}

void CMFCOSG::Render(void* ptr)
{

    CMFCOSG* mfcosg= (CMFCOSG*) ptr;
osgViewer::Viewer* osgviewer=mfcosg->GetViewer();
while(!osgviewer->done())
{
  mfcosg->reFrameUpdate();
  osgviewer->frame();
  mfcosg->PostFrameUpdate();
  //Sleep(10);//让其它程也占用CPU,放出M
}
//退出了程序,弹出个对话框
//AfxMessageBox("线程退出");
_endthread();
}

错误提示:

"Windows 已在 osgMFC.exe 中触发一个断点。
其原因可能是堆被损坏,这也说明  osgMFC.exe 中或它所加载的任何 DLL 中有 bug。
输出窗口可能提供了更多诊断信息"


可以看出,void CPickHandler::pick(osgViewer::View* view, const osgGA::GUIEventAdapter& ea)
里除了求交判断,几乎什么都没做,调试的时候发现,程序运行到这个函数体的最后,再下一步F10就出错了,弄了两天了,一直不知道问题出在哪里。

该用户从未签到

 楼主| 发表于 2010-4-30 11:39:43 | 显示全部楼层
补充说明一下,同样的代码,在Win32控制台下,又不会出错。

该用户从未签到

发表于 2010-4-30 14:02:01 | 显示全部楼层
检查您的工程设置,凭现有的信息我个人也判断不了什么

该用户从未签到

 楼主| 发表于 2010-4-30 14:56:19 | 显示全部楼层
后来又测试一下发现,MFC工程下:
float x = ea.getX();
float y = ea.getY();
获得的鼠标位置都在(-1,1)之间,这时鼠标点击就会出错。当将x,y的值设置到这个范围以外时,就不会出现内存的错误。

在控制台程序下,鼠标点击获取的值要远比(-1,1)之间的值大,所以就不会出现错误。

所以这里有两个问题:
1)MFC下,屏幕坐标和视图坐标是不是有一个转换关系,为什么控制台获取的x,y和在MFC中获取的x,y不一样;
2)为什么坐标值在(-1,1)之间时,求交运算后就会出现内存的错误?

不知道大家有没有遇到过类似的问题,请求解答。

该用户从未签到

发表于 2010-4-30 16:17:27 | 显示全部楼层
MFC下因为没办法正确计算窗口坐标,所以返回的是规范化后的窗口坐标,即窗口左上角为(-1,-1),右下角(1,1)。此时求交计算请使用PROJECTION而不是WINDOW坐标系

该用户从未签到

 楼主| 发表于 2010-5-4 12:42:12 | 显示全部楼层
非常感谢Array的解答,我后来查看了osgviewer::view 中的函数ComputeIntersection定义,该函数体前面有这样一段代码:
  1. bool View::computeIntersections(float x,float y, osgUtil::LineSegmentIntersector::Intersections& intersections, osg::Node::NodeMask traversalMask)
  2. {
  3. if (!_camera.valid()) return false;

  4. float local_x, local_y = 0.0;
  5. const osg::Camera* camera = getCameraContainingPosition(x, y, local_x, local_y);
  6. if (!camera) camera = _camera.get();


  7. osgUtil::LineSegmentIntersector::CoordinateFrame cf = camera->getViewport() ? osgUtil::Intersector::WINDOW : osgUtil::Intersector::PROJECTION;
  8. osg::ref_ptr< osgUtil::LineSegmentIntersector > picker = new osgUtil::LineSegmentIntersector(cf, local_x, local_y);
复制代码


我测试了一下getCameraContainingPosition这个函数的作用,该函数可以将规范化后的坐标转换成正常的屏幕坐标。另外,我的理解是该函数能通过判断相机是否有视口来确定选用WINDOW模式还是PROJECTION模式,我人为地将其设置为PROJECTION模式后,问题并没有得到解决。

关于那个因为堆内存问题引起的断言错误,现在也没弄明白究竟是怎么引起的。在MFC下,鼠标点击可以获得交点信息,并且和WIN32控制台下对比了一下,可以确认求交计算的结果是正确的。调试时,程序执行完求交计算,也并无任何错误提示,可见,内存的问题似乎与求交计算无关。但是为什么MFC中,pick函数运行到最后会出现堆内存损坏的问题,而pick函数中不做求交计算时,又不会出现此问题呢?

网上关于堆内存的问题,说一般是因为指针引起的,比如指针没有初始化,后者没有很好释放。但是我的pick()函数体里并未声明任何指针变量。另外一个奇怪的现象:我在VS2005 和 VS2008下重新建立了几个MFC的工程(代码几乎一样),来实现同样的鼠标点击求交计算,发现某些是会出现这样的内存错误,而某些又不会。

这个问题是因为MFC本身的问题,还是OSG的问题?我还不得而知,不知道大家在开发的过程中,有没有遇到类似的问题。

该用户从未签到

发表于 2010-5-4 15:05:16 | 显示全部楼层
这恐怕是由于您自己的工程配置的原因,我这里也有MFC的工程项目,并且在其中求交没有什么问题,只是要注意使用规范化后的坐标即可

该用户从未签到

 楼主| 发表于 2010-5-4 17:05:41 | 显示全部楼层
好的 非常感谢

该用户从未签到

发表于 2010-8-26 13:57:21 | 显示全部楼层
我遇到同样问题,不知道您最后解决没有?

该用户从未签到

发表于 2010-8-26 21:49:01 | 显示全部楼层
不知道您的是哪个例子,好像在《StepIntoOpenSceneGraph(Freesouth)》的有个例子中要把其中的退出消息改成wm_quit就ok了,不知道对您有没有帮助。

该用户从未签到

发表于 2010-8-26 22:07:06 | 显示全部楼层
void CPickPathView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
        mOSG ->getViewer() ->getEventQueue () ->keyPress (nChar) ;
        if(nChar ==VK_ESCAPE)
        {
                GetParent() ->SendMessage(WM_QUIT) ;
        }
}

该用户从未签到

发表于 2010-11-5 10:53:27 | 显示全部楼层
请问楼上最后怎么解决的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表