文章目錄
-
-
- 說明
- 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 ¢er, 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 ¢er, 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. 類參考,自己看去吧