最长的一帧 作者:王锐(array)
参考的osg源码版本为 3.6.3
osg自学笔记2——《最长的一帧》
- 0 概况
- 第一日
-
- 具体内容
-
- osgViewer::ViewerBase::frame()函数
- osgViewer::View::init()函数
- 总结
- 第二日
-
- 具体内容
-
- 一种常用的嵌入方式也许是这样实现的:
- osgViewer::Viewer::getContexts()函数
- 创建缺省 GraphicsContext 设备的方法有以下几种:
- 总结
0 概况
这里只研究一帧的渲染。
while (!viewer.done())
viewer.frame();
第一日
具体内容
osgViewer::ViewerBase::frame()函数
void ViewerBase::frame(double simulationTime)
{
if (_done) return;
// OSG_NOTICE<<std::endl<<"CompositeViewer::frame()"
// <<std::endl<<std::endl;
if (_firstFrame)//判断第一帧,初始化
{
viewerInit();//初始化
if (!isRealized())
{
realize();
}
_firstFrame = false;
}
advance(simulationTime);
eventTraversal();//事件遍历 鼠标键盘窗口
//遍历更新回调,负责更新 DatabasePager 与 ImagePager 分页数据处理组件。
updateTraversal();
//遍历渲染,线程处理方法,完成场景的筛选(cull)和绘制(draw)工作。
renderingTraversals();
}
osgViewer::View::init()函数
//完成视景器的初始化工作
void View::init()
{
OSG_INFO<<"View::init()"<<std::endl;
//_eventQueue 用于储存该视景器的事件队列。保存一个 GUIEventAdapter 的链表.
//createEvent 函数的作用是分配和返回一个新的 GUIEventAdapter事件的指针。
//osgGA::GUIEventAdapter,用于表达各种类型的鼠标、键盘、触压笔和窗口事件。
//initEvent 新事件的类型被指定为 FRAME 事件,即每帧都会触发的一个事件。
osg::ref_ptr<osgGA::GUIEventAdapter> initEvent =
_eventQueue->createEvent();
initEvent->setEventType(osgGA::GUIEventAdapter::FRAME);
//_cameraManipulator 是视景器中所用的场景漫游器,
//不同的漫游器初始化函数是不同的。
if (_cameraManipulator.valid())
{
_cameraManipulator->init(*initEvent, *this);
}
}
上面的代码将新创建的 FRAME 事件和 Viewer 对象本身传递给_cameraManipulator 的init 函数,不同的漫游器(如 TrackballManipulator、DriveManipulator)会重写各自的 init 函数,实现自己所需的初始化工作。如果读者希望自己编写一个场景的漫游器,那么覆写并使用 osgGA::MatrixManipulator::init 就可以灵活地初始化自定义漫游器的功能了,它的调用时机就在这里。
总结
-
解读成果:
osgGA::EventQueue::createEvent,
osgGA::MatrixManipulator::init,
osgViewer::View::init,
osgViewer::Viewer::viewerInit。
-
悬疑列表:
无
第二日
具体内容
一种常用的嵌入方式也许是这样实现的:
对于需要将 OSG 嵌合到各式各样的 GUI 系统(如 MFC,Qt,wxWidgets 等)的朋友来说,osg::GraphicsContext 类是经常要打交道的对象之一。
实现如下:
osg::ref_ptr<osg::GraphicsContext::Traits> traits =
new osg::GraphicsContext::Traits;
osg::ref_ptr<osg::Referenced> windata =
new osgViewer::GraphicsWindowWin32::WindowData(hWnd);
traits->x = 0;
traits->y = 0;
……
traits->inheritedWindowData = windata;
osg::GraphicsContext* gc =
osg::GraphicsContext::createGraphicsContext(traits.get());
Camera* camera = viewer.getCamera();
camera->setGraphicsContext(gc);
……
viewer.setCamera(camera);
这个过程虽然比较繁杂,但是顺序还是十分清楚的:
- 首先设置嵌入窗口的特性(Traits),例如 X、Y 位置,宽度和高度,以及父窗口的句柄(inheritedWindowData);
- 然后根据特性的设置创建一个新的图形设备上下文(GraphicsContext),将其赋予场景所用的摄像机。
osgViewer::Viewer::getContexts()函数
//主摄像机没有创建图形上下文,因此也就得不到设备的指针。?这里添加了设备上下文啊?
//contextSet这个局部变量是判断GraphicsContext是否重复。
void Viewer::getContexts(Contexts& contexts, bool onlyValid)
{
typedef std::set<osg::GraphicsContext*> ContextSet;
ContextSet contextSet;
contexts.clear();
//首先判断场景的主摄像机_camera 是否包含了一个有效的GraphicsContext 设备
if (_camera.valid() &&
_camera->getGraphicsContext() &&
(_camera->getGraphicsContext()->valid() || !onlyValid))
{
contextSet.insert(_camera->getGraphicsContext());
contexts.push_back(_camera->getGraphicsContext());
}
//然后再遍历所有的从摄像机_slaves,
//将所有找到的 GraphicsContext 图形上下文设备记录下来。
//随后,将这些 GraphicsContext 的指针追加到传入参数(contexts 向量组)中,
//并使用std::sort 执行了一步排序的工作,所
for(unsigned int i=0; i<getNumSlaves(); ++i)
{
Slave& slave = getSlave(i);
osg::GraphicsContext* sgc = slave._camera.valid() ?
slave._camera->getGraphicsContext() : 0;
if (sgc && (sgc->valid() || !onlyValid))
{
if (contextSet.count(sgc)==0)//不重复记录
{
contextSet.insert(sgc);
contexts.push_back(sgc);
}
}
}
}
创建缺省 GraphicsContext 设备的方法有以下几种:
1、读取 OSG_CONFIG_FILE 环境变量的内容:如果用户在这个环境变量中定义了一个文件路径的话,那么系统会尝试用 osgDB::readObjectFile 函数读入这个文件,使用 cfg 插件进行解析;如果成功的话,则调用 osgViewer::Viewer::take 函数,使用配置信息设置当前的视景器。这些工作在 osgViewer::Viewer::readConfiguration 函数中实现。
2、读取 OSG_WINDOW 环境变量的内容:如果用户以“x y w h”的格式在其中定义了窗口的左上角坐标(x,y)和尺寸(w,h)的话(注意要以空格为分隔符),系统会尝试使用 osgViewer::View::setUpViewInWindow 函数来创建设备。
3、读取 OSG_SCREEN 环境变量的内容:如果用户在其中定义了所用屏幕的数量的话,系统会尝试用 osgViewer::View::setUpViewOnSingleScreen 函数,为每一个显示屏创建一个全屏幕的图形窗口;如果同时还设置了 OSG_WINDOW,那么这两个环境变量都可以起到作用,此时将调用 setUpViewInWindow 函数。
4、如果上述环境变量都没有设置的话(事实上这也是最常见的情况),那么系统将调用osgViewer::View::setUpViewAcrossAllScreens 函数,尝试创建一个全屏显示的图形设备。
那么,下文就从这几种图形设备建立的方法开始。至于后面的路,果然遥遥无期呢。
总结
-
解读成果:
osgViewer::Viewer::getContexts,
osgViewer::Viewer::readConfiguration。
-
悬疑列表:
类变量_cameraWithFocus 的意义是什么?
————完结————