OpenSceneGraph 常用节点

本文详细介绍了OSG中的节点操作,包括节点访问器(如NodeVisitor)的使用,自定义节点查找,节点的更新和交互回调,以及LOD节点的应用。还涵盖了osgText库的文本渲染、光照设置、Material类和文件I/O功能的讲解。
摘要由CSDN通过智能技术生成

OSG中的节点相关操作

节点访问器

节点访问器就是获取某个节点对象后,执行一些用户自定义的操作,OSG中使用NodeVisitor类来控制节点访问,当调用节点访问器时,自动调用该访问器的apply() 成员函数。
image.png

其中traverse()函数会自动调用传入节点的子节点的apply()函数,ascend()函数会自动调用传入节点的父节点的apply()函数。

自定义节点访问器(常用)

class FindNamedNode : public osg::NodeVisitor 
{ 
public: 
 FindNamedNode( const std::string& name ) :
 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),  //初始化父类     
 _name( name ) {}			 //_name是指定的名称
 
 // 这个方法将调用场景功能图形中的每个节点,
 // 检查其名称是否符合输入的要求。
 // 如果符合的话,将保存节点的地址。
 virtual void apply( osg::Node& node )   
 { 
     if (node.getName() == _name)      //找到目标节点
     _node = &node;		//保存节点地址

     // 继续遍历该节点的子节点。
     traverse(node); 
 } 
 
 osg::Node* getNode() { return _node.get(); } 
 
 protected: 
     std::string _name; 
     osg::ref_ptr<osg::Node> _node; 
     
   virtual void apply( osg::Group& node )
   {
   }
   
    virtual void apply( osg::Geode& node )  
    {
    }
};


//使用自定义访问器
int main()
{
    osg::Node *root=……………………       //节点
    FindNamedNode k;              //自定义访问器对象
    
    root->accept(k);              //root节点调用自定义节点访问器
    
    return 0;
}

节点的回调

OSG中 节点回调分为更新回调交互回调,前者每一帧都会自动调用,后者需要与用户发生交互时才会自动调用。OSG中使用NodeCallback类来管理节点的回调。

image.png

operator()成员函数的参数是自动传入,在函数体中可以不使用。

节点绑定回调函数:
image.png
image.png

例程代码:

//回调
class RotateCB : public osg::NodeCallback
{
public:
	RotateCB() : _angle(0.) {}
	virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)  
	{
		// 通常应该确认一下更新访问器(update visitor)是否存在,
		// 不过这个例子中没有必要这样做。
		osg::MatrixTransform* mtLeft 
                =dynamic_cast<osg::MatrixTransform*>(node);  //设置一个变量
		osg::Matrix mR, mT;
		mT.makeTranslate(-6., 0., 0.);     //牛的位置
		mR.makeRotate(_angle, osg::Vec3(0., 0., 1.));  //牛旋转角度和轴
		mtLeft->setMatrix(mR * mT);    

		// 下一次回调时角度就会增大。
		_angle += 0.01;

		// 指定继续传递参数,
		// 这样 OSG 可以接着执行其它带有回调的节点。
		traverse(node, nv);     //本例程中无其他节点,因此本函数无效果
	}
protected:
	double _angle;
};

osg::ref_ptr<osg::Node> createScene()
{
	// 加载牛的模型。
	osg::Node* cow = osgDB::readNodeFile("cow.osg");
	// 设置数据变量为 STATIC,因为程序中不会修改它。
	cow->setDataVariance(osg::Object::STATIC);   //static 静态
	//保证cow的数据在更新遍历中不变
        

	// 创建 MatrixTransform 来显示左边的牛。
	osg::ref_ptr<osg::MatrixTransform> mtLeft =new osg::MatrixTransform;
	mtLeft->setName("Left Cow\nDYNAMIC");
	// 设置数据变量为 DYNAMIC,
	// 告诉 OSG 这个节点将在更新遍历中被修改。
	mtLeft->setDataVariance(osg::Object::DYNAMIC);  //dynamic
	// 绑定更新回调。
	mtLeft->setUpdateCallback(new RotateCB);

	osg::Matrix m;
	m.makeTranslate(-6.f, 0.f, 0.f);   //设置左边的牛在左边
	mtLeft->setMatrix(m);
	mtLeft->addChild(cow);

	// 创建 MatrixTransform 来显示右边的牛。
	osg::ref_ptr<osg::MatrixTransform> mtRight =new osg::MatrixTransform;
	mtRight->setName("Right Cow\nSTATIC");
	// 设置数据变量为 STATIC,因为程序中不会修改它。
	mtRight->setDataVariance(osg::Object::STATIC);   //static
	m.makeTranslate(6.f, 0.f, 0.f);
	mtRight->setMatrix(m);
	mtRight->addChild(cow);

	// 创建 Group 根节点。
	osg::ref_ptr<osg::Group> root = new osg::Group;
	root->setName("Root Node");

	// 设置数据变量为 STATIC,因为程序中不会修改它。
	root->setDataVariance(osg::Object::STATIC);
	root->addChild(mtLeft.get());
	root->addChild(mtRight.get());
	return root.get();
}

