最近再次阅读王锐的最长的一帧,将osg渲染过程的理解,总结下:

仿真循环过程执行如下:

advance(simulationTime); // 记录场景的帧数,帧速率信息
eventTraversal(); // 处理场景的交互事件及其回调
updateTraversal(); // 处理场景的更新回调,以及分页数据的更新
renderingTraversals(); // 场景的渲染遍历工

(1.执行eventTraversal函数,顾名思义,这个函数将负责处理系统产生的各种事件,诸如鼠标的移动,点击,键盘的响应,窗口的关闭等等,以及摄像机与场景图形的事件回调
(EventCallback)。
2.执行updateTraversal函数,这个函数负责遍历所有的更新回调(UpdateCallback);除此之外,它的另一个重要任务就是负责更新DatabasePager与ImagePager这两个重要的分
页数据处理组件。
3.执行renderingTraversals函数,这里将使用较为复杂的线程处理方法,完成场景的筛选(cull)和绘制(draw)工作)

对于场景中每一帧的更新,书上已经很明确,首先是各种事件遍历,然后更新遍历,最后是渲染遍历;

事件遍历和更新遍历有时间在总结,目前先总结渲染绘制过程:

      OSG的场景渲染过程可以简单地分为三个阶段:用户(APP)阶段,更新用户数据,负责场景对象的运动和管理等等;筛选(CULL)阶段,负责对场景中的对象进行筛选裁减,略过那些不会被用户所见(因而不必渲染)的物体,并根据渲染状态的相似性对即将进入渲染管线的对象排序(从而避免OpenGL状态量的频繁切换);绘制(DRAW)阶段,执行各种OpenGL操作,将数据送入OpenGL渲染管线及显示系统处理。

 绘制过程中线程模式主要有四种:SingleThreaded,CullDrawThreadPerContext,DrawThreadPerContext,CullThreadPerCameraDrawThreadPerContext

具体的选择模式可参考原文。

今天先学习单线程绘制的过程

单线程模式下,renderingTraversals函数的基本执行步骤如下:
1、首先使用ViewerBase::checkWindowStatus检查是否存在有效的图形设备,不存在的话,需要使用ViewerBase::stopThreading停止线程运行。
2、记录渲染遍历开始的时间。
3、遍历视景器对应的所有Scene场景(Viewer单视景器只存在一个场景),记录分页数据库的更新启动帧(使用DatabasePager::signalBeginFrame,这将决定DatabasePager中的数据请求是否过期),并计算场景节点的边界球。
4、获取当前所有的图形设备(GraphicsContext)和摄像机。
5、遍历所有摄像机的渲染器(Renderer),执行Renderer::cull场景筛选的操作!
6、遍历所有的图形设备,设置渲染上下文(使用ViewerBase::makeCurrent)并执行GraphicsContext::runOperations,实现场景绘制的操作!
7、再次遍历所有的图形设备,执行双缓存交换操作(GraphicsContext::swapBuffers),熟悉图形编程的朋友一看便知,这是避免动态绘图时产生闪烁的重要步骤。
8、遍历视景器中的场景,告知分页数据库更新已经结束(DatabasePager::signalEndFrame,目前这个函数没有作用)。
9、释放当前的渲染上下文(ViewerBase::releaseContext)。
10、记录渲染遍历结束的时间,并保存到记录器当中(ViewerBase::getStats)