2006-11-10 23:07:13 +08:00
# include <osg/ArgumentParser>
2006-10-06 22:16:11 +08:00
2006-11-30 20:05:51 +08:00
# include <osg/LightModel>
# include <osg/Depth>
# include <osg/BlendFunc>
2006-12-01 00:30:24 +08:00
# include <osg/Camera>
# include <osg/Stencil>
# include <osg/CullFace>
2006-11-30 20:05:51 +08:00
2006-11-10 23:07:13 +08:00
# include <osgProducer/Viewer>
2006-10-06 22:16:11 +08:00
2006-11-10 23:07:13 +08:00
# include <osgShadow/OccluderGeometry>
2006-10-06 22:16:11 +08:00
# include <osgDB/ReadFile>
2006-11-24 01:29:43 +08:00
class ComputeBoundingBoxVisitor : public osg : : NodeVisitor
{
public :
ComputeBoundingBoxVisitor ( ) :
osg : : NodeVisitor ( osg : : NodeVisitor : : TRAVERSE_ALL_CHILDREN )
{
}
virtual void reset ( )
{
_matrixStack . clear ( ) ;
_bb . init ( ) ;
}
osg : : BoundingBox & getBoundingBox ( ) { return _bb ; }
2006-11-25 01:20:01 +08:00
void getPolytope ( osg : : Polytope & polytope , float margin = 0.1 ) const
{
float delta = _bb . radius ( ) * margin ;
polytope . add ( osg : : Plane ( 0.0 , 0.0 , 1.0 , - ( _bb . zMin ( ) - delta ) ) ) ;
polytope . add ( osg : : Plane ( 0.0 , 0.0 , - 1.0 , ( _bb . zMax ( ) + delta ) ) ) ;
polytope . add ( osg : : Plane ( 1.0 , 0.0 , 0.0 , - ( _bb . xMin ( ) - delta ) ) ) ;
polytope . add ( osg : : Plane ( - 1.0 , 0.0 , 0.0 , ( _bb . xMax ( ) + delta ) ) ) ;
polytope . add ( osg : : Plane ( 0.0 , 1.0 , 0.0 , - ( _bb . yMin ( ) - delta ) ) ) ;
polytope . add ( osg : : Plane ( 0.0 , - 1.0 , 0.0 , ( _bb . yMax ( ) + delta ) ) ) ;
}
2006-11-24 01:29:43 +08:00
void apply ( osg : : Node & node )
{
traverse ( node ) ;
}
void apply ( osg : : Transform & transform )
{
osg : : Matrix matrix ;
if ( ! _matrixStack . empty ( ) ) matrix = _matrixStack . back ( ) ;
transform . computeLocalToWorldMatrix ( matrix , this ) ;
pushMatrix ( matrix ) ;
traverse ( transform ) ;
popMatrix ( ) ;
}
void apply ( osg : : Geode & geode )
{
for ( unsigned int i = 0 ; i < geode . getNumDrawables ( ) ; + + i )
{
apply ( geode . getDrawable ( i ) ) ;
}
}
void pushMatrix ( osg : : Matrix & matrix )
{
_matrixStack . push_back ( matrix ) ;
}
void popMatrix ( )
{
_matrixStack . pop_back ( ) ;
}
void apply ( osg : : Drawable * drawable )
{
if ( _matrixStack . empty ( ) ) _bb . expandBy ( drawable - > getBound ( ) ) ;
else
{
osg : : Matrix & matrix = _matrixStack . back ( ) ;
const osg : : BoundingBox & dbb = drawable - > getBound ( ) ;
if ( dbb . valid ( ) )
{
_bb . expandBy ( dbb . corner ( 0 ) * matrix ) ;
_bb . expandBy ( dbb . corner ( 1 ) * matrix ) ;
_bb . expandBy ( dbb . corner ( 2 ) * matrix ) ;
_bb . expandBy ( dbb . corner ( 3 ) * matrix ) ;
_bb . expandBy ( dbb . corner ( 4 ) * matrix ) ;
_bb . expandBy ( dbb . corner ( 5 ) * matrix ) ;
_bb . expandBy ( dbb . corner ( 6 ) * matrix ) ;
_bb . expandBy ( dbb . corner ( 7 ) * matrix ) ;
}
}
}
protected :
typedef std : : vector < osg : : Matrix > MatrixStack ;
MatrixStack _matrixStack ;
osg : : BoundingBox _bb ;
} ;
2006-10-06 22:16:11 +08:00
int main ( int argc , char * * argv )
{
// use an ArgumentParser object to manage the program arguments.
2006-11-10 23:07:13 +08:00
osg : : ArgumentParser arguments ( & argc , argv ) ;
2006-10-06 22:16:11 +08:00
// set up the usage document, in case we need to print out how to use this program.
arguments . getApplicationUsage ( ) - > setDescription ( arguments . getApplicationName ( ) + " is the example which demonstrates using of GL_ARB_shadow extension implemented in osg::Texture class " ) ;
arguments . getApplicationUsage ( ) - > setCommandLineUsage ( arguments . getApplicationName ( ) ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -h or --help " , " Display this information " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --with-base-texture " , " Adde base texture to shadowed model. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --no-base-texture " , " Adde base texture to shadowed model. " ) ;
// construct the viewer.
osgProducer : : Viewer viewer ( arguments ) ;
// set up the value with sensible default event handlers.
viewer . setUpViewer ( osgProducer : : Viewer : : STANDARD_SETTINGS ) ;
// get details on keyboard and mouse bindings used by the viewer.
viewer . getUsage ( * arguments . getApplicationUsage ( ) ) ;
// if user request help write it out to cout.
if ( arguments . read ( " -h " ) | | arguments . read ( " --help " ) )
{
arguments . getApplicationUsage ( ) - > write ( std : : cout ) ;
return 1 ;
}
2006-11-30 18:29:03 +08:00
bool postionalLight = false ;
while ( arguments . read ( " --positionalLight " ) ) postionalLight = true ;
while ( arguments . read ( " --directionalLight " ) ) postionalLight = false ;
bool addOccluderToScene = false ;
2006-12-01 00:30:24 +08:00
while ( arguments . read ( " --addOccluderToScene " ) ) addOccluderToScene = true ;
2006-11-30 18:29:03 +08:00
bool updateLightPosition = true ;
2006-12-01 00:30:24 +08:00
while ( arguments . read ( " --noUpdate " ) ) updateLightPosition = false ;
2006-11-30 18:29:03 +08:00
2006-12-01 23:19:21 +08:00
bool createBase = false ;
while ( arguments . read ( " --base " ) ) createBase = true ;
2006-11-30 20:05:51 +08:00
bool doShadow = true ;
2006-12-01 00:30:24 +08:00
while ( arguments . read ( " --noShadow " ) ) doShadow = false ;
2006-11-30 20:05:51 +08:00
2006-10-06 22:16:11 +08:00
// any option left unread are converted into errors to write out later.
arguments . reportRemainingOptionsAsUnrecognized ( ) ;
// report any errors if they have occured when parsing the program aguments.
if ( arguments . errors ( ) )
{
arguments . writeErrorMessages ( std : : cout ) ;
return 1 ;
}
2006-11-10 23:07:13 +08:00
osg : : ref_ptr < osg : : Node > model = osgDB : : readNodeFiles ( arguments ) ;
if ( ! model )
2006-10-06 22:16:11 +08:00
{
2006-11-10 23:07:13 +08:00
osg : : notify ( osg : : NOTICE ) < < " No model loaded, please specify a model to load. " < < std : : endl ;
return 1 ;
2006-10-06 22:16:11 +08:00
}
2006-11-30 18:29:03 +08:00
// get the bounds of the model.
ComputeBoundingBoxVisitor cbbv ;
model - > accept ( cbbv ) ;
osg : : BoundingBox bb = cbbv . getBoundingBox ( ) ;
2006-12-01 23:19:21 +08:00
if ( createBase )
{
osg : : ref_ptr < osg : : Group > newGroup = new osg : : Group ;
newGroup - > addChild ( model . get ( ) ) ;
osg : : Geode * geode = new osg : : Geode ;
osg : : Vec3 widthVec ( bb . radius ( ) , 0.0f , 0.0f ) ;
osg : : Vec3 depthVec ( 0.0f , bb . radius ( ) , 0.0f ) ;
osg : : Vec3 centerBase ( ( bb . xMin ( ) + bb . xMax ( ) ) * 0.5f , ( bb . yMin ( ) + bb . yMax ( ) ) * 0.5f , bb . zMin ( ) - bb . radius ( ) * 0.1f ) ;
geode - > addDrawable ( createTexturedQuadGeometry ( centerBase - widthVec * 1.5f - depthVec * 1.5f ,
widthVec * 3.0f , depthVec * 3.0f ) ) ;
newGroup - > addChild ( geode ) ;
model = newGroup . get ( ) ;
}
// get the bounds of the model.
cbbv . reset ( ) ;
model - > accept ( cbbv ) ;
bb = cbbv . getBoundingBox ( ) ;
2006-10-06 22:16:11 +08:00
2006-11-30 18:29:03 +08:00
osg : : ref_ptr < osg : : Group > group = new osg : : Group ;
2006-11-14 20:16:39 +08:00
2006-11-30 18:29:03 +08:00
// set up the occluder
2006-11-10 23:07:13 +08:00
osg : : ref_ptr < osgShadow : : OccluderGeometry > occluder = new osgShadow : : OccluderGeometry ;
occluder - > computeOccluderGeometry ( model . get ( ) ) ;
2006-11-25 01:20:01 +08:00
cbbv . getPolytope ( occluder - > getBoundingPolytope ( ) , 0.001 ) ;
2006-11-30 18:29:03 +08:00
if ( addOccluderToScene )
{
osg : : ref_ptr < osg : : Geode > geode = new osg : : Geode ;
geode - > addDrawable ( occluder . get ( ) ) ;
group - > addChild ( geode . get ( ) ) ;
}
2006-11-10 23:07:13 +08:00
2006-11-24 00:55:46 +08:00
osg : : ref_ptr < osgShadow : : ShadowVolumeGeometry > shadowVolume = new osgShadow : : ShadowVolumeGeometry ;
2006-11-24 19:37:57 +08:00
2006-11-30 18:29:03 +08:00
shadowVolume - > setUseDisplayList ( ! updateLightPosition ) ;
2006-10-06 22:16:11 +08:00
2006-11-30 18:29:03 +08:00
osg : : Vec4 lightpos ;
if ( postionalLight )
{
lightpos . set ( bb . center ( ) . x ( ) , bb . center ( ) . y ( ) , bb . zMax ( ) + bb . radius ( ) , 1.0f ) ;
}
else
{
2006-11-30 20:05:51 +08:00
lightpos . set ( 0.5f , 0.25f , 0.8f , 0.0f ) ;
2006-11-30 18:29:03 +08:00
}
2006-11-30 20:05:51 +08:00
2006-12-01 23:19:21 +08:00
2006-11-30 20:05:51 +08:00
osg : : ref_ptr < osg : : Light > light = new osg : : Light ;
if ( ! doShadow )
2006-11-30 18:29:03 +08:00
{
2006-11-30 20:05:51 +08:00
group - > addChild ( model . get ( ) ) ;
2006-11-30 18:29:03 +08:00
osg : : ref_ptr < osg : : Geode > geode = new osg : : Geode ;
2006-12-01 02:42:38 +08:00
occluder - > computeShadowVolumeGeometry ( lightpos , * shadowVolume ) ;
2006-11-30 18:29:03 +08:00
geode - > addDrawable ( shadowVolume . get ( ) ) ;
group - > addChild ( geode . get ( ) ) ;
2006-12-01 00:30:24 +08:00
osg : : StateSet * ss = geode - > getOrCreateStateSet ( ) ;
ss - > setAttributeAndModes ( new osg : : CullFace ( osg : : CullFace : : BACK ) , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
2006-11-30 18:29:03 +08:00
}
2006-11-30 20:05:51 +08:00
else
{
2006-12-01 00:30:24 +08:00
osg : : Vec4 ambient ( 0.2 , 0.2 , 0.2 , 1.0 ) ;
osg : : Vec4 diffuse ( 0.8 , 0.8 , 0.8 , 1.0 ) ;
2006-11-30 20:05:51 +08:00
osg : : Vec4 zero_colour ( 0.0 , 0.0 , 0.0 , 1.0 ) ;
// first group
{
osg : : Group * first_model_group = new osg : : Group ;
first_model_group - > addChild ( model . get ( ) ) ;
group - > addChild ( first_model_group ) ;
osg : : StateSet * ss1 = first_model_group - > getOrCreateStateSet ( ) ;
osg : : LightModel * lm1 = new osg : : LightModel ;
lm1 - > setAmbientIntensity ( ambient ) ;
ss1 - > setAttribute ( lm1 ) ;
2006-11-24 00:55:46 +08:00
2006-11-30 20:05:51 +08:00
osg : : Light * light1 = new osg : : Light ;
light1 - > setAmbient ( ambient ) ;
light1 - > setDiffuse ( zero_colour ) ;
light1 - > setPosition ( lightpos ) ;
2006-12-01 00:30:24 +08:00
ss1 - > setAttributeAndModes ( light1 , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
ss1 - > setMode ( GL_LIGHTING , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
2006-11-30 20:05:51 +08:00
}
// second group
{
2006-12-01 00:30:24 +08:00
// use a camera here just to implement a seperate post rendering stage.
osg : : Camera * camera = new osg : : Camera ;
camera - > setRenderOrder ( osg : : Camera : : POST_RENDER ) ;
camera - > setClearMask ( GL_STENCIL_BUFFER_BIT ) ;
group - > addChild ( camera ) ;
2006-11-30 20:05:51 +08:00
2006-12-01 00:30:24 +08:00
osg : : StateSet * ss_camera = camera - > getOrCreateStateSet ( ) ;
2006-11-30 20:05:51 +08:00
osg : : Depth * depth = new osg : : Depth ;
depth - > setWriteMask ( false ) ;
depth - > setFunction ( osg : : Depth : : LEQUAL ) ;
2006-12-01 00:30:24 +08:00
ss_camera - > setAttribute ( depth ) ;
{
osg : : ref_ptr < osg : : Geode > geode = new osg : : Geode ;
2006-12-01 02:42:38 +08:00
occluder - > computeShadowVolumeGeometry ( lightpos , * shadowVolume ) ;
2006-12-01 00:30:24 +08:00
geode - > addDrawable ( shadowVolume . get ( ) ) ;
// switch off the writing to the color bit planes.
osg : : ColorMask * colourMask = new osg : : ColorMask ;
colourMask - > setMask ( false , false , false , false ) ;
osg : : Stencil * stencil = new osg : : Stencil ;
stencil - > setFunction ( osg : : Stencil : : ALWAYS , 0 , ~ 0u ) ;
stencil - > setOperation ( osg : : Stencil : : KEEP , osg : : Stencil : : KEEP , osg : : Stencil : : INCR ) ;
osg : : StateSet * ss_sv1 = geode - > getOrCreateStateSet ( ) ;
ss_sv1 - > setRenderBinDetails ( 0 , " RenderBin " ) ;
ss_sv1 - > setAttributeAndModes ( stencil , osg : : StateAttribute : : ON ) ;
ss_sv1 - > setAttribute ( colourMask ) ;
ss_sv1 - > setAttributeAndModes ( new osg : : CullFace ( osg : : CullFace : : BACK ) , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
camera - > addChild ( geode . get ( ) ) ;
}
2006-11-30 20:05:51 +08:00
2006-12-01 00:30:24 +08:00
if ( true )
{
osg : : ref_ptr < osg : : Geode > geode = new osg : : Geode ;
2006-12-01 02:42:38 +08:00
occluder - > computeShadowVolumeGeometry ( lightpos , * shadowVolume ) ;
2006-12-01 00:30:24 +08:00
geode - > addDrawable ( shadowVolume . get ( ) ) ;
// switch off the writing to the color bit planes.
osg : : ColorMask * colourMask = new osg : : ColorMask ;
colourMask - > setMask ( false , false , false , false ) ;
osg : : Stencil * stencil = new osg : : Stencil ;
stencil - > setFunction ( osg : : Stencil : : ALWAYS , 0 , ~ 0u ) ;
stencil - > setOperation ( osg : : Stencil : : KEEP , osg : : Stencil : : KEEP , osg : : Stencil : : DECR ) ;
osg : : StateSet * ss_sv1 = geode - > getOrCreateStateSet ( ) ;
ss_sv1 - > setRenderBinDetails ( 1 , " RenderBin " ) ;
ss_sv1 - > setAttributeAndModes ( stencil , osg : : StateAttribute : : ON ) ;
ss_sv1 - > setAttribute ( colourMask ) ;
ss_sv1 - > setAttributeAndModes ( new osg : : CullFace ( osg : : CullFace : : FRONT ) , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
camera - > addChild ( geode . get ( ) ) ;
}
2006-11-30 20:05:51 +08:00
2006-12-01 00:30:24 +08:00
{
osg : : Group * second_model_group = new osg : : Group ;
second_model_group - > addChild ( model . get ( ) ) ;
osg : : StateSet * ss1 = second_model_group - > getOrCreateStateSet ( ) ;
ss1 - > setRenderBinDetails ( 5 , " RenderBin " ) ;
osg : : LightModel * lm1 = new osg : : LightModel ;
lm1 - > setAmbientIntensity ( zero_colour ) ;
ss1 - > setAttribute ( lm1 ) ;
osg : : LightSource * lightsource = new osg : : LightSource ;
lightsource - > setLight ( light . get ( ) ) ;
light - > setAmbient ( zero_colour ) ;
light - > setDiffuse ( diffuse ) ;
light - > setPosition ( lightpos ) ;
second_model_group - > addChild ( lightsource ) ;
ss1 - > setMode ( GL_LIGHT0 , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
// set up the stencil ops so that only operator on this mirrors stencil value.
osg : : Stencil * stencil = new osg : : Stencil ;
stencil - > setFunction ( osg : : Stencil : : EQUAL , 0 , ~ 0u ) ;
stencil - > setOperation ( osg : : Stencil : : KEEP , osg : : Stencil : : KEEP , osg : : Stencil : : KEEP ) ;
ss1 - > setAttributeAndModes ( stencil , osg : : StateAttribute : : ON ) ;
osg : : BlendFunc * blend = new osg : : BlendFunc ;
blend - > setFunction ( osg : : BlendFunc : : ONE , osg : : BlendFunc : : ONE ) ;
ss1 - > setAttributeAndModes ( blend , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
ss1 - > setMode ( GL_LIGHTING , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
camera - > addChild ( second_model_group ) ;
}
}
2006-11-30 20:05:51 +08:00
}
2006-11-24 00:55:46 +08:00
viewer . setSceneData ( group . get ( ) ) ;
2006-10-06 22:16:11 +08:00
// create the windows and run the threads.
viewer . realize ( ) ;
while ( ! viewer . done ( ) )
{
// wait for all cull and draw threads to complete.
viewer . sync ( ) ;
2006-11-30 18:29:03 +08:00
if ( updateLightPosition )
{
float t = viewer . getFrameStamp ( ) - > getReferenceTime ( ) ;
if ( postionalLight )
{
lightpos . set ( bb . center ( ) . x ( ) + sinf ( t ) * bb . radius ( ) , bb . center ( ) . y ( ) + cosf ( t ) * bb . radius ( ) , bb . zMax ( ) + bb . radius ( ) , 1.0f ) ;
}
else
{
2006-11-30 20:05:51 +08:00
lightpos . set ( sinf ( t ) , cosf ( t ) , 0.8f , 0.0f ) ;
2006-11-30 18:29:03 +08:00
}
2006-11-30 20:05:51 +08:00
light - > setPosition ( lightpos ) ;
2006-12-01 02:42:38 +08:00
occluder - > computeShadowVolumeGeometry ( lightpos , * shadowVolume ) ;
2006-11-30 18:29:03 +08:00
}
2006-10-06 22:16:11 +08:00
// update the scene by traversing it with the the update visitor which will
// call all node update callbacks and animations.
viewer . update ( ) ;
// fire off the cull and draw traversals of the scene.
viewer . frame ( ) ;
}
// wait for all cull and draw threads to complete.
viewer . sync ( ) ;
// run a clean up frame to delete all OpenGL objects.
viewer . cleanup_frame ( ) ;
// wait for all the clean up frame to complete.
viewer . sync ( ) ;
return 0 ;
}