OpenSceneGraph FAQ 【转】
1、地球背面的一个点,计算它在屏幕上的坐标,能得到吗? 不是被挡住了吗?
答:计算一个空间点的屏幕坐标,使用osgAPEx::GetScreenPosition函数。当空间点处于相机视空间内(不管它是否被别的物体遮挡)时,都是可以得到它对应的屏幕坐标的。
如何判断一个点是否在地球背面?可以通过计算该点处垂直地面的方向UP,与相机方向的夹角,如果夹角为锐角,则可认为该点在地球背面。计算地球上任意点的UP方向使用osgAPEx::ComputeLocalUpVector。
2、OSG中可以播放视频吗?
答:可以使用quicktime插件或ffmpeg插件在OSG中播放视频,quicktime插件的编译需要QuickTimeSDK,ffmpeg插件的编译需要ffmpeg库(www.ffmpeg.org www.ffmpeg.com.cn http://ffmpeg.arrozcru.org/builds/)。OSG的quicktime插件已经停止更新了,现在力推ffmpeg。
ffmpeg插件好像是从2.9版开始提供的。
利用视频播放插件可以读入avi等视频文件到OSG纹理中,并把纹理渲染在模型上,比如实现一个立体广告牌。
3、模型缩放后光照结果错误,是什么原因?
答:OpenGL的放缩矩阵会同时变换模型的法线,进而影响光照效果,因此放大时可能造成模型表面光照过强,需要打开GL_NORMALIZE。
在OSG中使用stateset->setMode( GL_NORMALIZE, osg::StateAttribute::ON );
4、OSG中如何打开双面光照
答:使用osg::LightModel渲染属性
5、OSG中可以播放GIF动画么?
答:可以,使用OSG提供的gif插件,可以读取动态GIF图片,并通过设置为模型纹理来渲染该图片。通过GIF插件读取GIF图片返回的对象派生自osg::ImageStream,因此,可以使用paly等接口控制动画播放。
GIF插件提供了轻量级的动画纹理播放方式,较quicktime等视频播放插件更适合一些简单的应用场合。
另外,OSG还提供osg::ImageSequence类,可以通过读入多个静态图片形成一个sequence,并通过ImageStream接口函数控制多张图片的连续播放。
6、什么是烘培,在OSG中怎样实现烘培?
答:烘培又叫纹理烘培,是指通过每帧预渲染一副场景到指定纹理上,实现模型贴图的动态效果。如水面倒影、镜子、倒计时牌上跳动的文字等效果的实现,都可以使用纹理烘培技术。
在OSG中实现纹理烘培是非常容易的,大致步骤如下:
创建纹理对象,设置纹理的大小、像素格式,并把纹理对象绑定到模型;
创建烘培用的相机,指定渲染顺序为PRE_RENDER,指定实现方式为FRAME_BUFFER_OBJECT,并把相机的颜色缓冲区绑定到纹理对象;
把要渲染到纹理上的场景加入相机的下级;
把相机加入场景。
具体例子可参考examples\osgprerender或demos\RTT
7、为什么我的OSG窗口看到的圆球是扁的?
答:这是因为投影矩阵的设置有问题,一般情况下应该根据视口实际的宽高比来设置投影矩阵,如视口宽、高分别为width和height,则设置相机 投影矩阵为camera->setProjectionMatrixAsPerspective(30, (double)width/height, 1.0f,10000.0f);
如果没有按实际视口宽高来设置投影矩阵,就会出现画面被压缩或拉伸的效果。
当窗口大小发生变化时,系统通过GraphicsContext对象自动响应WM_SIZE消息,对该GraphicsContext对象相关联的 所有相机(通过调用osg::Camera::setGraphicsContext将相机与GraphicsContext关联)自动更新视口和投影矩 阵,更新投影矩阵的方法为根据宽高比的改变来等比缩放投影矩阵。
可以通过osg::Camera::setProjectionResizePolicy设置相机在窗口大小发生变化时重置投影矩阵的策略,设置为FIXED则不会自动重置投影矩阵,缺省设置为HORIZONTAL。
对于HUD相机,由于其使用正交投影矩阵,不能通过上述缩放的方式修改投影矩阵(正交投影矩阵不但和宽高比有关,还和宽高值有关)。可以自己实现一个GUIEventHandler响应RESIZE事件,根据当前主视口宽高重设HUD相机的视口和投影矩阵。
8、什么是VBO,什么是DisplayList?
答:VBO和DisplayList是OpenGL提供的两种用于提高渲染效率的技术。
VBO(Vertex Buffer Object)-顶点缓冲区对象,DisplayList-显示列表。
在使用VBO时,如果修改顶点数组内容,则需要调用顶点数组的dirty()函数应用修改;使用DisplayList时,如果修改顶点数组内容,则需要调用dirtyDisplayList()来应用修改。
OSG中缺省使用显示列表而不使用VBO。
9、OSG中分页数据库线程、渲染线程和筛选线程是在什么时候退出的?
答:1.osgViewer::Viewer对象析构时会调用stopThreading同步退出渲染和筛选线程,并调用DatabasePager::cancel通知分页数据库线程退出。
2.在收到WM_CLOSE消息时会调用stopThreading同步退渲染和筛选线程。
3.可以在需要的时候手动调用stopThreading同步退出渲染和筛选线程。
10、OSG处理事件的时机和顺序是怎样的?
答:OSG在Viewer::eventTraversal函数中处理输入事件,eventTraversal在帧循环的更新遍历和渲染遍历之前被调用。
eventTraversal中事件处理的顺序为:
1.为本帧每一个事件遍历场景树,调用Node、Drawable、StateSet对象的事件处理回调处理事件。
2.为本帧每一个事件遍历Viewer的事件处理器(GUIEventHandler)队列,调用事件处理器处理事件。
3.为本帧每一个事件,调用Viewer的相机操作器(CameraManipulator)处理事件。
11、Switch(开关)节点的作用是什么?
答:Switch节点继承自Group节点,对应于childLis有一个boolList,为每一个子节点保存了一个开关值,当子节点开关关闭时,保证子节点不会被访问类型为Active子节点的访问器访问到。
当子节点开关关闭时,子节点不参与包围盒计算。
12、NodeMask、TraversalMask的作用是什么?
答:NodeMask(32位无符号整形)作为Node类的属性,用于限定节点是否能被指定的节点访问器访问。缺省值为0xffffffff。
TraversalMask(还有OverrideMask)作为节点访问器的属性,用于限定节点访问器能够访问哪些节点。缺省值为0xffffffff。
节点是否能被访问器访问取决于:TraversalMask & ( OverrideMask | NodeMask )
13、osg::ColorMask的作用是什么?
答:ColorMask封装了glColorMask函数的功能,用于设置对颜色缓冲区的写掩码,即设置是否对R、G、B、A位执行写入操作。
在只需要写深度缓冲或模板缓冲,而不实际绘制物体时,可以使用ColorMask并设置对RGBA的写入掩码均为false。
14、怎样布局屏幕元素(文字、图片等)
答:屏幕元素一般使用HUD的方式(即正交投影)渲染,在osg中可以定义一个正交投影的相机,把屏幕元素作为子节点添加给这个HUD相机进行渲染。元素的布局和缩放,一般有两种处理方式:
一、
按视口实际大小布局,同时跟踪输出窗口的大小变化,并按窗口实际大小更新HUD相机的投影矩阵和视口。这种方式不但要动态更新相机的投影矩阵和视口,而且
要自己编写代码根据视口大小变化动态更新屏幕元素的位置和大小,如按指定的对齐方式更新位置、按指定的尺寸比例更新大小。也可以只更新位置不更新大小,这
样得到的效果就是屏幕元素的大小不随窗口缩放。
二、
按指定的固定大小布局,同时设置HUD相机的投影矩阵为以相同宽高计算的固定值,跟踪输出窗口大小变化,按窗口实际大小更新HUD相机的视口。这种方式只
需要编写代码更新相机的视口即可,而屏幕元素的大小和位置始终按初始的固定视口大小计算,不需随窗口变化做调整。这样得到的效果就是屏幕元素的大小和布局
与窗口等比缩放。
15、setAttribute与setAttributeAndModes的异同
答:setAttribute用于设置渲染属性和属性的覆盖模式,第二个参数的有效值只有OVERRIDE和PROTECTED的组合,不影响属性状态的开关(设置ON/OFF是无效的)!
setAttributeAndModes设置渲染属性和覆盖模式的同时,也会设置属性状态的开关。
setAttribute用于只需设置渲染属性而不改变状态的场合,具体是否打开该状态取决于子节点的设置。
16、OSG场景筛选中有哪些优化效率的算法
答:OSG场景筛选主要用到的筛选方法有:视景体筛选、最
小像素筛选和遮挡筛选。其中视景体筛选是最基本和最常用的筛选方法,它的算法是:使用构成视景体的各个面与节点包围盒求交,如果节点在某个面以外,则剔除
掉该节点及其子节点;如果节点完全在某个面以内,则该节点的所有子节点在进行筛选计算的时候不需要再与这个面求交(子节点必然也完全在这个面以内)。鉴于
这种筛选实现,恰当使用树形结构场景图组织场景节点,能够提高筛选效率。
17、我在MFC的Static控件中使用OSG渲染,但不能响应鼠标事件是为什么?
答:这完全是MFC控件使用的问题,要使对话框中的Static控件接收鼠标消息,需要把Static控件属性的Notify设置为True。
18、OSG渲染排序是怎么做的,有哪些接口可以用来控制渲染顺序?
答:OSG通过场景拣选(cull)生成一棵由RenderStage(根节点)、RenderBin(分支节点)和RenderLeaf(渲染叶)构成的渲染树,同时生成一棵由StateGraph构成的渲染状态树,最终的渲染操作通过渲染树进行,渲染的顺序为:
RenderStage::draw
|
RenderStage::drawPreRenderStages
|
RenderStage::drawInner ------------------------------------------- RenderBin::draw
| |
RenderStage::drawPostRenderStages BinNum小于0的子Bin(按BinNum升序)
|
本Bin的渲染叶列表(排序的)
|
本Bin下挂的所有StateGraph中的渲染叶
|
其他的子Bin(按BinNum升序)
在
拣选过程中,通过拣选测试的Drawable对象被添加到当前StateGraph对象的渲染叶列表中,而StateGraph则被当前
RenderBin对象引用,而最终渲染时,部分渲染叶也是通过RenderBin引用的StateGraph对象找到并渲染的,其他渲染叶(对应
RenderBin的排序模式为FRONT_TO_BACK/BACK_TO_FRONT/TRAVERSAL_ORDER的)被转移到
RenderBin的渲染叶列表中排序然后渲染。
我们可以通过StateSet的BinNum和BinName设置来控制对应节点的渲染顺序。
1)BinName为"RenderBin"、"StateSortedBin"的缺省排序方式为SORT_BY_STATE(目前实现为不排序)
BinName为"DepthSortedBin"的缺省排序方式为SORT_BACK_TO_FRONT(由远到近,用于半透物体的alpha混合)
BinName为"TraversalOrderBin"的缺省排序方式为TRAVERSAL_ORDER(即按遍历到的先后顺序排序)。
2)BinNum小的靠前渲染
3)setNestRenderBins设置RenderBin是否允许嵌套,为true时新的RenderBin被添加为当前RenderBin的子节点,为false时新的RenderBin被添加为RenderStage(根节点)的子节点。
19、OSG对组合键是怎样映射的?
答:由于Win32 API的特点,OSG不得不将Ctrl+letter变换到了{1,..,26},也就是说,CTRL+a的getKey()为1,而CTRL+z的getKey()为26;Shift+a~z被映射到大写的'A'~'Z'。
20、为什么OSG自动为我的纹理对象创建了mipmap?
答:当纹理过滤方式min_filter设
置为基于mipmap的4种之一时,OSG将自动为非mipmap贴图纹理对象创建mipmap。min_filter的缺省值是
LINEAR_MIPMAP_LINEAR,因此如果未显式设置纹理过滤方式的话,即会启用自动创建mipmap的功能。
21、Texture::setUnRefImageDataAfterApply的作用?
答:当该值设置为true时,OSG在应用过该纹理对象后(apply),自动释放其对Image对象的引用,以减少内存占用。
22、osgDB::SharedStateManager的作用?
答:SharedStateManager
用于对系统中的StateSet、Texture对象执行共享优化,即对系统中内容相同的多个Texture对象,只保留一个实例,其他使用引用,以减少
内存、显存的占用,提高渲染效率。使用方式为,为新加载或创建的节点对象调用
osgDB::Registry()->getOrCreateSharedStateManager()->share函数。
23、如何打开分页数据库的预编译功能?
答:需要做两件事,1)设置
osg::DisplaySettings::instance()->setCompileContextsHint(true),使
Viewer在realize时创建后台GC用于预编译操作;2)调用
osgDB::DabasePager::setDoPreCompile(true)开启预编译功能。