查看: 4421|回复: 26

新手求助speedtree与osg结合的问题

[复制链接]

该用户从未签到

发表于 2012-10-23 09:56:08 | 显示全部楼层 |阅读模式
各位老师好,本人刚接触osg不久近来就要求解决osg中使用speedtree模型的问题,网上相关资料太少了,能否给些思路?首先如何解决第一个问题,将speedtree变为osg节点添加到场景中?第二是重写Drawble类?有没有相关的例子?还望各位老师多多帮忙,不胜感激,拜托给位老师了!

该用户从未签到

发表于 2012-10-23 10:11:34 | 显示全部楼层

该用户从未签到

 楼主| 发表于 2012-10-23 19:17:06 | 显示全部楼层
liuzhiyu123 发表于 2012-10-23 10:11
http://forum.openscenegraph.org/viewtopic.php?t=10693&highlight=speedtree
http://forum.openscenegr ...

亲,谢谢你,看了一下,但没找到想要的信息……还望指点一二

该用户从未签到

发表于 2012-10-29 09:52:37 | 显示全部楼层
重写Drawable类是最直接也是最好的方法,因为SpeedTree自己的虚接口不适合再改造成scene graph的形式了

该用户从未签到

 楼主| 发表于 2012-10-29 17:38:56 | 显示全部楼层
array 发表于 2012-10-29 09:52
重写Drawable类是最直接也是最好的方法,因为SpeedTree自己的虚接口不适合再改造成scene graph的形式了

就是重写个Drawable类,把这个Drawable对象加到一个geode上然后添加到osg场景中就可以吧?Drawable对象上设置派生的setUpdateCallback可以进入里面的update函数,但setCullCallBack却进入不了cull函数,现在把Applicaion类的Advance()和Culll()都放在setUpdateCallback中了,在drawimplementation中调用Applicaion类的Render()之后现在是可以显示例子中的森林,但地形与草地显示不出来,而且鼠标任意操作后屏幕乱画……还请老师指点一下,谢谢

该用户从未签到

发表于 2012-10-30 10:37:28 | 显示全部楼层
您就这么一说,是提供不了什么有用的信息的

该用户从未签到

 楼主| 发表于 2012-10-30 17:41:32 | 显示全部楼层
array 发表于 2012-10-30 10:37
您就这么一说,是提供不了什么有用的信息的

代码在下方,具体遇到以下问题,恳请老师批评指正:
   1)绘制方法思路是否正确?
   2) 相机更新函数是否正确?
   3)现在,单独添加speedtree节点,可以显示森林(但角度不正确),但是地形、草地不显示(控制台提示"CTerrainRI:Render,BindVertexBuffer(),failed",
     "CGeometryBufferRI::BindVertexBuffer,the Vertexbuffer has not been set up ,yet","CGeometryBufferRI::OverWriteVertices,cannot be called
        until a VB is established with AppendVertices()+EndVertices").同时鼠标拖动屏幕远离树木后会花屏,屏蔽掉地形、草地、天空后不会出现花屏
   4)添加上osg节点后只能看到osg模型,看不到speedtree森林模型。

       
使用的speedtree SDK5.1 (32位),osg3.0.032位)

//全局变量
static  CApplication*  g_pApplication = NULL;
static  osgViewer::Viewer viewer;

//1. 自定义Drawable类
class SpeedTreeDrawable:public osg:rawable
{
public:
        SpeedTreeDrawable()
        {
                g_pApplication = st_new(CApplication, "CApplication");

                //为方便跟踪调试,使用了以下固定参数
                st_int32 argc = 3;
                char* argv[] = {"E:\\我的日常工作\\练习\\speed\\SpeedTree\\Debug\\SpeedTree_OpenGL_App_MT_Static_d.exe","-cmdline_file","E:\\我的日常工作\\练习\\speed\\Forests\\Huangshan\\__Settings__.txt"};
                if (argc > 0)
                        SetCurrentDirectoryA(CFixedString(argv[0]).Path( ).c_str( ));

                g_pApplication->Init(argc, argv);        //CApplication类里面,其实就是获取外部配置参数

                setUseDisplayList(false);        //关闭

        }

