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/