OSG学习:用多通道(multiple passes)实现透明度
osgFX库提供了一个用于多通道渲染(multi-pass rendering)的框架。每个你想要渲染的子图都应该被添加到osgFX::Effect节点,多通道技术的定义和使用都可以在这个节点中完成。你可能已经熟悉一些预定义的效果,例如osgFX::Scribe和osgFX::Outline。但是在这个教程中,我们的任务是我们自己设计一个多通道技术。这就是所谓的多通道透明度,当我们在透明模式(transparent mode)下它可以消除一些错误。
如何使用
- 添加必要的头文件:
#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() );
- 我们设计完技术之后,现在我们可以声明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;
}
};
- 在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)实现透明度的更多相关文章
- osg学习示例之遇到问题四骨骼动画编译osgCal
osg学习示例之遇到问题四骨骼动画编译osgCal 转自:http://blog.csdn.net/wuwangrun/article/details/8239451 今天学到书<OpenSce ...
- 【OSG学习笔记之一:】OSG+VS2010+win7 64位环境搭建
虽然出生的时候,没有说过“Hello World!”,但是自从走上了编程之路,每一次输出“Hello World!”的时候,都觉得好比中了彩票大奖似的: 仔细算算,从2012年暑假到现在,经历了3年半 ...
- Arm开发板+Qt学习之路-multiple definition of
问题描述:在一个头文件a.h中定义一些变量x,在其他.c文件中(b.c,c.c)要用到.用一般的全局变量的方法,编译时总是提示error:multiple definition of x 问题分析:o ...
- osg学习笔记3 简单几何模型
osg::Geode (geometry node) osg::Geode类表示场景中的渲染几何叶节点,它包含了渲染用的几何信息,没有子节点. 要绘制的几何数据保存在osg::Geode管理的一组os ...
- osg学习笔记2, 命令行参数解析器ArgumentParser
ArgumentParser主要负责命令行参数的读取 #include <osgDB/ReadFile> #include <osgViewer/Viewer> int mai ...
- OSG学习:裁剪变换(2)
接着上一篇博客说. 还有一种裁剪的方法:osg::Scissor类. 这个类封装了OpenGL中的glScissor()函数. 该类主要用于设置一个视口裁剪平面举行.设置裁剪平面举行的函数如下: vo ...
- OSG学习:裁剪变换(1)
在OSG中,默认了6个裁剪平面以去除没有必要显示的物体.也可以自己定义其他的裁剪平面来确定裁剪. osg::ClipPlane类继承自osg::StateAttribute类,封装了OpenGL中的g ...
- OSG学习:计算纹理坐标
在很多时候,直接指定纹理坐标是非常不方便的,如曲面纹理坐标,只有少数的曲面(如圆锥.圆柱等)可以在不产生扭曲的情况下映射到平面上,其他的曲面在映射到表面时都会产生一定程度的扭曲.一般而言,曲面表面的曲 ...
- OSG学习:LOD、数据分页、动态调度
LOD(level of detail):是指根据物体模型的结点在显示环境中所处的位置和重要度,决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算.在OSG的场景结点组织结 ...
随机推荐
- Hadoop(二)CentOS7.5搭建Hadoop2.7.6完全分布式集群
一 完全分布式集群(单点) Hadoop官方地址:http://hadoop.apache.org/ 1 准备3台客户机 1.1防火墙,静态IP,主机名 关闭防火墙,设置静态IP,主机名此处略,参考 ...
- ACM1019:Least Common Multiple
Problem Description The least common multiple (LCM) of a set of positive integers is the smallest po ...
- java int 与 Integer之间的区别
int与integer的区别从大的方面来说就是基本数据类型与其包装类的区别: int 是基本类型,直接存数值,而integer是对象,用一个引用指向这个对象 1.Java 中的数据类型分为基本数据类型 ...
- 域名和IP之间的关系
域名和IP的关系 在早期的互联网时代,没有那么多的主机,全部是用ip直接访问.可是IP不符合人类的记忆习惯,于是出现域名. 域名和IP的对应关系,在早期通过电脑的hosts文件直接解析,后来互联网的发 ...
- fgets()
fgets()函数简介 读字符串函数fgets()的功能是从指定的文件中读一个字符串到字符数组中,函数调用的形式为: fgets(字符数组名,n,文件指针),要从键盘输入时文件指针的参数为:stdin ...
- Linux入门——shell脚本常用信息小结
1.shell中的$默认变量 $n $1 表示第一个参数,$2 表示第二个参数 ... $# 命令行参数的个数 $0 当前 ...
- 客户端与服务器端同步Evernote
原文地址:http://www.zhihu.com/question/20238731 Evernote的同步方式是 以本地为基准同步到网络 还是 以网络为基准同步到本地 的? 若客户端从未与服务器端 ...
- wpf- DataGrid 常用属性和事件
组件所在命名空间: System.Windows.Controls 组件常用方法: BeginEdit:使DataGrid进入编辑状态. CancelEdit:取消DataGrid的编辑状态. Col ...
- Linux系统运维基础管理命令总结
1.查看系统负载命令:w.uptime [root@localhost ~]# w :: up days, :, user, load average: 0.00, 0.01, 0.05 USER T ...
- SOAPUI参数中xml中CDATA包含问题
<![CDATA[ <Request> <CardNo>000002629518</CardNo> <SecrityNo/> <BankTr ...