osg资料收集 - 图文

发布时间 : 星期六 文章osg资料收集 - 图文更新完毕开始阅读

这种特效使用单一通道,它使用了一种各向异性的光照来替代OpenGL的标准光照模型。几何体顶点的颜色在这里不是直接进行计算的,而是纹理映射到用户指定的光照图板的结果。这里需要使用顶点着色器(vertex program)来计算纹理坐标S和T的值:S = N · H;T = N · L。(其中的数学运算为点乘)这里N表示顶点的法线,L表示光到顶点的向量,H表示中间向量。这种特效很好地演示了State::getInitialViewMatrix()方法的使用,它可以直接获取视口的初始矩阵并实现直接与视口相关的特效,而不需要任何假借的工作。 该特效需要ARB_vertex_program扩展的支持。 卡通渲染(Cartoon)

这种特效实现了一种名为卡通着色(Cel-Shading)的技法,从而产生一种卡通式的(非真实感的)的渲染效果。它需要两个通道支持;第一个用于绘制实体表面,第二个用于绘制轮廓线。该特效需要使用顶点着色器来设置纹理坐标,以便在运行时生成的纹理单元0上实现一种尖锐的光照效果。

该特效需要ARB_vertex_program扩展或者OpenGL着色语言的支持。 基于立方映射图的镜面高光(Cubemap-based Specular Highlights)

这种特效在片断层级(fragment level)上(而不是OpenGL通常的顶点层级)应用了镜面高光,它使用了立方映射图和反射纹理生成(reflective texgen)的技术。首先要计算出纹理矩阵以实现立方映射图的自动旋转;这样无论从观察的方向和光照位置上来说,镜面光的效果都将是始终不变的。用户可以选择使用何种光照来计算纹理矩阵。

该特效需要GL_ARB_texture_env_add扩展以及任意一种立方映射图扩展(GL_EXT_texture_cube_map,GL_ARB_texture_cube_map,或者OpenGL 1.3)的支持。 凹凸贴图(Bump Mapping)

这种特效可以创建一种凹凸不平的表面效果。其子节点必须使用两种纹理,其一是漫反射颜色,另一个是法线贴图(可以使用nVIDIA的法线贴图生成器或者其它工具,根据高度图自动生成)。此外,还需要创建正切空间(tangent-space)的基向量并将其关联到每个Geometry几何体上;这一步骤可以调用BumpMapping::prepareChildren()方法来迅速完成。注意Geometry对象的漫反射颜色和法线贴图纹理都必须提前定义好对应的UV贴图。

该特效推荐使用一种运用了ARB顶点和片断着色器的技法,另外还定义了一种不使用片断着色器的技法。后者无法处理环境和镜面组件的运算,因此在运行时很受限制。

23:35 | 添加评论 | 固定链接 | 写入日志 | OSG 8月26日

osgcallback程序注解及CallBack回调的介绍

本文的目的是通过对示例程序osgcallback的详细注解和分析,学习OSG节点回调的方法和执行过程,并进行程序的适当注解和知识总结。

详细的源代码请参阅OSG 2.0发行版的附带示例程序examples/osgcallback.cpp。本文只是针对其中的重点代码进行注解和分析,文中所述的程序代码并不完整,基本无法直接执行。

观察main函数中场景调用和加载节点回调的语句: // 加载文件读取回调MyReadFileCallBack。

osgDB::Registry::instance()->setReadFileCallback(new MyReadFileCallback()); // 读取命令行指定的场景图形模型文件,或者读取缺省的cow.osg。 osgViewer::Viewer viewer;

osg::Node* rootnode = osgDB::readNodeFiles(arguments); if (!rootnode) rootnode = osgDB::readNodeFile(\if (!rootnode) {

osg::notify(osg::NOTICE)<<\ return 1; }

// 优化场景图形树结构。 osgUtil::Optimizer optimzer; optimzer.optimize(rootnode);

// 从根节点rootnode开始,遍历所有节点并执行节点访问器icv。 InsertCallbacksVisitor icv; rootnode->accept(icv);

// 加载摄像机更新回调CameraUpdateCallBack,以及摄像机事件回调CameraEventCallBack。 viewer.getCamera()->setUpdateCallback(new CameraUpdateCallback()); viewer.getCamera()->setEventCallback(new CameraEventCallback());

// 设置视口的场景图形根节点为rootnode。 viewer.setSceneData(rootnode);

这其中涉及到一些用户自定义的结构体和类,分别是MyReadFileCallback,InsertCallbacksVisitor,CameraUpdateCallback和CameraEventCallback。 观察MyReadFileCallback结构体的内容,可以发现它继承自osgDB::Registry::ReadFileCallback,并重载了一个函数readNode,分析源代码可知,该函数在osgDB::readNodeFile函数中被调用,即,在加载模型文件时,即会调用MyReadFileCallback结构体所重载的readNode函数并执行相应的内容。示例程序中该函数的内容如下:

virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) {

std::cout<<\ osgDB::ReaderWriter::ReadResult result =

osgDB::Registry::instance()->readNodeImplementation(fileName,options); std::cout<<\ return result; }

其中较为重要的是readNodeImplementation一行,这是模型文件读取的实际执行函数,如果在回调中对于这一语句的使用有错,那么模型无论怎样都不能被加载。

InsertCallbacksVisitor的内容比较复杂,它继承自osg::NodeVisitor,属于用户自定义的节点访问器。换句话说,当执行到: InsertCallbacksVisitor icv; rootnode->accept(icv);

节点访问器将从根节点rootnode开始,遍历所有的子节点并执行相应的操作。

节点访问器InsertCallbacksVisitor的构造函数中,可以传递一个遍历方式的枚举量TraversalMode ,它的取值意义如下:

