OSG 之学习六:OSG 更新和回调

说明


  • OSG 入门看的,大佬绕道
  • 示例来源于《OSG程序设计教程》
  • 没有此电子书的小伙伴们,我已上传至CSDN
  • 部分代码错误已改正

1. 使用已有回调


  • 程序功能:隐藏模型 fountain.osg 下的第一个结点,然后不断的旋转喷头
#include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform>
#include <osg/Geode>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgViewer/Viewer>

// 创建一条路径
osg::AnimationPath *createAnimationPath(const osg::Vec3 &center, float radius, double looptime) {
    // 路径实体
    osg::AnimationPath *animationPath = new osg::AnimationPath;
    // 设置循环模式为LOOP
    animationPath->setLoopMode(osg::AnimationPath::LOOP);
    // 设置关键点数
    int numSamples = 40;
    float yaw = 0.0f;
    float yaw_delta = 2.0f * osg::PI / ((float)numSamples - 1.0f);
    float roll = osg::inDegrees(30.0f);
    // 设置时间间隔
    double time = 0.0f;
    double time_delta = looptime / (double)numSamples;
    // 插入关键点与时间以及旋转角度和位置
    for (int i = 0; i < numSamples; ++i) {
        osg::Vec3 position(0, 0, 0);
        osg::Quat rotation(osg::Quat(roll, osg::Vec3(0.0, 1.0, 0.0))*osg::Quat(-(yaw + osg::inDegrees(90.0f)), osg::Vec3(0.0, 0.0, 1.0)));

        // 具体插入操作
        animationPath->insert(time, osg::AnimationPath::ControlPoint(position, rotation));
        yaw += yaw_delta;
        time += time_delta;
    }
    return animationPath;
}

// 创建移动模型
osg::Node *createMovingModel(const osg::Vec3 &center, float radius) {
    float animationLength = 10.0f;
    // 创建的路径
    osg::AnimationPath *animationPath = createAnimationPath(center, radius, animationLength);
    osg::Group *model = new osg::Group;
    // 读取模型,并隐藏它下面的第一个结点
    osg::Node *fountain = osgDB::readNodeFile("fountain.osgt");
    fountain->asGroup()->getChild(0)->setNodeMask(0);
    // 如果读取成功,则更新负于它的路径
    if (fountain) {
        osg::PositionAttitudeTransform *xform = new osg::PositionAttitudeTransform;
        // 设置更新回调
        xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath, 0.0, 1.0));
        // 加入子模型结点
        xform->addChild(fountain);
        model->addChild(xform);
    }
    return model;
}

// 创建模型
osg::Node *createModel() {
    osg::Vec3 center(0.0f, 0.0f, 0.0f);
    float radius = 1.0f;
    osg::Group *root = new osg::Group;
    // 创建移动的结点,以radius为半径转圈
    osg::Node *movingModel = createMovingModel(center, radius * 0.8f);
    // 把结点加入到root中并返回
    root->addChild(movingModel);
    return root;
}

int main(int argc, char **argv) {
    osgViewer::Viewer viewer;
    // 创建模型
    osg::Node *model = createModel();
    viewer.setSceneData(model);
    viewer.setCameraManipulator(new osgGA::TrackballManipulator());
    viewer.realize();
    return viewer.run();
}

注意这里是 fountain.osgt ,不是 fountain.osg,就是说后缀有 t

在这里插入图片描述

2. 自定义回调


在这里插入图片描述

  • 程序功能:自已定义一个 NodeCallBack 派生的类,完成一个对 Transform 的 node 的改变,然后完成的功能是让 transform 下的一个模型来回动
#include <osgViewer/Viewer>
#include <osg/Math>
#include <osgDB/ReadFile>
#include <osg/NodeCallback>
#include <osg/MatrixTransform>

// 申请一个类,从NodeCallBack下派生而来
class MyTransformCallback : public osg::NodeCallback {
public:

