OSG 编程

本文介绍了OpenSceneGraph(OSG)编程的关键概念和技术细节,包括对象管理、矩阵变换、混合渲染、状态继承等内容。通过实例说明如何实现动态旋转、混合透明效果、禁用光照等效果,适合OSG初学者及进阶读者。
摘要由CSDN通过智能技术生成

OpenSceneGraph Programming



OSG 编程

对象管理

  • 使用new osg::Class创建osg对象,不用使用delete,是OSG编程的特色.
  • OSG内部使用含有引用计数智能指针 (OSG::Referenced)
  • 通过OSG API传递的OSG对象会将权限赋给OSG, 场景(graph)拥有所有通过addChild()方法加载的对象
  • osg::ref_ptr
    如果一个程序在通过API传递OSG对象之后,仍需要继续跟踪这个对象 则必须使用 osg::ref_ptr 来增加其引用计数(防止此对象被意外删除).

对象引用计数

有一个容易犯的错误:在构造函数中使用this传递自身到ref_ptr中,这是因为C++在进行赋值操作时,先检测右值再检测左值

构造函数在model增加引用计数之前就被执行了,所以此时新建的对象未被分配到引用计数

当构造函数传递this后,此对象被过早的删除,

osg::ref_ptr<Model> mode; = new Model();

void
EnableAlphaBlending( osg::ref_ptr<Model> model );

Model::Model( void )
{
    EnableAlphaBlending( this );  // oops!
}

矩阵,变换

矩阵的旋转操作,可建立一个旋转矩阵,然后进行矩阵乘法运算

例如,动态旋转一个飞机模型,每帧旋转1度

首先根据单位矩阵计算一个1度的转置矩阵,

然后每帧与变换的矩阵相乘。

如果你不需要改变旋转的角度(每帧1度),转置矩阵可以一直保持不变

class
{
   osg::ref_ptr<osg::MatrixTransform> mTransform;       // 每帧旋转一次
   osg::ref_ptr<osg::Matrix>          mRotationMatrix;  // 矩阵相乘的系数
};

// 建立一个转换矩阵:
mRotationMatrix.makeRotate( degree, osg::Vec3f( 1.0f, 0.0f, 0.0f ) );  // X轴

// 每帧进行一次转换 (matrix of OSG::MatrixTransform):
...
osg::Matrix m = mTransform->getMatrix();
m = mRotationMatrix * m;
mTransform->setMatrix( m );

矩阵运算,旋转轴

矩阵的旋转可以在对象空间或指定空间进行

绕远路:找一本代数课本然后学学什么是左乘和右乘

走捷径:直接运行程序,如果旋转角度是反的,就调换一下系数

m = mRotationMatrix * m; // 绕本地轴

m = m * mRotationMatrix; // 绕固定轴

混合

OSG中的混合与OpenGL相似,OSG为透明体添加了透明渲染属性(transparent bin,一般由其他渲染元传递进来).

// 启用混合,设置透明.
stateSet->setMode( GL_BLEND, osg::StateAttribute::ON );
stateSet->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );

// 启用深度检测,使不透明的多边形遮挡它后面的透明物体
stateSet->setMode( GL_DEPTH_TEST, osg::StateAttribute::ON );

// 相反地,禁用写入深度缓存,
// 使透明多边形背后的物体可以显示出来
// OSG先绘制透明多边形,然后绘制不透明的多边形
osg::Depth* depth = new osg::Depth;
depth->setWriteMask( false );
stateSet->setAttributeAndModes( depth, osg::StateAttribute::ON );

// 禁用 conflicting modes.
stateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF );

公告板

osg::AutoTransform是 osg::Billboard的替代品,AutoTransform 在视角接近它时不会发生旋转

读取压缩的3D文件

-- OSG 2.9 可以读取压缩的3D文件(.gz格式等). --

One way is to pass a C++ stream to osg::ReaderWriter::readNode( istreamstream& ). The C++ stream is the buffer for the decompressed file.

// Read gzip-compressed file into a C++ string.
string buf;
ReadGzipFile( buf, filename );

// Convert C++ string to a C++ stream.
istringstream ss( buf );

// Pass the C++ stringstream, containing the decompressed file, to OSG.
osg::ref_ptr<osgDB::ReaderWriter> readerWriter = /
   osgDB::Registry::instance()->getReaderWriterForExtension( modelFileSuffix );
osgDB::ReaderWriter::ReadResult res = readerWriter->readNode( ss );

OSG编程杂记

  • drawable, geode:
Geometry不是一个节点(Node)继承自Drawable
从字面上也可以大致看出来,Geode 是一个包含Drawable的节点(Node),

Drawable --> Geometry
Node --> Geode

