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


    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::OVE
    RRIDE );
    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》第六章

  • 相关阅读:
    5 Python3 函数进阶&迭代器与生成器
    2 python第三章文件操作
    4 python内置函数
    python内置函数 eval()、exec()以及complie()函数
    0 字符与字节的区别
    python enumerate() 函数
    1 python 文件处理
    python 之编写登陆接口
    python 之九九乘法表
    第一模块第二章-数据类型整理
  • 原文地址:https://www.cnblogs.com/huahai/p/7270929.html
Copyright © 2020-2023  润新知