OSG学习<2> GraphicsContext与窗口建立
所谓的GraphicsContext 我这么翻译它吧:图形设备上下文?..就像在使用OpenGL在win32的窗口里绘制的时候.曾使用的hrc = wglCreateContext(hdc)一样.创建一个图形设备上下文 ,然后使用wglMakeCurrent(hdc,hrc)设置当前使用的图形设备一样.在这之后 我们就可以使用OGL绘制图形一样.osg中的GraphicsContext 就是跟hrc一样的.只是它将所有需要的内容集成在GraphicsContext这个类当中.这就是面向对象的封装性>_<.
在打开osg/GraphicsContext的头文件当中.我们可以找到这么一些函数 swapBuffers() makeCurrent() 等与我们之前所说的可以说十分相同的.因此对于在OSG当中需要最终显示图形的地方就是这个GraphicsContext .
相对来说,我们通常的第一个例子:
第一个例子
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
int main()
{
osg::Node* node = osgDB::readNodeFile("cow.osg");
osgViewer::Viewer viewer;
viewer.setSceneData(node);
return viewer.run();
}
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
int main()
{
osg::Node* node = osgDB::readNodeFile("cow.osg");
osgViewer::Viewer viewer;
viewer.setSceneData(node);
return viewer.run();
}
这个时候我们得到的是一个全屏的窗口.这是默认的创建的一个GraphicsContext.( 通常情况下只有一个).它是通过执行 Viewer::realize()函数创建的. 最后执行View::setUpViewAcrossAllScreens() 创建全屏的GraphicsContext你可详看源码 就可以发现它就是创建一个GraphicsContext..并把它附加到viewer 的主摄像机上..因此我们最后看到的结果就是在全屏上显示一头牛...假设没有这个GraphicsContext 就会看不到.在后面我会用一副图来说明摄像机与GraphicsContext得关系.这是至关重要的.因为.每个摄像机若需要显示场景.则必须要有一个GraphicsContext.来负责显示.不管是主摄像机还是从摄像机.(Viewer可以有多个摄像机).
在我们了解了GraphicsContext之后.其实上面这个图已经给我们一个很大的启发了.其实最后的GraphicsContext应当是GraphicsWindowWIN32或者GraphicsWindowX11等三个中的一个.这是面向对象多态性的体现.. 因此.我们现在就要开始创建一个GraphicsContext了.
在创建之前.我也许需要说明一个.static GraphicsContext* GraphicsContext::createGraphicsContext(Traits _traits) 需要传入一个Traits的变量.因此我们需要了解这个Traits.
Traits.是什么呢?它GraphicsContext一些特征.我罗列一些能够表示这些特征的属性就能够非常直白的说明这个对象了.
_traits->x //x偏移
_traits->y //y偏移
_traits->width //宽度
_traits->height //高度
_traits->doubleBuffer //是否支持双缓存
_traits->sharedContext //共享GraphicsContext
_traits->windowName //窗口名称
_traits->windowDecoration //是否支持窗口一些装饰属性..如最大化 最小化等
_traits->inheritedWindowData //继承自某个窗口句柄? 这个可以用于嵌入到QT.MFC等GUI系统中.
因此只要设置这些内容.并调用上面的方法则会创建一个GraphicsContext. .而如上那个函数关于创建GraphicsContext实则应当是调用了窗口系统API 来创建的.见如下函数:
创建窗口的API
GraphicsContext* GraphicsContext::createGraphicsContext(Traits* traits)
{
/** 获得系统API接口... */
ref_ptr<GraphicsContext::WindowingSystemInterface> &wsref = windowingSystemInterfaceRef();
if ( wsref.valid())
{
// catch any undefined values.
if (traits) traits->setUndefinedScreenDetailsToDefaultScreen();
return wsref->createGraphicsContext(traits);
}
else
return 0;
}
GraphicsContext* GraphicsContext::createGraphicsContext(Traits* traits)
{
/** 获得系统API接口... */
ref_ptr<GraphicsContext::WindowingSystemInterface> &wsref = windowingSystemInterfaceRef();
if ( wsref.valid())
{
// catch any undefined values.
if (traits) traits->setUndefinedScreenDetailsToDefaultScreen();
return wsref->createGraphicsContext(traits);
}
else
return 0;
}
当你去详细阅读 GraphicsWindowWIN32.cpp 文件和GraphicsWindow 头文件时.你会发觉设计的非常巧妙. 用static全局静态变量和 宏定义实现这个非常宏伟的API获得...
Function
//函数指针的定义
extern "C"
{
typedef void (* CGraphicsWindowFunction) (void);
}
// 结构构造
struct GraphicsWindowFunctionProxy
{
GraphicsWindowFunctionProxy(CGraphicsWindowFunction function) { (function)(); }
};
// 宏定义
#define USE_GRAPICSWINDOW_IMPLEMENTATION(ext) \
extern "C" void graphicswindow_##ext(void); \
static osgViewer::GraphicsWindowFunctionProxy graphicswindowproxy_##ext(graphicswindow_##ext);
#if defined(_WIN32)
#define USE_GRAPHICSWINDOW() USE_GRAPICSWINDOW_IMPLEMENTATION(Win32)
#elif defined(__APPLE__)
#define USE_GRAPHICSWINDOW() USE_GRAPICSWINDOW_IMPLEMENTATION(Carbon)
#else
#define USE_GRAPHICSWINDOW() USE_GRAPICSWINDOW_IMPLEMENTATION(X11)
#endif
}
//函数指针的定义
extern "C"
{
typedef void (* CGraphicsWindowFunction) (void);
}
// 结构构造
struct GraphicsWindowFunctionProxy
{
GraphicsWindowFunctionProxy(CGraphicsWindowFunction function) { (function)(); }
};
// 宏定义
#define USE_GRAPICSWINDOW_IMPLEMENTATION(ext) \
extern "C" void graphicswindow_##ext(void); \
static osgViewer::GraphicsWindowFunctionProxy graphicswindowproxy_##ext(graphicswindow_##ext);
#if defined(_WIN32)
#define USE_GRAPHICSWINDOW() USE_GRAPICSWINDOW_IMPLEMENTATION(Win32)
#elif defined(__APPLE__)
#define USE_GRAPHICSWINDOW() USE_GRAPICSWINDOW_IMPLEMENTATION(Carbon)
#else
#define USE_GRAPHICSWINDOW() USE_GRAPICSWINDOW_IMPLEMENTATION(X11)
#endif
}
GetInterface
struct RegisterWindowingSystemInterfaceProxy
{
RegisterWindowingSystemInterfaceProxy()
{
osg::GraphicsContext::setWindowingSystemInterface(Win32WindowingSystem::getInterface());
}
~RegisterWindowingSystemInterfaceProxy()
{
if (osg::Referenced::getDeleteHandler())
{
osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
osg::Referenced::getDeleteHandler()->flushAll();
}
osg::GraphicsContext::setWindowingSystemInterface(0);
}
};
static RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
} // namespace OsgViewer
// declare C entry point for static compilation.
extern "C" void graphicswindow_Win32(void)
{
osg::GraphicsContext::setWindowingSystemInterface(osgViewer::Win32WindowingSystem::getInterface());
}
struct RegisterWindowingSystemInterfaceProxy
{
RegisterWindowingSystemInterfaceProxy()
{
osg::GraphicsContext::setWindowingSystemInterface(Win32WindowingSystem::getInterface());
}
~RegisterWindowingSystemInterfaceProxy()
{
if (osg::Referenced::getDeleteHandler())
{
osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
osg::Referenced::getDeleteHandler()->flushAll();
}
osg::GraphicsContext::setWindowingSystemInterface(0);
}
};
static RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
} // namespace OsgViewer
// declare C entry point for static compilation.
extern "C" void graphicswindow_Win32(void)
{
osg::GraphicsContext::setWindowingSystemInterface(osgViewer::Win32WindowingSystem::getInterface());
}
因此 假设我们使用的是Window系统 那么所创建的GraphicsContext 则win32模式的.那么具体的窗口创建或者说嵌入等.请详细看GraphicsWindowWIN32.cpp 我们可以非常熟悉的看到开头部分所叙述的wgl等函数..很熟悉吧..
说了这么多.我们是否应当创建一个窗口来实践一下呢? 这将在之后的代码当中详细说出..
为了渲染与显示图形.. 我们需要一个视景器.osgViewer::Viewer ..Viewer当中包含一个主摄像机.因此我们不必在创建一个摄像机了.好了.开始代码的叙述.由于我们只是创建一个简单的WIN32窗口 并没有嵌入MFC.只需设置一些相关的值即可.
Window
void Window::init(int width,int height)
{
/**//** 获得窗口系统的API接口*/
osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
/**//** 创建一个GraphicsContext 的特征表示*/
osg::ref_ptr<osg::GraphicsContext::Traits> _traits = new osg::GraphicsContext::Traits;
/**//** 一个显示器设备一些信息*/
osg::GraphicsContext::ScreenIdentifier is;
is.readDISPLAY();
/**//** get display setting and get the scene width and height*/
unsigned int scenewidth ;
unsigned int sceneheight;
wsi->getScreenResolution(is,scenewidth,sceneheight);
/**//** set window attribute*/
_traits->x = (scenewidth - width)/2;
_traits->y = (sceneheight - height)/2;
_traits->width = width;
_traits->height = height;
_traits->doubleBuffer = true;
_traits->sharedContext = 0;
_traits->windowName = "OSG_CITY";
_traits->windowDecoration =true;
//_traits->useCursor = false;
/**//** create grahicscontext for viewer camara*/
osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(_traits.get());
if(!gc.valid()){
string error("Error: can't create graphiscontext!..");
throw error;
}
_gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc.get());
if(!_gw.valid())
{
string error("Error: can't get the graphisWindow for handle input!");
throw error;
}
//_gw->setCursor(osgViewer::GraphicsWindow::NoCursor);
/**//** set context and viewport*/
_sceneviewer->getCamera()->setGraphicsContext(gc.get());
_sceneviewer->getCamera()->setViewport(0,0,width,height);
/**//** adjust the projectionmatrix*/
double fovy,aspect,znear,zfar;
_sceneviewer->getCamera()->getProjectionMatrixAsPerspective(fovy,aspect,znear,zfar);
double aspectchange = (double)width/(double)height/aspect;
if(aspectchange !=1.0)
_sceneviewer->getCamera()->getProjectionMatrix() *=osg::Matrixd::scale(aspectchange,1.0,1.0);
/**//** set the double buffer */
GLenum buffer = _traits->doubleBuffer ? GL_BACK : GL_FRONT;
_sceneviewer->getCamera()->setDrawBuffer(buffer);
_sceneviewer->getCamera()->setReadBuffer(buffer);
/**//** realize*/
_sceneviewer->realize();
}
void Window::init(int width,int height)
{
/**//** 获得窗口系统的API接口*/
osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
/**//** 创建一个GraphicsContext 的特征表示*/
osg::ref_ptr<osg::GraphicsContext::Traits> _traits = new osg::GraphicsContext::Traits;
/**//** 一个显示器设备一些信息*/
osg::GraphicsContext::ScreenIdentifier is;
is.readDISPLAY();
/**//** get display setting and get the scene width and height*/
unsigned int scenewidth ;
unsigned int sceneheight;
wsi->getScreenResolution(is,scenewidth,sceneheight);
/**//** set window attribute*/
_traits->x = (scenewidth - width)/2;
_traits->y = (sceneheight - height)/2;
_traits->width = width;
_traits->height = height;
_traits->doubleBuffer = true;
_traits->sharedContext = 0;
_traits->windowName = "OSG_CITY";
_traits->windowDecoration =true;
//_traits->useCursor = false;
/**//** create grahicscontext for viewer camara*/
osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(_traits.get());
if(!gc.valid()){
string error("Error: can't create graphiscontext!..");
throw error;
}
_gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc.get());
if(!_gw.valid())
{
string error("Error: can't get the graphisWindow for handle input!");
throw error;
}
//_gw->setCursor(osgViewer::GraphicsWindow::NoCursor);
/**//** set context and viewport*/
_sceneviewer->getCamera()->setGraphicsContext(gc.get());
_sceneviewer->getCamera()->setViewport(0,0,width,height);
/**//** adjust the projectionmatrix*/
double fovy,aspect,znear,zfar;
_sceneviewer->getCamera()->getProjectionMatrixAsPerspective(fovy,aspect,znear,zfar);
double aspectchange = (double)width/(double)height/aspect;
if(aspectchange !=1.0)
_sceneviewer->getCamera()->getProjectionMatrix() *=osg::Matrixd::scale(aspectchange,1.0,1.0);
/**//** set the double buffer */
GLenum buffer = _traits->doubleBuffer ? GL_BACK : GL_FRONT;
_sceneviewer->getCamera()->setDrawBuffer(buffer);
_sceneviewer->getCamera()->setReadBuffer(buffer);
/**//** realize*/
_sceneviewer->realize();
}
最后许多方面的注释将会在源代码中给出.附源代码下载: 下载地址