    // 构造函数,传入一个角度,这个角度为计算移动值的,移动的原理是,每一次时间变化乘以这个角度的量纲
    MyTransformCallback(float angularVelocity) {
        m_angularVelocity = angularVelocity;
    }

    // nodevisitor可以判断出哪个是需要的结点
    virtual void operator() (osg::Node *node, osg::NodeVisitor *nv) {
        // 验证得到的结点是不是MatrixTransform
        osg::MatrixTransform *transform = dynamic_cast<osg::MatrixTransform *>(node);
        // 如果是的
        if (nv && transform && nv->getFrameStamp()) {
            //  得到参考时间与当前时间差,用来计算cos然后改变移动值
            double time = nv->getFrameStamp()->getReferenceTime();
            transform->setMatrix(osg::Matrix::translate(0.0f, 1.0f + cosf(time * m_angularVelocity), 0.0f));
        }
        // 向下遍历node,以便找到transform
        traverse(node, nv);
    }
protected:
    float m_angularVelocity;

};

int main(int argc, char **argv) {
    osgViewer::Viewer viewer;
    osg::Group *root = new osg::Group;
    // 读入一个小飞机
    osg::Node *node = osgDB::readNodeFile("glider.osg");
    // 设置transform,随后将设置它的CallBack
    osg::MatrixTransform *transform = new osg::MatrixTransform();
    transform->setUpdateCallback(new MyTransformCallback(10.0f)); transform->addChild(node);

    // 把带有callback的结点加入到场景当中
    root->addChild(transform);
    viewer.setSceneData(root);
    viewer.realize();
    viewer.run();
    return 0;
}

在这里插入图片描述

3. NodeVisitor


在这里插入图片描述

  • 程序功能:输出模型所有顶点
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/NodeVisitor>
#include <osg/Geometry>
#include <fstream>
#include <iostream>

//定义一个顶点访问的nodevisitor,名字自己取
class VertexExtractor : public osg::NodeVisitor {
public:  //所有的顶点
    osg::ref_ptr<osg::Vec3Array> extracted_verts;
    // 构造函数,选择向下遍历全孩子的方式
    VertexExtractor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {
        extracted_verts = new osg::Vec3Array;
    }

    // apply
    void apply(osg::Geode &geode) {
        // 看看有多少可绘制结点
        for (unsigned int i = 0; i < geode.getNumDrawables(); ++i) {
            osg::Geometry *geom = dynamic_cast<osg::Geometry *>(geode.getDrawable(i));
            if (!geom)
                continue;
            // 得到可绘制结点的顶点序列
            osg::Vec3Array *verts = dynamic_cast<osg::Vec3Array *>(geom->getVertexArray());
            if (!verts)
                continue;
            // 把顶点序列插入到顶点集中以便输出
            extracted_verts->insert(extracted_verts->end(), verts->begin(), verts->end());
        }
    }
};

int main(int argc, char **argv) {
    osgViewer::Viewer viewer;
    // 读取模型
    osg::Node *rootNode = osgDB::readNodeFile("glider.osg");
    // 申请一个对象,nodevisitor的对象
    VertexExtractor ivea;
    // accept
    rootNode->accept(ivea);
    // 设置场景数据
    viewer.setSceneData(rootNode);
    // 实现
    viewer.realize();
    // 输出到C盘下的test.vertexs文件当中,可用写字板打开查看
    std::ofstream out("E:/test.vertexs");
    int size_t = ivea.extracted_verts.get()->size();
    std::vector <osg::Vec3 > ::iterator iter = ivea.extracted_verts.get()->begin();
    for (int i = 0; i < size_t; i++) {
        out << iter->x() << "   " << iter->y() << "   " << iter->z() << std::endl;
        iter++;
    }
    std::cout << "输出所有结点完毕" << std::endl;
    return 0;
}

在这里插入图片描述

4. 类参考,自己看去吧


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值