Creating a Sphere (using osg::Geometry) in OpenSceneGraph

后端 未结 3 769
遥遥无期
遥遥无期 2021-02-05 20:40

I spent quite some time to get this working, but my Sphere just won\'t display.
Used the following code to make my function:
Creating a 3D sphere in Opengl using Visual

3条回答
  •  孤独总比滥情好
    2021-02-05 20:53

    @JoeZ's answer is excellent, but the OSG code has some errors/bad practices. Here's the updated code. It's been tested and it shows a very nice sphere.

        osg::ref_ptr buildSphere( const double radius,
                                              const unsigned int rings,
                                              const unsigned int sectors )
        {
            osg::ref_ptr      sphereGeode = new osg::Geode;
            osg::ref_ptr   sphereGeometry = new osg::Geometry;
            osg::ref_ptr  sphereVertices = new osg::Vec3Array;
            osg::ref_ptr  sphereNormals = new osg::Vec3Array;
            osg::ref_ptr  sphereTexCoords = new osg::Vec2Array;
    
            float const R = 1. / static_cast( rings - 1 );
            float const S = 1. / static_cast( sectors - 1 );
    
            sphereGeode->addDrawable( sphereGeometry );
    
            // Establish texture coordinates, vertex list, and normals
            for( unsigned int r( 0 ); r < rings; ++r ) {
                for( unsigned int s( 0) ; s < sectors; ++s ) {
                    float const y = sin( -M_PI_2 + M_PI * r * R );
                    float const x = cos( 2 * M_PI * s * S) * sin( M_PI * r * R );
                    float const z = sin( 2 * M_PI * s * S) * sin( M_PI * r * R );
    
                    sphereTexCoords->push_back( osg::Vec2( s * R, r * R ) );
    
                    sphereVertices->push_back ( osg::Vec3( x * radius,
                                                           y * radius,
                                                           z * radius) )
                    ;
                    sphereNormals->push_back  ( osg::Vec3( x, y, z ) );
    
                }
            }
    
            sphereGeometry->setVertexArray  ( sphereVertices  );
            sphereGeometry->setTexCoordArray( 0, sphereTexCoords );
    
            // Generate quads for each face.
            for( unsigned int r( 0 ); r < rings - 1; ++r ) {
                for( unsigned int s( 0 ); s < sectors - 1; ++s ) {
    
                    osg::ref_ptr face =
                            new osg::DrawElementsUInt( osg::PrimitiveSet::QUADS,
                                                       4 )
                    ;
                    // Corners of quads should be in CCW order.
                    face->push_back( ( r + 0 ) * sectors + ( s + 0 ) );
                    face->push_back( ( r + 0 ) * sectors + ( s + 1 ) );
                    face->push_back( ( r + 1 ) * sectors + ( s + 1 ) );
                    face->push_back( ( r + 1 ) * sectors + ( s + 0 ) );
    
                    sphereGeometry->addPrimitiveSet( face );
                }
            }
    
            return sphereGeode;
        }
    

    Changes:

    • The OSG elements used in the code now are smart pointers1. Moreover, classes like Geode and Geometry have their destructors protected, so the only way to instantiate them are via dynamic allocation.

    • Removed spherePrimitiveSets as it isn't needed in the current version of the code.

    • I put the code in a free function, as I don't need a Sphere class in my code. I omitted the getters and the protected attributes. They aren't needed: if you need to access, say, the geometry, you can get it via: sphereGeode->getDrawable(...). The same goes for the rest of the attributes.

    [1] See Rule of thumb #1 here. It's a bit old but the advice maintains.

提交回复
热议问题