/* The main entry */ int main( int argc, char** argv ) { osg::ArgumentParser arguments( &argc, argv ); osg::ApplicationUsage* usage = arguments.getApplicationUsage(); usage->setDescription( arguments.getApplicationName() + " is the example which demonstrates how to render high-resolution images (posters)."); usage->setCommandLineUsage( arguments.getApplicationName() + " [options] scene_file" ); usage->addCommandLineOption( "-h or --help", "Display this information." ); usage->addCommandLineOption( "--color <r> <g> <b>", "The background color." ); usage->addCommandLineOption( "--ext <ext>", "The output tiles' extension (Default: bmp)." ); usage->addCommandLineOption( "--poster <filename>", "The output poster's name (Default: poster.bmp)." ); usage->addCommandLineOption( "--tilesize <w> <h>", "Size of each image tile (Default: 640 480)." ); usage->addCommandLineOption( "--finalsize <w> <h>", "Size of the poster (Default: 6400 4800)." ); usage->addCommandLineOption( "--enable-output-poster", "Output the final poster file (Default)." ); usage->addCommandLineOption( "--disable-output-poster", "Don't output the final poster file." ); //usage->addCommandLineOption( "--enable-output-tiles", "Output all tile files." ); //usage->addCommandLineOption( "--disable-output-tiles", "Don't output all tile files (Default)." ); usage->addCommandLineOption( "--use-fb", "Use Frame Buffer for rendering tiles (Default, recommended)."); usage->addCommandLineOption( "--use-fbo", "Use Frame Buffer Object for rendering tiles."); usage->addCommandLineOption( "--use-pbuffer","Use Pixel Buffer for rendering tiles."); usage->addCommandLineOption( "--use-pbuffer-rtt","Use Pixel Buffer RTT for rendering tiles."); usage->addCommandLineOption( "--inactive", "Inactive capturing mode." ); usage->addCommandLineOption( "--camera-eye <x> <y> <z>", "Set eye position in inactive mode." ); usage->addCommandLineOption( "--camera-latlongheight <lat> <lon> <h>", "Set eye position on earth in inactive mode." ); usage->addCommandLineOption( "--camera-hpr <h> <p> <r>", "Set eye rotation in inactive mode." ); if ( arguments.read("-h") || arguments.read("--help") ) { usage->write( std::cout ); return 1; } // Poster arguments bool activeMode = true; bool outputPoster = true; //bool outputTiles = false; int tileWidth = 640, tileHeight = 480; int posterWidth = 640*2, posterHeight = 480*2; std::string posterName = "poster.bmp", extName = "bmp"; osg::Vec4 bgColor(0.2f, 0.2f, 0.6f, 1.0f); osg::Camera::RenderTargetImplementation renderImplementation = osg::Camera::FRAME_BUFFER_OBJECT; while ( arguments.read("--inactive") ) { activeMode = false; } while ( arguments.read("--color", bgColor.r(), bgColor.g(), bgColor.b()) ) {} while ( arguments.read("--tilesize", tileWidth, tileHeight) ) {} while ( arguments.read("--finalsize", posterWidth, posterHeight) ) {} while ( arguments.read("--poster", posterName) ) {} while ( arguments.read("--ext", extName) ) {} while ( arguments.read("--enable-output-poster") ) { outputPoster = true; } while ( arguments.read("--disable-output-poster") ) { outputPoster = false; } //while ( arguments.read("--enable-output-tiles") ) { outputTiles = true; } //while ( arguments.read("--disable-output-tiles") ) { outputTiles = false; } while ( arguments.read("--use-fbo")) { renderImplementation = osg::Camera::FRAME_BUFFER_OBJECT; } while ( arguments.read("--use-pbuffer")) { renderImplementation = osg::Camera::PIXEL_BUFFER; } while ( arguments.read("--use-pbuffer-rtt")) { renderImplementation = osg::Camera::PIXEL_BUFFER_RTT; } while ( arguments.read("--use-fb")) { renderImplementation = osg::Camera::FRAME_BUFFER; } // Camera settings for inactive screenshot bool useLatLongHeight = true; osg::Vec3d eye; osg::Vec3d latLongHeight( 50.0, 10.0, 2000.0 ); osg::Vec3d hpr( 0.0, 0.0, 0.0 ); if ( arguments.read("--camera-eye", eye.x(), eye.y(), eye.z()) ) { useLatLongHeight = false; activeMode = false; } else if ( arguments.read("--camera-latlongheight", latLongHeight.x(), latLongHeight.y(), latLongHeight.z()) ) { activeMode = false; latLongHeight.x() = osg::DegreesToRadians( latLongHeight.x() ); latLongHeight.y() = osg::DegreesToRadians( latLongHeight.y() ); } if ( arguments.read("--camera-hpr", hpr.x(), hpr.y(), hpr.z()) ) { activeMode = false; hpr.x() = osg::DegreesToRadians( hpr.x() ); hpr.y() = osg::DegreesToRadians( hpr.y() ); hpr.z() = osg::DegreesToRadians( hpr.z() ); } // Construct scene graph osg::ref_ptr<osg::Node> scene = osgDB::readRefNodeFiles( arguments ); if ( !scene ) scene = osgDB::readRefNodeFile( "cow.osgt" ); if ( !scene ) { std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl; return 1; } // Create camera for rendering tiles offscreen. FrameBuffer is recommended because it requires less memory. osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setClearColor( bgColor ); camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF ); camera->setRenderOrder( osg::Camera::PRE_RENDER ); camera->setRenderTargetImplementation( renderImplementation ); camera->setViewport( 0, 0, tileWidth, tileHeight ); camera->addChild( scene ); // Set the printer osg::ref_ptr<PosterPrinter> printer = new PosterPrinter; printer->setTileSize( tileWidth, tileHeight ); printer->setPosterSize( posterWidth, posterHeight ); printer->setCamera( camera.get() ); osg::ref_ptr<osg::Image> posterImage = 0; if ( outputPoster ) { posterImage = new osg::Image; posterImage->allocateImage( posterWidth, posterHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE ); printer->setFinalPoster( posterImage.get() ); printer->setOutputPosterName( posterName ); } #if 0 // While recording sub-images of the poster, the scene will always be traversed twice, from its two // parent node: root and camera. Sometimes this may not be so comfortable. // To prevent this behaviour, we can use a switch node to enable one parent and disable the other. // However, the solution also needs to be used with care, as the window will go blank while taking // snapshots and recover later. osg::ref_ptr<osg::Switch> root = new osg::Switch; root->addChild( scene, true ); root->addChild( camera.get(), false ); #else osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild( scene ); root->addChild( camera.get() ); #endif osgViewer::Viewer viewer; viewer.setSceneData( root.get() ); viewer.getDatabasePager()->setDoPreCompile( false ); if ( renderImplementation==osg::Camera::FRAME_BUFFER ) { // FRAME_BUFFER requires the window resolution equal or greater than the to-be-copied size viewer.setUpViewInWindow( 100, 100, tileWidth, tileHeight ); } else { // We want to see the console output, so just render in a window viewer.setUpViewInWindow( 100, 100, 800, 600 ); } if ( activeMode ) { viewer.addEventHandler( new PrintPosterHandler(printer.get()) ); viewer.addEventHandler( new osgViewer::StatsHandler ); viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) ); viewer.setCameraManipulator( new osgGA::TrackballManipulator ); viewer.run(); } else { osg::Camera* camera = viewer.getCamera(); if ( !useLatLongHeight ) computeViewMatrix( camera, eye, hpr ); else computeViewMatrixOnEarth( camera, scene.get(), latLongHeight, hpr ); osg::ref_ptr<CustomRenderer> renderer = new CustomRenderer( camera ); camera->setRenderer( renderer.get() ); viewer.setThreadingModel( osgViewer::Viewer::SingleThreaded ); // Realize and initiate the first PagedLOD request viewer.realize(); viewer.frame(); printer->init( camera ); while ( !printer->done() ) { viewer.advance(); // Keep updating and culling until full level of detail is reached renderer->setCullOnly( true ); while ( viewer.getDatabasePager()->getRequestsInProgress() ) { viewer.updateTraversal(); viewer.renderingTraversals(); } renderer->setCullOnly( false ); printer->frame( viewer.getFrameStamp(), viewer.getSceneData() ); viewer.renderingTraversals(); } } return 0; }
/* The main entry */ int render(osg::Node *scene,osg::ref_ptr<osg::Image> &image,osg::GraphicsContext &gc,osg::Matrix &toScreen,const osg::Vec4 &sizes) { // Poster arguments bool activeMode = false; bool outputPoster = true; assert(sizes[2]== sizes[3]); int tileWidth = sizes[0], tileHeight = sizes[1]; int posterWidth = sizes[2], posterHeight = sizes[3]; std::string posterName = "poster.bmp", extName = "bmp"; osg::Vec4 bgColor(0.2f, 0.2f, 0.6f, 1.0f); osg::Camera::RenderTargetImplementation renderImplementation = osg::Camera::FRAME_BUFFER_OBJECT; // Camera settings for inactive screenshot osg::Vec3d latLongHeight( 50.0, 10.0, 2000.0 ); osg::Vec3d hpr( 0.0, 0.0, 0.0 ); const osg::BoundingSphere &bs=scene->getBound(); osg::Vec3d eye(bs.center()+osg::Vec3(0,0,3.5*bs.radius())); osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN); scene->traverse(cbbv); osg::BoundingBox bb = cbbv.getBoundingBox(); if ( !scene ) { std::cout << "No data loaded" << std::endl; return 1; } // Create camera for rendering tiles offscreen. FrameBuffer is recommended because it requires less memory. osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setClearColor( bgColor ); camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF ); camera->setRenderOrder( osg::Camera::PRE_RENDER ); camera->setRenderTargetImplementation( renderImplementation ); camera->setViewport( 0, 0, tileWidth, tileHeight ); camera->addChild( scene ); // Set the printer osg::ref_ptr<PosterPrinter> printer = new PosterPrinter; printer->setTileSize( tileWidth, tileHeight ); printer->setPosterSize( posterWidth, posterHeight ); printer->setCamera( camera.get() ); if ( outputPoster ) { image = new osg::Image; image->allocateImage( posterWidth, posterHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE ); printer->setFinalPoster( image.get() ); printer->setOutputPosterName( posterName ); } #if 0 // While recording sub-images of the poster, the scene will always be traversed twice, from its two // parent node: root and camera. Sometimes this may not be so comfortable. // To prevent this behaviour, we can use a switch node to enable one parent and disable the other. // However, the solution also needs to be used with care, as the window will go blank while taking // snapshots and recover later. osg::ref_ptr<osg::Switch> root = new osg::Switch; root->addChild( scene, true ); root->addChild( camera.get(), false ); #else osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild( scene ); root->addChild( camera.get() ); #endif osgViewer::Viewer viewer; viewer.setSceneData( root.get() ); viewer.getDatabasePager()->setDoPreCompile( false ); viewer.getCamera()->setGraphicsContext(&gc); if ( renderImplementation==osg::Camera::FRAME_BUFFER ) { // FRAME_BUFFER requires the window resolution equal or greater than the to-be-copied size viewer.setUpViewInWindow( 200, 200, tileWidth, tileHeight ); } else { // We want to see the console output, so just render in a window // viewer.setUpViewInWindow( 200, 200, tileWidth, tileHeight ); viewer.getCamera()->setViewport(new osg::Viewport(0,0,tileWidth,tileHeight)); } if ( activeMode ) { //viewer.addEventHandler( new PrintPosterHandler(printer.get()) ); viewer.addEventHandler( new osgViewer::StatsHandler ); viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) ); viewer.setCameraManipulator( new osgGA::TrackballManipulator ); viewer.run(); } else { osg::Camera* camera = viewer.getCamera(); computeViewMatrix( camera, eye, hpr ); osg::Vec3 centeredMin,centeredMax; centeredMin=(bb._min-bb.center()); centeredMax=(bb._max-bb.center()); // camera->setProjectionMatrixAsOrtho2D(-bs.radius(),bs.radius(),-bs.radius(),bs.radius()); camera->setProjectionMatrixAsOrtho2D(centeredMin[0],centeredMax[0],centeredMin[1],centeredMax[1]); toScreen=getToScreenMatrix(camera,osg::Vec2(posterWidth,posterHeight)); osg::ref_ptr<CustomRenderer> renderer = new CustomRenderer( camera ); camera->setRenderer( renderer.get() ); viewer.setThreadingModel( osgViewer::Viewer::SingleThreaded ); // Realize and initiate the first PagedLOD request viewer.realize(); viewer.frame(); printer->init( camera ); while ( !printer->done() ) { viewer.advance(); // Keep updating and culling until full level of detail is reached renderer->setCullOnly( true ); while ( viewer.getDatabasePager()->getRequestsInProgress() ) { viewer.updateTraversal(); viewer.renderingTraversals(); } renderer->setCullOnly( false ); printer->frame( viewer.getFrameStamp(), viewer.getSceneData() ); viewer.renderingTraversals(); } } return 0; }