From John Vidar Larring, osgautocapture example that captures an image from a paged database by frame loop to the paging is complete, then takes a snapshot.
This commit is contained in:
parent
b2762c4788
commit
270fd48536
@ -21,6 +21,7 @@ IF(DYNAMIC_OPENSCENEGRAPH)
|
||||
ADD_SUBDIRECTORY(osgautotransform)
|
||||
ADD_SUBDIRECTORY(osgbillboard)
|
||||
ADD_SUBDIRECTORY(osgblendequation)
|
||||
ADD_SUBDIRECTORY(osgautocapture)
|
||||
ADD_SUBDIRECTORY(osgcallback)
|
||||
ADD_SUBDIRECTORY(osgcamera)
|
||||
ADD_SUBDIRECTORY(osgcatch)
|
||||
|
4
examples/osgautocapture/CMakeLists.txt
Normal file
4
examples/osgautocapture/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
SET(TARGET_SRC osgautocapture.cpp )
|
||||
|
||||
#### end var setup ###
|
||||
SETUP_EXAMPLE(osgautocapture)
|
346
examples/osgautocapture/osgautocapture.cpp
Normal file
346
examples/osgautocapture/osgautocapture.cpp
Normal file
@ -0,0 +1,346 @@
|
||||
/**
|
||||
* TODO:
|
||||
* 1) Change example to use offscreen rendering (pbuffer) so that it becomes a true commandline tool with now windows
|
||||
* 2) Make example work with other threading models than SingleThreaded
|
||||
* 3) Add support for autocapture to movies
|
||||
*
|
||||
*/
|
||||
#include <osg/ArgumentParser>
|
||||
#include <osg/CoordinateSystemNode>
|
||||
#include <osg/Matrix>
|
||||
#include <osg/NodeVisitor>
|
||||
|
||||
#include <osgUtil/IntersectionVisitor>
|
||||
#include <osgUtil/GLObjectsVisitor>
|
||||
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osgDB/WriteFile>
|
||||
|
||||
#include <osgGA/DriveManipulator>
|
||||
#include <osgGA/FlightManipulator>
|
||||
#include <osgGA/KeySwitchMatrixManipulator>
|
||||
#include <osgGA/TerrainManipulator>
|
||||
#include <osgGA/TrackballManipulator>
|
||||
|
||||
#include <osgTerrain/Terrain>
|
||||
#include <osgTerrain/GeometryTechnique>
|
||||
|
||||
#include <osgViewer/Viewer>
|
||||
#include <osgViewer/ViewerEventHandlers>
|
||||
#include <osgViewer/Renderer>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
/** Helper class*/
|
||||
template<class T>
|
||||
class FindTopMostNodeOfTypeVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
FindTopMostNodeOfTypeVisitor():
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
_foundNode(0)
|
||||
{}
|
||||
|
||||
void apply(osg::Node& node)
|
||||
{
|
||||
T* result = dynamic_cast<T*>(&node);
|
||||
if (result)
|
||||
_foundNode = result;
|
||||
else
|
||||
traverse(node);
|
||||
}
|
||||
|
||||
T* _foundNode;
|
||||
};
|
||||
|
||||
/** Convenience function*/
|
||||
template<class T>
|
||||
T* findTopMostNodeOfType(osg::Node* node)
|
||||
{
|
||||
if (!node) return 0;
|
||||
|
||||
FindTopMostNodeOfTypeVisitor<T> fnotv;
|
||||
node->accept(fnotv);
|
||||
|
||||
return fnotv._foundNode;
|
||||
}
|
||||
|
||||
/** Capture the frame buffer and write image to disk*/
|
||||
class WindowCaptureCallback : public osg::Camera::DrawCallback
|
||||
{
|
||||
public:
|
||||
WindowCaptureCallback(GLenum readBuffer, const std::string& name):
|
||||
_readBuffer(readBuffer),
|
||||
_fileName(name)
|
||||
{
|
||||
_image = new osg::Image;
|
||||
}
|
||||
|
||||
virtual void operator () (osg::RenderInfo& renderInfo) const
|
||||
{
|
||||
glReadBuffer(_readBuffer);
|
||||
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
osg::GraphicsContext* gc = renderInfo.getState()->getGraphicsContext();
|
||||
if (gc->getTraits())
|
||||
{
|
||||
GLenum pixelFormat;
|
||||
|
||||
if (gc->getTraits()->alpha)
|
||||
pixelFormat = GL_RGBA;
|
||||
else
|
||||
pixelFormat = GL_RGB;
|
||||
|
||||
int width = gc->getTraits()->width;
|
||||
int height = gc->getTraits()->height;
|
||||
|
||||
std::cout<<"Capture: size="<<width<<"x"<<height<<", format="<<(pixelFormat == GL_RGBA ? "GL_RGBA":"GL_RGB")<<std::endl;
|
||||
|
||||
_image->readPixels(0, 0, width, height, pixelFormat, GL_UNSIGNED_BYTE);
|
||||
}
|
||||
|
||||
if (!_fileName.empty())
|
||||
{
|
||||
std::cout << "Writing to: " << _fileName << std::endl;
|
||||
osgDB::writeImageFile(*_image, _fileName);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
GLenum _readBuffer;
|
||||
std::string _fileName;
|
||||
osg::ref_ptr<osg::Image> _image;
|
||||
mutable OpenThreads::Mutex _mutex;
|
||||
};
|
||||
|
||||
|
||||
/** Do Culling only while loading PagedLODs*/
|
||||
class CustomRenderer : public osgViewer::Renderer
|
||||
{
|
||||
public:
|
||||
CustomRenderer(osg::Camera* camera)
|
||||
: osgViewer::Renderer(camera),
|
||||
_cullOnly(true)
|
||||
{
|
||||
setTargetFrameRate(1);
|
||||
setMinimumTimeAvailableForGLCompileAndDeletePerFrame(1);
|
||||
}
|
||||
|
||||
/** Set flag to omit drawing in renderingTraversals */
|
||||
void setCullOnly(bool on) { _cullOnly = on; }
|
||||
|
||||
virtual void operator () (osg::GraphicsContext* /*context*/)
|
||||
{
|
||||
if (_graphicsThreadDoesCull)
|
||||
{
|
||||
if (_cullOnly)
|
||||
cull();
|
||||
else
|
||||
cull_draw();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void cull()
|
||||
{
|
||||
osgUtil::SceneView* sceneView = _sceneView[0].get();
|
||||
if (!sceneView || _done ) return;
|
||||
|
||||
updateSceneView(sceneView);
|
||||
|
||||
osgViewer::View* view = dynamic_cast<osgViewer::View*>(_camera->getView());
|
||||
if (view) sceneView->setFusionDistance(view->getFusionDistanceMode(), view->getFusionDistanceValue());
|
||||
|
||||
sceneView->inheritCullSettings(*(sceneView->getCamera()));
|
||||
sceneView->cull();
|
||||
}
|
||||
|
||||
bool _cullOnly;
|
||||
};
|
||||
|
||||
|
||||
//===============================================================
|
||||
// MAIN
|
||||
//
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
osg::ArgumentParser arguments(&argc, argv);
|
||||
osg::ApplicationUsage* usage = arguments.getApplicationUsage();
|
||||
|
||||
usage->setApplicationName(arguments.getApplicationName());
|
||||
usage->setDescription(arguments.getApplicationName()+" loads a model, sets a camera position and automatically captures screenshot to disk");
|
||||
usage->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
|
||||
usage->addCommandLineOption("--camera <lat> <lon> <alt> <heading> <incline> <roll>", "Specify camera position for image capture. Angles are specified in degrees and altitude in meters above sealevel (e.g. --camera 55 10 300000 0 30 0)");
|
||||
usage->addCommandLineOption("--filename", "Filename for the captured image", "autocapture.jpg");
|
||||
usage->addCommandLineOption("--db-threads", "Number of DatabasePager threads to use", "2");
|
||||
usage->addCommandLineOption("--active", "Use active rendering instead of passive / lazy rendering");
|
||||
|
||||
// Construct the viewer and register options arguments.
|
||||
osgViewer::Viewer viewer(arguments);
|
||||
|
||||
if (arguments.argc()<=1)
|
||||
{
|
||||
arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get user specified number of DatabaseThreads
|
||||
int dbThreads = 2;
|
||||
arguments.read("--db-threads", dbThreads);
|
||||
if (dbThreads < 1) dbThreads = 1;
|
||||
|
||||
osg::DisplaySettings::instance()->setNumOfDatabaseThreadsHint(dbThreads);
|
||||
|
||||
// Get user specified file name
|
||||
std::string fileName("autocapture.jpg");
|
||||
arguments.read("--filename", fileName);
|
||||
|
||||
// Rendering mode is passive by default
|
||||
bool activeMode = false;
|
||||
if (arguments.read("--active"))
|
||||
activeMode = true;
|
||||
|
||||
// Read camera settings for screenshot
|
||||
double lat=50;
|
||||
double lon=10;
|
||||
double alt=2000;
|
||||
double heading=0;
|
||||
double incline=45;
|
||||
double roll=0;
|
||||
bool camera_specified=false;
|
||||
if (arguments.read("--camera", lat, lon, alt, heading, incline, roll))
|
||||
{
|
||||
camera_specified=true;
|
||||
lat = lat * M_PI / 180.0; // Convert to radians
|
||||
lon = lon * M_PI / 180.0; // Convert to radians
|
||||
heading = heading * M_PI / 180.0; // Convert to radians
|
||||
incline = incline * M_PI / 180.0; // Convert to radians
|
||||
roll = roll * M_PI / 180.0; // Convert to radians
|
||||
}
|
||||
|
||||
// load the data
|
||||
osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
|
||||
if (!loadedModel)
|
||||
{
|
||||
std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// any option left unread are converted into errors to write out later.
|
||||
arguments.reportRemainingOptionsAsUnrecognized();
|
||||
|
||||
// report any errors if they have occurred when parsing the program arguments.
|
||||
if (arguments.errors())
|
||||
{
|
||||
arguments.writeErrorMessages(std::cout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Setup specified camera
|
||||
if (camera_specified)
|
||||
{
|
||||
osg::CoordinateSystemNode* csn = findTopMostNodeOfType<osg::CoordinateSystemNode>(loadedModel.get());
|
||||
if(!csn) return 1;
|
||||
|
||||
// Compute eye point in world coordiantes
|
||||
osg::Vec3d eye;
|
||||
csn->getEllipsoidModel()->convertLatLongHeightToXYZ(lat, lon, alt, eye.x(), eye.y(), eye.z());
|
||||
|
||||
// Build matrix for computing target vector
|
||||
osg::Matrixd target_matrix = osg::Matrixd::rotate(-heading, osg::Vec3d(1,0,0),
|
||||
-lat, osg::Vec3d(0,1,0),
|
||||
lon, osg::Vec3d(0,0,1));
|
||||
|
||||
// Compute tangent vector ...
|
||||
osg::Vec3d tangent = target_matrix.preMult(osg::Vec3d(0, 0, 1));
|
||||
|
||||
// Compute non-inclined, non-rolled up vector ...
|
||||
osg::Vec3d up(eye);
|
||||
up.normalize();
|
||||
|
||||
// Incline by rotating the target- and up vector around the tangent/up-vector
|
||||
// cross-product ...
|
||||
osg::Vec3d up_cross_tangent = up ^ tangent;
|
||||
osg::Matrixd incline_matrix = osg::Matrixd::rotate(incline, up_cross_tangent);
|
||||
osg::Vec3d target = incline_matrix.preMult(tangent);
|
||||
|
||||
// Roll by rotating the up vector around the target vector ...
|
||||
osg::Matrixd roll_matrix = incline_matrix * osg::Matrixd::rotate(roll, target);
|
||||
up = roll_matrix.preMult(up);
|
||||
|
||||
viewer.getCamera()->setViewMatrixAsLookAt(eye, eye+target, up);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only add camera manipulators if camera is not specified
|
||||
camera_specified=false;
|
||||
osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
|
||||
|
||||
keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
|
||||
keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
|
||||
keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
|
||||
keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
|
||||
}
|
||||
|
||||
|
||||
// Optimize DatabasePager for auto-capture
|
||||
osgDB::DatabasePager* pager = viewer.getDatabasePager();
|
||||
pager->setDoPreCompile(false);
|
||||
|
||||
// Install custom renderer
|
||||
osg::ref_ptr<CustomRenderer> customRenderer = new CustomRenderer(viewer.getCamera());
|
||||
viewer.getCamera()->setRenderer(customRenderer.get());
|
||||
|
||||
// Override threading model
|
||||
viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
|
||||
|
||||
// Set the final SceneData to show
|
||||
viewer.setSceneData(loadedModel.get());
|
||||
|
||||
// Realize GUI
|
||||
viewer.realize();
|
||||
|
||||
//--- Load PageLOD tiles ---
|
||||
|
||||
// Initiate the first PagedLOD request
|
||||
viewer.frame();
|
||||
|
||||
osg::Timer_t beforeLoadTick = osg::Timer::instance()->tick();
|
||||
|
||||
// Keep updating and culling until full level of detail is reached
|
||||
while(!viewer.done() && pager->getRequestsInProgress())
|
||||
{
|
||||
// std::cout <<pager->getRequestsInProgress()<<" ";
|
||||
viewer.updateTraversal();
|
||||
viewer.renderingTraversals();
|
||||
}
|
||||
// std::cout<<std::endl;
|
||||
|
||||
osg::Timer_t afterLoadTick = osg::Timer::instance()->tick();
|
||||
std::cout<<"Load and Compile time = "<<osg::Timer::instance()->delta_s(beforeLoadTick, afterLoadTick)<<" seconds"<<std::endl;
|
||||
|
||||
|
||||
//--- Capture the image!!! ---
|
||||
if (!activeMode)
|
||||
{
|
||||
// Do cull and draw to render the scene correctly
|
||||
customRenderer->setCullOnly(false);
|
||||
|
||||
// Add the WindowCaptureCallback now that we have full resolution
|
||||
viewer.getCamera()->setFinalDrawCallback(new WindowCaptureCallback(GL_BACK, fileName));
|
||||
|
||||
osg::Timer_t beforeRenderTick = osg::Timer::instance()->tick();
|
||||
|
||||
// Do rendering with capture callback
|
||||
viewer.renderingTraversals();
|
||||
|
||||
osg::Timer_t afterRenderTick = osg::Timer::instance()->tick();
|
||||
std::cout<<"Rendring time = "<<osg::Timer::instance()->delta_s(beforeRenderTick, afterRenderTick) <<" seconds"<<std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return viewer.run();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user