/* OpenSceneGraph example, osgthirdpersonview. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // This code is originally Copyright (c) 2008 Skew Matrix Software LLC, // but you may use the code under the terms of the OSGPL as described above. // This example demonstrates how CompositeViewer can be used to // provide a third person view of another view, including eyepoint and // view frustum. // // The code creates a CompositeViewer with two Views. Each of the two // Views has its own window. One View is the typical scene view, // showing the loaded model(s). // // The second View is a third person view showing not just the loaded // model(s), but also a wireframe representation of the first View's // frustum. Interactions with the first View are reflect5ed in the // second View's displayed frustum. // // Command line arguments are taken to be models for display. If you // specify no command line arguments, the code attempts to load cow.osg. #include #include #include #include #include #include #include // Given a Camera, create a wireframe representation of its // view frustum. Create a default representation if camera==NULL. osg::Node* makeFrustumFromCamera( osg::Camera* camera ) { // Projection and ModelView matrices osg::Matrixd proj; osg::Matrixd mv; if (camera) { proj = camera->getProjectionMatrix(); mv = camera->getViewMatrix(); } else { // Create some kind of reasonable default Projection matrix. proj.makePerspective( 30., 1., 1., 10. ); // leave mv as identity } // Get near and far from the Projection matrix. const double near = proj(3,2) / (proj(2,2)-1.0); const double far = proj(3,2) / (1.0+proj(2,2)); // Get the sides of the near plane. const double nLeft = near * (proj(2,0)-1.0) / proj(0,0); const double nRight = near * (1.0+proj(2,0)) / proj(0,0); const double nTop = near * (1.0+proj(2,1)) / proj(1,1); const double nBottom = near * (proj(2,1)-1.0) / proj(1,1); // Get the sides of the far plane. const double fLeft = far * (proj(2,0)-1.0) / proj(0,0); const double fRight = far * (1.0+proj(2,0)) / proj(0,0); const double fTop = far * (1.0+proj(2,1)) / proj(1,1); const double fBottom = far * (proj(2,1)-1.0) / proj(1,1); // Our vertex array needs only 9 vertices: The origin, and the // eight corners of the near and far planes. osg::Vec3Array* v = new osg::Vec3Array; v->resize( 9 ); (*v)[0].set( 0., 0., 0. ); (*v)[1].set( nLeft, nBottom, -near ); (*v)[2].set( nRight, nBottom, -near ); (*v)[3].set( nRight, nTop, -near ); (*v)[4].set( nLeft, nTop, -near ); (*v)[5].set( fLeft, fBottom, -far ); (*v)[6].set( fRight, fBottom, -far ); (*v)[7].set( fRight, fTop, -far ); (*v)[8].set( fLeft, fTop, -far ); osg::Geometry* geom = new osg::Geometry; geom->setUseDisplayList( false ); geom->setVertexArray( v ); osg::Vec4Array* c = new osg::Vec4Array; c->push_back( osg::Vec4( 1., 1., 1., 1. ) ); geom->setColorArray( c ); geom->setColorBinding( osg::Geometry::BIND_OVERALL ); GLushort idxLines[8] = { 0, 5, 0, 6, 0, 7, 0, 8 }; GLushort idxLoops0[4] = { 1, 2, 3, 4 }; GLushort idxLoops1[4] = { 5, 6, 7, 8 }; geom->addPrimitiveSet( new osg::DrawElementsUShort( osg::PrimitiveSet::LINES, 8, idxLines ) ); geom->addPrimitiveSet( new osg::DrawElementsUShort( osg::PrimitiveSet::LINE_LOOP, 4, idxLoops0 ) ); geom->addPrimitiveSet( new osg::DrawElementsUShort( osg::PrimitiveSet::LINE_LOOP, 4, idxLoops1 ) ); osg::Geode* geode = new osg::Geode; geode->addDrawable( geom ); geode->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED ); // Create parent MatrixTransform to transform the view volume by // the inverse ModelView matrix. osg::MatrixTransform* mt = new osg::MatrixTransform; mt->setMatrix( osg::Matrixd::inverse( mv ) ); mt->addChild( geode ); return mt; } int main( int argc, char ** argv ) { osg::ArgumentParser arguments( &argc, argv ); osg::ref_ptr< osg::Group > root = new osg::Group; // Child 0: We'll replace this every frame with an updated representation // of the view frustum. root->addChild( makeFrustumFromCamera( NULL ) ); osg::ref_ptr< osg::Node > scene; scene = osgDB::readNodeFiles( arguments ); if (!scene) { // User didn't specify anything, or file(s) didn't exist. // Try to load the cow... osg::notify( osg::WARN ) << arguments.getApplicationName() << ": Could not find specified files. Trying \"cow.osg\" instead." << std::endl; if ( !(scene = osgDB::readNodeFile( std::string( "cow.osg" ) ) ) ) { osg::notify( osg::FATAL ) << arguments.getApplicationName() << ": No data loaded." << std::endl; return 1; } } root->addChild( scene.get() ); osgViewer::CompositeViewer viewer( arguments ); // Turn on FSAA, makes the lines look better. osg::DisplaySettings::instance()->setNumMultiSamples( 4 ); // Create View 0 -- Just the loaded model. { osgViewer::View* view = new osgViewer::View; viewer.addView( view ); view->setUpViewInWindow( 10, 10, 640, 480 ); view->setSceneData( scene.get() ); view->setCameraManipulator( new osgGA::TrackballManipulator ); } // Create view 1 -- Contains the loaded moel, as well as a wireframe frustum derived from View 0's Camera. { osgViewer::View* view = new osgViewer::View; viewer.addView( view ); view->setUpViewInWindow( 10, 510, 640, 480 ); view->setSceneData( root.get() ); view->setCameraManipulator( new osgGA::TrackballManipulator ); } while (!viewer.done()) { // Update the wireframe frustum root->removeChild( 0, 1 ); root->insertChild( 0, makeFrustumFromCamera( viewer.getView( 0 )->getCamera() ) ); viewer.frame(); } return 0; }