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
@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.