Files
OpenSceneGraph/src/osgShadow/OccluderGeometry.cpp
Robert Osfield eac3dc1963 From Paul Melis, "Here is a list of fixes to misspelled APIs. Unfortunately, more than one
of these are public APIs and therefore will break linkage to existing
shared libraries."

Note from Robert Osfield, updated wrappers.
2007-06-27 20:36:16 +00:00

1002 lines
29 KiB
C++

/* -*-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);
}
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::Geode& geode)
{
if (geode.getStateSet()) pushState(geode.getStateSet());
for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
{
osg::Drawable* drawable = geode.getDrawable(i);
if (drawable->getStateSet()) pushState(drawable->getStateSet());
apply(geode.getDrawable(i));
if (drawable->getStateSet()) popState();
}
if (geode.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::notify(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::notify(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::notify(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():_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, bool treatVertexDataAsTemporary)
{
if (treatVertexDataAsTemporary)
{
// osg::notify(osg::NOTICE)<<"Triangle temp ("<<v1<<") ("<<v2<<") ("<<v3<<")"<<std::endl;
_tempoaryTriangleVertices.push_back(v1);
_tempoaryTriangleVertices.push_back(v2);
_tempoaryTriangleVertices.push_back(v3);
}
else
{
// osg::notify(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::notify(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::notify(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::notify(osg::NOTICE)<<"v "<<*vitr<<std::endl;
}
for(UIntList::iterator titr = _triangleIndices.begin();
titr != _triangleIndices.end();
)
{
osg::notify(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::notify(osg::NOTICE)<<"removeDuplicateVertices "<<osg::Timer::instance()->delta_m(t0,t1)<<" ms"<<std::endl;
osg::notify(osg::NOTICE)<<"removeNullTriangles "<<osg::Timer::instance()->delta_m(t1,t2)<<" ms"<<std::endl;
osg::notify(osg::NOTICE)<<"computeNormals "<<osg::Timer::instance()->delta_m(t2,t3)<<" ms"<<std::endl;
osg::notify(osg::NOTICE)<<"buildEdgeMaps "<<osg::Timer::instance()->delta_m(t3,t4)<<" ms"<<std::endl;
osg::notify(osg::NOTICE)<<"setUpInternalStructures "<<osg::Timer::instance()->delta_m(t0,t4)<<" ms"<<std::endl;
dirtyBound();
dirtyDisplayList();
}
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::notify(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::notify(osg::NOTICE)<<"Num diplicates = "<<numDuplicates<<std::endl;
osg::notify(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::notify(osg::NOTICE)<<"OccluderGeometry::removeDuplicates() after = "<<_vertices.size()<<std::endl;
}
void OccluderGeometry::removeNullTriangles()
{
// osg::notify(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::notify(osg::NOTICE)<<"Null triangle"<<std::endl;
}
}
if (lastValidItr != _triangleIndices.end())
{
// osg::notify(osg::NOTICE)<<"Pruning end - before "<<_triangleIndices.size()<<std::endl;
_triangleIndices.erase(lastValidItr,_triangleIndices.end());
// osg::notify(osg::NOTICE)<<"Pruning end - after "<<_triangleIndices.size()<<std::endl;
}
}
void OccluderGeometry::computeNormals()
{
// osg::notify(osg::NOTICE)<<"OccluderGeometry::computeNormals()"<<std::endl;
unsigned int numTriangles = _triangleIndices.size() / 3;
unsigned int redundentIndices = _triangleIndices.size() - numTriangles * 3;
if (redundentIndices)
{
osg::notify(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::notify(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::notify(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::notify(osg::NOTICE)<<"Num of indices "<<_triangleIndices.size()<<std::endl;
osg::notify(osg::NOTICE)<<"Num of triangles "<<triNo<<std::endl;
osg::notify(osg::NOTICE)<<"Num of numTriangleErrors "<<numTriangleErrors<<std::endl;
osg::notify(osg::NOTICE)<<"Num of edges "<<edgeSet.size()<<std::endl;
osg::notify(osg::NOTICE)<<"Num of numEdgesWithNoTriangles "<<numEdgesWithNoTriangles<<std::endl;
osg::notify(osg::NOTICE)<<"Num of numEdgesWithOneTriangles "<<numEdgesWithOneTriangles<<std::endl;
osg::notify(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::notify(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::notify(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);
osg::Vec3 offset( lightdirection*5.0f );
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::notify(osg::NOTICE)<<"Positional light"<<std::endl;
UIntList silhouetteIndices;
computeLightPositionSilhouetteEdges(lightposition, silhouetteIndices);
// osg::notify(osg::NOTICE)<<"basePlane "<<basePlane[0]<<" "<<basePlane[1]<<" "<<basePlane[2]<<" "<<basePlane[3]<<std::endl;
// osg::notify(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.dirtyDisplayList();
svg.dirtyBound();
// osg::Timer_t t1 = osg::Timer::instance()->tick();
// osg::notify(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::computeBound() 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)
{
}
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
{
glNormal3f(0.0f, 0.0f, 0.0f);
}
glColor4f(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::computeBound() const
{
osg::BoundingBox bb;
for(Vec3List::const_iterator itr = _vertices.begin();
itr != _vertices.end();
++itr)
{
bb.expandBy(*itr);
}
return bb;
}