TRAVERSE_NONE:仅仅传递到当前节点,然后停止传递;

TRAVERSE_PARENTS:传递给当前节点及其父节点,注意,如果当前节点有不止一个父节点,

那么访问器将列举出所有的传递路线,其中可能有多个重复出现的节点;

TRAVERSE_ALL_CHILDREN:传递给当前节点及其所有子节点,同样,对于多个子节点的情况, 访问器将列举所有的传递路线;

TRAVERSE_ACTIVE_CHILDREN:传递给当前节点及所有被激活的子节点,例如遇到LOD节点 和Switch节点时,将不会传递给当前无法显示的子节点。

在节点访问器中,使用apply函数来实现对各种类型的节点的访问。当遍历过程中遇到与某

个重载的apply的输入参数相符合的节点时,将执行这一apply函数的内容。示例代码中重载了Node,Geode和Transform节点的访问函数。在Geode节点的访问函数中,实现了对场景图形结构中每个节点的回调指定: // 指定Geode节点的更新回调。

geode.setUpdateCallback(new UpdateCallback());

// 指定Geode节点中所有关联几何体(Drawables)的绘制回调,拣选回调和更新回调。 for(unsigned int i=0;i

geode.getDrawable(i)->setUpdateCallback(new DrawableUpdateCallback()); geode.getDrawable(i)->setCullCallback(new DrawableCullCallback()); geode.getDrawable(i)->setDrawCallback(new DrawableDrawCallback()); }

在Geode之外的其它节点的apply函数中,往往包含有下面的语句: traverse(node);

这表示对场景图形节点的遍历将继续进行。换句话说,如果某种类型的节点的apply函数中不包含这一语句,那么场景图形遍历到这一类型的节点时,当前遍历的路线将自动结束,以下的子节点均被忽略。而对Geode节点来说,因为不存在子节点,因此也不必添加这一语句。

使用节点访问器为场景图形节点或几何体添加的回调主要有以下几种: 几何体绘制遍历(DrawableDrawCallback):重载函数drawImplementation,当几何体进行绘

制时,函数的内容被调用,注意需要添加Drawable::drawImplementation函数以实现几何体的实际绘制,否则将无法画出当前的几何形状。可以参阅include/osg/Drawable,draw函数中的调用过程。

几何体拣选遍历(DrawableCullCallback):重载函数cull,当几何体进行拣选优化时,函数的内容被调用。可以参阅src/osgUtil/CullVisitor,apply(Geode&)函数中的调用过程。 几何体更新遍历(DrawableUpdateCallback):重载函数update,当几何体更新时,函数的内容被调用。可以参阅include/osgUtil/UpdateVisitor,handle_geode_callbacks函数中的调用过程。

拣选遍历(CullCallBack):重载操作符operator(),当场景执行拣选优化时,operator()的内容被调用,注意需要添加traverse函数以实现节点的继续遍历。可以参阅include/osgUtil/CullVisitor,handle_cull_callbacks_and_traverse函数中的调用过程。 更新遍历(UpdateCallBack):重载操作符operator(),当场景更新时,operator()的内容被调用,注意需要添加traverse函数以实现节点的继续遍历。可以参阅src/osg/StateSet.cpp,runUpdateCallbacks函数中的调用过程。

最后,观察CameraUpdateCallback和CameraEventCallback结构体的内容,可以发现它们均继承自osg::NodeCallback,并重载了操作符operator(),当执行摄像机更新或者事件回调时,operator()的内容将被调用,添加traverse函数可以实现节点的继续遍历。

此外,还可以使用Node::setEventCallback来设置节点的事件回调,其输入参数为继承自osg::NodeCallback的用户类,且需要重载操作符operator()以实现回调过程的处理。

综上,可以得出回调的编写方法:

1、编写用户结构体,继承OSG中相应的虚函数结构体,如osg::NodeCallBack; 2、重载回调执行函数,根据回调种类的不同,执行函数的名称也不同,可以参考osgcallback中的设置;

3、注意在回调执行的过程中,有一些必要的系统操作需要交由用户来完成,例如readNodeImplementation,Drawable::drawImplementation,traverse等,否则系统本身的渲染工作可能会不正常。

编译运行osgcallback之后,可以看到控制台不断输出各种回调的执行结果,用户可以根据自己的需要在不同的时间段进入不同的回调来完成所需的工作。 23:11 | 添加评论 | 阅读评论 (6) | 固定链接 | 写入日志 | OSG 缘起

每天的心情,是无法用文字来承载的。 因为它太庞大了,往往也太沉重了。

所以只好简单地加以记录,用笔也好,用计算机也好,倾泻也好,一点一滴也好,挤榨在小小的纸杯中,以之为乐。 和海相比,这始终太渺小了。 不过谁能饮尽大海呢? 谁能彻底地背负起过去呢? 而回忆的话,虽然只有一点, 已经足够。

这里将会出现的主要内容:

1、关于OpenSceneGraph(OSG)三维图形开发库的学习报告。同样对此感兴趣的朋友欢迎交流,本人在VRDEV上的用户名是array,同时也是《OpenSceneGraph快速入门指导》(Paul Martz,CGSD)的中文版译者。

2、原创的小说和文章。以前所写的《无常界》已经在Sohu原创上连载完毕,新的涂鸦可能会索性堆积在这里~~

3、其它技术类文章,可能是原创或摘抄,三维设计及编程技术相关。 4、心情特别好或者特别不好的时候,可能会有心情日记……

5、脑子进水或短路的时候,可能会出现其它的不知所云的东西,概率应当比较低。 20:56 | 添加评论 | 阅读评论 (4) | 固定链接 | 写入日志

联系合同范文客服:xxxxx#qq.com(#替换为@)