osg下如何将物体拉近拉远

本文介绍了在OpenSceneGraph中如何实现物体的拉近拉远效果,包括通过MatrixTransform节点调整物体位置和自定义CameraManipulator派生类改变视点位置两种方法,并提供了详细代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1. 需求的提出

2. 第1种方法

3. 第2种方法

4. 其它方法


1. 需求的提出

      osg下如何将物体拉近拉远?有两种方法:

  • 保持相机不动,将物体拉近或拉远。
  • 保持物体不动,将相机拉近或拉远。

2. 第1种方法

       在将物体也即模型加入到视图时,先要将物体加入到MatrixTranform节点中去,如下:

osg::ref_ptr<osg::MatrixTransform> spMatrixTransform = new osg::MatrixTransform;
spMatrixTransform ->addChild(m_spNode);

然后调用tranlate拉近或拉远物体,代码如下:

osg::ref_ptr< osg::Node> spRootNode = m_pViewer->getSceneData();
 if (nullptr == spRootNode)
 {
  return;
 }
 osg::ref_ptr<osg::Transform> spTransformNode = spRootNode->asTransform();
 if (nullptr == spTransformNode)
 {
  return;
 }
 osg::ref_ptr<osg::MatrixTransform> spMatrixTransformNode = spTransformNode->asMatrixTransform();
 if (nullptr == spMatrixTransformNode)
 {
  return;
 }

static int a = 500;
 osg::Matrix curMatrix = spMatrixTransformNode->getMatrix();
 curMatrix *= osg::Matrix::translate(0, a, 0);   // 更改a值也即y值实现拉近拉远
spMatrixTransformNode->setMatrix(curMatrix);

可以写个事件处理类,在该类中实现按下键盘a键,拉远物体;按下键盘s键拉近物体,整个实现代码如下:

#include<osgViewer/Viewer>
#include<osgGA/GUIEventHandler>
#include<osgDB/ReadFile>
#include<osg/MatrixTransform>
using namespace osgGA;

class moveNearOrFarHandler : public GUIEventHandler
{
public:
    moveNearOrFarHandler(const osg::ref_ptr< osg::MatrixTransform>& matTrans)
    {
        _matTrans = matTrans;
    }
private:
    virtual bool handle(osgGA::Event* event, osg::Object* object, osg::NodeVisitor* nv) override
    {
        auto pGUIEvent = (GUIEventAdapter*)event;
        if (GUIEventAdapter::KEYDOWN == pGUIEvent->getEventType())
        {
            auto keyValue = pGUIEvent->getKey();
           if ( ('a' == keyValue) || ('A' == keyValue) )
            {
               const osg::Matrix& mat = _matTrans->getMatrix();
               _matTrans->setMatrix( mat * osg::Matrix::translate(0.0, _moveOffset, 0.0));
            }
             else if ( ('s' == keyValue) || ('S' == keyValue) )
            {
                const osg::Matrix& mat = _matTrans->getMatrix();
                _matTrans->setMatrix(mat * osg::Matrix::translate(0.0, -_moveOffset, 0.0));
            }
        }

        return false;
    }
private:
    osg::ref_ptr< osg::MatrixTransform > _matTrans;
    float _moveOffset{0.5}; // 每次移动的距离
};

int main(int argc, char *argv[])
{
    auto pCowNode = osgDB::readNodeFile("cow.osg");
    if (nullptr == pCowNode)
    {
        OSG_WARN << "node is null!";
        return 1;
    }

    auto pRoot = new osg::Group;
    auto pMatrixTrans = new osg::MatrixTransform;
    pMatrixTrans->addChild(pCowNode);
    pRoot->addChild(pMatrixTrans);

    osgViewer::Viewer viewer;
    viewer.addEventHandler(new moveNearOrFarHandler(pMatrixTrans));
    viewer.setSceneData(pRoot);

    return viewer.run();
}

 注意:考虑到大小写的问题,如果按下a、s键没反应,请先按一下shift键,再按a、s键试试。

3. 第2种方法

       从osgGA::CameraManipulator类派生一个自己的操控器,重载操控器的Handle函数,在该函数中更改视点的位置,具体代码参见:自定义一个简单的操控器类 博文。

4. 其它方法

         如果相机操控器支持鼠标滚轮滚动时,场景能随滚轮滚动而拉近拉远,则可以模拟鼠标滚轮滚动来使场景拉近拉远。如 osgGA::TrackballManipulator操控器,如下代码就是模拟滚轮滚动从而使场景拉近拉远:

#include<osgViewer/Viewer>
#include<osgGA/GUIEventHandler>
#include<osgDB/ReadFile>
#include<osg/MatrixTransform>
#include<osgGA/TrackballManipulator>
using namespace osgGA;

class moveNearOrFarHandler : public GUIEventHandler
{

private:
    virtual bool  handle(const GUIEventAdapter&ea, GUIActionAdapter&aa) override
    {
        if (GUIEventAdapter::KEYDOWN == ea.getEventType())
        {
            auto keyValue = ea.getKey();
            if ( ('a' == keyValue) || ('A' == keyValue) )
            {
                // 模拟鼠标滚轮朝向人滚动,以便场景离人显得更近些
                auto pViewer = (osgViewer::Viewer*)(&aa);
                pViewer->getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_DOWN);
            }
            else if ( ('s' == keyValue) || ('S' == keyValue) )
            {
                // 模拟鼠标滚轮背向人滚动,以便场景离人显得更远些
                auto pViewer = (osgViewer::Viewer*)(&aa);
                pViewer->getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_UP);
            }
        }

        return false;
    }
};

int main(int argc, char* argv[])
{
    auto pCowNode = osgDB::readNodeFile("cow.osg");
    if (nullptr == pCowNode)
    {
        OSG_WARN << "node is null!";
        return 1;
    }

    auto pRoot = new osg::Group;
    pRoot->addChild(pCowNode );

    osgViewer::Viewer viewer;
    viewer.addEventHandler(new moveNearOrFarHandler());
    viewer.setSceneData(pRoot);
      
    // 设置操控器为跟踪球操控器,这句代码也可以不要,没有设置操控器,则默认为跟踪球操控器
    viewer.setCameraManipulator(new osgGA::TrackballManipulator);

    return viewer.run();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值