From 8983544a86cfe9e7586f2b5440eebbf552751ca0 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 10 Nov 2006 15:07:13 +0000 Subject: [PATCH] Further work on osgShadow::GeometryOccluder --- examples/osgshadow/osgshadow.cpp | 445 +---------------------------- include/osg/Material | 4 +- include/osgShadow/OccluderGeometry | 6 +- src/osgShadow/OccluderGeometry.cpp | 210 +++++++++++++- 4 files changed, 230 insertions(+), 435 deletions(-) diff --git a/examples/osgshadow/osgshadow.cpp b/examples/osgshadow/osgshadow.cpp index d5a6d1a14..9319471e9 100644 --- a/examples/osgshadow/osgshadow.cpp +++ b/examples/osgshadow/osgshadow.cpp @@ -1,418 +1,16 @@ +#include + #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include +#include #include -using namespace osg; - -class LightTransformCallback: public osg::NodeCallback -{ - -public: - - LightTransformCallback(float angular_velocity, float height, float radius): - _angular_velocity(angular_velocity), - _height(height), - _radius(radius), - _previous_traversal_number(-1), - _previous_time(-1.0f), - _angle(0) - { - } - - void operator()(Node* node, NodeVisitor* nv); - -protected: - - float _angular_velocity; - float _height; - float _radius; - int _previous_traversal_number; - double _previous_time; - float _angle; -}; - - -void -LightTransformCallback::operator()(Node* node, NodeVisitor* nv) -{ - MatrixTransform* transform = dynamic_cast(node); - if (nv && transform) - { - const FrameStamp* fs = nv->getFrameStamp(); - if (!fs) return; // not frame stamp, no handle on the time so can't move. - - double new_time = fs->getReferenceTime(); - if (nv->getTraversalNumber() != _previous_traversal_number) - { - _angle += _angular_velocity * (new_time - _previous_time); - - Matrix matrix = Matrix::rotate(atan(_height / _radius), -X_AXIS) * - Matrix::rotate(PI_2, Y_AXIS) * - Matrix::translate(Vec3(_radius, 0, 0)) * - Matrix::rotate(_angle, Y_AXIS) * - Matrix::translate(Vec3(0, _height, 0)); - - // update the specified transform - transform->setMatrix(matrix); - - _previous_traversal_number = nv->getTraversalNumber(); - } - - _previous_time = new_time; - } - - // must call any nested node callbacks and continue subgraph traversal. - traverse(node,nv); - -} - - -ref_ptr _create_lights() -{ - ref_ptr transform_0 = new MatrixTransform; - - // create a spot light. - ref_ptr light_0 = new Light; - light_0->setLightNum(0); - light_0->setPosition(Vec4(0, 0, 0, 1.0f)); - light_0->setAmbient(Vec4(0.0f, 0.0f, 0.0f, 1.0f)); - light_0->setDiffuse(Vec4(1.0f, 0.8f, 0.8f, 1.0f)); - light_0->setSpotCutoff(60.0f); - light_0->setSpotExponent(2.0f); - - ref_ptr light_source_0 = new LightSource; - light_source_0->setLight(light_0.get()); - light_source_0->setLocalStateSetModes(StateAttribute::ON); - transform_0->setUpdateCallback(new LightTransformCallback(inDegrees(90.0f), 8, 5)); - transform_0->addChild(light_source_0.get()); - - ref_ptr geode = new Geode; - - ref_ptr shape; - ref_ptr hints = new TessellationHints; - hints->setDetailRatio(0.3f); - shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f), 0.15f), hints.get()); - shape->setColor(Vec4(1.0f, 0.5f, 0.5f, 1.0f)); - geode->addDrawable(shape.get()); - shape = new ShapeDrawable(new Cylinder(Vec3(0.0f, 0.0f, -0.4f), 0.05f, 0.8f), hints.get()); - shape->setColor(Vec4(1.0f, 0.5f, 0.5f, 1.0f)); - geode->addDrawable(shape.get()); - - - geode->getOrCreateStateSet()->setMode(GL_LIGHTING, StateAttribute::OFF); - transform_0->addChild(geode.get()); - - return transform_0; -} - -ref_ptr _create_scene() -{ - ref_ptr scene = new Group; - ref_ptr geode_1 = new Geode; - scene->addChild(geode_1.get()); - - ref_ptr geode_2 = new Geode; - ref_ptr transform_2 = new MatrixTransform; - transform_2->addChild(geode_2.get()); - transform_2->setUpdateCallback(new osg::AnimationPathCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(45.0f))); - scene->addChild(transform_2.get()); - - ref_ptr geode_3 = new Geode; - ref_ptr transform_3 = new MatrixTransform; - transform_3->addChild(geode_3.get()); - transform_3->setUpdateCallback(new osg::AnimationPathCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(-22.5f))); - scene->addChild(transform_3.get()); - - const float radius = 0.8f; - const float height = 1.0f; - ref_ptr hints = new TessellationHints; - hints->setDetailRatio(2.0f); - ref_ptr shape; - - shape = new ShapeDrawable(new Box(Vec3(0.0f, -2.0f, 0.0f), 10, 0.1f, 10), hints.get()); - shape->setColor(Vec4(0.5f, 0.5f, 0.7f, 1.0f)); - geode_1->addDrawable(shape.get()); - - shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f), radius * 2), hints.get()); - shape->setColor(Vec4(0.8f, 0.8f, 0.8f, 1.0f)); - geode_1->addDrawable(shape.get()); - - shape = new ShapeDrawable(new Sphere(Vec3(-3.0f, 0.0f, 0.0f), radius), hints.get()); - shape->setColor(Vec4(0.6f, 0.8f, 0.8f, 1.0f)); - geode_2->addDrawable(shape.get()); - - shape = new ShapeDrawable(new Box(Vec3(3.0f, 0.0f, 0.0f), 2 * radius), hints.get()); - shape->setColor(Vec4(0.4f, 0.9f, 0.3f, 1.0f)); - geode_2->addDrawable(shape.get()); - - shape = new ShapeDrawable(new Cone(Vec3(0.0f, 0.0f, -3.0f), radius, height), hints.get()); - shape->setColor(Vec4(0.2f, 0.5f, 0.7f, 1.0f)); - geode_2->addDrawable(shape.get()); - - shape = new ShapeDrawable(new Cylinder(Vec3(0.0f, 0.0f, 3.0f), radius, height), hints.get()); - shape->setColor(Vec4(1.0f, 0.3f, 0.3f, 1.0f)); - geode_2->addDrawable(shape.get()); - - shape = new ShapeDrawable(new Box(Vec3(0.0f, 3.0f, 0.0f), 2, 0.1f, 2), hints.get()); - shape->setColor(Vec4(0.8f, 0.8f, 0.4f, 1.0f)); - geode_3->addDrawable(shape.get()); - - // material - ref_ptr matirial = new Material; - matirial->setColorMode(Material::DIFFUSE); - matirial->setAmbient(Material::FRONT_AND_BACK, Vec4(0, 0, 0, 1)); - matirial->setSpecular(Material::FRONT_AND_BACK, Vec4(1, 1, 1, 1)); - matirial->setShininess(Material::FRONT_AND_BACK, 64.0f); - scene->getOrCreateStateSet()->setAttributeAndModes(matirial.get(), StateAttribute::ON); - - return scene; -} - - -class UpdateCameraAndTexGenCallback : public osg::NodeCallback -{ - public: - - UpdateCameraAndTexGenCallback(osg::MatrixTransform* light_transform, osg::CameraNode* cameraNode, osg::TexGenNode* texgenNode): - _light_transform(light_transform), - _cameraNode(cameraNode), - _texgenNode(texgenNode) - { - } - - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - // first update subgraph to make sure objects are all moved into postion - traverse(node,nv); - - // now compute the camera's view and projection matrix to point at the shadower (the camera's children) - osg::BoundingSphere bs; - for(unsigned int i=0; i<_cameraNode->getNumChildren(); ++i) - { - bs.expandBy(_cameraNode->getChild(i)->getBound()); - } - - if (!bs.valid()) - { - osg::notify(osg::WARN) << "bb invalid"<<_cameraNode.get()<getMatrix().getTrans(); - - float centerDistance = (position-bs.center()).length(); - - float znear = centerDistance-bs.radius(); - float zfar = centerDistance+bs.radius(); - float zNearRatio = 0.001f; - if (znearsetReferenceFrame(osg::CameraNode::ABSOLUTE_RF); - _cameraNode->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar); - _cameraNode->setViewMatrixAsLookAt(position,bs.center(),osg::Vec3(0.0f,1.0f,0.0f)); - - // compute the matrix which takes a vertex from local coords into tex coords - // will use this later to specify osg::TexGen.. - osg::Matrix MVPT = _cameraNode->getViewMatrix() * - _cameraNode->getProjectionMatrix() * - osg::Matrix::translate(1.0,1.0,1.0) * - osg::Matrix::scale(0.5f,0.5f,0.5f); - - _texgenNode->getTexGen()->setMode(osg::TexGen::EYE_LINEAR); - _texgenNode->getTexGen()->setPlanesFromMatrix(MVPT); - - } - - protected: - - virtual ~UpdateCameraAndTexGenCallback() {} - - osg::ref_ptr _light_transform; - osg::ref_ptr _cameraNode; - osg::ref_ptr _texgenNode; - -}; - -////////////////////////////////////////////////////////////////// -// fragment shader -// -char fragmentShaderSource_noBaseTexture[] = - "uniform sampler2DShadow shadowTexture; \n" - "uniform vec2 ambientBias; \n" - "\n" - "void main(void) \n" - "{ \n" - " gl_FragColor = gl_Color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[0] ) * ambientBias.y); \n" - "}\n"; - -////////////////////////////////////////////////////////////////// -// fragment shader -// -char fragmentShaderSource_withBaseTexture[] = - "uniform sampler2D baseTexture; \n" - "uniform sampler2DShadow shadowTexture; \n" - "uniform vec2 ambientBias; \n" - "\n" - "void main(void) \n" - "{ \n" - " vec4 color = gl_Color * texture2D( baseTexture, gl_TexCoord[0].xy ); \n" - " gl_FragColor = color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[1] ) * ambientBias.y); \n" - "}\n"; - - -osg::Group* createShadowedScene(osg::Node* shadowed,osg::MatrixTransform* light_transform, unsigned int unit) -{ - osg::Group* group = new osg::Group; - - unsigned int tex_width = 1024; - unsigned int tex_height = 1024; - - osg::Texture2D* texture = new osg::Texture2D; - texture->setTextureSize(tex_width, tex_height); - - texture->setInternalFormat(GL_DEPTH_COMPONENT); - texture->setShadowComparison(true); - texture->setShadowTextureMode(Texture::LUMINANCE); - texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); - texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); - - // set up the render to texture camera. - { - - // create the camera - osg::CameraNode* camera = new osg::CameraNode; - - camera->setClearMask(GL_DEPTH_BUFFER_BIT); - camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); - camera->setComputeNearFarMode(osg::CameraNode::DO_NOT_COMPUTE_NEAR_FAR); - - // set viewport - camera->setViewport(0,0,tex_width,tex_height); - - osg::StateSet* _local_stateset = camera->getOrCreateStateSet(); - - _local_stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - - - float factor = 0.0f; - float units = 1.0f; - - ref_ptr polygon_offset = new PolygonOffset; - polygon_offset->setFactor(factor); - polygon_offset->setUnits(units); - _local_stateset->setAttribute(polygon_offset.get(), StateAttribute::ON | StateAttribute::OVERRIDE); - _local_stateset->setMode(GL_POLYGON_OFFSET_FILL, StateAttribute::ON | StateAttribute::OVERRIDE); - - ref_ptr cull_face = new CullFace; - cull_face->setMode(CullFace::FRONT); - _local_stateset->setAttribute(cull_face.get(), StateAttribute::ON | StateAttribute::OVERRIDE); - _local_stateset->setMode(GL_CULL_FACE, StateAttribute::ON | StateAttribute::OVERRIDE); - - - // set the camera to render before the main camera. - camera->setRenderOrder(osg::CameraNode::PRE_RENDER); - - // tell the camera to use OpenGL frame buffer object where supported. - camera->setRenderTargetImplementation(osg::CameraNode::FRAME_BUFFER_OBJECT); - - // attach the texture and use it as the color buffer. - camera->attach(osg::CameraNode::DEPTH_BUFFER, texture); - - // add subgraph to render - camera->addChild(shadowed); - - group->addChild(camera); - - // create the texgen node to project the tex coords onto the subgraph - osg::TexGenNode* texgenNode = new osg::TexGenNode; - texgenNode->setTextureUnit(unit); - group->addChild(texgenNode); - - // set an update callback to keep moving the camera and tex gen in the right direction. - group->setUpdateCallback(new UpdateCameraAndTexGenCallback(light_transform, camera, texgenNode)); - } - - - // set the shadowed subgraph so that it uses the texture and tex gen settings. - { - osg::Group* shadowedGroup = new osg::Group; - shadowedGroup->addChild(shadowed); - group->addChild(shadowedGroup); - - osg::StateSet* stateset = shadowedGroup->getOrCreateStateSet(); - stateset->setTextureAttributeAndModes(unit,texture,osg::StateAttribute::ON); - stateset->setTextureMode(unit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); - stateset->setTextureMode(unit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); - stateset->setTextureMode(unit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); - - stateset->setTextureMode(unit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); - - osg::Program* program = new osg::Program; - stateset->setAttribute(program); - - if (unit==0) - { - osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture); - program->addShader(fragment_shader); - - osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)unit); - stateset->addUniform(shadowTextureSampler); - } - else - { - osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture); - program->addShader(fragment_shader); - - osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0); - stateset->addUniform(baseTextureSampler); - - osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)unit); - stateset->addUniform(shadowTextureSampler); - } - - osg::Uniform* ambientBias = new osg::Uniform("ambientBias",osg::Vec2(0.3f,1.2f)); - stateset->addUniform(ambientBias); - - } - - // add the shadower and shadowed. - group->addChild(light_transform); - - return group; -} - int main(int argc, char** argv) { // use an ArgumentParser object to manage the program arguments. - ArgumentParser arguments(&argc, argv); + osg::ArgumentParser arguments(&argc, argv); // 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"); @@ -430,10 +28,6 @@ int main(int argc, char** argv) // get details on keyboard and mouse bindings used by the viewer. viewer.getUsage(*arguments. getApplicationUsage()); - bool withBaseTexture = true; - while(arguments.read("--with-base-texture")) { withBaseTexture = true; } - while(arguments.read("--no-base-texture")) { withBaseTexture = false; } - // if user request help write it out to cout. if (arguments.read("-h") || arguments.read("--help")) { @@ -451,31 +45,22 @@ int main(int argc, char** argv) return 1; } - ref_ptr scene = new MatrixTransform; - scene->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(125.0),1.0,0.0,0.0)); - ref_ptr shadowed_scene = _create_scene(); - if (!shadowed_scene.valid()) return 1; - - ref_ptr light_transform = _create_lights(); - if (!light_transform.valid()) return 1; - - ref_ptr shadowedScene; - - - if (withBaseTexture) + osg::ref_ptr model = osgDB::readNodeFiles(arguments); + if (!model) { - shadowed_scene->getOrCreateStateSet()->setTextureAttributeAndModes( 0, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb")), osg::StateAttribute::ON); - shadowedScene = createShadowedScene(shadowed_scene.get(),light_transform.get(),1); - } - else - { - shadowedScene = createShadowedScene(shadowed_scene.get(),light_transform.get(),0); + osg::notify(osg::NOTICE)<<"No model loaded, please specify a model to load."<addChild(shadowedScene.get()); + + osg::ref_ptr occluder = new osgShadow::OccluderGeometry; + occluder->computeOccluderGeometry(model.get()); + + osg::ref_ptr geode = new osg::Geode; + geode->addDrawable(occluder.get()); - viewer.setSceneData(scene.get()); + viewer.setSceneData(geode.get()); // create the windows and run the threads. viewer.realize(); diff --git a/include/osg/Material b/include/osg/Material index be87d5457..f9249b942 100644 --- a/include/osg/Material +++ b/include/osg/Material @@ -79,7 +79,9 @@ class OSG_EXPORT Material : public StateAttribute virtual bool getModeUsage(ModeUsage& usage) const { - usage.usesMode(GL_COLOR_MATERIAL); + // note, since Material does it's own glEnable/glDisable of GL_COLOR_MATERIAL + // we shouldn't declare usage of that mode, so commenting out the below usage. + // usage.usesMode(GL_COLOR_MATERIAL); return true; } diff --git a/include/osgShadow/OccluderGeometry b/include/osgShadow/OccluderGeometry index 7cca6b0c7..a58b07f6e 100644 --- a/include/osgShadow/OccluderGeometry +++ b/include/osgShadow/OccluderGeometry @@ -68,14 +68,16 @@ class OSGSHADOW_EXPORT OccluderGeometry : public osg::Drawable /** Compute an occluder geometry containing all the geometry in specified subgraph.*/ - void computeOccluderGeometry(osg::Node* subgraph, float sampleRatio=1.0f); + void computeOccluderGeometry(osg::Node* subgraph, osg::Matrix* matrix=0, float sampleRatio=1.0f); /** Compute an occluder geometry containing the geometry in specified drawable.*/ - void computeOccluderGeometry(osg::Drawable* drawable, float sampleRatio=1.0f); + void computeOccluderGeometry(osg::Drawable* drawable, osg::Matrix* matrix=0, float sampleRatio=1.0f); /** Render the occluder geometry. */ virtual void drawImplementation(osg::RenderInfo& renderInfo) const; + /** Compute the bounding box around occluder geometry.*/ + virtual osg::BoundingBox computeBound() const; protected : diff --git a/src/osgShadow/OccluderGeometry.cpp b/src/osgShadow/OccluderGeometry.cpp index 6e376a13b..6024906da 100644 --- a/src/osgShadow/OccluderGeometry.cpp +++ b/src/osgShadow/OccluderGeometry.cpp @@ -12,6 +12,11 @@ */ #include +#include +#include +#include +#include +#include using namespace osgShadow; @@ -26,14 +31,215 @@ OccluderGeometry::OccluderGeometry(const OccluderGeometry& oc, const osg::CopyOp } -void OccluderGeometry::computeOccluderGeometry(osg::Node* subgraph, float sampleRatio) +class CollectOccludersVisitor : public osg::NodeVisitor { +public: + CollectOccludersVisitor(OccluderGeometry* oc, osg::Matrix* matrix, float ratio): + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN), + _oc(oc), + _ratio(ratio) + { + if (matrix) pushMatrix(*matrix); + } + + void apply(osg::Node& node) + { + if (node.getStateSet()) pushState(node.getStateSet()); + + traverse(node); + + if (node.getStateSet()) popState(); + } + + void apply(osg::Transform& transform) + { + if (transform.getStateSet()) pushState(transform.getStateSet()); + + osg::Matrix matrix; + if (!_matrixStack.empty()) matrix = _matrixStack.back(); + + transform.computeLocalToWorldMatrix(matrix,this); + + pushMatrix(matrix); + + traverse(transform); + + popMatrix(); + + if (transform.getStateSet()) popState(); + } + + void apply(osg::Geode& geode) + { + if (geode.getStateSet()) pushState(geode.getStateSet()); + + for(unsigned int i=0; igetStateSet()) pushState(drawable->getStateSet()); + + apply(geode.getDrawable(i)); + + if (drawable->getStateSet()) popState(); + } + + if (geode.getStateSet()) popState(); + } + + void pushState(osg::StateSet* stateset) + { + osg::StateAttribute::GLModeValue prevBlendModeValue = _blendModeStack.empty() ? osg::StateAttribute::GLModeValue(osg::StateAttribute::INHERIT) : _blendModeStack.back(); + osg::StateAttribute::GLModeValue newBlendModeValue = stateset->getMode(GL_BLEND); + + if (!(newBlendModeValue & osg::StateAttribute::PROTECTED) && + (prevBlendModeValue & osg::StateAttribute::OVERRIDE) ) + { + newBlendModeValue = prevBlendModeValue; + } + + _blendModeStack.push_back(newBlendModeValue); + } + + void popState() + { + _blendModeStack.pop_back(); + } + + void pushMatrix(osg::Matrix& matrix) + { + _matrixStack.push_back(matrix); + } + + void popMatrix() + { + _matrixStack.pop_back(); + } + + void apply(osg::Drawable* drawable) + { + osg::StateAttribute::GLModeValue blendModeValue = _blendModeStack.empty() ? osg::StateAttribute::GLModeValue(osg::StateAttribute::INHERIT) : _blendModeStack.back(); + if (blendModeValue & osg::StateAttribute::ON) + { + osg::notify(osg::NOTICE)<<"Ignoring transparent drawable."<computeOccluderGeometry(drawable, (_matrixStack.empty() ? 0 : &_matrixStack.back()), _ratio); + + } + + + +protected: + + OccluderGeometry* _oc; + + typedef std::vector MatrixStack; + typedef std::vector ModeStack; + + float _ratio; + MatrixStack _matrixStack; + ModeStack _blendModeStack; + +}; + +void OccluderGeometry::computeOccluderGeometry(osg::Node* subgraph, osg::Matrix* matrix, float sampleRatio) +{ + osg::notify(osg::NOTICE)<<"computeOccluderGeometry(osg::Node* subgraph, float sampleRatio)"<accept(cov); + + osg::notify(osg::NOTICE)<<"done"< TriangleIndexCollectorFunctor; + +struct TriangleCollector +{ + OccluderGeometry::Vec3List& _vertices; + OccluderGeometry::UIntList& _triangleIndices; + + typedef std::vector VertexPointers; + VertexPointers _vertexPointers; + + OccluderGeometry::Vec3List _tempoaryTriangleVertices; + + TriangleCollector(OccluderGeometry::Vec3List& vertices, OccluderGeometry::UIntList& triangleIndices): + _vertices(vertices), + _triangleIndices(triangleIndices) + { + } + + // bool intersect(const Vec3& v1,const Vec3& v2,const Vec3& v3,float& r) + inline void operator () (const osg::Vec3& v1,const osg::Vec3& v2,const osg::Vec3& v3, bool treatVertexDataAsTemporary) + { + if (treatVertexDataAsTemporary) + { + _tempoaryTriangleVertices.push_back(v1); + _tempoaryTriangleVertices.push_back(v2); + _tempoaryTriangleVertices.push_back(v3); + } + else + { + _vertexPointers.push_back(&v1); + _vertexPointers.push_back(&v2); + _vertexPointers.push_back(&v3); + } + + } + +}; +typedef osg::TriangleFunctor TriangleCollectorFunctor; + +void OccluderGeometry::computeOccluderGeometry(osg::Drawable* drawable, osg::Matrix* matrix, float sampleRatio) +{ + osg::notify(osg::NOTICE)<<"computeOccluderGeometry(osg::Node* subgraph, float sampleRatio)"<