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》第六章

OSG学习:用多通道(multiple passes)实现透明度的更多相关文章

  1. osg学习示例之遇到问题四骨骼动画编译osgCal

    osg学习示例之遇到问题四骨骼动画编译osgCal 转自:http://blog.csdn.net/wuwangrun/article/details/8239451 今天学到书<OpenSce ...

  2. 【OSG学习笔记之一:】OSG+VS2010+win7 64位环境搭建

    虽然出生的时候,没有说过“Hello World!”,但是自从走上了编程之路,每一次输出“Hello World!”的时候,都觉得好比中了彩票大奖似的: 仔细算算,从2012年暑假到现在,经历了3年半 ...

  3. Arm开发板+Qt学习之路-multiple definition of

    问题描述:在一个头文件a.h中定义一些变量x,在其他.c文件中(b.c,c.c)要用到.用一般的全局变量的方法,编译时总是提示error:multiple definition of x 问题分析:o ...

  4. osg学习笔记3 简单几何模型

    osg::Geode (geometry node) osg::Geode类表示场景中的渲染几何叶节点,它包含了渲染用的几何信息,没有子节点. 要绘制的几何数据保存在osg::Geode管理的一组os ...

  5. osg学习笔记2, 命令行参数解析器ArgumentParser

    ArgumentParser主要负责命令行参数的读取 #include <osgDB/ReadFile> #include <osgViewer/Viewer> int mai ...

  6. OSG学习:裁剪变换(2)

    接着上一篇博客说. 还有一种裁剪的方法:osg::Scissor类. 这个类封装了OpenGL中的glScissor()函数. 该类主要用于设置一个视口裁剪平面举行.设置裁剪平面举行的函数如下: vo ...

  7. OSG学习:裁剪变换(1)

    在OSG中,默认了6个裁剪平面以去除没有必要显示的物体.也可以自己定义其他的裁剪平面来确定裁剪. osg::ClipPlane类继承自osg::StateAttribute类,封装了OpenGL中的g ...

  8. OSG学习:计算纹理坐标

    在很多时候,直接指定纹理坐标是非常不方便的,如曲面纹理坐标,只有少数的曲面(如圆锥.圆柱等)可以在不产生扭曲的情况下映射到平面上,其他的曲面在映射到表面时都会产生一定程度的扭曲.一般而言,曲面表面的曲 ...

  9. OSG学习:LOD、数据分页、动态调度

    LOD(level of detail):是指根据物体模型的结点在显示环境中所处的位置和重要度,决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算.在OSG的场景结点组织结 ...

随机推荐

  1. day 33 线程

    1.线程理论 什么是线程:线程是cpu的最小执行单位(实体),进程是操作系统的数据资源分配单位   2.线程的两种创建方式(重点) 查看线程的pid:使用os模块查看id,线程的id应该是相同的 3. ...

  2. Delphi Firemonkey在主线程 异步调用函数(延迟调用)

    先看下面的FMX.Layouts.pas中一段代码 procedure TCustomScrollBox.MouseDown(Button: TMouseButton; Shift: TShiftSt ...

  3. Python学习 :异常处理

    异常处理 什么是异常处理 - python解释器检测到错误,触发异常(也允许程序员自己触发了异常) - 程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,只与异常处理有关) - 如果 ...

  4. IDEA-Debug调试操作

    基本概念 快捷键和eclipse还是有区别的,不过基本概念是相通的   Step into F7 单步调试进入函数内部.  Step over F8 单步调试不进入函数内部,如果装了金山词霸2006则 ...

  5. 20155211 《Java程序设计》实验四 Android程序设计

    20155211 <Java程序设计>实验四 Android程序设计 一.实验内容及步骤 1.Android Stuidio的安装测试: 安装 Android Stuidio 完成Hell ...

  6. 20155213 2016-2017-2《Java程序设计》第三周学习总结

    20155213 2016-2017-2<Java程序设计>第三周学习总结 教材学习内容总结 类与对象 类和对象的关系:类决定对象,对象反映类的性质 定义值域成员:在新建的类中定义变量,可 ...

  7. 20155224 实验一《Java开发环境的熟悉》实验报告

    实验内容 1.使用JDK编译.运行简单的Java程序: 2.使用Eclipse 编辑.编译.运行.调试Java程序. 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版) ...

  8. Week6课下作业

    课本练习p2.96 p2.97 浮点数 float 单精度浮点数(32位) double 双精度浮点数(64位) 练习对应书上内容P78--P81页 知识点是IEEE浮点表示 符号(sign):s决定 ...

  9. 使用cursor递归遍历sqlserver的相应表

    use rc GO )DECLARE cur1 cursor for select [name] from sys.tables where name LIKE 'index_%' drop tabl ...

  10. [agc004D]Teleporter

    Description 传送门 Solution 依题意我们可以知道,以2-n为出发点的边和1号节点会构成一课树(不然2-n号节点无法都达到首都). 为了让2-n号节点中,离1号节点的距离<k的 ...