Removed osgShadow::ShadowVolume as it functionality isn't functional

This commit is contained in:
Robert Osfield
2018-04-03 11:35:31 +01:00
parent d0f891ca31
commit 3450b9fee8
9 changed files with 45 additions and 1734 deletions

View File

@@ -36,7 +36,6 @@
#include <osgViewer/ViewerEventHandlers>
#include <osgShadow/ShadowedScene>
#include <osgShadow/ShadowVolume>
#include <osgShadow/ShadowTexture>
#include <osgShadow/ShadowMap>
#include <osgShadow/SoftShadowMap>
@@ -707,7 +706,6 @@ int main(int argc, char** argv)
arguments.getApplicationUsage()->addCommandLineOption("--receivesShadowMask", "Override default receivesShadowMask (default - 0x1)");
arguments.getApplicationUsage()->addCommandLineOption("--base", "Add a base geometry to test shadows.");
arguments.getApplicationUsage()->addCommandLineOption("--sv", "Select ShadowVolume implementation.");
arguments.getApplicationUsage()->addCommandLineOption("--ssm", "Select SoftShadowMap implementation.");
arguments.getApplicationUsage()->addCommandLineOption("--sm", "Select ShadowMap implementation.");
@@ -873,15 +871,8 @@ int main(int argc, char** argv)
}
else if (arguments.read("--sv"))
{
// hint to tell viewer to request stencil buffer when setting up windows
osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);
osg::ref_ptr<osgShadow::ShadowVolume> sv = new osgShadow::ShadowVolume;
sv->setDynamicShadowVolumes(updateLightPosition);
while (arguments.read("--two-sided")) sv->setDrawMode(osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED);
while (arguments.read("--two-pass")) sv->setDrawMode(osgShadow::ShadowVolumeGeometry::STENCIL_TWO_PASS);
shadowedScene->setShadowTechnique(sv.get());
OSG_NOTICE<<"Warning: ShadowVolume no longer supported."<<std::endl;
return 1;
}
else if (arguments.read("--st"))
{

View File

@@ -1,259 +0,0 @@
/* -*-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 <osg/Drawable>
#include <osg/Array>
#include <osg/PrimitiveSet>
#include <osg/Polytope>
#include <osgShadow/Export>
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 separate 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<const OccluderGeometry*>(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 computeBoundingBox() const;
typedef std::vector<osg::Vec3> Vec3List;
typedef std::vector<GLuint> 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<Edge> 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 computeLightDirectionSilhouetteEdges(const osg::Vec3& lightdirection, UIntList& silhouetteIndices) const;
void computeLightPositionSilhouetteEdges(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<const ShadowVolumeGeometry*>(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<osg::Vec3> Vec3List;
typedef std::vector<GLuint> 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 computeBoundingBox() const;
public:
protected :
virtual ~ShadowVolumeGeometry() {}
DrawMode _drawMode;
Vec3List _vertices;
Vec3List _normals;
UIntList _indices;
};
}
#endif

View File

@@ -1,91 +0,0 @@
/* -*-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_SHADOWVOLUME
#define OSGSHADOW_SHADOWVOLUME 1
#include <osg/Camera>
#include <osg/Light>
#include <osg/Geode>
#include <osgShadow/ShadowTechnique>
#include <osgShadow/OccluderGeometry>
namespace osgShadow {
/** ShadowedTexture provides an implementation of shadow textures.*/
class OSGSHADOW_EXPORT ShadowVolume : public ShadowTechnique
{
public :
ShadowVolume();
ShadowVolume(const ShadowVolume& es, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
META_Object(osgShadow, ShadowVolume);
void setDrawMode(osgShadow::ShadowVolumeGeometry::DrawMode drawMode);
osgShadow::ShadowVolumeGeometry::DrawMode getDrawMode() const { return _drawMode; }
void setDynamicShadowVolumes(bool dynamicShadowVolumes);
bool getDynamicShadowVolumes() const { return _dynamicShadowVolumes; }
/** initialize the ShadowedScene and local cached data structures.*/
virtual void init();
/** run the update traversal of the ShadowedScene and update any loca chached data structures.*/
virtual void update(osg::NodeVisitor& nv);
/** run the cull traversal of the ShadowedScene and set up the rendering for this ShadowTechnique.*/
virtual void cull(osgUtil::CullVisitor& cv);
/** Clean scene graph from any shadow technique specific nodes, state and drawables.*/
virtual void cleanSceneGraph();
/** Resize any per context GLObject buffers to specified size. */
virtual void resizeGLObjectBuffers(unsigned int maxSize);
/** If State is non-zero, this function releases any associated OpenGL objects for
* the specified graphics context. Otherwise, releases OpenGL objects
* for all graphics contexts. */
virtual void releaseGLObjects(osg::State* = 0) const;
protected :
virtual ~ShadowVolume();
osgShadow::ShadowVolumeGeometry::DrawMode _drawMode;
bool _dynamicShadowVolumes;
osg::ref_ptr<osgShadow::OccluderGeometry> _occluder;
OpenThreads::Mutex _shadowVolumeMutex;
osg::ref_ptr<osgShadow::ShadowVolumeGeometry> _shadowVolume;
osg::Vec4 _lightpos;
osg::ref_ptr<osg::Light> _ambientLight;
osg::ref_ptr<osg::Light> _diffuseLight;
osg::ref_ptr<osg::StateSet> _ss1;
osg::ref_ptr<osg::StateSet> _mainShadowStateSet;
osg::ref_ptr<osg::StateSet> _shadowVolumeStateSet;
osg::ref_ptr<osg::StateSet> _shadowedSceneStateSet;
};
}
#endif

View File

@@ -11,9 +11,9 @@
*/
#include <osgShadow/ShadowedScene>
#include <osgShadow/ShadowVolume>
#include <osgShadow/ShadowTexture>
#include <osgShadow/ShadowMap>
#include <osgShadow/ViewDependentShadowMap>
#include <osgDB/ReaderWriter>
#include <osgDB/FileNameUtils>
@@ -110,15 +110,14 @@ public:
osg::ref_ptr<osgShadow::ShadowTechnique> technique;
if (!params.empty())
{
if (params=="ShadowVolume" || params=="sv") technique = new osgShadow::ShadowVolume;
else if (params=="ShadowTexture" || params=="st") technique = new osgShadow::ShadowTexture;
else if (params=="ShadowMap" || params=="sm") technique = new osgShadow::ShadowMap;
// else if (params=="ParallelSplitShadowMap" || params=="pssm") technique = new osgShadow::ParallelSplitShadowMap;
if (params=="ShadowTexture" || params=="st") technique = new osgShadow::ShadowTexture;
else if (params=="ViewDependentShadowMap" || params=="vdsm") technique = new osgShadow::ViewDependentShadowMap;
else if (params=="ShadowMap" || params=="sm") technique = new osgShadow::ShadowMap;
else subFileName += std::string(".") + params;
}
// default fallback to using ShadowVolume
if (!technique) technique = new osgShadow::ShadowVolume;
if (!technique) technique = new osgShadow::ViewDependentShadowMap;
// recursively load the subfile.
osg::ref_ptr<osg::Node> node = osgDB::readRefNodeFile( subFileName, options );

View File

@@ -18,11 +18,9 @@ SET(LIB_NAME osgShadow)
SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME})
SET(TARGET_H
${HEADER_PATH}/Export
${HEADER_PATH}/OccluderGeometry
${HEADER_PATH}/ShadowMap
${HEADER_PATH}/ShadowTechnique
${HEADER_PATH}/ShadowTexture
${HEADER_PATH}/ShadowVolume
${HEADER_PATH}/ShadowedScene
${HEADER_PATH}/ShadowSettings
${HEADER_PATH}/SoftShadowMap
@@ -42,11 +40,9 @@ SET(TARGET_H
# FIXME: For OS X, need flag for Framework or dylib
SET(TARGET_SRC
OccluderGeometry.cpp
ShadowMap.cpp
ShadowTechnique.cpp
ShadowTexture.cpp
ShadowVolume.cpp
ShadowedScene.cpp
ShadowSettings.cpp
SoftShadowMap.cpp

View File

@@ -1,984 +0,0 @@
/* -*-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.
*/
#include <osgShadow/OccluderGeometry>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/io_utils>
#include <osg/TriangleFunctor>
#include <osg/TriangleIndexFunctor>
#include <osg/GL>
#include <osg/Timer>
#include <algorithm>
using namespace osgShadow;
OccluderGeometry::OccluderGeometry()
{
}
OccluderGeometry::OccluderGeometry(const OccluderGeometry& oc, const osg::CopyOp& copyop):
osg::Drawable(oc,copyop)
{
}
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);
}
META_NodeVisitor("osgShadow","CollectOccludersVisitor")
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::Drawable& drawable)
{
if (drawable.getStateSet()) pushState(drawable.getStateSet());
apply(&drawable);
if (drawable.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_NOTICE<<"Ignoring transparent drawable."<<std::endl;
return;
}
_oc->processGeometry(drawable, (_matrixStack.empty() ? 0 : &_matrixStack.back()), _ratio);
}
protected:
OccluderGeometry* _oc;
typedef std::vector<osg::Matrix> MatrixStack;
typedef std::vector<osg::StateAttribute::GLModeValue> ModeStack;
float _ratio;
MatrixStack _matrixStack;
ModeStack _blendModeStack;
};
void OccluderGeometry::computeOccluderGeometry(osg::Node* subgraph, osg::Matrix* matrix, float sampleRatio)
{
OSG_NOTICE<<"computeOccluderGeometry(osg::Node* subgraph, float sampleRatio)"<<std::endl;
osg::Timer_t startTick = osg::Timer::instance()->tick();
CollectOccludersVisitor cov(this, matrix, sampleRatio);
subgraph->accept(cov);
setUpInternalStructures();
osg::Timer_t endTick = osg::Timer::instance()->tick();
OSG_NOTICE<<"done in "<<osg::Timer::instance()->delta_m(startTick, endTick)<<" ms"<<std::endl;
}
void OccluderGeometry::computeOccluderGeometry(osg::Drawable* drawable, osg::Matrix* matrix, float sampleRatio)
{
processGeometry(drawable, matrix, sampleRatio);
setUpInternalStructures();
}
struct TriangleCollector
{
OccluderGeometry::Vec3List* _vertices;
OccluderGeometry::UIntList* _triangleIndices;
osg::Matrix* _matrix;
typedef std::vector<const osg::Vec3*> VertexPointers;
VertexPointers _vertexPointers;
OccluderGeometry::Vec3List _tempoaryTriangleVertices;
TriangleCollector():
_vertices(0),
_triangleIndices(0),
_matrix(0) { }
void set(OccluderGeometry::Vec3List* vertices, OccluderGeometry::UIntList* triangleIndices, osg::Matrix* matrix)
{
_vertices = vertices;
_triangleIndices = triangleIndices;
_matrix = matrix;
}
// 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)
{
// OSG_NOTICE<<"Triangle ("<<v1<<") ("<<v2<<") ("<<v3<<")"<<std::endl;
_vertexPointers.push_back(&v1);
_vertexPointers.push_back(&v2);
_vertexPointers.push_back(&v3);
}
void copyToLocalData()
{
if ((_vertexPointers.size()+_tempoaryTriangleVertices.size())<3) return;
const osg::Vec3* minVertex = _vertexPointers.empty() ? 0 : _vertexPointers.front();
const osg::Vec3* maxVertex = _vertexPointers.empty() ? 0 : _vertexPointers.front();
VertexPointers::iterator itr;
for(itr = _vertexPointers.begin();
itr != _vertexPointers.end();
++itr)
{
if (*itr < minVertex) minVertex = *itr;
if (*itr > maxVertex) maxVertex = *itr;
}
unsigned int base = _vertices->size();
unsigned int numberNewVertices = _vertexPointers.empty() ? 0 : (maxVertex - minVertex) + 1;
// OSG_NOTICE<<"base = "<<base<<" numberNewVertices="<<numberNewVertices<<std::endl;
_vertices->resize(base + numberNewVertices + _tempoaryTriangleVertices.size());
for(itr = _vertexPointers.begin();
itr != _vertexPointers.end();
++itr)
{
const osg::Vec3* vec = *itr;
unsigned int index = base + (vec - minVertex);
(*_vertices)[index] = *vec;
_triangleIndices->push_back(index);
}
unsigned int pos = base + numberNewVertices;
for(OccluderGeometry::Vec3List::iterator vitr = _tempoaryTriangleVertices.begin();
vitr != _tempoaryTriangleVertices.end();
++vitr, ++pos)
{
(*_vertices)[pos] = *vitr;
_triangleIndices->push_back(pos);
}
if (_matrix)
{
for(unsigned int i=base; i<_vertices->size(); ++i)
{
(*_vertices)[i] = (*_vertices)[i] * (*_matrix);
}
}
}
};
typedef osg::TriangleFunctor<TriangleCollector> TriangleCollectorFunctor;
void OccluderGeometry::processGeometry(osg::Drawable* drawable, osg::Matrix* matrix, float /*sampleRatio*/)
{
// OSG_NOTICE<<"computeOccluderGeometry(osg::Node* subgraph, float sampleRatio)"<<std::endl;
TriangleCollectorFunctor tc;
tc.set(&_vertices, &_triangleIndices, matrix);
drawable->accept(tc);
tc.copyToLocalData();
#if 0
for(Vec3List::iterator vitr = _vertices.begin();
vitr != _vertices.end();
++vitr)
{
OSG_NOTICE<<"v "<<*vitr<<std::endl;
}
for(UIntList::iterator titr = _triangleIndices.begin();
titr != _triangleIndices.end();
)
{
OSG_NOTICE<<"t "<<*titr++<<" "<<*titr++<<" "<<*titr++<<std::endl;
}
#endif
}
void OccluderGeometry::setUpInternalStructures()
{
osg::Timer_t t0 = osg::Timer::instance()->tick();
removeDuplicateVertices();
osg::Timer_t t1 = osg::Timer::instance()->tick();
removeNullTriangles();
osg::Timer_t t2 = osg::Timer::instance()->tick();
computeNormals();
osg::Timer_t t3 = osg::Timer::instance()->tick();
buildEdgeMaps();
osg::Timer_t t4 = osg::Timer::instance()->tick();
OSG_NOTICE<<"removeDuplicateVertices "<<osg::Timer::instance()->delta_m(t0,t1)<<" ms"<<std::endl;
OSG_NOTICE<<"removeNullTriangles "<<osg::Timer::instance()->delta_m(t1,t2)<<" ms"<<std::endl;
OSG_NOTICE<<"computeNormals "<<osg::Timer::instance()->delta_m(t2,t3)<<" ms"<<std::endl;
OSG_NOTICE<<"buildEdgeMaps "<<osg::Timer::instance()->delta_m(t3,t4)<<" ms"<<std::endl;
OSG_NOTICE<<"setUpInternalStructures "<<osg::Timer::instance()->delta_m(t0,t4)<<" ms"<<std::endl;
dirtyBound();
dirtyGLObjects();
}
struct IndexVec3PtrPair
{
IndexVec3PtrPair():
vec(0),
index(0) {}
IndexVec3PtrPair(const osg::Vec3* v, unsigned int i):
vec(v),
index(i) {}
inline bool operator < (const IndexVec3PtrPair& rhs) const
{
return *vec < *rhs.vec;
}
inline bool operator == (const IndexVec3PtrPair& rhs) const
{
return *vec == *rhs.vec;
// return (*vec - *rhs.vec).length2() < 1e-2;
}
const osg::Vec3* vec;
unsigned int index;
};
void OccluderGeometry::removeDuplicateVertices()
{
if (_vertices.empty()) return;
OSG_NOTICE<<"OccluderGeometry::removeDuplicates() before = "<<_vertices.size()<<std::endl;
typedef std::vector<IndexVec3PtrPair> IndexVec3PtrPairs;
IndexVec3PtrPairs indexVec3PtrPairs;
indexVec3PtrPairs.reserve(_vertices.size());
unsigned int i = 0;
for(OccluderGeometry::Vec3List::iterator vitr = _vertices.begin();
vitr != _vertices.end();
++vitr, ++i)
{
indexVec3PtrPairs.push_back(IndexVec3PtrPair(&(*vitr),i));
}
std::sort(indexVec3PtrPairs.begin(),indexVec3PtrPairs.end());;
// compute size
IndexVec3PtrPairs::iterator prev = indexVec3PtrPairs.begin();
IndexVec3PtrPairs::iterator curr = prev;
++curr;
unsigned int numDuplicates = 0;
unsigned int numUnique = 1;
for(; curr != indexVec3PtrPairs.end(); ++curr)
{
if (*prev==*curr)
{
++numDuplicates;
}
else
{
prev = curr;
++numUnique;
}
}
OSG_NOTICE<<"Num diplicates = "<<numDuplicates<<std::endl;
OSG_NOTICE<<"Num unique = "<<numUnique<<std::endl;
if (numDuplicates==0) return;
// now assign the unique Vec3 to the newVertices arrays
typedef std::vector<unsigned int> IndexMap;
IndexMap indexMap(indexVec3PtrPairs.size());
Vec3List newVertices;
newVertices.reserve(numUnique);
unsigned int index = 0;
prev = indexVec3PtrPairs.begin();
curr = prev;
// add first vertex
indexMap[curr->index] = index;
newVertices.push_back(*(curr->vec));
++curr;
for(; curr != indexVec3PtrPairs.end(); ++curr)
{
if (*prev==*curr)
{
indexMap[curr->index] = index;
}
else
{
++index;
// add new unique vertex
indexMap[curr->index] = index;
newVertices.push_back(*(curr->vec));
prev = curr;
}
}
// copy over need arrays and index values
_vertices.swap(newVertices);
for(UIntList::iterator titr = _triangleIndices.begin();
titr != _triangleIndices.end();
++titr)
{
*titr = indexMap[*titr];
}
// OSG_NOTICE<<"OccluderGeometry::removeDuplicates() after = "<<_vertices.size()<<std::endl;
}
void OccluderGeometry::removeNullTriangles()
{
// OSG_NOTICE<<"OccluderGeometry::removeNullTriangles()"<<std::endl;
UIntList::iterator lastValidItr = _triangleIndices.begin();
for(UIntList::iterator titr = _triangleIndices.begin();
titr != _triangleIndices.end();
)
{
UIntList::iterator currItr = titr;
GLuint p1 = *titr++;
GLuint p2 = *titr++;
GLuint p3 = *titr++;
if ((p1 != p2) && (p1 != p3) && (p2 != p3))
{
if (lastValidItr!=currItr)
{
*lastValidItr++ = p1;
*lastValidItr++ = p2;
*lastValidItr++ = p3;
}
else
{
lastValidItr = titr;
}
}
else
{
// OSG_NOTICE<<"Null triangle"<<std::endl;
}
}
if (lastValidItr != _triangleIndices.end())
{
// OSG_NOTICE<<"Pruning end - before "<<_triangleIndices.size()<<std::endl;
_triangleIndices.erase(lastValidItr,_triangleIndices.end());
// OSG_NOTICE<<"Pruning end - after "<<_triangleIndices.size()<<std::endl;
}
}
void OccluderGeometry::computeNormals()
{
// OSG_NOTICE<<"OccluderGeometry::computeNormals()"<<std::endl;
unsigned int numTriangles = _triangleIndices.size() / 3;
unsigned int redundentIndices = _triangleIndices.size() - numTriangles * 3;
if (redundentIndices)
{
OSG_NOTICE<<"Warning OccluderGeometry::computeNormals() has found redundent trailing indices"<<std::endl;
_triangleIndices.erase(_triangleIndices.begin() + numTriangles * 3, _triangleIndices.end());
}
_triangleNormals.clear();
_triangleNormals.reserve(numTriangles);
_normals.resize(_vertices.size());
for(UIntList::iterator titr = _triangleIndices.begin();
titr != _triangleIndices.end();
)
{
GLuint p1 = *titr++;
GLuint p2 = *titr++;
GLuint p3 = *titr++;
osg::Vec3 normal = (_vertices[p2] - _vertices[p1]) ^ (_vertices[p3] - _vertices[p2]);
normal.normalize();
_triangleNormals.push_back(normal);
if (!_normals.empty())
{
_normals[p1] += normal;
_normals[p2] += normal;
_normals[p3] += normal;
}
}
for(Vec3List::iterator nitr = _normals.begin();
nitr != _normals.end();
++nitr)
{
nitr->normalize();
}
}
void OccluderGeometry::buildEdgeMaps()
{
// OSG_NOTICE<<"OccluderGeometry::buildEdgeMaps()"<<std::endl;
typedef std::set<Edge> EdgeSet;
EdgeSet edgeSet;
unsigned int numTriangleErrors = 0;
unsigned int triNo=0;
for(UIntList::iterator titr = _triangleIndices.begin();
titr != _triangleIndices.end();
++triNo)
{
GLuint p1 = *titr++;
GLuint p2 = *titr++;
GLuint p3 = *titr++;
{
Edge edge12(p1,p2);
EdgeSet::iterator itr = edgeSet.find(edge12);
if (itr == edgeSet.end())
{
if (!edge12.addTriangle(triNo)) ++numTriangleErrors;
edgeSet.insert(edge12);
}
else
{
if (!itr->addTriangle(triNo)) ++numTriangleErrors;
}
}
{
Edge edge23(p2,p3);
EdgeSet::iterator itr = edgeSet.find(edge23);
if (itr == edgeSet.end())
{
if (!edge23.addTriangle(triNo)) ++numTriangleErrors;
edgeSet.insert(edge23);
}
else
{
if (!itr->addTriangle(triNo)) ++numTriangleErrors;
}
}
{
Edge edge31(p3,p1);
EdgeSet::iterator itr = edgeSet.find(edge31);
if (itr == edgeSet.end())
{
if (!edge31.addTriangle(triNo)) ++numTriangleErrors;
edgeSet.insert(edge31);
}
else
{
if (!itr->addTriangle(triNo)) ++numTriangleErrors;
}
}
}
_edges.clear();
_edges.reserve(edgeSet.size());
unsigned int numEdgesWithNoTriangles = 0;
unsigned int numEdgesWithOneTriangles = 0;
unsigned int numEdgesWithTwoTriangles = 0;
for(EdgeSet::iterator eitr = edgeSet.begin();
eitr != edgeSet.end();
++eitr)
{
const Edge& edge = *eitr;
osg::Vec3 pos(0.0,0.0,0.0);
osg::Vec3 mid = (_vertices[edge._p1] + _vertices[edge._p2]) * 0.5f;
unsigned int numTriangles = 0;
if (edge._t1>=0)
{
++numTriangles;
GLuint p1 = _triangleIndices[edge._t1*3];
GLuint p2 = _triangleIndices[edge._t1*3+1];
GLuint p3 = _triangleIndices[edge._t1*3+2];
GLuint opposite = p1;
if (p1 != edge._p1 && p1 != edge._p2) opposite = p1;
else if (p2 != edge._p1 && p2 != edge._p2) opposite = p2;
else if (p3 != edge._p1 && p3 != edge._p2) opposite = p3;
pos = _vertices[opposite];
}
if (edge._t2>=0)
{
++numTriangles;
GLuint p1 = _triangleIndices[edge._t2*3];
GLuint p2 = _triangleIndices[edge._t2*3+1];
GLuint p3 = _triangleIndices[edge._t2*3+2];
GLuint opposite = p1;
if (p1 != edge._p1 && p1 != edge._p2) opposite = p1;
else if (p2 != edge._p1 && p2 != edge._p2) opposite = p2;
else if (p3 != edge._p1 && p3 != edge._p2) opposite = p3;
pos += _vertices[opposite];
}
switch(numTriangles)
{
case(0):
++numEdgesWithNoTriangles;
edge._normal.set(0.0,0.0,0.0);
OSG_NOTICE<<"Warning no triangles on edge."<<std::endl;
break;
case(1):
++numEdgesWithOneTriangles;
edge._normal = pos - mid;
edge._normal.normalize();
break;
default:
++numEdgesWithTwoTriangles;
edge._normal = (pos*0.5f) - mid;
edge._normal.normalize();
break;
}
_edges.push_back(edge);
}
#if 0
OSG_NOTICE<<"Num of indices "<<_triangleIndices.size()<<std::endl;
OSG_NOTICE<<"Num of triangles "<<triNo<<std::endl;
OSG_NOTICE<<"Num of numTriangleErrors "<<numTriangleErrors<<std::endl;
OSG_NOTICE<<"Num of edges "<<edgeSet.size()<<std::endl;
OSG_NOTICE<<"Num of numEdgesWithNoTriangles "<<numEdgesWithNoTriangles<<std::endl;
OSG_NOTICE<<"Num of numEdgesWithOneTriangles "<<numEdgesWithOneTriangles<<std::endl;
OSG_NOTICE<<"Num of numEdgesWithTwoTriangles "<<numEdgesWithTwoTriangles<<std::endl;
#endif
}
void OccluderGeometry::computeLightDirectionSilhouetteEdges(const osg::Vec3& lightdirection, UIntList& silhouetteIndices) const
{
silhouetteIndices.clear();
for(EdgeList::const_iterator eitr = _edges.begin();
eitr != _edges.end();
++eitr)
{
const Edge& edge = *eitr;
if (isLightDirectionSilhouetteEdge(lightdirection,edge))
{
const osg::Vec3& v1 = _vertices[edge._p1];
const osg::Vec3& v2 = _vertices[edge._p2];
osg::Vec3 normal = (v2-v1) ^ lightdirection;
if (normal * edge._normal > 0.0)
{
silhouetteIndices.push_back(edge._p1);
silhouetteIndices.push_back(edge._p2);
}
else
{
silhouetteIndices.push_back(edge._p2);
silhouetteIndices.push_back(edge._p1);
}
}
}
}
void OccluderGeometry::computeLightPositionSilhouetteEdges(const osg::Vec3& lightpos, UIntList& silhouetteIndices) const
{
silhouetteIndices.clear();
for(EdgeList::const_iterator eitr = _edges.begin();
eitr != _edges.end();
++eitr)
{
const Edge& edge = *eitr;
if (isLightPointSilhouetteEdge(lightpos,edge))
{
const osg::Vec3& v1 = _vertices[edge._p1];
const osg::Vec3& v2 = _vertices[edge._p2];
osg::Vec3 normal = (v2-v1) ^ (v1-lightpos);
if (normal * edge._normal > 0.0)
{
silhouetteIndices.push_back(edge._p1);
silhouetteIndices.push_back(edge._p2);
}
else
{
silhouetteIndices.push_back(edge._p2);
silhouetteIndices.push_back(edge._p1);
}
}
}
}
void OccluderGeometry::computeShadowVolumeGeometry(const osg::Vec4& lightpos, ShadowVolumeGeometry& svg) const
{
// osg::Timer_t t0 = osg::Timer::instance()->tick();
ShadowVolumeGeometry::Vec3List& shadowVertices = svg.getVertices();
shadowVertices.clear();
ShadowVolumeGeometry::Vec3List& shadowNormals = svg.getNormals();
shadowNormals.clear();
// need to have some kind of handling of case when no planes exist.
if (_boundingPolytope.getPlaneList().empty())
{
OSG_NOTICE<<"Warning: no bounding polytope registered with OccluderGeometry."<<std::endl;
return;
}
if (lightpos.w()==0.0)
{
// directional light.
osg::Vec3 lightdirection( -lightpos.x(), -lightpos.y(), -lightpos.z());
// OSG_NOTICE<<"Directional light"<<std::endl;
// choose the base plane
const osg::Polytope::PlaneList& planes = _boundingPolytope.getPlaneList();
osg::Polytope::PlaneList::const_iterator pitr = planes.begin();
osg::Plane basePlane = *pitr;
++pitr;
for(;
pitr != planes.end();
++pitr)
{
if (basePlane.dotProductNormal(lightdirection) > pitr->dotProductNormal(lightdirection))
{
basePlane = *pitr;
}
}
// compute the silhouette edge
UIntList silhouetteIndices;
computeLightDirectionSilhouetteEdges(lightdirection, silhouetteIndices);
float directionScale = 1.0f / basePlane.dotProductNormal(lightdirection);
for(UIntList::iterator itr = silhouetteIndices.begin();
itr != silhouetteIndices.end();
)
{
const osg::Vec3& v1 = _vertices[*itr++];
const osg::Vec3& v2 = _vertices[*itr++];
float r1 = basePlane.distance(v1) * directionScale;
float r2 = basePlane.distance(v2) * directionScale;
osg::Vec3 v1_projected = v1 - (lightdirection * r1);
osg::Vec3 v2_projected = v2 - (lightdirection * r2);
shadowVertices.push_back( v1);
shadowVertices.push_back( v1_projected);
shadowVertices.push_back( v2_projected);
shadowVertices.push_back( v2);
osg::Vec3 normal = lightdirection ^ (v2-v1);
normal.normalize();
shadowNormals.push_back(normal);
shadowNormals.push_back(normal);
shadowNormals.push_back(normal);
shadowNormals.push_back(normal);
}
}
else
{
// positional light
osg::Vec3 lightposition( lightpos.x(), lightpos.y(), lightpos.z());
osg::Plane basePlane(0.0, 0.0, 1.0, 0.0);
// OSG_NOTICE<<"Positional light"<<std::endl;
UIntList silhouetteIndices;
computeLightPositionSilhouetteEdges(lightposition, silhouetteIndices);
// OSG_NOTICE<<"basePlane "<<basePlane[0]<<" "<<basePlane[1]<<" "<<basePlane[2]<<" "<<basePlane[3]<<std::endl;
// OSG_NOTICE<<"lightpos = "<<std::endl;
const osg::Polytope::PlaneList& planes = _boundingPolytope.getPlaneList();
for(UIntList::iterator itr = silhouetteIndices.begin();
itr != silhouetteIndices.end();
)
{
const osg::Vec3& v1 = _vertices[*itr++];
const osg::Vec3& v2 = _vertices[*itr++];
osg::Vec3 d1 = v1 - lightposition;
osg::Vec3 d2 = v2 - lightposition;
osg::Polytope::PlaneList::const_iterator pitr = planes.begin();
float r1 = - pitr->distance(v1) / (pitr->dotProductNormal(d1));
float r2 = - pitr->distance(v2) / (pitr->dotProductNormal(d2));
++pitr;
for(;
pitr != planes.end();
++pitr)
{
float lr1 = - pitr->distance(v1) / (pitr->dotProductNormal(d1));
float lr2 = - pitr->distance(v2) / (pitr->dotProductNormal(d2));
if (lr1>=0.0f && lr2>=0.0f && (lr1+lr2)<(r1+r2))
{
r1 = lr1;
r2 = lr2;
}
}
osg::Vec3 v1_projected = v1 + (d1 * r1);
osg::Vec3 v2_projected = v2 + (d2 * r2);
shadowVertices.push_back( v1);
shadowVertices.push_back( v1_projected);
shadowVertices.push_back( v2_projected);
shadowVertices.push_back( v2);
osg::Vec3 normal = d1 ^ (v2-v1);
normal.normalize();
shadowNormals.push_back(normal);
shadowNormals.push_back(normal);
shadowNormals.push_back(normal);
shadowNormals.push_back(normal);
}
}
svg.dirtyGLObjects();
svg.dirtyBound();
// osg::Timer_t t1 = osg::Timer::instance()->tick();
// OSG_NOTICE<<"computeShadowVolumeGeometry "<<osg::Timer::instance()->delta_m(t0,t1)<<" ms"<<std::endl;
}
void OccluderGeometry::drawImplementation(osg::RenderInfo& renderInfo) const
{
renderInfo.getState()->disableAllVertexArrays();
renderInfo.getState()->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) );
if (!_normals.empty())
{
renderInfo.getState()->setNormalPointer( GL_FLOAT, 0, &(_normals.front()) );
}
if (!_triangleIndices.empty())
{
glDrawElements(GL_TRIANGLES, _triangleIndices.size(), GL_UNSIGNED_INT, &(_triangleIndices.front()) );
}
}
osg::BoundingBox OccluderGeometry::computeBoundingBox() const
{
osg::BoundingBox bb;
for(Vec3List::const_iterator itr = _vertices.begin();
itr != _vertices.end();
++itr)
{
bb.expandBy(*itr);
}
return bb;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ShadowVolumeGeometry
//
ShadowVolumeGeometry::ShadowVolumeGeometry():
_drawMode(GEOMETRY)
{
}
ShadowVolumeGeometry::ShadowVolumeGeometry(const ShadowVolumeGeometry& oc, const osg::CopyOp& copyop):
osg::Drawable(oc,copyop),
_drawMode(oc._drawMode)
{
}
void ShadowVolumeGeometry::drawImplementation(osg::RenderInfo& renderInfo) const
{
if (_drawMode==GEOMETRY)
{
osg::State* state = renderInfo.getState();
state->disableAllVertexArrays();
state->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) );
if (!_normals.empty())
{
state->setNormalPointer( GL_FLOAT, 0, &(_normals.front()) );
}
else
{
state->Normal(0.0f, 0.0f, 0.0f);
}
state->Color(0.5f, 1.0f, 1.0f, 1.0f);
glDrawArrays( GL_QUADS, 0, _vertices.size() );
}
else if (_drawMode==STENCIL_TWO_PASS)
{
osg::State* state = renderInfo.getState();
state->disableAllVertexArrays();
state->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) );
// draw front faces of shadow volume
glCullFace(GL_BACK);
glStencilOp( GL_KEEP, GL_KEEP, GL_INCR);
glDrawArrays( GL_QUADS, 0, _vertices.size() );
// draw back faces of shadow volume
glCullFace(GL_FRONT);
glStencilOp( GL_KEEP, GL_KEEP, GL_DECR);
glDrawArrays( GL_QUADS, 0, _vertices.size() );
state->haveAppliedAttribute(osg::StateAttribute::CULLFACE);
state->haveAppliedAttribute(osg::StateAttribute::STENCIL);
}
else // stencil two sided, note state all set up separately.
{
osg::State* state = renderInfo.getState();
state->disableAllVertexArrays();
state->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) );
glDrawArrays( GL_QUADS, 0, _vertices.size() );
}
}
osg::BoundingBox ShadowVolumeGeometry::computeBoundingBox() const
{
osg::BoundingBox bb;
for(Vec3List::const_iterator itr = _vertices.begin();
itr != _vertices.end();
++itr)
{
bb.expandBy(*itr);
}
return bb;
}