        SpeedTreeDrawable(const SpeedTreeDrawable& speedtreedrawable,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
        osg::Drawable(speedtreedrawable,copyop) {}

        META_Object(mySpeedTreeDrawableApp,SpeedTreeDrawable)


                //bool g_bFirst = true;
                //重写drawImplementation函数
                virtual void drawImplementation(osg::RenderInfo& renderInfo)const
        {
                //设置状态参数
                static st_bool bFirstDisplay = true;
                if (bFirstDisplay)        //第一次显示
                {
                        //初始化speedtree
                        InitOpenGL( );                        //必须加,否则不识别dds等纹理
                        assert(g_pApplication);
                        g_pApplication->InitGraphics( );        //CApplication类里面,初始化场景等并生成森林
                       
                        bFirstDisplay = false;

                        return;                //必须加,否则不显示
                }

                g_pApplication->Render( );                //CApplication类里面,渲染森林、地形、草地、天空等
        }

protected:

        virtual ~SpeedTreeDrawable() {}
};

//2.自定义更新回调
class SpeedTreeUpdateCallback:public osg::Drawable::UpdateCallback
{
public:
        SpeedTreeUpdateCallback(){};

        //重载update函数
        virtual void update(osg::NodeVisitor*, osg::Drawable*)
        {
                if (g_pApplication->ReadyToRender())
                {
                        //更新相机
                        ChangeSpeedTreeCamera();        //自定义更新相机函数

                        //更新视图
                        g_pApplication->Advance();        //CApplication类里面,更新全局风等(屏蔽其UpdateView(更新相机))

                        g_pApplication->Cull();                //CApplication类里面,各种裁剪
                                                      //(注:本来Cull()应放在自定义的裁剪回调类里面的,但是程序进入不了裁剪回调函数中就放在此处了)
                }
        }
};

//3.更新相机
void ChangeSpeedTreeCamera()
{
        //获取osg视图投影矩阵
        osg::Matrixd vprojectMatrix;
        vprojectMatrix = viewer.getCamera()->getProjectionMatrix();
       
        //获取视点矩阵
        osg::Matrixd vViewerMatrix;
        vViewerMatrix = viewer.getCamera()->getViewMatrix();

        //获取视点位置
        osg::Vec3 camePos;
        osg::Vec3 center;
        osg::Vec3 up;
        float dis = 1.0f;
        viewer.getCamera()->getViewMatrixAsLookAt(camePos,center,up,dis);

        //逐参数赋值给SpeedTree中的相应变量
        SpeedTree::Vec3 spcamePos(camePos.x(),camePos.y(),camePos.z());

        const st_float32 afInit1[16]={vprojectMatrix(0,0),vprojectMatrix(0,1),vprojectMatrix(0,2),vprojectMatrix(0,3)
                                                                ,vprojectMatrix(1,0),vprojectMatrix(1,1),vprojectMatrix(1,2),vprojectMatrix(1,3)
                                                                ,vprojectMatrix(2,0),vprojectMatrix(2,1),vprojectMatrix(2,2),vprojectMatrix(2,3)
                                                                ,vprojectMatrix(3,0),vprojectMatrix(3,1),vprojectMatrix(3,2),vprojectMatrix(3,3)};
        SpeedTree::Mat4x4 spvprojectMatrix(afInit1);

        const st_float32 afInit2[16]={vViewerMatrix(0,0),vViewerMatrix(0,1),vViewerMatrix(0,2),vViewerMatrix(0,3)
                ,vViewerMatrix(1,0),vViewerMatrix(1,1),vViewerMatrix(1,2),vViewerMatrix(1,3)
                ,vViewerMatrix(2,0),vViewerMatrix(2,1),vViewerMatrix(2,2),vViewerMatrix(2,3)
                ,vViewerMatrix(3,0),vViewerMatrix(3,1),vViewerMatrix(3,2),vViewerMatrix(3,3)};
        SpeedTree::Mat4x4 spvViewerMatrix(afInit2);

         //因为是外部更改参数,将CApplication中以下参数设为public
         st_bool bViewChanged = g_pApplication->m_cView.Set(spcamePos,spvprojectMatrix,spvViewerMatrix,g_pApplication->GetUserSettings().m_fNearClip,g_pApplication->GetUserSettings().m_fVisibility);
         g_pApplication->m_bCameraChanged |= bViewChanged;

         g_pApplication->m_pCurrentNavigation->SetCameraPos(CCoordSys::ConvertFromStd(spcamePos));

}

//4.场景加载speedtree节点
main
{
        //定义speedtree节点
        osg::ref_ptr<osg::Geode> geode  = new osg::Geode;
        SpeedTreeDrawable* drable = new SpeedTreeDrawable();
        drable->setUpdateCallback(new SpeedTreeUpdateCallback);
        geode->addDrawable(drable);

        //定义osg样例节点
        osg::ref_ptr<osg::Node> node2 = osgDB::readNodeFile("cow.osg");

        osg::ref_ptr<osg::Group> root = new osg::Group;
        root->addChild(geode.get());
        //root->addChild(node2.get());

        viewer.addEventHandler(new osgViewer::StatsHandler());
       
        osgUtil::Optimizer optimizer;
        optimizer.optimize(root.get());

        viewer.setSceneData(root.get());
        viewer.run();
}

该用户从未签到

发表于 2012-10-31 08:02:37 | 显示全部楼层
红果儿 发表于 2012-10-30 17:41
代码在下方,具体遇到以下问题,恳请老师批评指正:
   1)绘制方法思路是否正确?
   2) 相机更新函数 ...

