第08节 实例-写个简单的操作器

缘由
应四川的群友:挑战高起点 的要求,我给大家写一个最简单的操作器,读完本文以最大程度让读者掌握在OSG中写个操作器是咋回事儿。代码在最后一个代码块,直接新建OSG工程,拷贝进去就可以运行。特别感谢这位网友,要不然真的不知道怎么为大家好呀。

另外如果您也想我来为您就某个功能写个例子,分享给大家,则只需要在本文评论区回复即可。或在本文出现的群里回复。

本节所有代码在网盘中:

注意:务必使用浏览器打开:
链接:https://pan.baidu.com/s/13gwJLwo_LbRnN3Bl2NXXXw
提取码:xrf5

功能说明
首先绘制一个场景如下,场景中间放着模型axes.osgt这个模型,它指明了xyz轴的方向,然后我们在xy方向,从-5~5,间隔0.5绘制网格,如下图所示。

image.png

然后我们操作器的功能是:点击a围绕z轴,眼睛看着(0,0,0)点,高度在5,逆时针旋转
点击d则顺时针旋转。

实现要点
1.写个类继承自osgGA::CameraManipulator,就我们的功能而言,有两个函数就可以了,一个是virtual osg::Matrixd getInverseMatrix() const,它要返回camera的ViewMatrix,也就是我说的,Camera会在事件遍历的时候,调用这个函数来设置他的ViewMatrix。所以我们要实现它。

实现它也很简单,自己写三个变量做成员函数:_eye(人头的位置), _center(人头在往哪看), _up(人头顶的朝向),自己想想自己的头,就能想明白这三个量一定,你在哪朝哪看就定了,接着直接构造ViewMatrix就可以了,代码如下:

    virtual osg::Matrixd getInverseMatrix() const
    {
        return osg::Matrix::lookAt(_eye, _center, _up);
    };

看看简单吧。那么现在的任务就是根据事件要来设置_eye了,因为根据我们的功能设想,_center始终是0,0,0,up始终是0,0,1。

2._Eye的更新在事件处理中,也就是另一个要实现的虚函数:virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us),我们定义了一个成员变量_theta,点A的时候就把它加一度,点D的时候就减一度。然后立即更新_eye的值,按半径是sqrt(55+55)来算:

    //事件处理,我们要点击A就围着Z轴顺时针转动,点D就逆时针转动,转的时候始终朝0 0 0 点看着
    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us)
    {
        if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN)
        {
            //若是A键
            if ((ea.getKey() == 'A') || (ea.getKey() == 'a'))
            {
                _theta += 1.0;
            }
            if ((ea.getKey() == 'D') || (ea.getKey() == 'd'))
            {
                _theta -= 1.0;
            }

            _eye = osg::Vec3(_r * std::cos(osg::DegreesToRadians(_theta)), _r * std::sin(osg::DegreesToRadians(_theta)), 5.0);
        }
        return false;
    }

3.关键代码就是上面那些。要写自己的操作器就是要看看自己按照事件怎么操作_eye,_center,_up这三个值了。多说一句,如果要让相机按着某个路径运动,可以使用AnimationPathManipulator类,它还支持将路径存在文件,然后读起来用。具体用法可以参考:applications/osgviewer/osgviewer.cpp这个程序的具体实现,主要看RecordCameraPathHandler这个类。

4.最后下面是这个示例的所有代码,大家直接拷贝就可以使用,是完整的,没有依赖的,依赖的axes.osgt是OSG自带的模型。就算读不了来只是轴不显示,也不影响其它的功能。

#include <osgViewer/viewer>
#include <osgDB/ReadFile>
#include <osg/Geode>
#include <osg/Geometry>
#include <osgGA/CameraManipulator>

