前言
上面我们用了四节课的内容,讲解了一些osg概念性的内部原理。希望大家可以再看今天的讲解之前先再仔细的研究一下前四节的内容。这样你就会对整个osg的渲染过程有一个更加清晰的认知,有助于理解下面两个函数cull()和draw()。
osg::Util::SceneView::cull()
好,相信大家已经又复习了上面几节的内容,那我们就进行sceneView的第一个重要功能osg::Util::SceneView::cull()函数。场景的筛选函数 cull 主要完成了以下几个工作。
1、通过_camera->getNodeMask()==0来判断主相机下的根节点是否可见,如果不可见则不用进行cull操作。
2、进行视图的渲染信息(_renderInfo)的初始化
3、通过updateUniforms();更新一些osg内设的 osg::Uniform 着色器变量(osg_FrameNumber,osg_FrameTime等)。因为opengl中Uniform表示这个变量可以被所有的shader访问到,所以我们在编写 GLSL 程序时调用这些变量获取 OSG 提供的一些场景和时间方面的信息。
4、对筛选访问器(_cullVisitor),状态树根节点(_stateGraph)和渲染树根节点(_renderStage)进行初始化操作。
5、通过_displaySettings->getStereo()来判断是否进行立体渲染(例如VR等),那么此时 OSG 会针对左/右眼(osg::DisplaySettings::LEFT_EYE/RIGHT_EYE)以其它各种设置做出适当的处理,相关的函数包括 SceneView 类成员 computeLeftEyeProjection,computeLeftEyeView,computeRightEyeProjection,computeRightEyeView 等。这些就等我们研究到osg与vr(ar)结合的时候我们再仔细的研究。
6、(不是立体渲染)进行普通渲染,通过cullStage进行cull操作。我们进入SceneView::cullStage内。
A、首先判断camera中是否存在遮挡节点(OccluderNodes)如果存在,就会通过_collectOccludersVisitor->traverse(*_camera),根据投影矩阵(projection)、视图模型矩阵(modelview)以及视口矩阵(modelview)来对场景图进行遍历,找到发生遮挡的位置(也就是得到被遮挡的节点)。将筛选所需的数据送入筛选访问器(CullVisitor),包括筛选设置(CullSettings),状态树根节点(StateGraph),渲染树根节点(RenderStage),渲染信息(RenderInfo)
B、设置状态树以及渲染树构建所需的各种信息。例如viewport、ClearColor、ClearDepth、ClearAccum、ClearStencil、ClearMask、camera等,还要对全局状态节点以及局部状态节点进行默认设置(上一节说到过)。
C、如果camera中设置了CullCallback回调函数,那么就要对摄像机下的所有节点都要进行遍历,并且执行回调函数。如果没有则使用筛选访问器cullVisitor遍历场景中的节点,在遍历过程中将筛选出那些无法被用户看到的对象(被遮挡的,以及超出视椎体的),并将它们裁减掉,从而提高场景绘制的效率。
7、进行完了cull操作后。先后“弹出”模型视点矩阵(所用函数为popModelViewMatrix,事实上只是弹出堆栈中的临时数据,计算结果仍然保留,下同)、投影矩阵、视口矩阵,渲染状态(使用 popStateSet))
8、依次对筛选访问器执行之后得到的渲染树内容进行排序RenderStage::sort和精简StateGraph::prune(构建过程中可能有些空节点需要剔除)
9、最后,计算出场景中动态对象(DYNAMIC)的数目,并保存到 SceneView 的成员变量_dynamicObjectCount 中
10、返回结果computeNearFar。
接下来我们将要深入osgUtil:: CullVisitor类,进一步研究裁剪操作。