以下内容来自:
1、《OpenSceneGraph三维渲染引擎设计与实践》王锐 钱学雷 清华大学出版社
2、自己的总结
下载完整工程OSG_1_NodeTransform、OSG_2_NodeSwitch
创建C++项目后,首先需要配置OSG环境。具体步骤看OSG学习:WIN10系统下OSG+VS2017编译及运行第六步:新建OSG项目测试。
1.空间变换节点
根据用户视点自动进行变换的AutoTransform节点;
直接使用矩阵进行变换的MatrixTransform节点;
使用位移、旋转和缩放值进行变换的PositionAttitudeTransform节点。
// stdafx.h
#include <osg/AutoTransform> //自动变换节点类,使节点自动对齐于摄像机或屏幕。
#include <osg/MatrixTransform> //移动节点的矩阵类,最常用的移动节点的类。可随动、旋转控制节点。
#include <osg/PositionAttitudeTransform> //位置变换节点类,提供模型的位置变换、大小缩放、原点位置的设置、坐标系的变换
#include <osgViewer/Viewer> //视窗管理库,显示场景。为单独的场景保存一个单独的view,每个单独场景的程序都有一个Viewer
#include <osgDB/ReadFile> //数据读写库
//.cpp
#include "stdafx.h"
/*创建自动变换节点对象AutoTransform,使其始终面对屏幕,即用户视点*/
osg::Transform *createAutoTransform(double posX, osg::Node *model)
{
//在osg智能指针中进行定义
osg::ref_ptr<osg::AutoTransform> at = new osg::AutoTransform;
at->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN); //设置自动变换模式,始终面对屏幕
at->setPosition(osg::Vec3(posX, 0.0, 0.0)); //设置模型的位置
at->addChild(model);
//新建对象作为函数结果返回时,应该返回release(),并尽快引入到别的场景中,否则发生内存泄露
return at.release();
}
/*创建空间变换矩阵节点对象MatrixTransform,并使其沿Z轴逆时针旋转45度*/
osg::Transform *createMatrixTransform(double posX, double rotateZ, osg::Node *model)
{
//在osg智能指针中进行定义
osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
//设置空间变换矩阵的内容,格式都为setMatrix(osg::Matrix::translate(x, y, z)),其中osg::Matrix::Scale和osg::Matrix::rotate也可以被用在其中,并且可以相乘叠加
//设置mat矩阵后把node加入到mat中,再把mat加入到Group中,在这个例子中model在main函数中就已加入到Group中了
mt->setMatrix(osg::Matrix::rotate(rotateZ, osg::Z_AXIS) *osg::Matrix::translate(posX, 0.0, 0.0));
mt->addChild(model);
//新建对象作为函数结果返回时,应该返回release(),并尽快引入到别的场景中,否则发生内存泄露
return mt.release();
}
/*创建位置姿态节点对象PositionAttitudeTransform,使其沿Z轴顺时针旋转45度*/
osg::Transform *createPositionAttitudeTransform(double posX, double rotateZ, osg::Node *model)
{
//在osg智能指针中进行定义
osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;
pat->setPosition(osg::Vec3(posX, 0.0, 0.0));
pat->setAttitude(osg::Quat(rotateZ, osg::Z_AXIS));
pat->addChild(model);
//新建对象作为函数结果返回时,应该返回release(),并尽快引入到别的场景中,否则发生内存泄露
return pat.release();
}
int main(int argc, char **argv)
{
//读取main函数参数以及外部参数的类,会自动识别外部参数正确与否
//它是一个单独的类
//ArgumentParser(int *argc, char **argv)构造函数,传入参数为main的两个参数,前者代表命令行参数个数,后者代表参数的具体值
osg::ArgumentParser arguments(&argc, argv);
//如果外部参数正确,则使用osgDB::readNodeFile读取该模型,否则读取本地坐标系模型文件axes.osgt
osg::Node *model = osgDB::readNodeFiles(arguments);
if (!model)
model = osgDB::readNodeFile("axes.osgt");
//将3个节点加入到场景根节点中,同时它们的子节点均为一个预设的模型节点model,因此实现了场景中叶节点的共享
osg::ref_ptr<osg::Group> root = new osg::Group;
//把新创建的节点加入到Group中
root->addChild(createMatrixTransform(-5.0, osg::PI / 4, model));
root->addChild(createAutoTransform(0.0, model));
root->addChild(createPositionAttitudeTransform(5.0, -osg::PI / 4, model));
//实例化显示图像的类osgViewer::Viewer
osgViewer::Viewer viewer;
//设置viewer显示的场景
viewer.setSceneData(root.get());
//开始执行渲染操作,返回值一般为1,程序退出或出错返回0
return viewer.run();
}
2、开关节点
// stdafx.h
#include <osg/Switch> //控制子类的显示与隐藏,这种隐藏不消耗内存
#include <osgViewer/Viewer> //视窗管理库,显示场景。为单独的场景保存一个单独的view,每个单独场景的程序都有一个Viewer
#include <osgDB/ReadFile> //数据读写库
//.cpp
#include "stdafx.h"
/*从NodeCallback类派生,并重构执行函数operator(),实现自定义的节点回调功能
定义名为CessnaCallback的节点更新回调,它使用getFrameNumber()随时取得当前的运行帧数
当帧数大于预先设定的切换值120时,使用setValue()执行子节点的切换*/
class CessnaCallback :public osg::NodeCallback
{
public:
static const int _fireStartFrame = 120; //起火开始时间,即切换模型时的运行帧数,秒
//虚函数。当回调动作发生时,将会执行这一操作符的内容,并将节点和访问器对象作为参数传入
//重载第一个(),而(osg::Node *node, osg::NodeVisitor *nv)是该重载函数的参数表,前者为场景节点,后者为访问器对象,即访问器当前访问的节点
virtual void operator()(osg::Node *node, osg::NodeVisitor *nv)
{
//dynamic_cast将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理
//dynamic_cast <type-id> (expression) 该运算符把expression转换成type-id类型的对象,Type-id 必须是类的指针、类的引用或者void*,它可以在执行期决定真正的类型
//如果type-id是类指针类型,那么expression也必须是一个指针,如果 type-id 是一个引用,那么 expression 也必须是一个引用
//dynamic_cast主要用于类层次间的上行转换(和static_cast效果一样)和下行转换(具有类型检查的功能,比static_cast更安全),还可以用于类之间的交叉转换
osg::Switch *cessnaSwitch = dynamic_cast<osg::Switch *>(node);
if (cessnaSwitch &&nv)
{
//实例化类osg::FrameStamp
//getFrameStamp()获取节点的帧数信息
const osg::FrameStamp *frameStamp = nv->getFrameStamp();
if (frameStamp)
{
//比较起火时的帧数和当前帧数,120帧以后关闭飞机模型cessna.osg开启起火后飞机模型cessnafire.osg
if (_fireStartFrame < frameStamp->getFrameNumber()) //获取上一帧的帧号,即时间,秒
{
//setValue()执行子节点的切换
cessnaSwitch->setValue(0, false);
cessnaSwitch->setValue(1, true);
}
}
}
traverse(node, nv); //向下一个需要访问的节点推进
}
};
int main(int argc, char **argv)
{
//在osg智能指针中定义开关节点
osg::ref_ptr<osg::Switch> root = new osg::Switch;
//读取模型并将之添加到开关节点中
//默认开启子节点飞机模型cessna.osg,默认关闭(切换后开启)子节点起火后的飞机模型cessnafire.osg
root->addChild(osgDB::readNodeFile("cessna.osg"), true);
root->addChild(osgDB::readNodeFile("cessnafire.osg"), false);
//setUpdateCallback自定义回调类CessnaCallback作为更新回调传递给节点,设置人机交互回调为node->setEventCallback(new CessnaCallback)
root->setUpdateCallback(new CessnaCallback);
//实例化显示图像的类osgViewer::Viewer
osgViewer::Viewer viewer;
//设置viewer显示的场景
viewer.setSceneData(root.get());
//开始执行渲染操作,返回值一般为1,程序退出或出错返回0
return viewer.run();
}