cull  设置CullBack 就可以了
添加osg模型是不是把spreed模型遮挡住,所以depth test 失败
还有在绘制之前应该把当前的OpenGL状态去掉,否则可能有影响

该用户从未签到

 楼主| 发表于 2012-11-2 10:42:08 | 显示全部楼层
liuzhiyu123 发表于 2012-10-31 08:02
cull  设置CullBack 就可以了
添加osg模型是不是把spreed模型遮挡住,所以depth test 失败
还有在绘制 ...

其实有写cullback类,但程序进不到该类的函数中去,就将cull()放在了updatecallback类中了;
单独加speedtree模型,地形、草地绘制不出来……
如果是遮挡怎么处理呢?
绘制之前的OpenGL状态怎么去掉?
如果可以还请刘老师结合我附上的部分代码给看看问题到底出现在哪里,不胜感激!

该用户从未签到

发表于 2012-11-5 09:59:29 | 显示全部楼层
您的代码具体是什么问题,很难一下子看出来,只能大概给出我当时做结合时候的思路给一段伪代码
  1. if ( !_initialized )
  2. {
  3.     glewInit();
  4.     CRenderStateOpenGL::InitializeForThreadedOpenGL( wglGetCurrentDC(), wglGetCurrentContext() );
  5.    
  6.     _application->InitGraphics();

  7.     // 计算包围体,所以你还要重写computeBound
  8.     non_const_this->dirrtyBound();
  9.     _initialized = true;
  10. }

  11. // 阻止OSG自己更新VA
  12. state->disableAllVertexArrays();

  13. // SpeedTree自己的导航、裁减和渲染
  14. if ( _application->ReadyToRender() )
  15. {
  16.     computeViewOfCNavigationBase( state->getModelViewMatrix(), state->getProjectionMatrix() );
  17.     _application->Advance();
  18.     _application->Cull();
  19. }
  20. _application->Render();
复制代码
此处的草地和树木都是可以渲染并且和OSG模型的遮挡关系正确。SpeedTree因为是纯商业软件,因此我不会放出结合它的案例代码,以免引起麻烦

