diff --git a/examples/osgshadow/osgshadow.cpp b/examples/osgshadow/osgshadow.cpp index 8f1183af3..b692fb57f 100644 --- a/examples/osgshadow/osgshadow.cpp +++ b/examples/osgshadow/osgshadow.cpp @@ -53,15 +53,27 @@ int main(int argc, char** argv) return 1; } + const osg::BoundingSphere& bs = model->getBound(); + osg::Plane basePlane(0.0, 0.0, 1.0, -( bs.center().z() - bs.radius() ) ); osg::ref_ptr geode = new osg::Geode; osg::ref_ptr occluder = new osgShadow::OccluderGeometry; occluder->computeOccluderGeometry(model.get()); + occluder->getBoundingPolytope().add(basePlane); + //geode->addDrawable(occluder.get()); - geode->addDrawable(occluder.get()); + osg::ref_ptr shadowVolume = new osgShadow::ShadowVolumeGeometry; + occluder->comptueShadowVolumeGeometry(osg::Vec4(0.0f,-.5f,-1.0f,0.0f), *shadowVolume); + geode->addDrawable(shadowVolume.get()); - viewer.setSceneData(geode.get()); + + osg::ref_ptr group = new osg::Group; + group->addChild(model.get()); + group->addChild(geode.get()); + + + viewer.setSceneData(group.get()); // create the windows and run the threads. viewer.realize(); diff --git a/include/osgShadow/OccluderGeometry b/include/osgShadow/OccluderGeometry index 5fda16945..32dd43b67 100644 --- a/include/osgShadow/OccluderGeometry +++ b/include/osgShadow/OccluderGeometry @@ -17,12 +17,15 @@ #include #include #include +#include #include namespace osgShadow { +class ShadowVolumeGeometry; + /** OccluderGeometry provides a sepecialised geometry representation of objects in scene that occlude light and therefore cast shadows. * OccluderGeometry supports the computation of silhouette edges and shadow volume geometries, as well as use as geometry that one can rendering * into a shadow map or end caps for the ZP+ algorithm. OccluderGeometry may be of the same resolution as an underlying geometry that it @@ -98,6 +101,8 @@ class OSGSHADOW_EXPORT OccluderGeometry : public osg::Drawable // argg more than two triangles assigned return false; } + + bool boundaryEdge() const { return _t2<0; } unsigned int _p1; unsigned int _p2; @@ -108,11 +113,27 @@ class OSGSHADOW_EXPORT OccluderGeometry : public osg::Drawable typedef std::vector EdgeList; + /** Compute an occluder geometry containing all the geometry in specified subgraph.*/ 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, osg::Matrix* matrix=0, float sampleRatio=1.0f); + + + /** Compute ShadowVolumeGeometry. */ + void comptueShadowVolumeGeometry(const osg::Vec4& lightpos, ShadowVolumeGeometry& svg); + + + /** Set the bounding polytope of the OccluderGeometry.*/ + void setBoundingPolytope(const osg::Polytope& polytope) { _boundingPolytope = polytope; } + + /** Get the bounding polytope of the OccluderGeometry.*/ + osg::Polytope& getBoundingPolytope() { return _boundingPolytope; } + + /** Get the const bounding polytope of the OccluderGeometry.*/ + const osg::Polytope& getBoundingPolytope() const { return _boundingPolytope; } + /** Render the occluder geometry. */ virtual void drawImplementation(osg::RenderInfo& renderInfo) const; @@ -128,17 +149,29 @@ class OSGSHADOW_EXPORT OccluderGeometry : public osg::Drawable virtual ~OccluderGeometry() {} - inline float testLightPointSilhouetteEdge(const osg::Vec3& lightpos, const Edge& edge) const + inline bool isLightPointSilhouetteEdge(const osg::Vec3& lightpos, const Edge& edge) const { + if (edge.boundaryEdge()) return true; + osg::Vec3 delta(lightpos-_vertices[edge._p1]); - return ( delta * _triangleNormals[edge._t1] ) * - ( delta * _triangleNormals[edge._t2] ); + float n1 = delta * _triangleNormals[edge._t1]; + float n2 = delta * _triangleNormals[edge._t2]; + + if (n1==0.0f && n2==0.0f) return false; + + return n1*n2 <= 0.0f; } - inline float testLightDirectionSilhouetteEdge(const osg::Vec3& lightdirection, const Edge& edge) const + inline bool isLightDirectionSilhouetteEdge(const osg::Vec3& lightdirection, const Edge& edge) const { - return ( lightdirection * _triangleNormals[edge._t1] ) * - ( lightdirection * _triangleNormals[edge._t2] ); + if (edge.boundaryEdge()) return true; + + float n1 = lightdirection * _triangleNormals[edge._t1]; + float n2 = lightdirection * _triangleNormals[edge._t2]; + + if (n1==0.0f && n2==0.0f) return false; + + return n1*n2 <= 0.0f; } void setUpInternalStructures(); @@ -151,6 +184,8 @@ class OSGSHADOW_EXPORT OccluderGeometry : public osg::Drawable void computeLightPointSlihouetteEdges(const osg::Vec3& lightpos); void computeLightDirectionSlihouetteEdges(const osg::Vec3& lightdirection); + osg::Polytope _boundingPolytope; + Vec3List _vertices; Vec3List _normals; Vec3List _triangleNormals; @@ -161,6 +196,49 @@ class OSGSHADOW_EXPORT OccluderGeometry : public osg::Drawable UIntList _silhouetteIndices; }; +class OSGSHADOW_EXPORT ShadowVolumeGeometry : public osg::Drawable +{ + public : + ShadowVolumeGeometry(); + + ShadowVolumeGeometry(const ShadowVolumeGeometry& oc, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); + + virtual Object* cloneType() const { return new ShadowVolumeGeometry(); } + virtual Object* clone(const osg::CopyOp& copyop) const { return new ShadowVolumeGeometry(*this,copyop); } + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual const char* libraryName() const { return "osgShadow"; } + virtual const char* className() const { return "ShadowVolumeGeometry"; } + + + typedef std::vector Vec3List; + typedef std::vector UIntList; + + void setVertices(const Vec3List& vertices) { _vertices = vertices; } + Vec3List& getVertices() { return _vertices; } + const Vec3List& getVertices() const { return _vertices; } + + void setNormals(const Vec3List& normals) { _normals = normals; } + Vec3List& getNormals() { return _normals; } + const Vec3List& getNormals() const { return _normals; } + + + /** Render the occluder geometry. */ + virtual void drawImplementation(osg::RenderInfo& renderInfo) const; + + /** Compute the bounding box around occluder geometry.*/ + virtual osg::BoundingBox computeBound() const; + + public: + + protected : + + virtual ~ShadowVolumeGeometry() {} + + Vec3List _vertices; + Vec3List _normals; + UIntList _indices; +}; + } #endif diff --git a/src/osgShadow/OccluderGeometry.cpp b/src/osgShadow/OccluderGeometry.cpp index dce50ad5d..6631349e6 100644 --- a/src/osgShadow/OccluderGeometry.cpp +++ b/src/osgShadow/OccluderGeometry.cpp @@ -650,7 +650,7 @@ void OccluderGeometry::computeLightPointSlihouetteEdges(const osg::Vec3& lightpo ++eitr) { Edge& edge = *eitr; - if (testLightPointSilhouetteEdge(lightpos,edge)<=0.0f) + if (isLightPointSilhouetteEdge(lightpos,edge)) { _silhouetteIndices.push_back(edge._p1); _silhouetteIndices.push_back(edge._p2); @@ -667,7 +667,7 @@ void OccluderGeometry::computeLightDirectionSlihouetteEdges(const osg::Vec3& lig ++eitr) { Edge& edge = *eitr; - if (testLightDirectionSilhouetteEdge(lightdirection,edge)<=0.0f) + if (isLightDirectionSilhouetteEdge(lightdirection,edge)) { _silhouetteIndices.push_back(edge._p1); _silhouetteIndices.push_back(edge._p2); @@ -675,10 +675,82 @@ void OccluderGeometry::computeLightDirectionSlihouetteEdges(const osg::Vec3& lig } } +void OccluderGeometry::comptueShadowVolumeGeometry(const osg::Vec4& lightpos, ShadowVolumeGeometry& svg) +{ + ShadowVolumeGeometry::Vec3List& shadowVertices = svg.getVertices(); + shadowVertices.clear(); + + ShadowVolumeGeometry::Vec3List& shadowNormals = svg.getNormals(); + shadowNormals.clear(); + + osg::Plane basePlane(0.0, 0.0, 1.0, 0.0); + + const osg::Polytope::PlaneList& planes = _boundingPolytope.getPlaneList(); + + if (!planes.empty()) + { + basePlane = planes[0]; + } + + osg::Vec3 offset; + + if (lightpos.w()==0.0) + { + osg::Vec3 lightdirection( lightpos.x(), lightpos.y(), lightpos.z()); + + osg::notify(osg::NOTICE)<<"Directional light"<disableAllVertexArrays(); renderInfo.getState()->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) ); @@ -711,7 +783,52 @@ osg::BoundingBox OccluderGeometry::computeBound() const bb.expandBy(*itr); } - osg::notify(osg::NOTICE)<<"computeBB "<disableAllVertexArrays(); + + renderInfo.getState()->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) ); + + if (!_normals.empty()) + { + renderInfo.getState()->setNormalPointer( GL_FLOAT, 0, &(_normals.front()) ); + } + else + { + glNormal3f(0.0f, 0.0f, 0.0f); + } + + + glColor4f(0.5f, 1.0f, 1.0f, 1.0f); + + glDrawArrays( GL_QUADS, 0, _vertices.size() ); +} + +osg::BoundingBox ShadowVolumeGeometry::computeBound() const +{ + osg::BoundingBox bb; + for(Vec3List::const_iterator itr = _vertices.begin(); + itr != _vertices.end(); + ++itr) + { + bb.expandBy(*itr); + } return bb; }