geode->addDrawable( geometry );
modes vs. attributes:
OSG 模式(modes) 与OpenGL的模式(modes)直接关联,如着色,混合等
属性(Attributes)是模式的参数,如阴影模型和混合方程
OSG定义了一系列的属性类,这些类继承自StateAttribute,如BlendFunc等
mode是StateSet的一部分,所以可以这样使用:
osg::StateSet::setMode()
为了简单起见,使用方法setAttributeAndModes()可以同时设置模式(mode)和属性(attribute)
如下:
osg::BlendFunc* bf = new osg::BlendFunc();
state->setAttributeAndModes( bf, osg::StateAttribute::ON );
state->setAttributeAndModes( bf );  // 默认设置为ON
状态继承
一个子对象的状态继承自其父对象
osg::StateAttribute::OVERRIDE 如果你将一个渲染属性和模式设置为
OVERRIDE,那么所有的子节点都将继承这一属性或模式,子节点对它
们更改将会无效。
osg::StateAttribute::PROTECTED 这种形式可以视为OVERRIDE 的一
个例外。凡是设置为PROTECTED 的渲染属性或模式,均不会受到父节
点的影响。
默认情况下,子节点的STATESET渲染模式为OVERRIDE [Martz].

   A
  / /
 B   C

A 颜色设置为Blue
B 颜色设置为Red
C 不改变颜色
那么c的颜色会是什么样?
C的颜色是Red!
是不是有点惊讶?
因为OSG会保留最后执行的glColor()函数的效果(此函数在设置B的时候被调用)
从B-->A的"回访"不会保存或弹出OpenGL状态
这并不是OSG所独有的(这是其他场景图库的通用做法);
停用节点:
node->setNodeMask(0)

这可以有效的禁用不太明显的类如Cameras等
访问者模式
OSG使用访问者模式,并apply()相当于访问者模式中的visit()方法
从NodeVisitor 派生出来的对象,要重写apply()方法

class Visitor : public osg::NodeVisitor
{
    virtual void apply( osg::Node& node )  // visit() method
    {
        ...
          // Keep searching.
          traverse( node );
    }
};
屏幕截图,记录和图像:
osg::Image* shot = new osg::Image();
shot->allocateImage(width, height, 24, GL_RGB, GL_UNSIGNED_BYTE);
camera->attach(osg::Camera::COLOR_BUFFER, shot);
osgDB::writeImageFile(*shot,"image_file.png");
若要获取屏幕截图,需要使用Viewer渲染一个帧(frame)
Direct rendering:
OSG 提供几种方式用于直接调用OpenGL:

1.osg::Operation -osg::Window 的回调函数
2.osg::Camera::DrawCallback
3.继承osg::Drawable

前两种方式以frame为单位进行渲染
第三种方式(osg::Drawable)以节node为单位进行渲染

对于节点渲染(osg::Drawable),一个极好的例子是osgteapot.

class Teapot : public osg::Drawable
{
    virtual void drawImplementation( osg::RenderInfo& ) const;

    // 我们需要为数据建立一个包容盒,这样场景才能知道
    // 对象的位置,这对初始化时确定相机位置和
    // 执行拣选(culling)十分重要
    virtual osg::BoundingBox computeBound() const;
};
渲染元:
[Martz]
"主题: Re: [osg-users] 渲染序列
osgUtil::CullVisitor 从可见的Drawable对象创建渲染元(RenderBins)
然后处理每一个RenderBin。所以,查看CullVisitor和RenderBin的代码
然后在看看osg::Geometry::apply等,了解Geometry是如何传递给OpenGL的。
你可以使用GLIntercept等工具来捕获OpenGL命令,这样可以让你看到OSG是如何渲染场景的"

[Osfield]
"在将多个Drawable,Stateset和RenderBin/RenderStage以及一个状态图放入渲染后端时,
OSG 中的状态排序(state sorting)是作为拣选过程的一部分来完成的,一个渲染元(RenderBin )排序完成时,
其状态值(state)为sorted,这个过程是通过一个STL的映射容器完成的,此容器保存指针与StateSet的映射"
禁用光照: osg::StateAttribute::OVERRIDE 渲染模式下可以禁用光照,但PROTECTED下不行,如下: mSwitchNode->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
多光源:
osg::Light 是一个状态属性(state attribute);
osg::LightSource 是一个组(Group)
一个LightSource只能包含一个osg::Light
所以,要使用多光源,需要建立由一个由LightSource组成的线性链表
然后将渲染对象(geometry)放置到此链表的末端

   root
    |
    V
lightSource 0
    |
    V
lightSource 1
    |
    V
  geodes
处理ESC键:
viewer->setKeyEventSetsDone( 0 );
相机:
Cameras 定义3D的模型视图矩阵(modelview matrix),2D的视点和渲染对象。
Cameras 包含在一个图形窗口的图形上下文中

Cameras 可以作为节点(node)放入一个场景图中(原始方式)
或添加到osg::Viewer中(新方式)

操作机(Manipulator)可以控制Camera
Manipulator可以高效的定义一个模型视图矩阵(modelview matrix)
使用Manipulator::getInverseMatrix()可以提取一个模型视图矩阵

一个Camera定义需要渲染的目标
对于2D窗口中不同视角,OSG通过添加多个Camera来对每一个视角进行单独渲染
纹理渲染(RTT)也是由osg::Camera完成的,
将一个纹理设置为camera的"渲染目标"(render target)即可.

在绘制视图前/后调用的回调函数(Callbacks),可以通过osg::Camera来注册.
在视图中启用窗口模式:
viewer.setUpViewInWindow( 0, 0, 1024, 768 );



原文地址:http://www.palomino3d.com/pal_com/openscenegraph/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值