View File

@@ -1,375 +0,0 @@
/* -*-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.
*/
#include <osgShadow/ShadowVolume>
#include <osgShadow/ShadowedScene>
#include <osg/Notify>
#include <osg/LightModel>
#include <osg/Depth>
#include <osg/BlendFunc>
#include <osg/Camera>
#include <osg/Stencil>
#include <osg/StencilTwoSided>
#include <osg/CullFace>
#include <osg/Geometry>
#include <osg/ComputeBoundsVisitor>
#include <osg/io_utils>
using namespace osgShadow;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ShadowVolume
//
ShadowVolume::ShadowVolume():
_drawMode(osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED),
_dynamicShadowVolumes(false)
{
// _drawMode = osgShadow::ShadowVolumeGeometry::GEOMETRY;
OSG_INFO<<"Warning: osgShadow::ShadowVolume technique is still in development, with current limitations that make it unsuitable for deployment. Please contact the osg-users for an update of developements."<<std::endl;
}
ShadowVolume::ShadowVolume(const ShadowVolume& sv, const osg::CopyOp& copyop):
ShadowTechnique(sv,copyop),
_drawMode(sv._drawMode),
_dynamicShadowVolumes(sv._dynamicShadowVolumes)
{
}
ShadowVolume::~ShadowVolume()
{
}
void ShadowVolume::resizeGLObjectBuffers(unsigned int maxSize)
{
osg::resizeGLObjectBuffers(_occluder, maxSize);
osg::resizeGLObjectBuffers(_shadowVolume, maxSize);
osg::resizeGLObjectBuffers(_ss1, maxSize);
osg::resizeGLObjectBuffers(_mainShadowStateSet, maxSize);
osg::resizeGLObjectBuffers(_shadowVolumeStateSet, maxSize);
osg::resizeGLObjectBuffers(_shadowedSceneStateSet, maxSize);
}
void ShadowVolume::releaseGLObjects(osg::State* state) const
{
osg::releaseGLObjects(_occluder, state);
osg::releaseGLObjects(_shadowVolume, state);
osg::releaseGLObjects(_ss1, state);
osg::releaseGLObjects(_mainShadowStateSet, state);
osg::releaseGLObjects(_shadowVolumeStateSet, state);
osg::releaseGLObjects(_shadowedSceneStateSet, state);
}
void ShadowVolume::setDrawMode(osgShadow::ShadowVolumeGeometry::DrawMode drawMode)
{
if (_drawMode == drawMode) return;
_drawMode = drawMode;
dirty();
}
void ShadowVolume::setDynamicShadowVolumes(bool dynamicShadowVolumes)
{
_dynamicShadowVolumes = dynamicShadowVolumes;
}
void ShadowVolume::init()
{
if (!_shadowedScene) return;
// get the bounds of the model.
osg::ComputeBoundsVisitor cbbv;
_shadowedScene->osg::Group::traverse(cbbv);
osg::Vec4 ambient(0.2,0.2,0.2,1.0);
osg::Vec4 diffuse(0.8,0.8,0.8,1.0);
osg::Vec4 zero_colour(0.0,0.0,0.0,1.0);
osg::Vec4 lightpos;
lightpos.set(0.5f,0.25f,0.8f,0.0f);
// set up the occluder
_occluder = new osgShadow::OccluderGeometry;
_occluder->computeOccluderGeometry(_shadowedScene);
// cbbv.getPolytope(_occluder->getBoundingPolytope(),0.001);
cbbv.getBase(_occluder->getBoundingPolytope(),0.001);
// set up shadow volume
_shadowVolume = new osgShadow::ShadowVolumeGeometry;
_shadowVolume->setUseDisplayList(!_dynamicShadowVolumes);
_shadowVolume->setDrawMode(_drawMode);
_occluder->computeShadowVolumeGeometry(lightpos, *_shadowVolume);
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
_shadowedScene->addChild(geode.get());
int shadowVolumeBin = 1000;
if (_drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
{
OSG_NOTICE<<"STENCIL_TWO_SIDED selected"<<std::endl;
osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
ss_sv1->setRenderBinDetails(shadowVolumeBin, "RenderBin");
geode->addDrawable(_shadowVolume.get());
}
else
{
OSG_NOTICE<<"STENCIL_TWO_PASSES selected"<<std::endl;
osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
ss_sv1->setRenderBinDetails(shadowVolumeBin, "RenderBin");
geode->addDrawable(_shadowVolume.get());
}
{
// first group, render the depth buffer + ambient light contribution
{
_ss1 = new osg::StateSet;
osg::LightModel* lm1 = new osg::LightModel;
lm1->setAmbientIntensity(ambient);
_ss1->setAttribute(lm1);
_ambientLight = new osg::Light;
_ambientLight->setAmbient(ambient);
_ambientLight->setDiffuse(zero_colour);
_ss1->setAttributeAndModes(_ambientLight.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
_ss1->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
}
{
_mainShadowStateSet = new osg::StateSet;
osg::Depth* depth = new osg::Depth;
depth->setWriteMask(false);
depth->setFunction(osg::Depth::LEQUAL);
_mainShadowStateSet->setAttribute(depth);
_mainShadowStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
}
{
_shadowVolumeStateSet = new osg::StateSet;
osg::Depth* depth = new osg::Depth;
depth->setWriteMask(false);
depth->setFunction(osg::Depth::LEQUAL);
_shadowVolumeStateSet->setAttribute(depth);
_shadowVolumeStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
_shadowVolumeStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
if (_drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
{
osg::StencilTwoSided* stencil = new osg::StencilTwoSided;
stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS,0,~0u);
stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::DECR_WRAP);
stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS,0,~0u);
stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::INCR_WRAP);
osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);
_shadowVolumeStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
_shadowVolumeStateSet->setAttribute(colourMask, osg::StateAttribute::OVERRIDE);
_shadowVolumeStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
}
else
{
osg::Stencil* stencil = new osg::Stencil;
stencil->setFunction(osg::Stencil::ALWAYS,0,~0u);
stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);
_shadowVolumeStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON);
_shadowVolumeStateSet->setAttribute(colourMask);
_shadowVolumeStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
}
}
{
_shadowedSceneStateSet = new osg::StateSet;
osg::Depth* depth = new osg::Depth;
depth->setWriteMask(false);
depth->setFunction(osg::Depth::LEQUAL);
_shadowedSceneStateSet->setAttribute(depth);
_shadowedSceneStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
// _shadowedSceneStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
osg::LightModel* lm1 = new osg::LightModel;
lm1->setAmbientIntensity(zero_colour);
_shadowedSceneStateSet->setAttribute(lm1);
_diffuseLight = new osg::Light;
_diffuseLight->setAmbient(zero_colour);
_diffuseLight->setDiffuse(diffuse);
_shadowedSceneStateSet->setMode(GL_LIGHT0, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
_shadowedSceneStateSet->setAttribute(_diffuseLight.get());
// set up the stencil ops so that only operator on this mirrors stencil value.
osg::Stencil* stencil = new osg::Stencil;
stencil->setFunction(osg::Stencil::EQUAL,0,~0u);
stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
_shadowedSceneStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON);
osg::BlendFunc* blend = new osg::BlendFunc;
blend->setFunction(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
_shadowedSceneStateSet->setAttributeAndModes(blend, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
// _shadowedSceneStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
}
_ss1->setThreadSafeRefUnref(true);
_mainShadowStateSet->setThreadSafeRefUnref(true);
_shadowVolumeStateSet->setThreadSafeRefUnref(true);
_shadowedSceneStateSet->setThreadSafeRefUnref(true);
}
_dirty = false;
}
void ShadowVolume::update(osg::NodeVisitor& nv)
{
_shadowedScene->osg::Group::traverse(nv);
}
void ShadowVolume::cull(osgUtil::CullVisitor& cv)
{
osg::ref_ptr<osgUtil::RenderBin> original_bin = cv.getCurrentRenderBin();
osg::ref_ptr<osgUtil::RenderBin> new_bin = original_bin->find_or_insert(0,"RenderBin");
cv.setCurrentRenderBin(new_bin.get());
_shadowedScene->osg::Group::traverse(cv);
cv.setCurrentRenderBin(original_bin.get());
osg::ref_ptr<osgUtil::RenderBin> shadowVolumeBin;
osgUtil::RenderBin::RenderBinList::iterator rb_itr = new_bin->getRenderBinList().find(1000);
if (rb_itr != new_bin->getRenderBinList().end())
{
shadowVolumeBin = rb_itr->second;
if (shadowVolumeBin.valid())
{
//OSG_NOTICE<<"Found shadow volume bin, now removing it"<<std::endl;
new_bin->getRenderBinList().erase(rb_itr);
}
}
if (shadowVolumeBin.valid())
{
original_bin->setStateSet(_ss1.get());
osgUtil::RenderStage* orig_rs = cv.getRenderStage();
osgUtil::RenderStage* new_rs = new osgUtil::RenderStage;
orig_rs->addPostRenderStage(new_rs);
new_rs->setViewport(orig_rs->getViewport());
new_rs->setClearColor(orig_rs->getClearColor());
new_rs->setClearMask(GL_STENCIL_BUFFER_BIT);
new_rs->setDrawBuffer(orig_rs->getDrawBuffer(), orig_rs->getDrawBufferApplyMask());
new_rs->setReadBuffer(orig_rs->getReadBuffer(), orig_rs->getReadBufferApplyMask());
new_rs->setColorMask(orig_rs->getColorMask());
osg::Vec4 lightpos;
osg::ref_ptr<osgUtil::PositionalStateContainer> ps = new osgUtil::PositionalStateContainer;
new_rs->setPositionalStateContainer(ps.get());
const osg::Light* selectLight = 0;
osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
itr != aml.end();
++itr)
{
const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
if (light)
{
osg::RefMatrix* matrix = itr->second.get();
if (matrix) lightpos = light->getPosition() * (*matrix);
else lightpos = light->getPosition();
selectLight = light;
}
else
{
ps->addPositionedAttribute(itr->second.get(), itr->first.get());
}
}
_ambientLight->setPosition(lightpos);
orig_rs->addPositionedAttribute(0,_ambientLight.get());
_diffuseLight->setPosition(lightpos);
if (selectLight)
{
_ambientLight->setAmbient(selectLight->getAmbient());
_diffuseLight->setDiffuse(selectLight->getDiffuse());
_diffuseLight->setSpecular(selectLight->getSpecular());
_diffuseLight->setDirection(selectLight->getDirection());
_diffuseLight->setConstantAttenuation(selectLight->getConstantAttenuation());
_diffuseLight->setLinearAttenuation(selectLight->getLinearAttenuation());
_diffuseLight->setQuadraticAttenuation(selectLight->getQuadraticAttenuation());
_diffuseLight->setSpotExponent(selectLight->getSpotExponent());
_diffuseLight->setSpotCutoff(selectLight->getSpotCutoff());
}
ps->addPositionedAttribute(0, _diffuseLight.get());
if (_lightpos != lightpos && _dynamicShadowVolumes)
{
_lightpos = lightpos;
osg::Matrix eyeToWorld;
eyeToWorld.invert(*cv.getModelViewMatrix());
_occluder->computeShadowVolumeGeometry(lightpos * eyeToWorld, *_shadowVolume);
}
if (shadowVolumeBin.valid())
{
// new_rs->setStateSet(_mainShadowStateSet.get());
new_rs->getRenderBinList()[0] = shadowVolumeBin;
shadowVolumeBin->setStateSet(_shadowVolumeStateSet.get());
osg::ref_ptr<osgUtil::RenderBin> nested_bin = new_rs->find_or_insert(1,"RenderBin");
nested_bin->getRenderBinList()[0] = new_bin;
nested_bin->setStateSet(_shadowedSceneStateSet.get());
}
}
}
void ShadowVolume::cleanSceneGraph()
{
}

