Object Ownership
-
new osg::Class without a matching delete is an OSG programming idiom.
-
Internally, OSG is based on smart pointers with intrusive reference-counts (OSG::Referenced).
-
Passing an OSG object to an OSG API function transfers ownership to OSG.
The graph will own what was attached by addChild().
-
osg::ref_ptr
If an app needs to hold onto an OSG object after passing it to an OSG API function,
the app must store it inside a osg::ref_ptr in order to increment its reference-count
(to avoid unexpected deletion).
Reference-counted Objects
A pitfall is when a constructor passes itself as this in a ref_ptr.
The pitfall opens because C/C++ evaluates the right side of an assignment before the left.
The ctor executes before model has incremented the ref-cnt,
so effectively nothing is holding a ref-cnt yet.1
When ctor passes this, upon returning, a premature deletion happens!
osg::ref_ptr<Model> mode; = new Model();
void
EnableAlphaBlending( osg::ref_ptr<Model> model );
Model::Model( void )
{
EnableAlphaBlending( this ); // oops!
}
Matrix, Transform
Rotating a matrix can be done by making a rotation matrix, then doing matrix multiplication.
Eg, to animate rotating an aircraft by 1 degree every frame,
pre-compute a 1 degree rotation matrix from an identity matrix,
then multiply it by a transform's matrix every frame.
The rotation matrix can remain unchanged until the angle (rotation rate) has to change.
class
{
osg::ref_ptr<osg::MatrixTransform> mTransform; // rotated every frame
osg::ref_ptr<osg::Matrix> mRotationMatrix; // coefficient of matrix multiplication
};
// Make a rotation matrix:
mRotationMatrix.makeRotate( degree, osg::Vec3f( 1.0f, 0.0f, 0.0f ) ); // X axis
// Rotate matrix every frame (matrix of OSG::MatrixTransform):
...
osg::Matrix m = mTransform->getMatrix();
m = mRotationMatrix * m;
mTransform->setMatrix( m );
Matrix Multiplication, Rotating Around Which Axis
Rotation of a matrix can be either in object space or fixed space.
Long way: Read a linear algebra textbook and study premultiply or postmultiply.
Short way: Run your program: if rotation is wrong, swap the coefficients.
m = mRotationMatrix * m; // rotate around local axis
m = m * mRotationMatrix; // rotate around fixed axis
Blending
Blending in OSG is similar to OpenGL,
with the addition of using OSG's transparent bin
(essentially another rendering pass) for transparent primitives.
// Enable blending, select transparent bin.
stateSet->setMode( GL_BLEND, osg::StateAttribute::ON );
stateSet->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
// Enable depth test so that an opaque polygon will occlude a transparent one behind it.
stateSet->setMode( GL_DEPTH_TEST, osg::StateAttribute::ON );
// Conversely, disable writing to depth buffer so that
// a transparent polygon will allow polygons behind it to shine thru.
// OSG renders transparent polygons after opaque ones.
osg::Depth* depth = new osg::Depth;
depth->setWriteMask( false );
stateSet->setAttributeAndModes( depth, osg::StateAttribute::ON );
// Disable conflicting modes.
stateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
Billboards
osg::AutoTransform is an alternative to osg::Billboard.
AutoTransform doesn't rotate as the viewpoint move close to it.
Reading Compressed 3D files
One way is to pass a C++ stream to osg::ReaderWriter::readNode( istreamstream& ).
The C++ stream is the buffer for the decompressed file.
// Read gzip-compressed file into a C++ string.
string buf;
ReadGzipFile( buf, filename );
// Convert C++ string to a C++ stream.
istringstream ss( buf );
// Pass the C++ stringstream, containing the decompressed file, to OSG.
osg::ref_ptr<osgDB::ReaderWriter> readerWriter = \
osgDB::Registry::instance()->getReaderWriterForExtension( modelFileSuffix );
osgDB::ReaderWriter::ReadResult res = readerWriter->readNode( ss );