Removed osgShadow::ShadowVolume as it functionality isn't functional
This commit is contained in:
@@ -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"))
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user