天天看點

OSG 之學習六:OSG 更新和回調

文章目錄

      • 說明
      • 1. 使用已有回調
      • 2. 自定義回調
      • 3. NodeVisitor
      • 4. 類參考,自己看去吧

說明

  • 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
OSG 之學習六:OSG 更新和回調

2. 自定義回調

OSG 之學習六:OSG 更新和回調
  • 程式功能:自已定義一個 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;
}
           
OSG 之學習六:OSG 更新和回調

3. NodeVisitor

OSG 之學習六:OSG 更新和回調
  • 程式功能:輸出模型所有頂點
#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;
}
           
OSG 之學習六:OSG 更新和回調

4. 類參考,自己看去吧