| 1 | /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield |
|---|
| 2 | * |
|---|
| 3 | * This library is open source and may be redistributed and/or modified under |
|---|
| 4 | * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or |
|---|
| 5 | * (at your option) any later version. The full license is in LICENSE file |
|---|
| 6 | * included with this distribution, and on the openscenegraph.org website. |
|---|
| 7 | * |
|---|
| 8 | * This library is distributed in the hope that it will be useful, |
|---|
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 11 | * OpenSceneGraph Public License for more details. |
|---|
| 12 | */ |
|---|
| 13 | |
|---|
| 14 | #ifndef OSGSHADOW_OCCLUDERGEOMETRY |
|---|
| 15 | #define OSGSHADOW_OCCLUDERGEOMETRY 1 |
|---|
| 16 | |
|---|
| 17 | #include <osg/Drawable> |
|---|
| 18 | #include <osg/Array> |
|---|
| 19 | #include <osg/PrimitiveSet> |
|---|
| 20 | #include <osg/Polytope> |
|---|
| 21 | |
|---|
| 22 | #include <osgShadow/Export> |
|---|
| 23 | |
|---|
| 24 | |
|---|
| 25 | namespace osgShadow { |
|---|
| 26 | |
|---|
| 27 | class ShadowVolumeGeometry; |
|---|
| 28 | |
|---|
| 29 | /** OccluderGeometry provides a sepecialised geometry representation of objects in scene that occlude light and therefore cast shadows. |
|---|
| 30 | * OccluderGeometry supports the computation of silhouette edges and shadow volume geometries, as well as use as geometry that one can rendering |
|---|
| 31 | * into a shadow map or end caps for the ZP+ algorithm. OccluderGeometry may be of the same resolution as an underlying geometry that it |
|---|
| 32 | * represents, or can be of lower resolution and combine manager seperate geometries together into a single shadow casting object. |
|---|
| 33 | * OccluderGeometry may be attached as UserData to Nodes or to Drawables. */ |
|---|
| 34 | class OSGSHADOW_EXPORT OccluderGeometry : public osg::Drawable |
|---|
| 35 | { |
|---|
| 36 | public : |
|---|
| 37 | OccluderGeometry(); |
|---|
| 38 | |
|---|
| 39 | OccluderGeometry(const OccluderGeometry& oc, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); |
|---|
| 40 | |
|---|
| 41 | virtual Object* cloneType() const { return new OccluderGeometry(); } |
|---|
| 42 | virtual Object* clone(const osg::CopyOp& copyop) const { return new OccluderGeometry(*this,copyop); } |
|---|
| 43 | virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const OccluderGeometry*>(obj)!=NULL; } |
|---|
| 44 | virtual const char* libraryName() const { return "osgShadow"; } |
|---|
| 45 | virtual const char* className() const { return "OccluderGeometry"; } |
|---|
| 46 | |
|---|
| 47 | /** Compute an occluder geometry containing all the geometry in specified subgraph.*/ |
|---|
| 48 | void computeOccluderGeometry(osg::Node* subgraph, osg::Matrix* matrix=0, float sampleRatio=1.0f); |
|---|
| 49 | |
|---|
| 50 | /** Compute an occluder geometry containing the geometry in specified drawable.*/ |
|---|
| 51 | void computeOccluderGeometry(osg::Drawable* drawable, osg::Matrix* matrix=0, float sampleRatio=1.0f); |
|---|
| 52 | |
|---|
| 53 | |
|---|
| 54 | /** Compute ShadowVolumeGeometry. */ |
|---|
| 55 | void computeShadowVolumeGeometry(const osg::Vec4& lightpos, ShadowVolumeGeometry& svg) const; |
|---|
| 56 | |
|---|
| 57 | |
|---|
| 58 | /** Set the bounding polytope of the OccluderGeometry.*/ |
|---|
| 59 | void setBoundingPolytope(const osg::Polytope& polytope) { _boundingPolytope = polytope; } |
|---|
| 60 | |
|---|
| 61 | /** Get the bounding polytope of the OccluderGeometry.*/ |
|---|
| 62 | osg::Polytope& getBoundingPolytope() { return _boundingPolytope; } |
|---|
| 63 | |
|---|
| 64 | /** Get the const bounding polytope of the OccluderGeometry.*/ |
|---|
| 65 | const osg::Polytope& getBoundingPolytope() const { return _boundingPolytope; } |
|---|
| 66 | |
|---|
| 67 | |
|---|
| 68 | /** Render the occluder geometry. */ |
|---|
| 69 | virtual void drawImplementation(osg::RenderInfo& renderInfo) const; |
|---|
| 70 | |
|---|
| 71 | /** Compute the bounding box around occluder geometry.*/ |
|---|
| 72 | virtual osg::BoundingBox computeBound() const; |
|---|
| 73 | |
|---|
| 74 | typedef std::vector<osg::Vec3> Vec3List; |
|---|
| 75 | typedef std::vector<GLuint> UIntList; |
|---|
| 76 | |
|---|
| 77 | public: |
|---|
| 78 | |
|---|
| 79 | void processGeometry(osg::Drawable* drawable, osg::Matrix* matrix=0, float sampleRatio=1.0f); |
|---|
| 80 | |
|---|
| 81 | protected : |
|---|
| 82 | |
|---|
| 83 | virtual ~OccluderGeometry() {} |
|---|
| 84 | |
|---|
| 85 | struct Edge |
|---|
| 86 | { |
|---|
| 87 | Edge(): |
|---|
| 88 | _p1(0), |
|---|
| 89 | _p2(0), |
|---|
| 90 | _t1(-1), |
|---|
| 91 | _t2(-1) {} |
|---|
| 92 | |
|---|
| 93 | Edge(unsigned int p1, unsigned int p2): |
|---|
| 94 | _p1(p1), |
|---|
| 95 | _p2(p2), |
|---|
| 96 | _t1(-1), |
|---|
| 97 | _t2(-1) |
|---|
| 98 | { |
|---|
| 99 | if (p1>p2) |
|---|
| 100 | { |
|---|
| 101 | // swap ordering so p1 is less than or equal to p2 |
|---|
| 102 | _p1 = p2; |
|---|
| 103 | _p2 = p1; |
|---|
| 104 | } |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | inline bool operator < (const Edge& rhs) const |
|---|
| 108 | { |
|---|
| 109 | if (_p1 < rhs._p1) return true; |
|---|
| 110 | if (_p1 > rhs._p1) return false; |
|---|
| 111 | return (_p2 < rhs._p2); |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | bool addTriangle(unsigned int tri) const |
|---|
| 115 | { |
|---|
| 116 | if (_t1<0) |
|---|
| 117 | { |
|---|
| 118 | _t1 = tri; |
|---|
| 119 | return true; |
|---|
| 120 | } |
|---|
| 121 | else if (_t2<0) |
|---|
| 122 | { |
|---|
| 123 | _t2 = tri; |
|---|
| 124 | return true; |
|---|
| 125 | } |
|---|
| 126 | // argg more than two triangles assigned |
|---|
| 127 | return false; |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | bool boundaryEdge() const { return _t2<0; } |
|---|
| 131 | |
|---|
| 132 | unsigned int _p1; |
|---|
| 133 | unsigned int _p2; |
|---|
| 134 | |
|---|
| 135 | mutable int _t1; |
|---|
| 136 | mutable int _t2; |
|---|
| 137 | |
|---|
| 138 | mutable osg::Vec3 _normal; |
|---|
| 139 | }; |
|---|
| 140 | |
|---|
| 141 | typedef std::vector<Edge> EdgeList; |
|---|
| 142 | |
|---|
| 143 | inline bool isLightPointSilhouetteEdge(const osg::Vec3& lightpos, const Edge& edge) const |
|---|
| 144 | { |
|---|
| 145 | if (edge.boundaryEdge()) return true; |
|---|
| 146 | |
|---|
| 147 | float offset = 0.0f; |
|---|
| 148 | |
|---|
| 149 | osg::Vec3 delta(lightpos-_vertices[edge._p1]); |
|---|
| 150 | delta.normalize(); |
|---|
| 151 | |
|---|
| 152 | float n1 = delta * _triangleNormals[edge._t1] + offset; |
|---|
| 153 | float n2 = delta * _triangleNormals[edge._t2] + offset; |
|---|
| 154 | |
|---|
| 155 | float angle_offset = 0.0f; |
|---|
| 156 | |
|---|
| 157 | n1 = cos(acosf(n1) + angle_offset); |
|---|
| 158 | n2 = cos(acosf(n2) + angle_offset); |
|---|
| 159 | |
|---|
| 160 | if (n1==0.0f && n2==0.0f) return false; |
|---|
| 161 | |
|---|
| 162 | return n1*n2 <= 0.0f; |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | inline bool isLightDirectionSilhouetteEdge(const osg::Vec3& lightdirection, const Edge& edge) const |
|---|
| 166 | { |
|---|
| 167 | if (edge.boundaryEdge()) return true; |
|---|
| 168 | |
|---|
| 169 | float offset = 0.0f; |
|---|
| 170 | |
|---|
| 171 | float n1 = lightdirection * _triangleNormals[edge._t1] + offset; |
|---|
| 172 | float n2 = lightdirection * _triangleNormals[edge._t2] + offset; |
|---|
| 173 | |
|---|
| 174 | float angle_offset = 0.0f; |
|---|
| 175 | |
|---|
| 176 | n1 = cos(acosf(n1) + angle_offset); |
|---|
| 177 | n2 = cos(acosf(n2) + angle_offset); |
|---|
| 178 | |
|---|
| 179 | if (n1==0.0f && n2==0.0f) return false; |
|---|
| 180 | |
|---|
| 181 | return n1*n2 <= 0.0f; |
|---|
| 182 | } |
|---|
| 183 | |
|---|
| 184 | void setUpInternalStructures(); |
|---|
| 185 | |
|---|
| 186 | void removeDuplicateVertices(); |
|---|
| 187 | void removeNullTriangles(); |
|---|
| 188 | void computeNormals(); |
|---|
| 189 | void buildEdgeMaps(); |
|---|
| 190 | |
|---|
| 191 | void computeLightDirectionSilhouetteEdges(const osg::Vec3& lightdirection, UIntList& silhouetteIndices) const; |
|---|
| 192 | void computeLightPositionSilhouetteEdges(const osg::Vec3& lightpos, UIntList& silhouetteIndices) const; |
|---|
| 193 | |
|---|
| 194 | osg::Polytope _boundingPolytope; |
|---|
| 195 | |
|---|
| 196 | Vec3List _vertices; |
|---|
| 197 | Vec3List _normals; |
|---|
| 198 | Vec3List _triangleNormals; |
|---|
| 199 | UIntList _triangleIndices; |
|---|
| 200 | |
|---|
| 201 | EdgeList _edges; |
|---|
| 202 | }; |
|---|
| 203 | |
|---|
| 204 | class OSGSHADOW_EXPORT ShadowVolumeGeometry : public osg::Drawable |
|---|
| 205 | { |
|---|
| 206 | public : |
|---|
| 207 | ShadowVolumeGeometry(); |
|---|
| 208 | |
|---|
| 209 | ShadowVolumeGeometry(const ShadowVolumeGeometry& oc, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); |
|---|
| 210 | |
|---|
| 211 | virtual Object* cloneType() const { return new ShadowVolumeGeometry(); } |
|---|
| 212 | virtual Object* clone(const osg::CopyOp& copyop) const { return new ShadowVolumeGeometry(*this,copyop); } |
|---|
| 213 | virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const ShadowVolumeGeometry*>(obj)!=NULL; } |
|---|
| 214 | virtual const char* libraryName() const { return "osgShadow"; } |
|---|
| 215 | virtual const char* className() const { return "ShadowVolumeGeometry"; } |
|---|
| 216 | |
|---|
| 217 | enum DrawMode |
|---|
| 218 | { |
|---|
| 219 | GEOMETRY, |
|---|
| 220 | STENCIL_TWO_PASS, |
|---|
| 221 | STENCIL_TWO_SIDED |
|---|
| 222 | }; |
|---|
| 223 | |
|---|
| 224 | void setDrawMode(DrawMode mode) { _drawMode = mode; } |
|---|
| 225 | DrawMode getDrawMode() const { return _drawMode; } |
|---|
| 226 | |
|---|
| 227 | typedef std::vector<osg::Vec3> Vec3List; |
|---|
| 228 | typedef std::vector<GLuint> UIntList; |
|---|
| 229 | |
|---|
| 230 | void setVertices(const Vec3List& vertices) { _vertices = vertices; } |
|---|
| 231 | Vec3List& getVertices() { return _vertices; } |
|---|
| 232 | const Vec3List& getVertices() const { return _vertices; } |
|---|
| 233 | |
|---|
| 234 | void setNormals(const Vec3List& normals) { _normals = normals; } |
|---|
| 235 | Vec3List& getNormals() { return _normals; } |
|---|
| 236 | const Vec3List& getNormals() const { return _normals; } |
|---|
| 237 | |
|---|
| 238 | |
|---|
| 239 | /** Render the occluder geometry. */ |
|---|
| 240 | virtual void drawImplementation(osg::RenderInfo& renderInfo) const; |
|---|
| 241 | |
|---|
| 242 | /** Compute the bounding box around occluder geometry.*/ |
|---|
| 243 | virtual osg::BoundingBox computeBound() const; |
|---|
| 244 | |
|---|
| 245 | public: |
|---|
| 246 | |
|---|
| 247 | protected : |
|---|
| 248 | |
|---|
| 249 | virtual ~ShadowVolumeGeometry() {} |
|---|
| 250 | |
|---|
| 251 | DrawMode _drawMode; |
|---|
| 252 | Vec3List _vertices; |
|---|
| 253 | Vec3List _normals; |
|---|
| 254 | UIntList _indices; |
|---|
| 255 | }; |
|---|
| 256 | |
|---|
| 257 | } |
|---|
| 258 | |
|---|
| 259 | #endif |
|---|