查看: 3558|回复: 7

世界坐标转屏幕坐标问题

[复制链接]

该用户从未签到

发表于 2011-1-10 09:43:29 | 显示全部楼层 |阅读模式
我想写段程序,导入多个三维模型,然后分别自动获取每个三维模型的图片,并将这些图片在列表控件中显示出来,这就存在两个问题:
问题1:如何自动获取三维模型的图片,我的解决办法是在viewer中分别导入每个三维模型,然后用截屏的代码截取模型的外观并导入至列表控件,请问大家有没有其他更好的方法?

问题2:在截屏的方法中,我想自动截取三维模型范围上的图片,而不是全屏,因此,我求取了模型节点的包围盒,将包围盒的最大最小坐标转换为屏幕坐标,再求屏幕坐标的包围盒,但在这世界坐标转为屏幕坐标的过程中出现了问题,我采用的是论坛上heishuijing2222的方法,传进去(1,1,1),但结果为(-1010,-1280,0),实现代码如下,还请大家帮我看看

int main(int argc, char** argv)
{
osgViewer::Viewer *pViewer=new osgViewer::Viewer();
osg::Group *pRoot=new osg::Group();
osg::Node *pNode=new osg::Node();
osgUtil::Optimizer optimizer;
optimizer.optimize(pRoot);
pViewer->setSceneData(pRoot);
pViewer->realize();
osg::Vec3 sv=WorldToScreen(pViewer,osg::Vec3(1,1,1));
pViewer->run();
}

void Transform_Point(double out[4], const double m[16], const double in[4])
{
#define M(row,col)  m[col*4+row]
out[0] =
  M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
out[1] =
  M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
out[2] =
  M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
out[3] =
  M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
#undef M
}
osg::Vec3d WorldToScreen(osgViewer::View* view,osg::Vec3 worldpoint)
{
double in[4], out[4];
in[0] = worldpoint._v[0];
in[1] = worldpoint._v[1];
in[2] = worldpoint._v[2];
in[3] = 1.0;
//获得当前的投影矩阵和模型视图矩阵
osg::Matrix projectMatrix= view->getCamera()->getProjectionMatrix();
osg::Matrix viewprojectMatrix = view->getCamera()->getViewMatrix();
//下面计算 模型视图矩阵 * 投影矩阵 * 视口窗口变换矩阵
double modelViewMatrix[16];
memcpy(modelViewMatrix,viewprojectMatrix.ptr(),sizeof(GLdouble) * 16);
Transform_Point(out, modelViewMatrix, in);

double myprojectMatrix[16];
memcpy(myprojectMatrix,projectMatrix.ptr(),sizeof(GLdouble) * 16);
Transform_Point(in, myprojectMatrix, out);
if (in[3] == 0.0)
  return osg::Vec3d(0,0,0);
in[0] /= in[3];
in[1] /= in[3];
in[2] /= in[3];

int viewPort[4];
osg::Viewport* myviewPort = view->getCamera()->getViewport();
viewPort[0] = myviewPort->x();
viewPort[1] = myviewPort->y();
viewPort[2] = myviewPort->width();
viewPort[3] = myviewPort->height();
//计算 三维点在屏幕上的二维投影点
osg::Vec3d sceenPoint;
sceenPoint._v[0] = (int)(viewPort[0] + (1 + in[0]) * viewPort[2] / 2 + 0.5);
sceenPoint._v[1] = (int)(viewPort[1] + (1 + in[1]) * viewPort[3] / 2 + 0.5);
sceenPoint._v[2]  = 0;
return sceenPoint;
}

该用户从未签到

发表于 2011-1-10 12:09:59 | 显示全部楼层
问题1:如何自动获取三维模型的图片,我的解决办法是在viewer中分别导入每个三维模型,然后用截屏的代码截取模型的外观并导入至列表控件,请问大家有没有其他更好的方法?
如果您一定要实时获取的话,那么这是唯一的方法

至于将世界坐标转换到屏幕坐标,使用MVPW矩阵就可以轻松实现了,即screenPoint = worldPoint * MVPW,这里的V,P,W都可以通过Camera节点获得,Model矩阵的值与您的节点层次有关

该用户从未签到

 楼主| 发表于 2011-1-10 15:50:56 | 显示全部楼层
我也用了MVPW,为什么也是错的,全部代码如下,大家帮我看看啊,急!!!
int main(int argc, char** argv)
{
        osgViewer::Viewer *pViewer=new osgViewer::Viewer();
        osg::Group *pRoot=new osg::Group();
        osg::Node *pNode=new osg::Node();
        pNode=osgDB::readNodeFile("3ds\\1.3ds");
        pRoot->addChild(pNode);

        osgUtil::Optimizer optimizer;
        optimizer.optimize(pRoot);
        pViewer->setSceneData(pRoot);
        pViewer->realize();

        osg::ComputeBoundsVisitor cbv;
        pNode->accept(cbv);
        osg::BoundingBox boundingBox= cbv.getBoundingBox();
       
        osg::Matrix mtxModelView = pViewer->getCamera()->getViewMatrix();
        osg::Matrix mtxProject = pViewer->getCamera()->getProjectionMatrix();
        osg::Matrix mtxWindow = pViewer->getCamera()->getViewport()->computeWindowMatrix();
        osg::Matrix mtxMVPW = mtxModelView * mtxProject * mtxWindow;

        osg::Vec4 vecWorldPt(0.0f, 0.0f, 0.0f, 1.0f);
        osg::Vec4 vecWindowPt = mtxMVPW.preMult(vecWorldPt);

        pViewer->run();

}

该用户从未签到

发表于 2011-1-10 16:42:10 | 显示全部楼层
您期望的值是多少?您得到的值是多少

该用户从未签到

 楼主| 发表于 2011-1-10 19:55:17 | 显示全部楼层
osg::Vec4 vecWorldPt(0.0f, 0.0f, 0.0f, 1.0f);
        osg::Vec4 vecWindowPt = mtxMVPW.preMult(vecWorldPt);
              //此处得到的值是(0, 0, -1, 0)

        osg::Vec4 vecWorldPt1(2.0f, 2.0f, 2.0f, 1.0f);
        osg::Vec4 vecWindowPt1 = mtxMVPW.preMult(vecWorldPt1);
              //此处得到的值是(2021.5386, 2561.5386, -3.0002999,  -2.0000000)

        osg::Vec4 minPt(boundingBox.xMin(), boundingBox.yMin(), boundingBox.zMin(), 1.0f);
              //此处获得包围盒的值是(-22.393204, -22.631639,-2.4326248,1.0000000)
        osg::Vec4 vecWindowPt_min = mtxMVPW.preMult(minPt);
              //转换后的值(-37005.980, -38075.465, 1.4327681, 2.4326248)

该用户从未签到

发表于 2011-1-11 08:44:40 | 显示全部楼层
我建议将这些计算代码放在handler中,而不是在viewer.run()之前——不然可能有一些数据没有初始化

该用户从未签到

 楼主| 发表于 2011-1-11 11:33:45 | 显示全部楼层
我刚接触osg,您是指派生个更新回调,在回调中进行坐标转换?

该用户从未签到

发表于 2011-1-11 13:39:21 | 显示全部楼层
可以是更新回调,也可以是EventHandler
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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