这最短的一帧,我们主要以数据处理为中心一路下去看看大致处理流程,也是非常粗浅的认识,详细分析请详阅最长的一帧教程,之所以起名最短的一帧,就是想沿一条最短路径穿越过去,故命名之。
我们把整个场景渲染过程可以看做是一个产品加工的过程,首先是原料,然后是原料经过哪些加工机器以及加工工序,最后加工成什么。所以我们也采用该思路,我们抛开旁枝末节,看看场景数据如果经过中间的处理最后渲染到屏幕的,我们只去剖析和数据关系最为紧密的环节,抛开其它的不看,这样内容将呈几何级下降,过程相对比较清晰。
我们的原料就是一头牛,我们要用这头牛加工成香喷喷的牛肉罐头,哈哈,是不是流口水了?废话不说了,以后也不说了,一切从简,单刀直入,逐一剖析。
创建工厂,也就是创建一个视景器,当然,里面有已经买好了所有的加工设备,但我们这里去繁从简,结合我们的标题“以数据为主线”,所有的分析绝不离开数据半步(话不离牛),这样我们不会被牵来牵去的最后搞的晕头转向,所以我们就不去分析里面的设备了。
购买原料(牛),这个谁都知道,osgDB::readNodeFile(“cow.osg”)。
放料,将场景给视景器,viewer.setSceneData(cow);
下面我们就看看怎么放料,都把牛放到什么地方。直接进入上面的函数可以看到,这头牛直接到了View::setSceneData(node);我们继续看,我们看到View里有一个Scene成员,一个Scene就是一颗场景树,这也就是该视图主相机对应的场景树,进入该函数后我们看到这头牛先被送给了这个Scene,_scene->setSceneData(node);往下看我们看到了
View::assignSceneDataToCameras(),根据函数名称我们不难看出这是要把这头牛指派给相机,进入该函数,我们发现确实是这样,首先它把牛给了场景漫游器,因为场景漫游器在进行计算的时候要用到这个牛,_cameraManipulator->setNode(sceneData);我们知道,一个视图有一个主相机,这个主相机一个最重要的工作就是用来实现视图变换,视图变换是离不开场景的,所以需要将这头牛给这个主相机,_camera->addChild(sceneData);这里我们看到,场景对象是作为子节点加入到这个主相机的。而我们知道,一个相机也就是一个变换节点,这样以来,把这头牛作为子节点加在这个相机下,只要我们通过变换这个相机节点的位置、姿态等就很容易实现场景的视图变换。别忘了,我们一个视图可以有多个相机的,除了这个主相机之外,可能还有若干从属相机,从属相机可以有自己的场景树,也可以直接用主相机的场景树,如果是沿用主相机的场景树(多个相机观察的是同一个场景),我们就要把场景赋给主相机的同时赋给所有从属相机,要不它们照谁去啊?所以接下来就是把这头牛给所有的从属相机(别忘了前提条件是这些相机也要照这头牛),
for(unsigned i=0; i<getNumSlaves(); ++i)
{
…..
if(sceneData) slave._camera->addChild(sceneData);
……
}
分析到这里,我们基本已经清楚了料是如何放的,都放到了哪里。
接下来我们就看看如何加工。
还是那句话,话不离牛,我们一下子可以漂洋过海来到void ViewerBase::frame(double simulationTime),这里是什么?我不说大家也都知道,这就是整个加工流水线。我们来看看吧。里面开始打扫卫生的工作我们就不去看了,直接看流水线上的三大环节:
eventTraversal();
updateTraversal();
renderingTraversals();
看过最长的一帧的对他们应该很熟悉(可能对osg全部已经很熟悉,呵呵),我这里就简单说一句,它们分别是事