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. hadoop伪分布式组件安装

    一.版本建议 Centos V7.5 Java V1.8 Hadoop V2.7.6 Hive V2.3.3 Mysql V5.7 Spark V2.3 Scala V2.12.6 Flume V1. ...

  2. 分别给Python类和实例增加属性和方法

    #定义一个类Student class Student(object): pass #给类增加一个属性name Student.name = 'xm' print Student.name # xm ...

  3. angular中的$cookies和$cookieStore设置过期时间

    angular1.4及以上版本才支持$cookies. 项目引入的是1.4.2版本,操作cookies原先一直用的是$cookieStore,用的飞起啊. $cookieStore.remove(&q ...

  4. poj 2349 Arctic Network(prime)

    Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 25165   Accepted: 7751 Description The ...

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

    实验一 Java开发环境的熟悉(Linux + IDEA) 实验内容 1.使用JDK编译.运行简单的Java程序: 2.使用IDEA编辑.编译.运行.调试Java程序. 实验要求 1.没有Linux基 ...

  6. [cogs347]地震

    COGS:地震(平衡树) COGS上一道题...文件名是equake 还是又打了一遍板子... 加个lazy标记就行了... 注意查询时先下传标记(lazy) // It is made by XZZ ...

  7. HBase 第四章 HBase原理

    1  体系图 HBase中的每张表都通过行键按照一定的范围被分割成多个子表(HRegion),默认一个HRegion超过256M就要被分割成两个,这个过程由HRegionServer管理,而HRegi ...

  8. abp 关闭审计日志

    在WebProject.Web.Mvc项目中的Startup文件夹下中的WebProjectWebMvcModule.cs public override void PreInitialize() { ...

  9. katalon系列十:Katalon Studio自定义关键字之拖拽

    Katalon Studio自带关键字“Drag And Drop To Object”,可以在这个网站实践:http://jqueryui.com/droppable/#default 不过“Dra ...

  10. centos下JDK安装及环境变量配置

    由于centos安装自带openjdk,需要将其卸载后安装自己的jdk 卸载centos自带jdk 1.查找java :rpm -qa | grep java 2.卸载时提示权限不够,进入root目录 ...