OpenSceneGraph based on materials from http://www.openscenegraph.org/ Katia Oleinik: koleinik@bu.edu Agenda: • • • • • • • • • Introduction to OpenSceneGraph Hardware requirements Overview of OSG structure First example – displaying a model Building primitives Transformations Using OpenGL primitives Texture Special nodes Introduction to OpenSceneGraph OpenSceneGraph • an open source 3D graphics API (application programming interface) • used for - visual simulation, - computer games, - scientific visualization, - modeling, - training, etc. Introduction to OpenSceneGraph OpenSceneGraph • written in C++ (encourages object oriented programming); • runs on a number of operating systems, including: - MS Windows - Max OS X - Linux - IRIX - Solaris - Sony Playstation uses OpenGL for rendering (allows for high performance graphics); supports the standard template library (STL); Introduction to OpenSceneGraph OpenSceneGraph 3.0 Features: • Support for performance increasing features o View frustum, small feature and occlusion culling o Level of detail (LOD) o State sorting and lazy state updating o OpenGL latest extensions o Multi-threading and database optimization • Support for OpenGL, from 1.1 through 2.0 including the latest extensions • Support for OpenGL Shading Language • Support for a wide range of 2D image and 3D database formats • Loaders available for OpenFlight, TerraPage, OBJ, 3DS, JPEG, PNG and GeoTIFF • Particle effects • Support for anti-aliased TrueType text • Multi-threaded and configurable support for multiple CPU/multiple GPU machines Introduction to OpenSceneGraph OpenSceneGraph 3.0 latest updates: • • • • Support for Windows MS Visual Studio Support for Android on tablets and phones Support for IOS (iPhone OS) on tablets and phones Improvements to osgVolume class enabling high quality volume rendering FightGear Flight Simulator FightGear Flight Simulator FightGear Flight Simulator Hardware requirements Processor • OSG runs on most contemporary CPUs. • OSG is thread-safe and can take advantage of multi-processor and dual core architectures. • OSG runs on both 32- and 64-bit processors. Graphics • OSG requires graphics hardware with robust OpenGL support • 256 MB of graphics RAM – good starting point RAM • 1GB – good enough for many application, but you might need more, depending on your dataset Disc • Depends on your data requirements Overview of OSG structure Overview of OSG structure Root Matrix Geode Drawable Transformation Geode Transformation Geode Drawable Matrix Drawable First example – displaying a model • ex_simple_viewer.cpp // load the nodes from the command line arguments. osg::Node* model = osgDB::readNodeFile(argv[1]); // initialize the viewer and set the scene to render osgViewer::Viewer viewer; viewer.setSceneData(model); // run viewer return viewer.run(); Root Node First example – displaying a model • ex_simple_viewer.cpp: compiling, linking and running To compile and link % make ex_simple_viewer To run the viewer % ex_simple_viewer cow.obj First button – rotate the model Second button – translate Third button – scale Press “q” (“Esc” for Windows) button to exit First example – displaying a model • ex_viewer_args.cpp // call argument parser osg::ArgumentParser arguments (&argc, argv); std::string filename; // define the argument line option arguments.read("--model", filename); // load the nodes from the command line arguments osg::Node* model = osgDB::readNodeFile(filename); First example – displaying a model • ex_viewer_args.cpp: running To compile and link % make ex_viewer_args To run the viewer % ex_viewer_args –-model cow.obj Try a few different models: dumptruck.osg teapot.osg First example – displaying a model • Input OSG model file structure Geode { name "teapot.osg" nodeMask 0xffffffff cullingActive TRUE num_drawables 1 Geometry { DataVariance STATIC useDisplayList FALSE useVertexBufferObjects TRUE PrimitiveSets 1 { DrawArrays TRIANGLES 0 9744 } VertexArray Vec3Array 9744 { 0.367875 -0 0.237053 0.375 -0 0.225 0.365248 0.086895 0.225 ..... } ColorBinding OVERALL ColorArray Vec4Array 1 { 1 1 1 1 } } } Building geometric primitives • ex_simple_cone.cpp // Create a vector to represent the "center of the cone" Vec3 vcen(xcen, ycen, zcen); osg::Cone* cone = new Cone(vcen, radius, height); cone // Create a drawable object based on the cone osg::ShapeDrawable *drawable = new ShapeDrawable(cone); // create a new geode (root node) osg::Geode* geode = new Geode(); geode->addDrawable(drawable); Root Node Drawable Geode Building geometric primitives • Improving ex_simple_cone.cpp // Create a vector to represent the "center of the cone" osg:: Vec3 vcen(xcen, ycen, zcen); osg::Cone* cone = new Cone(vcen, radius, height); cone // Create a drawable object based on the cone osg:: ShapeDrawable *drawable = new ShapeDrawable(cone); drawable->setColor(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); Drawable // create a new geode osg:: Geode* geode = new Geode(); geode->addDrawable(drawable); Geode // create a root node osg::Group *root = new osg::Group(); root->addChild(geode); Root Node Building geometric primitives • ex_simple_cone.cpp To compile and link % make ex_simple_cone To run the viewer % ex_simple_cone Building geometric primitives • ex_simple_cone.cpp OSG comes with a number of primitives Box Sphere Cone Cylinder Capsule Special shapes (e.g. InfinitePlane) • ex_arrow.cpp // Create a cone and a cylinder Geode *make_cone( float xcen, …){} Geode *make_cylinder( float xcen, …){} Building geometric primitives cone cylinder // create an arrow, as a transform node MatrixTransform* arrow = new MatrixTransform; arrow->setMatrix(Matrix::scale(1.0, 1.0, 1.0)); arrow->addChild(cone); arrow->addChild(cylinder); Transform Matrix // add the arrow to the upper transform MatrixTransform* mt = new MatrixTransform(); mt->setMatrix( Matrix::rotate(inDegrees(30.0), 1.0, 0.0, 0.0)); Transform Matrix mt->addChild(arrow); // create a root node osg::Group *root = new osg::Group(); root->addChild(mt); Root Node • Exercise Building 3 arrows Building geometric primitives cone cone cone cylinder cylinder cylinder Transform Matrix Transform Matrix Transform Matrix Root Node Transform Matrix • Exercise: Building 3 arrows Building geometric primitives Group *make_vec_arrow(float shaft_radius, float total_length, float r, float g, float b) { float cone_radius = 2*shaft_radius; float cone_height = cone_radius; float shaft_length = total_length - cone_height; osg::Geode *cylinder = make_cylinder(0.0, 0.0, shaft_length/2.0, shaft_radius, shaft_length, r,g,b,1.0); osg::Geode *cone = make_cone(0.0, 0.0, shaft_length + cone_height/4.0, cone_radius, cone_height, r, g, b, 1.0); osg::Group* vec_arrow = new Group; vec_arrow->addChild(cylinder); vec_arrow->addChild(cone); return vec_arrow; } osg::Group *red_arrow = make_vec_arrow(…); osg::MatrixTransform* xaxis = new MatrixTransform; xaxis->addChild(red_arrow); xaxis->setMatrix(…); • Reusing the geometry Building geometric primitives Faces Vertices Colors Geometry Geode 1 Transform Matrix Geode 2 Geode 3 Transform Matrix Transform Matrix Transform Matrix Root Node • PrimitiveSet Class 1 3 4 3 2 Lines 2 1 2 0 1 LineStrip 1 2 3 4 3 4 0 3 Points 0 4 1 2 Using OpenGL primitives 3 2 4 0 1 LineLoop 5 6 0 1 Triangles Polygon 2 3 0 1 Quads 0 2 4 TriangleStrip 1 0 4 0 5 7 2 4 QuadStrip 6 3 5 3 1 2 TriangleFan • PrimitiveSet Class Using OpenGL primitives osg::Group *root = new osg::Group(); Group … osg::Geode* primGeode = new osg::Geode(); root->addChild(primGeode); Geode … osg::Geometry* primGeom = new osg::Geometry(); primGeode->addDrawable(primGeom); Geometry … viewer.setSceneData(root) Vertices Faces Colors Texture • PrimitiveSet Class osg::Vec3Array* pyramidVertices = new osg::Vec3Array; pyramidVertices->push_back( osg::Vec3( 0, 0, 0) ); // pyramidVertices->push_back( osg::Vec3(10, 0, 0) ); // pyramidVertices->push_back( osg::Vec3(10,10, 0) ); // pyramidVertices->push_back( osg::Vec3( 0,10, 0) ); // pyramidVertices->push_back( osg::Vec3( 5, 5,10) ); // Using OpenGL primitives front left front right back right back left peak // create primitives: quad for the base osg::DrawElementsUInt* pyramidBase = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0); pyramidBase->push_back(3); pyramidBase->push_back(2); pyramidBase->push_back(1); pyramidBase->push_back(0); // create primitives: triangles for the sides osg::DrawElementsUInt* pyramidFaceOne = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0); pyramidFaceOne->push_back(0); pyramidFaceOne->push_back(1); pyramidFaceOne->push_back(4); • PrimitiveSet Class Using OpenGL primitives // assign all primitives to the Geometry node osg::Geometry* pyramidGeometry = new osg::Geometry(); pyramidGeometry->setVertexArray( pyramidVertices ); pyramidGeometry->addPrimitiveSet(pyramidBase); pyramidGeometry->addPrimitiveSet(pyramidFaceOne); pyramidGeometry->addPrimitiveSet(pyramidFaceTwo); pyramidGeometry->addPrimitiveSet(pyramidFaceThree); pyramidGeometry->addPrimitiveSet(pyramidFaceFour); geometry // create a geode and add the geometry to the geode osg::Geode* pyramidGeode = new osg::Geode(); pyramidGeode->addDrawable(pyramidGeometry); Geode // Create a root node and add the geode osg::Group* root = new osg::Group(); root->addChild(pyramidGeode); Root Node • PrimitiveSet Class // create an array of colors osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, colors->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, Using OpenGL primitives 1.0f) 1.0f) 1.0f) 1.0f) ); ); ); ); //index //index //index //index 0 1 2 3 red green blue white // create an index array osg::TemplateIndexArray <unsigned int, osg::Array::UIntArrayType,4,4> *colorIndexArray; colorIndexArray = new osg::TemplateIndexArray<unsigned int, osg::Array::UIntArrayType,4,4>; colorIndexArray->push_back(0); // vertex 0 assigned color array element 0 colorIndexArray->push_back(1); // vertex 1 assigned color array element 1 colorIndexArray->push_back(2); // vertex 2 assigned color array element 2 colorIndexArray->push_back(3); // vertex 3 assigned color array element 3 colorIndexArray->push_back(0); // vertex 4 assigned color array element 0 // assign the arrays to the geometry pyramidGeometry->setColorArray(colors); pyramidGeometry->setColorIndices(colorIndexArray); pyramidGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); Transformations OSG allows for hierarchies of transformation node. Such structure makes it much easier to control the motions of each limb, part or the whole body. transform transform geode geode transform transform geode geode transform geode Transformations OSG MatrixTransform Class: // direct transformation specification transform->getMatrix(); transform->setMatrix(); // set identity Identity(); // navigation osg::Matrix mt1 = osg::Matrix::Translate(x, y, z); osg::Matrix mt2 = osg::Matrix::Rotate(angle, x, y, z); osg::Matrix mt3 = osg::Matrix:: Scale(x, y, z); // for multiplying matrices osg::Matrix resultMat = mt1 * t2 * mt3; // invert matrix osg::Matrix::Invert(); AddingTexture // initialize texture class osg::Texture2D* texture = new osg::Texture2D; texture->setDataVariance(osg::Object::DYNAMIC); Any file format supported by the plugins // load the texture image from the file: osg::Image* texImage = osgDB::readImageFile(texture_file); if (! texImage){ std::cout << " couldn't find texture, quiting." << std::endl; return -1; } // Assign the texture to the image we read from file: texture->setImage(texImage); // Create a new StateSet with default settings: osg::StateSet* stateTex = new osg::StateSet(); // Assign texture unit 0 of our new StateSet to the texture // enable the texture. stateTex->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON); // Associate this state set with the Geode that contains // the primitive: geode->setStateSet(stateTex); • Exercise: Reading texture from the command line // Add parsing texture option from a command line // call argument parser osg::ArgumentParser arguments (&argc, argv); std::string filename; // define the argument line option arguments.read("--texture", texfilename); osg::Texture2D* texture = new osg::Texture2D; texture->setDataVariance(osg::Object::DYNAMIC); // load the texture image from the file: osg::Image* texImage = osgDB::readImageFile(texture_file); if (! texImage){ std::cout << " couldn't find texture, quiting." << std::endl; return -1; } … AddingTexture Special Nodes Switch node - Node for switching between different states of an object LOD node - Rendering Optimization node Billboard node – rendering optimization node Text node – node for presenting text on the screen Special Nodes LOD (“level of detail” node - Rendering Optimization node This node “switches” based on the distance from the viewer to the object. It works like a regular group node: load.addChild(detailedNode); Set the visible range from the viewer to the object: load.setRange(childNumber, near, far); Special Nodes LOD lod = new LOD(); Lod.addChild(detailedNode); Lod.setRange(0, 0, 10); Lod.addChild(NotSodetailedNode); Lod.setRange(1, 10, 100); Lod.addChild(CorseNode); Lod.setRange(2, 100, 1000); Lod.addChild(NoDetailNode); Lod.setRange(2,1000,10000); For up-to-date information on the project, in-depth details on how to compile and run libraries and examples, see the documentation on the OpenSceneGraph website: http://www.openscenegraph.org For support subscribe to OSG public mailing list: http://www.openscenegraph.org/projects/osg/wiki/MailingLists or forum: http://forum.openscenegraph.org Contact me: Katia Oleinik: koleinik@bu.edu Tutorial presentations and examples online: www.bu.edu/tech/research/training/presentations/list/ Online evaluation: http://scv.bu.edu/survey/tutorial_evaluation.html Resources • BU Scientific Computing and Visualization: http://www.bu.edu/tech/research/scv/ • OpenSceneGraph: http://www.openscenegraph.org/ Autodesk Maya