概述
frame()作为渲染函数,只有简单的一句,但是它的内部到底是怎样的呢,我会跟着《最长的一帧》一起慢慢学习。
///为frame()源码,后面会深入解析每一个变量,每一个函数的源码//
void ViewerBase::frame()//frame的内部实现
{
if(_done) return;
if(_firstFrame)
{
viwerInit();//如果是启动后第一帧,则执行该函数
}
if(!isRealised())
{
realize();//如果还没有执行realize(),则执行它
}
_firstFrame=false;
advance(simulationTime);
eventTraversal();//负责处理系统产生的各种事件,诸如鼠标的移动,点击,和键盘的相应,窗口的关闭,以及摄像机与场景图形的时间回调(
EventCallback) updateTraversal();//负责遍历所有的更新回调(UpdateCallback),负责更新DatabasePager和ImagePager这两个重要分页 数据处理组件
renderingTraversals();//使用比较负责的线程处理方法,完成场景的筛选(cull)和绘制(draw)工作
}
frame()函数内部执行的上面的几个步骤,但其功能来说,是完成了OSG场景渲染的一帧。
1.viewerInit函数调用了View::init()函数
void View::init()//完成视景器的初始化工作
{
OSG_INFO<<"View::init()"<<std::endl;
osg::ref_ptr<osgGA::GUIEventAdapter> initEvent = _eventQueue->createEvent();//
_eventQueue:视景器的事件队列,代表事件的类:osgGA::GUIEventAdapter,用于表达各种类型的鼠标键盘,触压笔和窗口事件。eventQueue保存了一个GUIEventAdapter链表,还提供了一系列对该链表及元素的操作函数。createEvent作用是分配和返回一个新的GUIEventAdapter事件指针。
initEvent->setEventType(osgGA::GUIEventAdapter::FRAME); //指定该事件类型为FRAME事件,即每帧都会触发的一个事件
if (_cameraManipulator.valid())
{
_cameraManipulator->init(*initEvent, *this);//_cammeraMainipulator是视景器中所用的场景漫游器的实例,将当前创建的 FRAME事件和Viewer对象传递给漫游器的初始化函数。
}
}
//GUI事件处理器:GUI事件适配器(GUIEventAdapter)和GUI动作适配器(GUIEventHandler)后面会写到
2.realize()函数 完成窗口和场景的“设置”工作
///realize()源码///
void Viewer::realize()
{ //OSG_INFO<<"Viewer::realize()"<<std::endl;
Contexts contexts;//
保存了osg::GraphicsContext指针的向量组
getContexts(contexts);//
获取所有的图形上下文,并保存在这个向量组中来(osg3.0中,根据函数功能来看,只获取了一个有效的图形上下文设备)
/*图形上下文:在osgViewer::Viewer还没有任何操作的时候,系统不会存在任何图形上下文,创建一个新的osg::Camera对象,也不会为其自动分配图形上下文。图形上下文是场景显示的唯一平台,系统有必要在开始渲染之前完成其创建工作*/
if (contexts.empty())
{
//如果此时contexts还没有得到任何图形上下文设备的花,说明仿真系统还没有合适的显示平台,此时需要创建一个缺省的GraphicsContext设备。
OSG_INFO<<"Viewer::realize() - No valid contexts found, setting up view across all screens."<<std::endl;
// no windows are already set up so set up a default view
const char* ptr = 0;
if ((ptr = getenv("OSG_CONFIG_FILE")) != 0)
{
readConfiguration(ptr);
//如果能够读取用户在该环境变量下定义的文件路径,并用cfg成功解析,调用take,使用配置信息设置当前视景器
}
else
{
int screenNum = -1;
if ((ptr = getenv("OSG_SCREEN")) != 0)
{
if (strlen(ptr)!=0)
screenNum = atoi(ptr);//
读取环境变量中的屏幕个数
else screenNum = -1;
}
int x = -1, y = -1, width = -1, height = -1;
if ((ptr = getenv("OSG_WINDOW")) != 0)
{
std::istringstream iss(ptr);
iss >> x >> y >> width >> height;//
读取环境变量中的x,y,宽和高
}
if (width>0 && height>0)
{
if (screenNum>=0)
setUpViewInWindow(x, y, width, height, screenNum);
else setUpViewInWindow(x,y,width,height);//
根据窗口信息创建设备
}
else if (screenNum>=0)
{
setUpViewOnSingleScreen(screenNum);//
根据屏幕数量创建图形窗口,为每一个显示屏创建一个全屏的图形窗口
}
else
{
setUpViewAcrossAllScreens();//
不满足上面条件时,创建一个全屏显示的图形设备
}
}
getContexts(contexts);
}
if (contexts.empty())
{
OSG_NOTICE<<"Viewer::realize() - failed to set up any windows"<<std::endl;
_done = true;
return;
}
//再次执行,如果还没有任何图形上下文的话,就不得不退出程序了
}
2.1 getContexts() 获取图形上下文设备,并保存在Contexts向量组中
void Viewer::getContexts(Contexts& contexts, bool onlyValid)
{
typedef std::set<osg::GraphicsContext*> ContextSet;
ContextSet contextSet;
contexts.clear();
if (_camera.valid() && _camera->getGraphicsContext() && (_camera->getGraphicsContext()->valid() || !onlyValid))//
判断场景的主摄像机是否包含了一个有效的GraphicContext设备
{
contextSet.insert(_camera->getGraphicsContext());
contexts.push_back(_camera->getGraphicsContext());//
如果主摄像机包含一个有效的GraphicContext设备,则存入到传入的参数中
}
for(unsigned int i=0; i<getNumSlaves(); ++i)//
遍历所有的摄像机
{
Slave& slave = getSlave(i);
osg::GraphicsContext* sgc = slave._camera.valid() ? slave._camera->getGraphicsContext() : 0;//
如果该相机有效,则定义一个新的图形上下文设备,并将当前的相机所包含的有效GraphicsContest设备赋值给sgc
if (sgc && (sgc->valid() || !onlyValid))
{
if (contextSet.count(sgc)==0)
{
contextSet.insert(sgc); contexts.push_back(sgc);//
查看contextset中有没有图像上下文设备,如果没有就添加给传入的向量数组contexts
}
}
}
}
总结:函数功能为-为传入的contests向量组中添加一个场景相机中所包含的图形上下文设备。优先添加主摄像机的图形上下文设备。
最后
以上就是光亮钢笔为你收集整理的OSG 《最长的一帧》 学习笔记-frame(一)的全部内容,希望文章能够帮你解决OSG 《最长的一帧》 学习笔记-frame(一)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复