`
NickWar
  • 浏览: 69745 次
  • 来自: 南京
文章分类
社区版块
存档分类

OSG 编程

 
阅读更多

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/

    分享到:
    评论

    相关推荐

    Global site tag (gtag.js) - Google Analytics