该用户从未签到

 楼主| 发表于 2012-11-6 07:55:53 | 显示全部楼层
array 发表于 2012-11-5 09:59
您的代码具体是什么问题,很难一下子看出来,只能大概给出我当时做结合时候的思路给一段伪代码此处的草地和 ...

恩,非常感谢array老师

该用户从未签到

 楼主| 发表于 2012-11-6 17:44:17 | 显示全部楼层
array 发表于 2012-11-5 09:59
您的代码具体是什么问题,很难一下子看出来,只能大概给出我当时做结合时候的思路给一段伪代码此处的草地和 ...

array老师还得请您帮忙,现在可以在osg中显示speedtree的树木了,但裁剪不对,这个computeBound()怎么个思路计算呢?

该用户从未签到

发表于 2012-11-7 07:54:37 | 显示全部楼层
计算包围体

该用户从未签到

 楼主| 发表于 2012-11-7 11:02:35 | 显示全部楼层
liuzhiyu123 发表于 2012-11-7 07:54
计算包围体

额……怎么计算呢?根据最近最远距离(例如0.5,1000)set  osg::BoundingBox对象的最小(0.5,0.5,0.5)、最大端点(1000,1000,1000)?还是其他方法?

该用户从未签到

发表于 2012-11-7 12:10:16 | 显示全部楼层
红果儿 发表于 2012-11-7 11:02
额……怎么计算呢?根据最近最远距离(例如0.5,1000)set  osg::BoundingBox对象的最小(0.5,0.5,0.5)、 ...

获取几何数据 还能怎么计算

该用户从未签到

 楼主| 发表于 2012-11-9 11:22:43 | 显示全部楼层
array 发表于 2012-11-5 09:59
您的代码具体是什么问题,很难一下子看出来,只能大概给出我当时做结合时候的思路给一段伪代码此处的草地和 ...

array老师您好,还得请教几个问题,第一:computeBound如何计算?我从m_cForest中获取所有实例树的范围,然后将各棵树的min点与max点包含到包围盒内对么?但是一开始执行computeBound时森林还没有形成就没有包围盒。这种情况下与其他osg节点一起加入场景时可以显示,但只单独加speedtree时就看不到模型了。第二:近远裁剪不起作用,不论远裁值设置多少,cull中cullAndComputeLOD()获取的visibleTree的m_aVisibleCells都与之无关。第三:场景中同时加载speedtree模型与osg模型时,若二者距离很近则osg的原有状态显示不对(例如线框模式下,osg模型并不显示线框,觉得requestDraw没有成功)。感谢老师百忙之中解答疑惑!

该用户从未签到

发表于 2012-11-9 12:05:58 | 显示全部楼层
您可以直接setCullingActive(false)暂时取消裁减,看看是否是这个问题

该用户从未签到

 楼主| 发表于 2012-11-9 16:17:02 | 显示全部楼层
array 发表于 2012-11-9 12:05
您可以直接setCullingActive(false)暂时取消裁减,看看是否是这个问题

额……另一个问题,也麻烦array老师指导一下:我想定义多个geode节点来加载speedtree模型,每个geode节点都加上自定义的speedtreeDrawable对象(可以传自己的stf文件路径参数)。这时存在问题是,drawimplementation只生成一次森林,所以每定义一个geode调用一次speedtreeDrawable构造函数将application中的stfFile列表增加一个,但是只要这个几个geode节点定义完(stfFile列表已经形成)并且第一个geode加到root上,其后geode节点是否加到root上都没作用了,因为森林已定。如何实现像osg动态增加场景节点一样动态增加speedtree节点呢?

该用户从未签到

发表于 2012-11-9 16:28:55 | 显示全部楼层
动态的向Geode中添加drawable和删除

该用户从未签到

 楼主| 发表于 2012-11-12 10:24:36 | 显示全部楼层
liuzhiyu123 发表于 2012-11-9 16:28
动态的向Geode中添加drawable和删除

