OpenSceneGraph 3.0: Beginner's Guide
上QQ阅读APP看书,第一时间看更新

Time for action—quickly creating simple objects

It is easy to create simple objects by using an osg::Shape subclass. We will take three typical shapes as examples: a box with different width, height, and depth values, a sphere with a radius value, and a cone with a radius and a height.

  1. Include necessary headers:
    #include <osg/ShapeDrawable>
    #include <osg/Geode>
    #include <osgViewer/Viewer>
  2. Add three osg::ShapeDrawable objects successively, each with a type of basic shape. We set these shapes to different positions to make them visible to viewers at the same time, and for the reason of distinguishing them from each other, we color the latter two shapes green and respectively, blue by using the setColor() method of osg::ShapeDrawable:
    osg::ref_ptr<osg::ShapeDrawable> shape1 = new osg::ShapeDrawable;
    shape1->setShape( new osg::Box(osg::Vec3(-3.0f, 0.0f, 0.0f),
                                   2.0f, 2.0f, 1.0f) );
    
    osg::ref_ptr<osg::ShapeDrawable> shape2 = new osg::ShapeDrawable;
    shape2->setShape( new osg::Sphere(osg::Vec3(3.0f, 0.0f, 0.0f),
                                      1.0f) );
    shape2->setColor( osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f) );
    
    osg::ref_ptr<osg::ShapeDrawable> shape3 = new osg::ShapeDrawable;
    shape3->setShape( new osg::Cone(osg::Vec3(0.0f, 0.0f, 0.0f),
                                    1.0f, 1.0f) );
    shape3->setColorS( osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f) );
  3. An osg::Geode object is created, and all the drawables are added to it. Note that the drawables and the geometry node are all managed by the osg::ref_ptr<> smart pointer here. The osg::Geode object is finally used as the scene root of the viewer:
    osg::ref_ptr<osg::Geode> root = new osg::Geode;
    root->addDrawable( shape1.get() );
    root->addDrawable( shape2.get() );
    root->addDrawable( shape3.get() );
    
    osgViewer::Viewer viewer;
    viewer.setSceneData( root.get() );
    return viewer.run();
  4. Now it's time to see if these shapes are rendered properly. We don't have to care about the actual drawing work of vertex positions, normals, and colors here, which brings convenience for debugging and quick shape viewing:
    Time for action—quickly creating simple objects

What just happened?

The osg::ShapeDrawable class is useful for quick display, but it is not an efficient way of drawing geometry primitives. It should only be used for quick prototyping and debugging when you develop 3D applications. To create geometries with high performance computation and visualization requirements, the osg::Geometry class, which is going to be introduced, is always a better choice.

OSG has an internal osg::GLBeginEndAdapter class that is used to perform basic shape drawing operations. This class enables the use of vertex arrays in the style of a glBegin() and glEnd() pair, which makes the implementation of basic shapes easy to understand and extend.

To get and use an initialized osg::GLBeginEndAdapter object, you should define a class derived from the osg::Drawable base class and re-implement its drawImplementation() method, and start programming as if you are writing the classic OpenGL 1.0 drawing calls:

void drawImplementation( osg::RenderInfo& renderInfo ) const
{ 
    osg::GLBeginEndAdapter& gl =
        renderInfo.getState()->getGLBeginEndAdapter();
    gl.Begin( … );
    gl.Vertex3fv( … );
    gl.End();
}

More information about re-implementing the osg::Drawable class can be found in the Implementing your own drawables section of this chapter.