效果图

image.png

顶点

image.png
image.png

颜色和法线数组必须设置对应的绑定方式,其余相关操作的与上图一致

geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);

//设置颜色数组和法线数组的绑定方式

颜色数组和法线数组的绑定参数:
image.png

开关节点

捕获.PNG

osg::Switch类参数:
捕获.PNG

细节层次节点(LOD)

使用osg::LOD节点(细节层次节点) 可以实现不同细节层次下物体的渲染。

LOD继承自Group类
每个子节点都有一个有效范围。根据距离(子节点与观察点)和有效范围的不同,OSG 可以不显示、显示任意一个,或者显示所有的 LOD 子节点(根据模型与观察者距离的不同)。

osg::ref_ptr<osg::Geode> geode;         //创建了一个叶节点
osg::ref_ptr<osg::LOD> lod = new osg::LOD;       //创建了一个LOD节点
lod->addChild(geode.get(), 0.f, 1000.f);        
// 当距离在 0.f 与 1000.f 之间时,显示 geode节点

addChild()函数,参数为空条件下,LOD 会自动以视点到物体包络体中心点的距离为距离
,如果这样并不符合渲染要求,那么用户可以指定一个自定义的中心点。

osg::ref_ptr<osg::LOD> lod = new osg::LOD;      //定义一个LOD节点
lod->setCenterMode(osg::LOD::USER_DEFINED_CENTER);    //使用用户定义的中心点来计算距离
Lod->setCenter(osg::Vec3(10.f, 100.f, 0.f));      
// 设置自定义中心点的 X坐标 10,Y坐标 100,Z坐标 0

//默认条件下,LOD 使用距离的最大值和最小值来表示范围,但是用户也可以要求
//LOD 使用像素大小来设置范围值。调用 osg::LOD::setRangeMode(),
//参数为 PIXEL_SIZE_ON_SCREEN(像素) 和 DISTANCE_FROM_EYE_POINT(视点)

image.png

设置文字与字体

osgText 组件:osgText 库定义了一个命名空间,osgText。其中有一些十分实用的字体加载和文字渲染类

  • osgText 库的核心组件是 osgText::Text 类。Text 继承自 Drawable,因此用户程序应当使用 addDrawable() 方法把 Text 实例添加到 Geode 中(与添加 Geometry实例的方法相同

  • osgText 库的另一个核心组件是 osgText::Font 类。osgText 的函数可以根据字体文件的名称来创建 Font 对象

要在程序中使用 osgText,用户通常要遵循下面三个步骤:

1、如果要使用一种字体显示多行文字,只需要创建一个 Font 对象,然后在Text 对象间共享即可。

2、为每一段要显示的字符串建立一个 Text 对象。指定其对齐方式,文字方向,位置和大小参数。将步骤 1 中创建的 Font 对象关联到新的 Text 对象中。

3、使用 addDrawable()函数将 Text 对象添加到 Geode 节点。用户可以向一个Geode 添加多个 Text 对象,或者根据自己的需要创建多个 Geode 节点,将 Geode 节点作为场景图形的子节点加入。

例程代码:

#include <osgText/Font> 
#include <osgText/Text>

osg::ref_ptr<osgText::Font> font = osgText::readFontFile("fonts/arial.ttf");  
//创建一个Font对象

osg::ref_ptr<osgText::Text> text = new osgText::Text;    //创建一个Text对象
text->setFont(font.get());   //关联Font对象,不关联Text会用默认字体替代
text->setText(“Display this message.);   //输入文本内容

text->setPosition( osg::Vec3( 10.f, 0.f, 1.f ) );    
//设置文字显示的位置,在(10.0,0.0,1.0)绘制文字,默认在原点

text->setAxisAlignment( osgText::Text::SCREEN )   //文字方向,一直朝向视点

//Text::XY_PLANE  文字朝向Z轴,水平放在XY平面上,Text::YZ_PLANE 文字朝向X轴,水平
//放在YZ平面上, Text::XZ_PLANE 文字朝向Y轴,水平放在XZ平面上

//Text::REVERSED_XY_PLANE,Text::REVERSED_XZ_PLANE 和 Text::REVERSED_YZ_PLANE 
//与此类似,但是文字朝向指定轴的负向;
//Text::SCREEN 使文字总是朝向屏幕

text->setAlignment( osgText::Text::CENTER_TOP );   //文字对齐方式,顶部对齐
//默认为Text::LEFT_BASE_LINE  基线对齐

text->setCharacterSize(1.0f);         //文字大小
text->setCharacterSizeMode( osgText::Text::SCREEN_COORDS ); 

//该方法可以指定使用屏幕坐标,此时Text 会根据视角,适当放缩文字几何体以保持它在屏幕上
//的恒定尺寸

text->setFontResolution( 128, 128 );   //分辨率

text->setColor( osg::Vec4( 0.f, 0.f, 1.f, 1.f ) ); //颜色

光照(使用光照必须设置几何体的单位长度的法线)

osg::StateSet* state = geode->setOrCreateStateSet(); 
state->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON);

