Show
Ignore:
Timestamp:
11/10/06 16:07:13 (7 years ago)
Author:
robert
Message:

Further work on osgShadow::GeometryOccluder?

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/examples/osgshadow/osgshadow.cpp

    r5641 r5701  
     1#include <osg/ArgumentParser> 
     2 
    13#include <osgProducer/Viewer> 
    24 
    3 #include <osg/Projection> 
    4 #include <osg/Geometry> 
    5 #include <osg/Texture> 
    6 #include <osg/TexGen> 
    7 #include <osg/Geode> 
    8 #include <osg/ShapeDrawable> 
    9 #include <osg/PolygonOffset> 
    10 #include <osg/Texture2D> 
    11 #include <osg/MatrixTransform> 
    12 #include <osg/Light> 
    13 #include <osg/LightSource> 
    14 #include <osg/PolygonOffset> 
    15 #include <osg/CullFace> 
    16 #include <osg/Material> 
    17 #include <osg/TexEnvCombine> 
    18 #include <osg/TexEnv> 
    19  
    20 #include <osg/CameraNode> 
    21 #include <osg/TexGenNode> 
     5#include <osgShadow/OccluderGeometry> 
    226 
    237#include <osgDB/ReadFile> 
    24  
    25 using namespace osg; 
    26  
    27 class LightTransformCallback: public osg::NodeCallback 
    28 { 
    29  
    30 public: 
    31  
    32   LightTransformCallback(float angular_velocity, float height, float radius): 
    33     _angular_velocity(angular_velocity), 
    34     _height(height), 
    35     _radius(radius), 
    36     _previous_traversal_number(-1), 
    37     _previous_time(-1.0f), 
    38     _angle(0) 
    39   { 
    40   } 
    41  
    42   void operator()(Node* node, NodeVisitor* nv); 
    43  
    44 protected: 
    45      
    46   float                                  _angular_velocity; 
    47   float                                  _height; 
    48   float                                  _radius; 
    49   int                                    _previous_traversal_number; 
    50   double                                 _previous_time; 
    51   float                                  _angle; 
    52 }; 
    53  
    54  
    55 void  
    56 LightTransformCallback::operator()(Node* node, NodeVisitor* nv) 
    57 { 
    58   MatrixTransform* transform = dynamic_cast<MatrixTransform*>(node); 
    59   if (nv && transform) 
    60     { 
    61       const FrameStamp* fs = nv->getFrameStamp(); 
    62       if (!fs) return; // not frame stamp, no handle on the time so can't move. 
    63          
    64       double new_time = fs->getReferenceTime(); 
    65       if (nv->getTraversalNumber() != _previous_traversal_number) 
    66         { 
    67           _angle += _angular_velocity * (new_time - _previous_time); 
    68  
    69           Matrix matrix = Matrix::rotate(atan(_height / _radius), -X_AXIS) * 
    70             Matrix::rotate(PI_2, Y_AXIS) * 
    71             Matrix::translate(Vec3(_radius, 0, 0)) * 
    72             Matrix::rotate(_angle, Y_AXIS) * 
    73             Matrix::translate(Vec3(0, _height, 0)); 
    74  
    75           // update the specified transform 
    76           transform->setMatrix(matrix); 
    77  
    78           _previous_traversal_number = nv->getTraversalNumber(); 
    79         } 
    80  
    81       _previous_time = new_time;  
    82     } 
    83  
    84   // must call any nested node callbacks and continue subgraph traversal. 
    85   traverse(node,nv); 
    86  
    87 } 
    88  
    89  
    90 ref_ptr<MatrixTransform> _create_lights() 
    91 { 
    92   ref_ptr<MatrixTransform> transform_0 = new MatrixTransform; 
    93  
    94   // create a spot light. 
    95   ref_ptr<Light> light_0 = new Light; 
    96   light_0->setLightNum(0); 
    97   light_0->setPosition(Vec4(0, 0, 0, 1.0f)); 
    98   light_0->setAmbient(Vec4(0.0f, 0.0f, 0.0f, 1.0f)); 
    99   light_0->setDiffuse(Vec4(1.0f, 0.8f, 0.8f, 1.0f)); 
    100   light_0->setSpotCutoff(60.0f); 
    101   light_0->setSpotExponent(2.0f); 
    102  
    103   ref_ptr<LightSource> light_source_0 = new LightSource;     
    104   light_source_0->setLight(light_0.get()); 
    105   light_source_0->setLocalStateSetModes(StateAttribute::ON);  
    106   transform_0->setUpdateCallback(new LightTransformCallback(inDegrees(90.0f), 8, 5)); 
    107   transform_0->addChild(light_source_0.get()); 
    108  
    109   ref_ptr<Geode> geode = new Geode; 
    110  
    111   ref_ptr<ShapeDrawable> shape; 
    112   ref_ptr<TessellationHints> hints = new TessellationHints; 
    113   hints->setDetailRatio(0.3f); 
    114   shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f), 0.15f), hints.get()); 
    115   shape->setColor(Vec4(1.0f, 0.5f, 0.5f, 1.0f)); 
    116   geode->addDrawable(shape.get()); 
    117   shape = new ShapeDrawable(new Cylinder(Vec3(0.0f, 0.0f, -0.4f), 0.05f, 0.8f), hints.get()); 
    118   shape->setColor(Vec4(1.0f, 0.5f, 0.5f, 1.0f)); 
    119   geode->addDrawable(shape.get()); 
    120  
    121  
    122   geode->getOrCreateStateSet()->setMode(GL_LIGHTING, StateAttribute::OFF); 
    123   transform_0->addChild(geode.get()); 
    124  
    125   return transform_0; 
    126 } 
    127  
    128 ref_ptr<Group> _create_scene() 
    129 { 
    130   ref_ptr<Group> scene = new Group; 
    131   ref_ptr<Geode> geode_1 = new Geode; 
    132   scene->addChild(geode_1.get()); 
    133  
    134   ref_ptr<Geode> geode_2 = new Geode; 
    135   ref_ptr<MatrixTransform> transform_2 = new MatrixTransform; 
    136   transform_2->addChild(geode_2.get()); 
    137   transform_2->setUpdateCallback(new osg::AnimationPathCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(45.0f))); 
    138   scene->addChild(transform_2.get()); 
    139  
    140   ref_ptr<Geode> geode_3 = new Geode; 
    141   ref_ptr<MatrixTransform> transform_3 = new MatrixTransform; 
    142   transform_3->addChild(geode_3.get()); 
    143   transform_3->setUpdateCallback(new osg::AnimationPathCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(-22.5f))); 
    144   scene->addChild(transform_3.get()); 
    145  
    146   const float radius = 0.8f; 
    147   const float height = 1.0f; 
    148   ref_ptr<TessellationHints> hints = new TessellationHints; 
    149   hints->setDetailRatio(2.0f); 
    150   ref_ptr<ShapeDrawable> shape; 
    151  
    152   shape = new ShapeDrawable(new Box(Vec3(0.0f, -2.0f, 0.0f), 10, 0.1f, 10), hints.get()); 
    153   shape->setColor(Vec4(0.5f, 0.5f, 0.7f, 1.0f)); 
    154   geode_1->addDrawable(shape.get()); 
    155  
    156   shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f), radius * 2), hints.get()); 
    157   shape->setColor(Vec4(0.8f, 0.8f, 0.8f, 1.0f)); 
    158   geode_1->addDrawable(shape.get()); 
    159  
    160   shape = new ShapeDrawable(new Sphere(Vec3(-3.0f, 0.0f, 0.0f), radius), hints.get()); 
    161   shape->setColor(Vec4(0.6f, 0.8f, 0.8f, 1.0f)); 
    162   geode_2->addDrawable(shape.get()); 
    163  
    164   shape = new ShapeDrawable(new Box(Vec3(3.0f, 0.0f, 0.0f), 2 * radius), hints.get()); 
    165   shape->setColor(Vec4(0.4f, 0.9f, 0.3f, 1.0f)); 
    166   geode_2->addDrawable(shape.get()); 
    167  
    168   shape = new ShapeDrawable(new Cone(Vec3(0.0f, 0.0f, -3.0f), radius, height), hints.get()); 
    169   shape->setColor(Vec4(0.2f, 0.5f, 0.7f, 1.0f)); 
    170   geode_2->addDrawable(shape.get()); 
    171  
    172   shape = new ShapeDrawable(new Cylinder(Vec3(0.0f, 0.0f, 3.0f), radius, height), hints.get()); 
    173   shape->setColor(Vec4(1.0f, 0.3f, 0.3f, 1.0f)); 
    174   geode_2->addDrawable(shape.get()); 
    175  
    176   shape = new ShapeDrawable(new Box(Vec3(0.0f, 3.0f, 0.0f), 2, 0.1f, 2), hints.get()); 
    177   shape->setColor(Vec4(0.8f, 0.8f, 0.4f, 1.0f)); 
    178   geode_3->addDrawable(shape.get()); 
    179  
    180   // material 
    181   ref_ptr<Material> matirial = new Material; 
    182   matirial->setColorMode(Material::DIFFUSE); 
    183   matirial->setAmbient(Material::FRONT_AND_BACK, Vec4(0, 0, 0, 1)); 
    184   matirial->setSpecular(Material::FRONT_AND_BACK, Vec4(1, 1, 1, 1)); 
    185   matirial->setShininess(Material::FRONT_AND_BACK, 64.0f); 
    186   scene->getOrCreateStateSet()->setAttributeAndModes(matirial.get(), StateAttribute::ON); 
    187  
    188   return scene; 
    189 } 
    190  
    191  
    192 class UpdateCameraAndTexGenCallback : public osg::NodeCallback 
    193 { 
    194     public: 
    195      
    196         UpdateCameraAndTexGenCallback(osg::MatrixTransform* light_transform, osg::CameraNode* cameraNode, osg::TexGenNode* texgenNode): 
    197             _light_transform(light_transform), 
    198             _cameraNode(cameraNode), 
    199             _texgenNode(texgenNode) 
    200         { 
    201         } 
    202         
    203         virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) 
    204         { 
    205             // first update subgraph to make sure objects are all moved into postion 
    206             traverse(node,nv); 
    207              
    208             // now compute the camera's view and projection matrix to point at the shadower (the camera's children) 
    209             osg::BoundingSphere bs; 
    210             for(unsigned int i=0; i<_cameraNode->getNumChildren(); ++i) 
    211             { 
    212                 bs.expandBy(_cameraNode->getChild(i)->getBound()); 
    213             } 
    214              
    215             if (!bs.valid()) 
    216             { 
    217                 osg::notify(osg::WARN) << "bb invalid"<<_cameraNode.get()<<std::endl; 
    218                 return; 
    219             } 
    220              
    221             osg::Vec3 position = _light_transform->getMatrix().getTrans(); 
    222  
    223             float centerDistance = (position-bs.center()).length(); 
    224  
    225             float znear = centerDistance-bs.radius(); 
    226             float zfar  = centerDistance+bs.radius(); 
    227             float zNearRatio = 0.001f; 
    228             if (znear<zfar*zNearRatio) znear = zfar*zNearRatio; 
    229  
    230 #if 0 
    231             // hack to illustrate the precision problems of excessive gap between near far range. 
    232             znear = 0.00001*zfar; 
    233 #endif 
    234             float top   = (bs.radius()/centerDistance)*znear; 
    235             float right = top; 
    236  
    237             _cameraNode->setReferenceFrame(osg::CameraNode::ABSOLUTE_RF); 
    238             _cameraNode->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar); 
    239             _cameraNode->setViewMatrixAsLookAt(position,bs.center(),osg::Vec3(0.0f,1.0f,0.0f)); 
    240  
    241             // compute the matrix which takes a vertex from local coords into tex coords 
    242             // will use this later to specify osg::TexGen.. 
    243             osg::Matrix MVPT = _cameraNode->getViewMatrix() *  
    244                                _cameraNode->getProjectionMatrix() * 
    245                                osg::Matrix::translate(1.0,1.0,1.0) * 
    246                                osg::Matrix::scale(0.5f,0.5f,0.5f); 
    247                                 
    248             _texgenNode->getTexGen()->setMode(osg::TexGen::EYE_LINEAR); 
    249             _texgenNode->getTexGen()->setPlanesFromMatrix(MVPT); 
    250  
    251         } 
    252          
    253     protected: 
    254      
    255         virtual ~UpdateCameraAndTexGenCallback() {} 
    256          
    257         osg::ref_ptr<osg::MatrixTransform>  _light_transform; 
    258         osg::ref_ptr<osg::CameraNode>       _cameraNode; 
    259         osg::ref_ptr<osg::TexGenNode>       _texgenNode; 
    260  
    261 }; 
    262  
    263 ////////////////////////////////////////////////////////////////// 
    264 // fragment shader 
    265 // 
    266 char fragmentShaderSource_noBaseTexture[] =  
    267     "uniform sampler2DShadow shadowTexture; \n" 
    268     "uniform vec2 ambientBias; \n" 
    269     "\n" 
    270     "void main(void) \n" 
    271     "{ \n" 
    272     "    gl_FragColor = gl_Color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[0] ) * ambientBias.y); \n" 
    273     "}\n"; 
    274  
    275 ////////////////////////////////////////////////////////////////// 
    276 // fragment shader 
    277 // 
    278 char fragmentShaderSource_withBaseTexture[] =  
    279     "uniform sampler2D baseTexture; \n" 
    280     "uniform sampler2DShadow shadowTexture; \n" 
    281     "uniform vec2 ambientBias; \n" 
    282     "\n" 
    283     "void main(void) \n" 
    284     "{ \n" 
    285     "    vec4 color = gl_Color * texture2D( baseTexture, gl_TexCoord[0].xy ); \n" 
    286     "    gl_FragColor = color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[1] ) * ambientBias.y); \n" 
    287     "}\n"; 
    288  
    289  
    290 osg::Group* createShadowedScene(osg::Node* shadowed,osg::MatrixTransform* light_transform, unsigned int unit) 
    291 { 
    292     osg::Group* group = new osg::Group; 
    293      
    294     unsigned int tex_width = 1024; 
    295     unsigned int tex_height = 1024; 
    296      
    297     osg::Texture2D* texture = new osg::Texture2D; 
    298     texture->setTextureSize(tex_width, tex_height); 
    299  
    300     texture->setInternalFormat(GL_DEPTH_COMPONENT); 
    301     texture->setShadowComparison(true); 
    302     texture->setShadowTextureMode(Texture::LUMINANCE); 
    303     texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); 
    304     texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); 
    305      
    306     // set up the render to texture camera. 
    307     { 
    308  
    309         // create the camera 
    310         osg::CameraNode* camera = new osg::CameraNode; 
    311  
    312         camera->setClearMask(GL_DEPTH_BUFFER_BIT); 
    313         camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); 
    314         camera->setComputeNearFarMode(osg::CameraNode::DO_NOT_COMPUTE_NEAR_FAR); 
    315  
    316         // set viewport 
    317         camera->setViewport(0,0,tex_width,tex_height); 
    318  
    319         osg::StateSet*  _local_stateset = camera->getOrCreateStateSet(); 
    320  
    321         _local_stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); 
    322  
    323  
    324         float factor = 0.0f; 
    325         float units = 1.0f; 
    326  
    327         ref_ptr<PolygonOffset> polygon_offset = new PolygonOffset; 
    328         polygon_offset->setFactor(factor); 
    329         polygon_offset->setUnits(units); 
    330         _local_stateset->setAttribute(polygon_offset.get(), StateAttribute::ON | StateAttribute::OVERRIDE); 
    331         _local_stateset->setMode(GL_POLYGON_OFFSET_FILL, StateAttribute::ON | StateAttribute::OVERRIDE); 
    332  
    333         ref_ptr<CullFace> cull_face = new CullFace; 
    334         cull_face->setMode(CullFace::FRONT); 
    335         _local_stateset->setAttribute(cull_face.get(), StateAttribute::ON | StateAttribute::OVERRIDE); 
    336         _local_stateset->setMode(GL_CULL_FACE, StateAttribute::ON | StateAttribute::OVERRIDE); 
    337  
    338  
    339         // set the camera to render before the main camera. 
    340         camera->setRenderOrder(osg::CameraNode::PRE_RENDER); 
    341  
    342         // tell the camera to use OpenGL frame buffer object where supported. 
    343         camera->setRenderTargetImplementation(osg::CameraNode::FRAME_BUFFER_OBJECT); 
    344  
    345         // attach the texture and use it as the color buffer. 
    346         camera->attach(osg::CameraNode::DEPTH_BUFFER, texture); 
    347  
    348         // add subgraph to render 
    349         camera->addChild(shadowed); 
    350          
    351         group->addChild(camera); 
    352          
    353         // create the texgen node to project the tex coords onto the subgraph 
    354         osg::TexGenNode* texgenNode = new osg::TexGenNode; 
    355         texgenNode->setTextureUnit(unit); 
    356         group->addChild(texgenNode); 
    357  
    358         // set an update callback to keep moving the camera and tex gen in the right direction. 
    359         group->setUpdateCallback(new UpdateCameraAndTexGenCallback(light_transform, camera, texgenNode)); 
    360     } 
    361     
    362  
    363     // set the shadowed subgraph so that it uses the texture and tex gen settings.     
    364     { 
    365         osg::Group* shadowedGroup = new osg::Group; 
    366         shadowedGroup->addChild(shadowed); 
    367         group->addChild(shadowedGroup); 
    368                  
    369         osg::StateSet* stateset = shadowedGroup->getOrCreateStateSet(); 
    370         stateset->setTextureAttributeAndModes(unit,texture,osg::StateAttribute::ON); 
    371         stateset->setTextureMode(unit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); 
    372         stateset->setTextureMode(unit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); 
    373         stateset->setTextureMode(unit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); 
    374  
    375         stateset->setTextureMode(unit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); 
    376  
    377         osg::Program* program = new osg::Program; 
    378         stateset->setAttribute(program); 
    379  
    380         if (unit==0) 
    381         { 
    382             osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture); 
    383             program->addShader(fragment_shader); 
    384  
    385             osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)unit); 
    386             stateset->addUniform(shadowTextureSampler); 
    387         } 
    388         else 
    389         { 
    390             osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture); 
    391             program->addShader(fragment_shader); 
    392  
    393             osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0); 
    394             stateset->addUniform(baseTextureSampler); 
    395  
    396             osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)unit); 
    397             stateset->addUniform(shadowTextureSampler); 
    398         } 
    399          
    400         osg::Uniform* ambientBias = new osg::Uniform("ambientBias",osg::Vec2(0.3f,1.2f)); 
    401         stateset->addUniform(ambientBias); 
    402  
    403     } 
    404      
    405     // add the shadower and shadowed. 
    406     group->addChild(light_transform); 
    407      
    408     return group; 
    409 } 
    4108 
    4119 
     
    41311{ 
    41412    // use an ArgumentParser object to manage the program arguments. 
    415     ArgumentParser arguments(&argc, argv); 
     13    osg::ArgumentParser arguments(&argc, argv); 
    41614 
    41715    // set up the usage document, in case we need to print out how to use this program. 
     
    43028    // get details on keyboard and mouse bindings used by the viewer. 
    43129    viewer.getUsage(*arguments. getApplicationUsage()); 
    432  
    433     bool withBaseTexture = true; 
    434     while(arguments.read("--with-base-texture")) { withBaseTexture = true; } 
    435     while(arguments.read("--no-base-texture")) { withBaseTexture = false; } 
    43630 
    43731    // if user request help write it out to cout. 
     
    45246    } 
    45347 
    454     ref_ptr<MatrixTransform> scene = new MatrixTransform; 
    455     scene->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(125.0),1.0,0.0,0.0)); 
    45648 
    457     ref_ptr<Group> shadowed_scene = _create_scene();     
    458     if (!shadowed_scene.valid()) return 1; 
    459  
    460     ref_ptr<MatrixTransform> light_transform = _create_lights(); 
    461     if (!light_transform.valid()) return 1; 
    462  
    463     ref_ptr<Group> shadowedScene; 
     49    osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments); 
     50    if (!model) 
     51    { 
     52        osg::notify(osg::NOTICE)<<"No model loaded, please specify a model to load."<<std::endl; 
     53        return 1; 
     54    } 
    46455     
    46556     
    466     if (withBaseTexture) 
    467     { 
    468         shadowed_scene->getOrCreateStateSet()->setTextureAttributeAndModes( 0, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb")), osg::StateAttribute::ON); 
    469         shadowedScene = createShadowedScene(shadowed_scene.get(),light_transform.get(),1); 
    470     } 
    471     else 
    472     { 
    473         shadowedScene = createShadowedScene(shadowed_scene.get(),light_transform.get(),0); 
    474     } 
     57    osg::ref_ptr<osgShadow::OccluderGeometry> occluder = new osgShadow::OccluderGeometry; 
     58    occluder->computeOccluderGeometry(model.get()); 
    47559     
    476     scene->addChild(shadowedScene.get()); 
     60    osg::ref_ptr<osg::Geode> geode = new osg::Geode; 
     61    geode->addDrawable(occluder.get()); 
    47762 
    478     viewer.setSceneData(scene.get()); 
     63    viewer.setSceneData(geode.get()); 
    47964 
    48065    // create the windows and run the threads.