/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #ifndef OSGSHADOW_OCCLUDERGEOMETRY #define OSGSHADOW_OCCLUDERGEOMETRY 1 #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 * represents, or can be of lower resolution and combine manager seperate geometries together into a single shadow casting object. * OccluderGeometry may be attached as UserData to Nodes or to Drawables. */ class OSGSHADOW_EXPORT OccluderGeometry : public osg::Drawable { public : OccluderGeometry(); OccluderGeometry(const OccluderGeometry& oc, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); virtual Object* cloneType() const { return new OccluderGeometry(); } virtual Object* clone(const osg::CopyOp& copyop) const { return new OccluderGeometry(*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 "OccluderGeometry"; } /** 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 computeShadowVolumeGeometry(const osg::Vec4& lightpos, ShadowVolumeGeometry& svg) const; /** 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; /** Compute the bounding box around occluder geometry.*/ virtual osg::BoundingBox computeBound() const; typedef std::vector Vec3List; typedef std::vector UIntList; public: void processGeometry(osg::Drawable* drawable, osg::Matrix* matrix=0, float sampleRatio=1.0f); protected : virtual ~OccluderGeometry() {} struct Edge { Edge(): _p1(0), _p2(0), _t1(-1), _t2(-1) {} Edge(unsigned int p1, unsigned int p2): _p1(p1), _p2(p2), _t1(-1), _t2(-1) { if (p1>p2) { // swap ordering so p1 is less than or equal to p2 _p1 = p2; _p2 = p1; } } inline bool operator < (const Edge& rhs) const { if (_p1 < rhs._p1) return true; if (_p1 > rhs._p1) return false; return (_p2 < rhs._p2); } bool addTriangle(unsigned int tri) const { if (_t1<0) { _t1 = tri; return true; } else if (_t2<0) { _t2 = tri; return true; } // argg more than two triangles assigned return false; } bool boundaryEdge() const { return _t2<0; } unsigned int _p1; unsigned int _p2; mutable int _t1; mutable int _t2; mutable osg::Vec3 _normal; }; typedef std::vector EdgeList; inline bool isLightPointSilhouetteEdge(const osg::Vec3& lightpos, const Edge& edge) const { if (edge.boundaryEdge()) return true; float offset = 0.0f; osg::Vec3 delta(lightpos-_vertices[edge._p1]); delta.normalize(); float n1 = delta * _triangleNormals[edge._t1] + offset; float n2 = delta * _triangleNormals[edge._t2] + offset; float angle_offset = 0.0f; n1 = cos(acosf(n1) + angle_offset); n2 = cos(acosf(n2) + angle_offset); if (n1==0.0f && n2==0.0f) return false; return n1*n2 <= 0.0f; } inline bool isLightDirectionSilhouetteEdge(const osg::Vec3& lightdirection, const Edge& edge) const { if (edge.boundaryEdge()) return true; float offset = 0.0f; float n1 = lightdirection * _triangleNormals[edge._t1] + offset; float n2 = lightdirection * _triangleNormals[edge._t2] + offset; float angle_offset = 0.0f; n1 = cos(acosf(n1) + angle_offset); n2 = cos(acosf(n2) + angle_offset); if (n1==0.0f && n2==0.0f) return false; return n1*n2 <= 0.0f; } void setUpInternalStructures(); void removeDuplicateVertices(); void removeNullTriangles(); void computeNormals(); void buildEdgeMaps(); void computeLightDirectionSlihouetteEdges(const osg::Vec3& lightdirection, UIntList& silhouetteIndices) const; void computeLightPositionSlihouetteEdges(const osg::Vec3& lightpos, UIntList& silhouetteIndices) const; osg::Polytope _boundingPolytope; Vec3List _vertices; Vec3List _normals; Vec3List _triangleNormals; UIntList _triangleIndices; EdgeList _edges; }; 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"; } enum DrawMode { GEOMETRY, STENCIL_TWO_PASS, STENCIL_TWO_SIDED }; void setDrawMode(DrawMode mode) { _drawMode = mode; } DrawMode getDrawMode() const { return _drawMode; } 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() {} DrawMode _drawMode; Vec3List _vertices; Vec3List _normals; UIntList _indices; }; } #endif