//以上可以保证法线在均匀放缩变换时仍然保持单位长度,但当非均匀放缩时,就要如下处理:
osg::StateSet* state = geode->setOrCreateStateSet(); 
state->setMode(GL_NORMALIZE, osg::StateAttribute::ON);

StateSet 允许八个光源(GL_LIGHT0 —GL_LIGHT7):

state->setMode( GL_LIGHT0, osg::StateAttribute::ON );

可以创建一个 osg::Light 对象以定义光源参数,然后将 Light 添加到一个 osg::LightSource 节点中,并将 LightSource 节点(这是一个组节点)添加到场景图形

//向场景中添加光源
osg::ref_ptr<osg::Group> createLight(osg::ref_ptr<osg::Node> node)
{
        //node 为传入的一个节点
	osg::ref_ptr<osg::Group> lightRoot = new osg::Group();
	lightRoot->addChild(node);
 
	//开启光照
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
	stateset = lightRoot->getOrCreateStateSet();
	stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);
	stateset->setMode(GL_LIGHT0, osg::StateAttribute::ON);
 
	//计算包围盒
	osg::BoundingSphere bs;
	node->computeBound();
	bs = node->getBound();
 
	//创建一个Light对象
	osg::ref_ptr<osg::Light> light = new osg::Light();
	light->setLightNum(0);
	//设置方向
	light->setDirection(osg::Vec3(0.0f, 0.0f, -1.0f));
	//设置位置
	light->setPosition(osg::Vec4(bs.center().x(), bs.center().y(), bs.center().z() + bs.radius(), 1.0f));
	//设置环境光的颜色
	light->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
	//设置散射光颜色
	light->setDiffuse(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
 
	//设置恒衰减指数
	light->setConstantAttenuation(1.0f);
    //设置线形衰减指数
	light->setLinearAttenuation(0.0f);
	//设置二次方衰减指数
	light->setQuadraticAttenuation(0.0f);
 
	//创建光源
	osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource();
	lightSource->setLight(light.get());
 
	lightRoot->addChild(lightSource.get());
 
	return lightRoot.get();
}
//OSG 根据当前 LightSource 节点的变换状态来改变灯光的位置
//往往将 LightSource 关联为 MatrixTransform 的子节点,以控制灯光的位置

材质属性:(状态属性类osg::Material)

允许用户设置全局、散射、镜面反射和放射材质的颜色,以及镜面和高光指数参数
Material类定义了枚举量FRONT,BACK和FRONT_AND_BACK

osg::StateSet* state = node->getOrCreateStateSet(); 

osg::ref_ptr<osg::Material> mat = new osg::Material; 
mat->setDiffuse(osg::Material::FRONT, osg::Vec4(.2f, .9f, .9f, 1.f));   
//为几何体正面设置散射颜色,参数2为颜色

mat->setSpecular(osg::Material::FRONT,osg::Vec4(1.f, 1.f, 1.f, 1.f));
//为几何体正面设置镜面反射颜色,参数2为颜色

mat->setShininess(osg::Material::FRONT, 96.f);   
//为几何体正面设置镜面指数(指数必须在1.0到128.0之间)

state->setAttribute(mat.get());

颜色跟踪材质:允许用户程序通过改变当前颜色的方法,自动改变某一特定的材质属性
需要调用Material::setColorMode(); 该方法中定义:AMBIENT(环境光),DIFFUSE(散射),SPECULAR(反射),EMISSION(发射光),AMBIENT_AND_DIFFUSE(反射与散射)以及OFF(默认OFF)

osg::StateSet* state = node->getOrCreateStateSet(); 
osg::ref_ptr<osg::Material> mat = new osg::Material;

mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); //设置颜色模式

state->setAttribute(mat.get());

//上面代码使几何体正面材质根据当前颜色变化而变化。

文件IO

osgDB 提供了文件 I/O 的函数接口

#include <osgDB/ReadFile> 
#include <osgDB/WriteFile>

//使用函数 osgDB::readNodeFile()和 osgDB::readImageFile()来读取 3D 模型和2D 图像文件。

//使用函数 osgDB::writeNodeFile()和 osgDB::writeImageFile()
//将数据写入到3D模型或2D图像文件中

OSG 的写入操作会不作任何警告地覆盖同名文件。要避免这一特性的话,用户程序需要自行检查文件是否存在并采取相应的措施

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

freejackman

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值