class MyCameraManipulator : public osgGA::CameraManipulator
{
public:
    MyCameraManipulator() 
    {
        _theta = 0.0;
        _center = osg::Vec3(0.0, 0.0, 0.0);
        _up = osg::Vec3(0.0, 0.0, 1.0);
        _r = std::sqrt(5 * 5 + 5 * 5);
        _eye = osg::Vec3(_r*std::cos(osg::DegreesToRadians(_theta)), _r * std::sin(osg::DegreesToRadians(_theta)), 5.0);
    }

    //这三个纯虚函数本例不会使用
    virtual void setByMatrix(const osg::Matrixd& matrix) {};
    virtual void setByInverseMatrix(const osg::Matrixd& matrix) {};
    virtual osg::Matrixd getMatrix() const { return osg::Matrix::identity(); };

    //最关键的是这个,这个返回的就是ViewMatrix
    virtual osg::Matrixd getInverseMatrix() const
    {
        return osg::Matrix::lookAt(_eye, _center, _up);
    };

    //事件处理,我们要点击A就围着Z轴顺时针转动,点D就逆时针转动,转的时候始终朝0 0 0 点看着
    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us)
    {
        if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN)
        {
            //若是A键
            if ((ea.getKey() == 'A') || (ea.getKey() == 'a'))
            {
                _theta += 1.0;
            }
            if ((ea.getKey() == 'D') || (ea.getKey() == 'd'))
            {
                _theta -= 1.0;
            }

            _eye = osg::Vec3(_r * std::cos(osg::DegreesToRadians(_theta)), _r * std::sin(osg::DegreesToRadians(_theta)), 5.0);
        }
        return false;
    }

    //视点位置
    osg::Vec3d              _eye;
    //视点看向哪里
    osg::Vec3d              _center;
    //头顶的朝向
    osg::Vec3d              _up;

    //视点看向0 0 0的角度
    float              _theta;
    //视点离0 0 0的距离
    float              _r;
};

osg::Node* createScene()
{
    osg::Group* root = new osg::Group();
    root->addChild(osgDB::readNodeFile("axes.osgt"));

    osg::Geode* gnode = new osg::Geode;
    root->addChild(gnode);

    osg::Geometry* geom = new osg::Geometry;
    gnode->addChild(geom);

    osg::Vec3Array* vertex = new osg::Vec3Array;
    geom->setVertexArray(vertex);
    //沿xy平面画线,间隔0.5米,从-5,画到5
    for (float i = -5; i <= 5; i += 0.5)
    {
        vertex->push_back(osg::Vec3(i, -5, 0));
        vertex->push_back(osg::Vec3(i, 5, 0));
        vertex->push_back(osg::Vec3(-5, i, 0));
        vertex->push_back(osg::Vec3(5, i, 0));
    }
    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, vertex->size()));

    osg::Vec4Array* color = new osg::Vec4Array();
    color->push_back(osg::Vec4(0.7, 0.7, 0.7, 1.0));
    geom->setColorArray(color, osg::Array::BIND_OVERALL);
    geom->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

    return root;
}


int main()
{
    osgViewer::Viewer viewer;

    viewer.setCameraManipulator(new MyCameraManipulator());
    viewer.setSceneData(createScene());

    return viewer.run();
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容

  • 文章发布之后,大家有很多疑问,我发现有些很基础。要求我再聊细一些,我就再重头来再比较细致的写一写。虽然不需要大家看...
    杨石兴阅读 2,342评论 6 4
  • 以下文章即Learn Threejs 第三版英文翻译学习记录,可以到正版书店购买对应书籍。 这章内容内容中,你将学...
    我的名字好长好长灬阅读 173评论 0 0
  • NumPy是Python中关于科学计算的一个类库,在这里简单介绍一下。 来源:https://docs.scipy...
    灰太狼_black阅读 1,227评论 0 5
  • 先决条件 在阅读这个教程之前,你多少需要知道点python。如果你想从新回忆下,请看看Python Tutoria...
    舒map阅读 2,572评论 1 13
  • 基础篇NumPy的主要对象是同种元素的多维数组。这是一个所有的元素都是一种类型、通过一个正整数元组索引的元素表格(...
    oyan99阅读 5,120评论 0 18