转自:http://blog.csdn.net/yungis/article/list/1
[原]osgmotionblur例子 |
该例子演示了运动模糊的效果。 一下内容是转自网上的: 原理: 引用内容 对于运动画面,将当前帧画面与上一帧画面进行alpha融合,以产生出残影——运动模糊效果。 通过使用累积缓存来完成这项工作。 OpenGL提供一个累积缓存,可以用来存储当前指定的颜色缓存里面的内容,并进行一定的运算操作。 通过函数glAccum可以对累积缓存进行操作。 glAccum介绍如下: (persistence)); 这里必须要深入研究一下,glAccum应用的时刻,以上的说明中可以看出,glAccum应该是一帧中颜色缓冲区中的值计算完之后应用,在这个例子中用了otionBlurOperation, (osgViewer::Viewer::Windows::iterator itr = windows.begin(); 对这个例子和积累缓冲区总算有了一些理解,但这里还存在一个问题,如果想只对场景中的某个部分做运动模糊应该如何处理???比如有一个足球场,一个运动中的足球,只对这个足球进行运动模糊处理,如何去做??? 这个问题自己还没有去验证,自己想的一个大概方法是,相同位置的的两个相机,一个关注足球之外的场景,不做运动模糊处理;另外一个只关注足球,做运动模糊处理,然后,两幅场景融合为一个场景。 作者:yungis 发表于2013/7/30 23:44:12 原文链接 阅读:518 评论:1 查看评论 |
[原]osgmemorytest例子 |
osgmemorytest这个例子也从一帧入手。 eventTraversal(); updateTraversal(); renderingTraversals(); 事件回调、更新回调、渲染。 OpenGL是状态机,调整好各个状态,然后绘制几何体。OSG中同理,renderingTraversals中根据每个StateSet绘制Drawable。无论是加载的模型还是自己绘制的几何体,最后都是Drawable。 renderingTraversals中最主要的还进行了剔除(CullVisitor),这里不多说,主要说OSG中OpenGL的状态的执行。 进入renderingTraversals函数内部,找到(*itr)->runOperations();(对于单线程来说),这句话进行了场景的绘制工作。顺着这个藤一直摸下去,为了思路清晰,列出序号: 几个重要的类,GraphicsContext--Renderer--SceneView--RenderStage(RenderBin)--RenderLeaf--Drawable。 最终的实现都在具体的Drawable中,就像上面说的,无论是加载的模型还是自己绘制的几何体,最后都是Drawable。这样最终会调用可用的Drawable实现绘制。 下面从这个调用说起,State存储了OpenGL需要的所有的状态,是OSG与OpenGL状态的接口,进入这个函数中看看做了什么。 StateAttribute是基类,打开API文档,看看继承StateAttribute的状态属性吧,有几十个之多,我们重点找几个看看。 定义了好多的基类,MemoryTest、GLObject、GLMemoryTest。 从以上几个类的功能来说,不难看出他们所作的事情,1、创建窗口;2、设置状态;3、绘制; 作者:yungis 发表于2013/6/7 23:32:32 原文链接 阅读:600 评论:0 查看评论 |
[原]关于例子 |
最近很久没有写文章了,很久没有登录csdn了。最初只是为了一边研究一遍学osg而写的一些体会,没想到有这么多的志同道合的朋友们关注。此时此刻觉得有些感动,osg例子还需要继续下去,专题还需要继续下去。有精力的话,osgearth、osgocean、delta3d真的想一边学习研究一边写下去。有那么多osgChina上的朋友支持,以后有新的例子会在osgChina上发表的,多谢支持!
作者:yungis 发表于2013/6/6 23:47:56 原文链接 阅读:580 评论:1 查看评论 |
[原]osgmanipulator例子 |
这个例子演示了osg中拖拽器的使用,可以控制模型的移动、旋转缩放。 createDemoScene函数,如果没有加载模型,默认的创建几个基本几何体,bool fixedSizeInScreen参数决定拖拽器是否固定大小。这个函数里面的代码很简单,创建了几个基 本几何体,然后把他们包装上不同的拖拽器,加入到场景中。 TabBoxDragger, TabPlaneDragger, TabBoxTrackballDragg, TrackballDragger,Translate1DDragger, Translate2DDragger, TranslateAxisDragger 一种有这么七种拖拽器,TabBoxDragger, 包围盒,用于缩放和移动几何体,TabPlaneDragger, 一 个平面,用于平面内缩放和移动几何体,TabBoxTrackballDragg, 一个包围盒和一个包围球,用 于移动、缩放、选择几何体,TrackballDragger包围球,用于旋转几何体, Translate1DDragger, Translate2DDragger, TranslateAxisDragger 一个、两个、三个箭头的拖拽 器,分别在不同的方向上移动几何体。 我们进入addDraggerToScene函数,这个函数就是包装拖拽器的地方,首先根据名称创建拖拽器 createDragger 我们进入osgManipulator这个库,看看他是怎么设计的,Dragger类继承MatrixTransform拖拽器 的基类,在拖拽器中考虑到继承关系,拖拽器可能会有父拖拽器, setActivationModKeyMask setActivationKeyEvent非常重要,设置按指定键的时候,鼠标才可 以拖动拖拽器。 traverse递归函数是场景中的每个节点都会调用的,因此在这个函数里,当是事件遍历的时候调 用了内置的handle方法。实现拖拽动作。 这个思路又给我们一些启示,与场景的交互,不一定要继承EventHandler,通过traverse同样可 以实现。这些需要深入理解在事件遍历的时候osg都干了些什么。 addTransformUpdating这个方法,通过回调实现变换。 还有其他的一些设置,比如操作器是否可以,是否接受事件,创建拖拽器几何体等等。 CompositeDragger类继承Dragger,是组合拖拽器,多个拖拽器组合成一个拖拽器。 RotateCylinderDragger、RotateSphereDragger、Scale1DDragger、Scale2DDragger、 Translate1DDragger、Translate2DDragger都是继承Dragger ScaleAxisDragger、TabBoxDragger、TabBoxTrackballDragger、TabPlaneDragger、 TabPlaneTrackballDragger、TrackballDragger、TranslateAxisDragger、 TranslatePlaneDragger都是继承CompositeDragger 而对外暴露的操作器一般都是组合操作器。 Command创建了移动,缩放,旋转的命令,在Dragger中使用。 回到例子中来,osgManipulator::Dragger* dragger = createDragger(name);根据指定的名称 创建拖拽器,判断是否缩放拖拽器,如果不缩放拖拽器,则通过DraggerContainer类,在遍历的 时候计算矩阵保持拖拽器的固定大小。 dragger->addTransformUpdating(selection);设置更新矩阵,用于更新拖拽器自身的位置。 dragger->setActivationModKeyMask(osgGA::GUIEventAdapter::MODKEY_CTRL); dragger- >setActivationKeyEvent(‘a‘); 设置了当按住ctrl+ a的时候,拖拽器有效。 前文分析的有些乱,下面做一个总结: 拖拽器实现指定模型的平移、缩放、选择等操作,(拖拽器本身也是模型,根据不同拖拽方式, setupDefaultGeometry设置geometry),Dragger类是基类,CompositeDragger是组合拖拽器的 基类,Dragger派生出很多子类,都是单一的功能,比如只向右移动,而我们应用的拖拽器一般 都是组合拖拽器,比如向x,y,z三个方向移动,这就是三个Dragger的叠加,组合拖拽器就是这 些基本拖拽器的叠加。 拖拽器在操控指定模型的时候,通过DraggerCallback来更新实现变换。 dragger->addTransformUpdating(selection);就把模型的MatrixTransform给了拖拽器用于更新 。拖拽器又是怎么更新的呢?拖拽器又是怎么样改变模型姿态的呢? 在Dragger递归的时候traverse,如果是事件遍历,调用Dragger的handle,然后判断鼠标的按下 、释放、移动等各种状态,求交运算, dragger->handle(_pointer, ea, aa);然后调用具体的 某个拖拽器的handle,通过Command和receive来最终实现拖拽效果。 作者:yungis 发表于2013/4/27 7:58:37 原文链接 阅读:2025 评论:0 查看评论 |
[原]osglogo例子 |
在osg中osgGetVersion()获取osg的版本信息。 本例子通过Geode和Geometry创建最基本的几何体,实现logo的绘制,不进行详细的研究。 里面的地球,通过ShapeDrawable纹理贴图,MatrixTransform的setUpdateCallback(new osg::AnimationPathCallback实现自动的旋转。 本例子MyBillboardTransform : public osg::PositionAttitudeTransform实现了朝向一直屏幕 的效果,这里需要比较一下MyBillboardTransform、Billboard、AutoTransform朝向屏幕的实现 方法。首先看MyBillboardTransform: 重写computeLocalToWorldMatrix方法,计算视点坐标 bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const { osg::Quat billboardRotation; osgUtil::CullVisitor* cullvisitor = dynamic_cast<osgUtil::CullVisitor*>(nv); if (cullvisitor) { osg::Vec3 eyevector = cullvisitor->getEyeLocal()- _position; eyevector.normalize(); osg::Vec3 side = _axis^_normal; side.normalize(); float angle = atan2 (eyevector*_normal,eyevector*side); matrix.preMultRotate(billboardRotation); 屏幕矩阵的计算。 作者:yungis 发表于2013/4/23 7:55:50 原文链接 阅读:645 评论:0 查看评论 |
[原]osglogicop例子 |
该例子演示了opengl中的glLogicOp功能,指定不同的逻辑运算实现当前颜色和帧缓冲的颜色计 算。有以下几种参数 GL_CLEAR 0 GL_SET 1 GL_COPY s GL_COPY_INVERTED ~s GL_NOOP d GL_INVERT ~d GL_AND s & d GL_NAND ~(s & d) GL_OR s | d GL_NOR ~(s | d) GL_XOR s ^ d GL_EQUIV ~(s ^ d) GL_AND_REVERSE s & ~d GL_AND_INVERTED ~s & d GL_OR_REVERSE s | ~d GL_OR_INVERTED ~s | d s代表当前颜色,d代表帧缓冲中的颜色。前面是glLogicOp中可以接受的参数,后面是运算结果 。在osg中对应LogicOp类,它继承StateAttribute,属于状态属性的一种。在类的内部定义了以 上参数的枚举。 回到例子中,定义了 osg::LogicOp* logicOp = new osg::LogicOp (osg::LogicOp::OR_INVERTED);并且 stateset->setAttributeAndModes (logicOp,osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);启用属性和模式。 stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);设置绘制优先级。 setRenderingHint和setRenderBinDetails都可以设置节点绘制的顺序,在osg中根据他们参数的 数值进行节点渲染顺序的配置,达到可以控制节点渲染顺序的功能。 接下来通过TechniqueEventHandler来控制当前logicOp 使用的逻辑运算符。 作者:yungis 发表于2013/4/22 7:36:58 原文链接 阅读:371 评论:0 查看评论 |
[原]osglightpoint例子 |
该例子演示了光点的效果,主要应用osgSim库中的LightPoint、LightPointNode、 SequenceGroup、BlinkSequence,osgSim库属于仿真库,扩展库。应用osg核心库完成一些指定 的效果。因此研究这个例子只需要指定以上这几个类的作用即可。 LightPoint是光点类,有如下属性: bool _on; osg::Vec3 _position; osg::Vec4 _color; float _intensity; float _radius; osg::ref_ptr<Sector> _sector; 作者:yungis 发表于2013/4/19 7:43:24 原文链接 阅读:510 评论:0 查看评论 |
[原]osglight例子 |
先列上两个链接介绍osg中的矩阵变换。 http://www.cnblogs.com/indif/archive/2011/05/13/2045106.html http://www.cppblog.com/acmiyou/archive/2009/08/24/94292.html opengl中矩阵是列主序,osg中是行主序。 个人觉得这样从应用上去考虑原因,opengl是最低层低级的软件和硬件的接口,考虑的是高效性 能,osg是高级三维引擎,考虑的是应用和便于理解。opengl中的矩阵使一个16大小的一维数组 ,因此在进行矩阵运算的时候只需要指针++就可以到下一个。 而实际的应用中,我们一般理解点是行主序的三个数, osg当中: newpos =oldpos * T *R //先执行平移 后执行旋转 (全局坐标系) 因此执行以上的变换,先平移后旋转,很容易理解。 在来说一下MatrixTransform 和PositionAttitudeTransform,一个是矩阵变换一个是位置姿态 ,MatrixTransform 是按着矩阵相乘的顺序做变换,而PositionAttitudeTransform是按着SRT的 顺序变换,所以对于PositionAttitudeTransform无论是先设置位置旋转缩放还是后设置结果都 一样。我们从源代码中看个究竟。 对于MatrixTransform bool MatrixTransform::computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*) const { if (_referenceFrame==RELATIVE_RF) { matrix.preMult(_matrix); } else // absolute { matrix = _matrix; } return true; } 直接做了矩阵的左乘,即_matrix*matrix 而PositionAttitudeTransform bool PositionAttitudeTransform::computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*) const _ambient; // r, g, b, w // r, g, b, w b, w _direction; // x, y, z // constant // exponent spread 作者:yungis 发表于2013/4/17 7:54:12 原文链接 阅读:615 评论:1 查看评论 |
[原]osglauncher例子 |
该例子通过读取osg.conf文件,把一些图片路径和应用程序路径读取到了Xample里面。通过 setupGraph函数把每个图片添加到窗体中,PickHandler继承GUIEventHandler,获取鼠标所选图 片对应的应用程序名称,同时更新_updateText(显示图片的名称),单击后运行响应的应用程 序。这里用了 system();指定指定的程序。 作者:yungis 发表于2013/4/12 7:37:23 原文链接 阅读:343 评论:0 查看评论 |
[原]osgkeyboardmouse例子 |
本例子演示了拾取的功能。 PickHandler继承GUIEventHandler ‘s’键通过CreateModelToSaveVisitor把选中的节点写出。 virtual void apply(osg::Node& node) { osgFX::Scribe* scribe = dynamic_cast<osgFX::Scribe*>(&node); if (scribe) { for (unsigned int i=0; i<scribe->getNumChildren(); ++i) { _group->addChild(scribe->getChild(i)); } } else { traverse(node); } } ‘o’键写出了整个场景。 ‘p’键切换拾取的方式。 在例子中用了两种求交的方式:1、PolytopeIntersector;指定一个矩形区域求交,构造函数 PolytopeIntersector(CoordinateFrame cf, double xMin, double yMin, double xMax, double yMax);通过cf指定了一种坐标参考,后面的参数指定了一个矩形。 enum CoordinateFrame { WINDOW, PROJECTION, VIEW, MODEL }; 关于这几种方式:MODEL方式表示使用世界坐标,传入参数也就直接是世界坐标;WINDOW、 PROJECTION和VIEW都是传入屏幕/投影窗口/视口坐标作为参数,并且设法在求交过程中将它们转 换为世界坐标。如果希望使用WINDOW等方式,需要节点是相机节点。我们进入代码中看看这几种 方式的实现: polytopeintersector.cpp中, osg::Matrix matrix; switch (_coordinateFrame) { case(WINDOW): if (iv.getWindowMatrix()) matrix.preMult( *iv.getWindowMatrix() ); if (iv.getProjectionMatrix()) matrix.preMult( *iv.getProjectionMatrix() ); *iv.getProjectionMatrix() ); *iv.getViewMatrix() ); *iv.getModelMatrix() ); (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); 作者:yungis 发表于2013/4/11 7:05:25 原文链接 阅读:499 评论:0 查看评论 |
[原]osgkeyboard例子 |
本例子演示了键盘事件,比较简单。 通过KeyboardModel类绘制出一个键盘,KeyboardEventHandler继承GUIEventHandler,实现键盘 事件的处理。 作者:yungis 发表于2013/4/11 6:18:42 原文链接 阅读:313 评论:0 查看评论 |
[原]osgkdtree例子 |
本例子演示了KDTree,实际上没什么内容。我们就在这没内容的几行代码中挖一挖。 关于KDTree的介绍http://www.cnblogs.com/eyeszjwang/articles/2429382.html,在这里可以 看看。我们不研究算法,只研究代码和实现。 KDTree为场景的求交提供了一种更加有效率、更加精确的算法。 例子中只有一句和KDTree有关的osgDB::Registry::instance()->setBuildKdTreesHint (osgDB::ReaderWriter::Options::BUILD_KDTREES);在Registry中注册构建KDTree。我们进入 Registry中,构造函数: _buildKdTreesHint = Options::NO_PREFERENCE; _kdTreeBuilder = new osg::KdTreeBuilder; const char* kdtree_str = getenv("OSG_BUILD_KDTREES"); if (kdtree_str) strcmp(kdtree_str, "OFF")==0 || strcmp(kdtree_str, "Off")==0 ); (switchOff) _buildKdTreesHint = Options::DO_NOT_BUILD_KDTREES; if (_kdTreeBuilder.valid()) 作者:yungis 发表于2013/4/9 7:36:45 原文链接 阅读:1030 评论:0 查看评论 |
[原]osgintersection例子 |
先说一下osgSim库,它提供虚拟仿真效果的节点工具,用于特殊效果。 这个例子中涉及到了osgSim::LineOfSight,我们就来看看这个类是干什么,从字面上可知,它 是视线、瞄准线。 DatabaseCacheReadCallback这个类继承ReadCallback,在相交的测试中,场景可能有PagedLOD ,而计算相交过程中,PagedLOD不是精度最高的节点(如地球),这样计算的就不准确,这个 ReadCallback类就保证了在IntersectionVisitor::apply(osg::PagedLOD& plod)时候,加载最 高精度的PagedLOD,从而保证计算的精度。但加载节点是比较耗时的。而这个 DatabaseCacheReadCallback是一个缓存数据库,把加载过的PagedLOD缓存下来,下次直接从缓 存中加载。readNodeFile是主要的函数。 LineOfSight类建立和地球的相交线。通过LOS结构存储一个起点和一个终点,把和场景的交点保 存在Intersections中。在内部保存一个osgUtil::IntersectionVisitor _intersectionVisitor;进行相交测试。 computeIntersections是相交计算的主要函数,IntersectorGroup存放了一组相交的线段,之前 我们提到过,在osg中有多种相交的计算(线、面、体),线与场景相交最为常见。 接下来: _intersectionVisitor.reset(); _intersectionVisitor.setTraversalMask (traversalMask); 作者:yungis 发表于2013/4/8 7:55:42 原文链接 阅读:1503 评论:0 查看评论 |
[原]osgimpostor例子 |
本例子演示了impostor代替节点的应用。 以下是转自网上翻译源码的内容: Impostor是一种LOD组节点,它既允许通过子结点到视点的距离来选择相应的子结点,又可以通 过到视点的距离来选择图片缓存。Impostor的原理是:通过缓存几何体(realgeometry)的图像 ,然后在之后的帧内使用该图像代替该几何体。这有点像Billboard,但是, 它是实时更新并与 视点的位置相关的。通过映射了该纹理的四边形,可以降低场景的复杂度以提高性能。OSG中的 impostor并不是完全按照上述网址中的技术来实现的,但是这应该是个不错的开始。OSG的 Impostor结点远没有那么复杂,因为使用时你并不需要重构(重新组织)你的整个场景。你所要 做的就是为Impostor结点的每一个子结点设置相应的LOD可见范围值(visiblerange value), 并且设置一个Impostor阈值,来告诉渲染器(renderer)在什么距离以外应该使用Impostor的图 像缓存。osg::CullVisitor会自动处理所有的渲染前期(pre-renderingstages)的设置,计算 出所需的ImpostorSprites(这个类封装了图像缓存与四边形),并随视点的变化更新它们。如 果你使用osg::SceneView/CullVisitor,所有为了支持Impostor的复杂过程都会被很好的隐藏。 关于Impostor还有很多改进计划: 1) 估计一个ImpostorSprite在多少帧内会被重用,如果被重用的次数不会多于一个最小阈值的 话,就不创建这个ImpostorSprite而是直接使用几何体 2)与内存中的纹理共享数据 3)对ImpostorSprite使用简单的3D几何体而不是Billboard 4)减小ImpostorSprite的大小使之更适合内在的(underlying)几何体 Impostor继承自LOD,我们都知道LOD实现在指定范围内显示物体,Switch节点可以开关节点,这 些是怎么实现的呢,我们进入源码看看究竟。 virtual void traverse(NodeVisitor& nv);每个类型的节点当访问它的时候,都会进行递归调 用,而递归的关键就是traverse。 void Group::traverse(NodeVisitor& nv) { for(NodeList::iterator itr=_children.begin(); 作者:yungis 发表于2013/4/2 7:17:31 原文链接 阅读:672 评论:1 查看评论 |
[原]osgimagesequence例子 |
本例子演示了图片的播放 createModel创建geometry,createState创建stateset。 ImageSequence继承自ImageStream,ImageStream继承自Image,实现图像流的播放控制, ImageSequence可以实现作为纹理贴图时纹理控制。有三种模式 enum Mode { PRE_LOAD_ALL_IMAGES, PAGE_AND_RETAIN_IMAGES, 作者:yungis 发表于2013/3/27 7:25:24 原文链接 阅读:400 评论:1 查看评论 |
[原]osghud例子 |
本例子演示了HUD的功能,之前的很多例子都用到了HUD,而且实现HUD有很多的方式。其实HUD也 是一个节点,唯一的特别之处就是从一个指定的位置观察这个节点,这个节点一直以平面的方式 投到创建的表面,不随着场景和视点的变换而变换。 createHUD()这个函数: 第一步、创建个相机,它的自节点绘制到这个HUD中。 第二步、设置投影矩阵,这个就是投影到场景的屏幕上。 第三部、设置相对帧,setReferenceFrame(osg::Transform::ABSOLUTE_RF);camera- >setViewMatrix(osg::Matrix::identity());这个保证这个节点不随着场景和视点的变换而变化 。 第四部、清除深度缓存camera->setClearMask(GL_DEPTH_BUFFER_BIT); 第五步、设置渲染顺序camera->setRenderOrder(osg::Camera::POST_RENDER);这个保证了最后 渲染,HUD一直在场景的最外面。 第六步、camera->setAllowEventFocus(false);保证该HUD不接受事件。 之后在HUD上添加文字和画板。 在main函数中颜色了添加HUD的几种方式: 第一种、因为这里的HUD载体是Camera节点,所以 osg::Camera* hudCamera = createHUD(); // set up cameras to render on the first window available. hudCamera->setGraphicsContext(windows[0]); hudCamera->setViewport (0,0,windows[0]->getTraits()->width, windows[0]->getTraits()->height); viewer.addSlave(hudCamera, false); 把相机设置了响应的图形上下文,作为一个附属相机添加 到viewer中。 第二种、这里的相机有事一个节点, group->addChild(createHUD()); 作为一个节点添加中场景中。 这里还有两个类: SnapImage* postDrawCallback = new SnapImage("PostDrawCallback.png"); viewer.getCamera()->setPostDrawCallback(postDrawCallback); viewer.addEventHandler(new SnapeImageHandler(‘p‘,postDrawCallback)); SnapImage* finalDrawCallback = new SnapImage("FinalDrawCallback.png"); viewer.getCamera()->setFinalDrawCallback(finalDrawCallback); viewer.addEventHandler(new SnapeImageHandler(‘f‘,finalDrawCallback)); 用于把HUD内容写出来,这里需要说明的是setPreDrawCallback、setPostDrawCallback、 setFinalDrawCallback相机在绘制中有三次的回调,回之前,绘制后,最后,在 RenderStage::draw函数中被调用。 作者:yungis 发表于2013/3/25 7:29:24 原文链接 阅读:831 评论:0 查看评论 |
[原]osghangglide例子 |
这个例子主要模拟了飞机视角的操作器,绘制了一些必要的场景。 从createModel开始,ClearNode是这样的一个节点,清除颜色和深度缓冲区,并且设 置“RenderBin”为-1。(关于RenderBin之前的例子中有说明)通过setRequiresClear设置清除颜色是否可用。这个节点比场景中的其 他节点先绘制。在CullVisitor中的CullVisitor::apply(osg::ClearNode& node)使用,也就是 说每一帧都调用这个函数清空颜色和深度缓冲。 Transform是变换的基类,MoveEarthySkyWithEyePointTransform继承Transform实现场景跟着鼠 标的变换。重写了computeLocalToWorldMatrix和computeWorldToLocalMatrix,这里用了 getEyeLocal()这个函数获取当前的视点坐标,进入CullStack这个函数,看看这里面有存储了当 前场景很多数据, inline osg::Viewport* getViewport(); inline osg::RefMatrix* getModelViewMatrix(); inline osg::RefMatrix* getProjectionMatrix(); inline osg::Matrix getWindowMatrix(); inline const osg::RefMatrix* getMVPW(); inline const osg::Vec3& getEyeLocal() const { return _eyePointStack.back(); } inline const osg::Vec3& getViewPointLocal() const { return _viewPointStack.back(); } 模型矩阵、投影矩阵、MVPW矩阵等等。相机是CullStack的孙子节点,因此说相机也有这些方法 可用。 例子之后构建了一颗模型树。 makeSky()绘制天空,RenderBin设置-2,makeBase()设置-1,makeTrees()绘制树, makeTerrain()绘制地形,makeTank()绘制坦克。 最后viewer.setCameraManipulator(new GliderManipulator());设置了GliderManipulator这个 操作器,写自己的操作器需要继承CameraManipulator,主要重写getInverseMatrix这个函数。 这个操作器中的其他函数就不做深入的研究了。 作者:yungis 发表于2013/3/25 7:02:49 原文链接 阅读:493 评论:1 查看评论 |
[原]osggraphicscost例子 |
这个例子比较有用,平均了三维场景CPU和GPU的花费。 进入GraphicsCostEstimator这个类, CostPair estimateCompileCost(const osg::Geometry* geometry) const { return _geometryEstimator->estimateCompileCost(geometry); } CostPair estimateDrawCost (const osg::Geometry* geometry) const { return _geometryEstimator->estimateDrawCost (geometry); } CostPair estimateCompileCost(const osg::Texture* texture) const { return _textureEstimator->estimateCompileCost(texture); } CostPair estimateDrawCost(const osg::Texture* texture) const { return _textureEstimator- >estimateDrawCost(texture); } CostPair estimateCompileCost(const osg::Program* program) const { return _programEstimator->estimateCompileCost(program); } CostPair estimateDrawCost(const osg::Program* program) const { return _programEstimator->estimateDrawCost(program); } CostPair estimateCompileCost (const osg::Node* node) const; CostPair estimateDrawCost(const osg::Node* node) const; 对Geometry、Texture、Program和Node的编译和绘制都做了评估。 typedef std::pair<double, double> CostPair; 代表CPU和GPU所花的时间。 GraphicsCostEstimator负责评估Geometry、Texture、Program、Node编译和绘制所用的时间。 CollectCompileCosts这个类是计算时间的类,继承自osg::NodeVisitor,先来回忆一下 osg::NodeVisitor,它是一个访问者模式,节点accept它,它就可以通过apply函数实现相应的 功能。NodeCallback就是通过NodeVisitor实现,只是在没一帧的更新回调中都调用了这个 accept递归遍历。 我们回到这个例子,这个例子统计的时间并不是运行时统计的,而是事先定制好了一些基本的时 间,然后通过Geometry、Texture、Program、Node中的数据量。 看GeometryCostEstimator的setDefaults函数: void GeometryCostEstimator::setDefaults() { double transfer_bandwidth = 10000000000.0; // 1GB/sec double gpu_bandwidth = 50000000000.0; // 50 GB/second double min_time = 0.00001; // 10 nano seconds. _arrayCompileCost.set(min_time, 1.0/transfer_bandwidth, 256); // min time 1/10th of millisecond, min size 256 _primtiveSetCompileCost.set(min_time, 1.0/transfer_bandwidth, 256); // min time 1/10th of millisecond, min size 256 1.0/gpu_bandwidth, 256); // min time 1/10th of millisecond, min size 256; 作者:yungis 发表于2013/3/24 11:23:19 原文链接 阅读:391 评论:0 查看评论 |
[原]osggpx例子 |
首先来看Track这个类,维护了一个TrackSegment集合。 TrackSegment维护了一个TrackPoint集合。 TrackPoint有经纬高和时间组成,在每一刻能唯一确定位置。 readTrack这个函数读取了一个gpx后缀的文件。 这个函数中涉及到了osg好些文件操作,osgDB::XmlNode是osg中对xml的处理,返回一个Track。 接下来看createTrackModel这个函数,根据Track绘制了很多线,值得注意的是,这里Track中存 储是的经纬高,需要通过EllipsoidModel把它转换到世界坐标,转换函数 convertLatLongHeightToXYZ,把这些路径绘制到了地球上。 computeAveragedSpeedTrackSegment、computeSmoothedTrackSegment这两个函数也很好理解, 在地球上绘制两点直接的线,可能出现不平滑,地球上弧型的,因此需要在两点中进行平滑处理。第一个函数根据平均速度。 如果outputFilename不为空,会把这个Track写出到指定文件中。 这个例子本身并不难,应用了osg中封装的的xml处理接口,应用了EllipsoidModel这个类,这个 类在编写数字地球的时候经常用到。 作者:yungis 发表于2013/3/22 6:50:36 原文链接 阅读:530 评论:0 查看评论 |
[原]osggeometryshaders例子 |
SomePoints继承Geometry,绘制了八个点,关闭了光照,设置点的大小为6. 然后应用的了shader,添加了"u_anim1"这个变量,并且添加了SineAnimation更新回调。 先来看createShader()这个函数,创建Program,添加了顶点着色器、片元着色器和几何着色器。 几何着色器介绍: Geometry Shader Tutorials:http://appsrv.cse.cuhk.edu.hk/~ymxie/Geometry_Shader/ Geometry Shader Concepts & Examples: http://www.cnblogs.com/Jedimaster/archive/2007/06/26/796107.html pgm->setParameter( GL_GEOMETRY_VERTICES_OUT_EXT, 4 ); 着色器输出元素个数 pgm->setParameter( GL_GEOMETRY_INPUT_TYPE_EXT, GL_POINTS );色器输入元素类型 pgm->setParameter( GL_GEOMETRY_OUTPUT_TYPE_EXT, GL_LINE_STRIP );着色器输出元素类型 这是几何着色器扩展支持,输入的是点,输出的是线。 在每个着色器中定义"#version 120\n" "#extension GL_EXT_geometry_shader4 : enable\n" 打开几个着色器 static const char* vertSource = { "#version 120\n" "#extension GL_EXT_geometry_shader4 : enable\n" "uniform float u_anim1;\n" "varying vec4 v_color;\n" "void main(void)\n" "{\n" " v_color = gl_Vertex;\n" " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" "}\n" }; 把点的坐标轴当做颜色传递,计算点的位置。 static const char* geomSource = { "#version 120\n" "#extension GL_EXT_geometry_shader4 : enable\n" "uniform float u_anim1;\n" "varying in vec4 v_color[];\n" "varying out vec4 v_color_out;\n" "void main(void)\n" "{\n" " vec4 v = gl_PositionIn[0];\n" " v_color_out = v + v_color[0];\n" "\n" " gl_Position = v + vec4(u_anim1,0.,0.,0.); EmitVertex();\n" " gl_Position = v - vec4(u_anim1,0.,0.,0.); EmitVertex();\n" " EndPrimitive();\n" "\n" " gl_Position = v + vec4(0.,1.0-u_anim1,0.,0.); EmitVertex();\n" " gl_Position = v - vec4(0.,1.0-u_anim1,0.,0.); EmitVertex();\n" " EndPrimitive();\n" "}\n" }; 计算了一下颜色,每两点作为一条线 static const char* fragSource = { "#version 120\n" "#extension GL_EXT_geometry_shader4 : enable\n" "uniform float u_anim1;\n" "varying vec4 v_color_out;\n" "void main(void)\n" "{\n" " gl_FragColor = v_color_out;\n" "}\n" }; 把最终的颜色写入gl_framcolor中 作者:yungis 发表于2013/3/22 6:16:15 原文链接 阅读:485 评论:0 查看评论 |