说明
- 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
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;
}