OSG学习:用多通道(multiple passes)实现透明度

来源:互联网 发布:软件开发做什么 编辑:程序博客网 时间:2024/06/06 15:41

osgFX库提供了一个用于多通道渲染(multi-pass rendering)的框架。每个你想要渲染的子图都应该被添加到osgFX::Effect节点,多通道技术的定义和使用都可以在这个节点中完成。你可能已经熟悉一些预定义的效果,例如osgFX::Scribe和osgFX::Outline。但是在这个教程中,我们的任务是我们自己设计一个多通道技术。这就是所谓的多通道透明度,当我们在透明模式(transparent mode)下它可以消除一些错误。

如何使用

  1. 添加必要的头文件:
#include <osg/BlendFunc>#include <osg/ColorMask>#include <osg/Depth>#include <osg/Material>#include <osgDB/ReadFile>#include <osgFX/Effect>#include <osgViewer/Viewer>

2.首先,我们将提供一个新技术,这个技术继承于osgFX::Technique节点。validate()方法是用于检查现在硬件是否支持这个技术,如果一切正常会返回true。

class TransparencyTechnique : public osgFX::Technique{public:TransparencyTechnique() : osgFX::Technique() {}virtual bool validate( osg::State& ss ) const{return true;}protected:virtual void define_passes();};

3.在这个类中,另一个必须有的方法是define_passes()。这是用于定义多通道的。在这个教程中,我们将有两个通道:一个是取消颜色掩膜(color mask)以及如果深度缓冲区值(depth buffer value)小于现在的就记录下来;另一个将使用颜色缓冲区,但只有在深度值等于已经记录下来的值的时候写进去。(the second one will enable the useage of the color buffer but only to write to it when the depth value equals to the recorded one.)

osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;ss->setAttributeAndModes( new osg::ColorMask(false, false, false, false) );ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS) );addPass( ss.get() );ss = new osg::StateSet;ss->setAttributeAndModes( new osg::ColorMask(true, true, true, true) );ss->setAttributeAndModes( new osg::Depth(osg::Depth::EQUAL) );addPass( ss.get() );
  1. 我们设计完技术之后,现在我们可以声明effect类,把技术添加到它的define_techniques()方法中。这里的META_Effect宏用于定义effect的基本方法:库名,类名,作者名和描述。
class TransparencyNode : public osgFX::Effect{public:TransparencyNode() : osgFX::Effect() {}TransparencyNode( const TransparencyNode& copy,const osg::CopyOp op=osg::CopyOp::SHALLOW_COPY ): osgFX::Effect(copy, op) {}META_Effect( osgFX, TransparencyNode, "TransparencyNode","", "" );protected:virtual bool define_techniques(){addTechnique(new TransparencyTechnique);return true;}};
  1. 在main函数中,我们将使用景点的Cessna模型。不过,为了使它透明,我们将在上面添加一个新的材料,把散射颜色(diffuse color)的alpha通道设置为小于1的值,以及把TRANSPARENT_BIN这个hint应用到state set中。
osg::Node* loadedModel = osgDB::readNodeFile( "cessna.osg" );osg::ref_ptr<osg::Material> material = new osg::Material;material->setAmbient( osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f) );material->setDiffuse( osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f, 1.0f, 1.0f, 0.5f) );loadedModel->getOrCreateStateSet()->setAttributeAndModes(material.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE );loadedModel->getOrCreateStateSet()->setAttributeAndModes(new osg::BlendFunc );loadedModel->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN );

6.创建一个新定义类的实例并添加到模型中。

osg::ref_ptr<TransparencyNode> fxNode = new TransparencyNode;fxNode->addChild( loadedModel );//Start the viewer now.osgViewer::Viewer viewer;viewer.setSceneData( fxNode.get() );return viewer.run();

7.现在你将看到适当渲染过的透明的Cessna。
这里写图片描述

全部代码:

#include <osg/BlendFunc>#include <osg/ColorMask>#include <osg/Depth>#include <osg/Material>#include <osgDB/ReadFile>#include <osgFX/Effect>#include <osgViewer/Viewer>#include "CommonFunctions"class TransparencyTechnique : public osgFX::Technique{public:    TransparencyTechnique() : osgFX::Technique() {}    virtual bool validate( osg::State& ss ) const { return true; }protected:    virtual void define_passes()    {        osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;        ss->setAttributeAndModes( new osg::ColorMask(false, false, false, false) );        ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS) );        addPass( ss.get() );        ss = new osg::StateSet;        ss->setAttributeAndModes( new osg::ColorMask(true, true, true, true) );        ss->setAttributeAndModes( new osg::Depth(osg::Depth::EQUAL) );        addPass( ss.get() );    }};class TransparencyNode : public osgFX::Effect{public:    TransparencyNode() : osgFX::Effect() {}    TransparencyNode( const TransparencyNode& copy, const osg::CopyOp op=osg::CopyOp::SHALLOW_COPY )    :   osgFX::Effect(copy, op) {}    META_Effect( osgFX, TransparencyNode, "TransparencyNode", "", "" );protected:    virtual bool define_techniques()    { addTechnique(new TransparencyTechnique); return true; }};int main( int argc, char** argv ){    osg::Node* loadedModel = osgDB::readNodeFile( "cessna.osg" );    osg::ref_ptr<osg::Material> material = new osg::Material;    material->setAmbient( osg::Material::FRONT_AND_BACK, osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f) );    material->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4(1.0f, 1.0f, 1.0f, 0.5f) );    loadedModel->getOrCreateStateSet()->setAttributeAndModes(        material.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE );    loadedModel->getOrCreateStateSet()->setAttributeAndModes( new osg::BlendFunc );    loadedModel->getOrCreateStateSet()->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );    osg::ref_ptr<TransparencyNode> fxNode = new TransparencyNode;    fxNode->addChild( loadedModel );    osgViewer::Viewer viewer;    viewer.setSceneData( fxNode.get() );    return viewer.run();}

原理

多通道透明度技术会绘制物体两次。第一个通道(见后面代码)仅仅更新深度缓冲区(depth buffer),以及找到最前面的多边形:

osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;ss->setAttributeAndModes( new osg::ColorMask(false, false, false, false) );ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS) );addPass( ss.get() );

第二个通道将会绘制进颜色缓冲区(color buffer),但由于在第一个通道中设置的深度值,只有前面的多边形能够通过深度检测,它们的颜色将被绘制,与现在的混合。这避免了我们之前讨论过的顺序问题。代码片段如下:

ss = new osg::StateSet;ss->setAttributeAndModes( new osg::ColorMask(true, true, true, true) );ss->setAttributeAndModes( new osg::Depth(osg::Depth::EQUAL) );addPass( ss.get() );

选自《OSG3 Cookbook》第六章

原创粉丝点击