由于需要自动抓取OSG中的场景截图,对OSG掌握不好,花费了一些时间才算搞定。
首先,OSG在类osgViewer::ScreenCaptureHandler中默认情况下按下c(小写c)可以截取单张图片,而且实现得比较全面,在按下C(大写c)时可以连续截图;经过继承osgViewer::ScreenCaptureHandler类和osgViewer::ScreenCaptureHandler::CaptureOperation类,由于需要自动在某个时刻保存,所以些了一个自定义的事件,并将事件压入OSG的事件队列。
上代码:
ScreenCapture.h文件
#pragma once
#ifndef SCREENCAPTURE_H
#define SCREENCAPTURE_H
#include <string>
#include <osgDB/WriteFile>
#include <osgViewer/ViewerEventHandlers>
class CScreenCapture : public osgViewer::ScreenCaptureHandler
{
public:
class WriteToImageFile : public osgViewer::ScreenCaptureHandler::CaptureOperation
{
public:
enum SavePolicy
{
OVERWRITE,
SEQUENTIAL_NUMBER
// ... any others?
};
WriteToImageFile(const std::string& filename, const std::string& extension, SavePolicy savePolicy = SEQUENTIAL_NUMBER);
virtual void operator()(const osg::Image& image, const unsigned int context_id);
void setFileName(const std::string &filename){ _filename = filename; }
void setSavePolicy(SavePolicy savePolicy) { _savePolicy = savePolicy; }
SavePolicy getSavePolicy() const { return _savePolicy; }
protected:
WriteToImageFile& operator = (const WriteToImageFile&) { return *this; }
std::string _filename;
std::string _extension;
SavePolicy _savePolicy;
std::vector<unsigned int> _contextSaveCounter;
};
CScreenCapture(CaptureOperation* defaultOperation = 0, int numFrames = 1);
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
void setFileName(const std::string& filename );
};
#endif // SCREENCAPTURE_H
ScreenCapture.cpp文件
/****************************************************************************
*
*
*
****************************************************************************/
#include "stdafx.h"
#include "ScreenCapture.h"
CScreenCapture::CScreenCapture(CaptureOperation* defaultOperation /*= 0*/, int numFrames/* = 1*/):
ScreenCaptureHandler( defaultOperation, numFrames )
{
}
bool CScreenCapture::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
{
osgViewer::ViewerBase* viewer = dynamic_cast<osgViewer::View*>(&aa)->getViewerBase();
if (!viewer) return false;
switch(ea.getEventType())
{
case (osgGA::GUIEventAdapter::FRAME):
{
// Booleans aren't the best way of doing this, but I want to do
// the actual adding here because I don't want to require
// startCapture() take a viewer as argument, which could not be
// the right one.
if (_startCapture)
{
// Start capturing with the currently set number of frames.
// If set to -1 it will capture continuously, if set to >0
// it will capture that number of frames.
_startCapture = false;
addCallbackToViewer(*viewer);
}
else if (_stopCapture)
{
_stopCapture = false;
removeCallbackFromViewer(*viewer);
}
break;
}
case ( osgGA::GUIEventAdapter::USER )://自定义的事件,需要进入OSG的事件队列
{
const OwnDefineEventAdpater* adpater= dynamic_cast< const MyEventAdpater *>(ea.getUserData());
switch(adpater->m_eventType)
{
case SAVE_IMAGE:// 保存图片的事件
{
if (getFramesToCapture() == 0)
{
setFramesToCapture(1);
}
addCallbackToViewer(*viewer);
return true;
}
default:
break;
}
//if (adpater->m_eventType == SaveImage )
//{
// // Check that we will capture at least one frame.
// // Just check for ==0, because >0 is means we're already
// // capturing and <0 means it will capture all frames.
// if (getFramesToCapture() == 0)
// {
// setFramesToCapture(1);
// }
// addCallbackToViewer(*viewer);
// return true;
//}
}
default:
break;
}
return false;
}
void CScreenCapture::setFileName( const std::string& filename )
{
CScreenCapture::WriteToImageFile* wtf = dynamic_cast<CScreenCapture::WriteToImageFile*>(getCaptureOperation());
wtf->setFileName( filename );
}
void CScreenCapture::WriteToImageFile::operator()( const osg::Image& image, const unsigned int context_id )//仿函数实现图片保存
{
if ( !_filename.empty() )
{
osgDB::writeImageFile( image, _filename );
}
}
CScreenCapture::WriteToImageFile::WriteToImageFile( const std::string& filename, const std::string& extension, SavePolicy savePolicy /*= SEQUENTIAL_NUMBER*/ )
: _filename( filename ),
_extension( extension ),
_savePolicy( savePolicy )
{
}