谢谢,另外请教场景视野范围中若同时显示speedtree模型与osg模型时osg模型的线框模式就不显示了,移动鼠标漫游视野范围只显示osg模型时又可以了,这是什么原因呢如何处理?

该用户从未签到

 楼主| 发表于 2012-11-12 17:09:18 | 显示全部楼层
array 发表于 2012-11-9 12:05
您可以直接setCullingActive(false)暂时取消裁减,看看是否是这个问题

请教array老师,场景视野范围中若同时显示speedtree模型与osg模型时osg模型的线框模式就不显示了,移动鼠标漫游时当视野范围只显示osg模型时就可以,这是什么原因呢,哪里冲突了,如何处理?

该用户从未签到

发表于 2012-11-15 13:32:18 | 显示全部楼层
您这么说我如何猜得到?

该用户从未签到

 楼主| 发表于 2012-11-17 13:40:47 | 显示全部楼层
array 发表于 2012-11-15 13:32
您这么说我如何猜得到?

谢谢array老师,这个问题已经解决了,是speedtree中RenderStyle的原因

该用户从未签到

 楼主| 发表于 2012-11-26 21:29:37 | 显示全部楼层
array 发表于 2012-11-15 13:32
您这么说我如何猜得到?

array老师您好,还有问题麻烦您给指导一下。我的包围盒如下计算是否正确:
virtual osg::BoundingBox computeBound() const
        {       
                osg::BoundingBox bb;

                //获取基础树
                TTreeArray basetree = g_pApplication->GetForest()->GetBaseTrees();

                //获取实例树几何信息
                TInstanceArray aInstances;
                CExtents cInstanceExtents ;
                for (int i=0;i<basetree.size();++i)
                {
                        aInstances.clear();
                        g_pApplication->GetForest()->GetInstances(basetree, aInstances);

                        for (int j=0;j<aInstances.size();++j)
                        {
                                cInstanceExtents = basetree->GetExtents( );        //树的范围

                                cInstanceExtents.Scale(aInstances[j].GetScale( ));
                                cInstanceExtents.Translate(aInstances[j].GetPos( ));

                                osg::Vec3 tmin(cInstanceExtents.Min().x,cInstanceExtents.Min().y,cInstanceExtents.Min().z);
                                osg::Vec3 tmax(cInstanceExtents.Max().x,cInstanceExtents.Max().y,cInstanceExtents.Max().z);

                                bb.expandBy(tmin);
                                bb.expandBy(tmax);               
                        }
                }

                return bb;
        }

利用这个函数,可以显示全部树木了,但裁剪不起作用,设置近远裁剪没有效果,还请老师给指导一下。
另外,例子中是全局application对象只生成一次森林,但我想实现动态森林生成,每加载一个Drawble向m_cforest对象增加一个stf文件重新生成一遍森林。但获取的森林不正确。如何实现动态的增加删除森林还望老师不吝赐教,谢谢!

该用户从未签到

发表于 2012-11-27 11:29:31 | 显示全部楼层
您是否有适当的dirtyBound()操作?

该用户从未签到

 楼主| 发表于 2012-11-27 20:29:27 | 显示全部楼层
array 发表于 2012-11-27 11:29
您是否有适当的dirtyBound()操作?

array老师,我只在你给的伪代码的地方dirtyBound()的,也就是生成完森林之后:
if ( !_initialized )

{

    glewInit();

    CRenderStateOpenGL::InitializeForThreadedOpenGL( wglGetCurrentDC(), wglGetCurrentContext() );

   

    _application->InitGraphics();



    // 计算包围体,所以你还要重写computeBound

    non_const_this->dirrtyBound();

   _initialized = true;

}

该用户从未签到

发表于 2012-11-30 18:59:41 | 显示全部楼层
array 发表于 2012-11-5 09:59
您的代码具体是什么问题,很难一下子看出来,只能大概给出我当时做结合时候的思路给一段伪代码此处的草地和 ...

array大哥,那能找公司花钱买您的融合方案么?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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