View File

@@ -1,5 +1,3 @@
#include <osgShadow/ShadowVolume>
#include <iostream>
#include <string>
@@ -17,7 +15,7 @@ bool ShadowVolume_writeLocalData(const osg::Object &obj, osgDB::Output &fw);
REGISTER_DOTOSGWRAPPER(ShadowVolume_Proxy)
(
new osgShadow::ShadowVolume,
0,
"ShadowVolume",
"Object ShadowTechnique ShadowVolume",
ShadowVolume_readLocalData,

View File

@@ -1,8 +1,44 @@
#include <osgShadow/ShadowVolume>
#include <osgShadow/ShadowTechnique>
#include <osgDB/ObjectWrapper>
#include <osgDB/InputStream>
#include <osgDB/OutputStream>
namespace osgShadow
{
class ShadowVolumeGeometry
{
public :
enum DrawMode
{
GEOMETRY,
STENCIL_TWO_PASS,
STENCIL_TWO_SIDED
};
};
class ShadowVolume : public osgShadow::ShadowTechnique
{
public:
ShadowVolume() {}
ShadowVolume(const ShadowVolume& es, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) {}
META_Object(osgShadow, ShadowVolume);
void setDrawMode(osgShadow::ShadowVolumeGeometry::DrawMode) {}
osgShadow::ShadowVolumeGeometry::DrawMode getDrawMode() const { return osgShadow::ShadowVolumeGeometry::GEOMETRY; }
void setDynamicShadowVolumes(bool) {}
bool getDynamicShadowVolumes() const { return false; }
virtual void resizeGLObjectBuffers(unsigned int maxSize) {}
virtual void releaseGLObjects(osg::State* = 0) const {}
};
}
REGISTER_OBJECT_WRAPPER( osgShadow_ShadowVolume,
new osgShadow::ShadowVolume,
osgShadow::ShadowVolume,