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>
2007-01-19 06:32:18 +08:00
# include <osg/StencilTwoSided>
2006-12-01 00:30:24 +08:00
# include <osg/CullFace>
2007-01-11 05:05:26 +08:00
# include <osg/Geometry>
2006-11-30 20:05:51 +08:00
2007-01-11 05:05:26 +08:00
# include <osgGA/TrackballManipulator>
2007-01-19 06:32:18 +08:00
# include <osgGA/AnimationPathManipulator>
2007-01-11 05:05:26 +08:00
# include <osgViewer/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>
2007-01-19 06:32:18 +08:00
# include <osgDB/WriteFile>
2006-10-06 22:16:11 +08:00
2007-01-11 05:05:26 +08:00
# include <iostream>
2006-10-06 22:16:11 +08:00
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
2007-01-19 06:32:18 +08:00
void getBase ( 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 ) ) ) ;
}
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.
2007-01-11 05:05:26 +08:00
osgViewer : : Viewer viewer ;
2006-10-06 22:16:11 +08:00
// 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 ;
2007-01-19 06:32:18 +08:00
osgShadow : : ShadowVolumeGeometry : : DrawMode drawMode = osgShadow : : ShadowVolumeGeometry : : STENCIL_TWO_PASS ;
while ( arguments . read ( " --two-sided " ) ) drawMode = osgShadow : : ShadowVolumeGeometry : : STENCIL_TWO_SIDED ;
std : : string pathfile ;
while ( arguments . read ( " -p " , pathfile ) )
{
osg : : ref_ptr < osgGA : : AnimationPathManipulator > apm = new osgGA : : AnimationPathManipulator ( pathfile ) ;
if ( apm - > valid ( ) ) viewer . setCameraManipulator ( apm . get ( ) ) ;
}
if ( ! viewer . getCameraManipulator ( ) ) viewer . setCameraManipulator ( new osgGA : : TrackballManipulator ( ) ) ;
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 ) ;
2007-01-11 05:05:26 +08:00
geode - > addDrawable ( osg : : createTexturedQuadGeometry ( centerBase - widthVec * 1.5f - depthVec * 1.5f ,
widthVec * 3.0f , depthVec * 3.0f ) ) ;
2006-12-01 23:19:21 +08:00
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 ( ) ) ;
2007-01-19 06:32:18 +08:00
// cbbv.getPolytope(occluder->getBoundingPolytope(),0.001);
cbbv . getBase ( occluder - > getBoundingPolytope ( ) , 0.001 ) ;
2006-11-25 01:20:01 +08:00
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
2007-01-19 06:32:18 +08:00
// shadowVolume->setUseDisplayList(!updateLightPosition);
shadowVolume - > setUseDisplayList ( false ) ;
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 ) ;
2007-01-19 06:32:18 +08:00
// first group, render the depth buffer + ambient light contribution
2006-11-30 20:05:51 +08:00
{
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 ) ;
2007-01-19 06:32:18 +08:00
shadowVolume - > setDrawMode ( drawMode ) ;
2006-12-01 00:30:24 +08:00
2007-01-19 06:32:18 +08:00
if ( drawMode = = osgShadow : : ShadowVolumeGeometry : : STENCIL_TWO_SIDED )
{
osg : : notify ( osg : : NOTICE ) < < " STENCIL_TWO_SIDED seleteced " < < std : : endl ;
2006-12-01 00:30:24 +08:00
2007-01-19 06:32:18 +08:00
osg : : StencilTwoSided * stencil = new osg : : StencilTwoSided ;
stencil - > setFunction ( osg : : StencilTwoSided : : BACK , osg : : StencilTwoSided : : ALWAYS , 0 , ~ 0u ) ;
stencil - > setOperation ( osg : : StencilTwoSided : : BACK , osg : : StencilTwoSided : : KEEP , osg : : StencilTwoSided : : KEEP , osg : : StencilTwoSided : : DECR_WRAP ) ;
stencil - > setFunction ( osg : : StencilTwoSided : : FRONT , osg : : StencilTwoSided : : ALWAYS , 0 , ~ 0u ) ;
stencil - > setOperation ( osg : : StencilTwoSided : : FRONT , osg : : StencilTwoSided : : KEEP , osg : : StencilTwoSided : : KEEP , osg : : StencilTwoSided : : INCR_WRAP ) ;
2006-12-01 00:30:24 +08:00
2007-01-19 06:32:18 +08:00
osg : : ColorMask * colourMask = new osg : : ColorMask ( false , false , false , false ) ;
2006-12-01 00:30:24 +08:00
2007-01-19 06:32:18 +08:00
osg : : StateSet * ss_sv1 = geode - > getOrCreateStateSet ( ) ;
ss_sv1 - > setRenderBinDetails ( 0 , " RenderBin " ) ;
ss_sv1 - > setAttributeAndModes ( stencil , osg : : StateAttribute : : ON ) ;
ss_sv1 - > setAttribute ( colourMask ) ;
ss_sv1 - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : OFF ) ;
geode - > addDrawable ( shadowVolume . get ( ) ) ;
camera - > addChild ( geode . get ( ) ) ;
2006-12-01 00:30:24 +08:00
2007-01-19 06:32:18 +08:00
}
else
{
osg : : notify ( osg : : NOTICE ) < < " STENCIL_TWO_PASSES seleteced " < < std : : endl ;
2006-12-01 00:30:24 +08:00
2007-01-19 06:32:18 +08:00
osg : : Stencil * stencil = new osg : : Stencil ;
stencil - > setFunction ( osg : : Stencil : : ALWAYS , 0 , ~ 0u ) ;
stencil - > setOperation ( osg : : Stencil : : KEEP , osg : : Stencil : : KEEP , osg : : Stencil : : KEEP ) ;
osg : : ColorMask * colourMask = new osg : : ColorMask ( false , false , false , false ) ;
osg : : StateSet * ss_sv1 = geode - > getOrCreateStateSet ( ) ;
ss_sv1 - > setRenderBinDetails ( 0 , " RenderBin " ) ;
ss_sv1 - > setAttributeAndModes ( stencil , osg : : StateAttribute : : ON ) ;
ss_sv1 - > setAttribute ( colourMask ) ;
ss_sv1 - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : ON ) ;
geode - > addDrawable ( shadowVolume . get ( ) ) ;
camera - > addChild ( geode . get ( ) ) ;
}
2006-12-01 00:30:24 +08:00
}
2006-11-30 20:05:51 +08:00
2007-01-19 06:32:18 +08:00
// render scene graph adding contribution of light
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
2007-01-12 00:59:50 +08:00
// hint to tell viewer to request stencil buffer when setting up windows
2007-01-11 20:06:24 +08:00
osg : : DisplaySettings : : instance ( ) - > setMinimumNumStencilBits ( 8 ) ;
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 ( ) ;
2007-01-19 06:32:18 +08:00
osgDB : : writeNodeFile ( * group , " test.osg " ) ;
2006-10-06 22:16:11 +08:00
while ( ! viewer . done ( ) )
{
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 ) ;
2007-01-11 05:05:26 +08:00
}
viewer . frame ( ) ;
2006-10-06 22:16:11 +08:00
}
return 0 ;
}