/* -*-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 #include #include #include #include #include #include #include #include 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; igetStateSet()) 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."<processGeometry(drawable, (_matrixStack.empty() ? 0 : &_matrixStack.back()), _ratio); } protected: OccluderGeometry* _oc; typedef std::vector MatrixStack; typedef std::vector 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)"<tick(); CollectOccludersVisitor cov(this, matrix, sampleRatio); subgraph->accept(cov); setUpInternalStructures(); osg::Timer_t endTick = osg::Timer::instance()->tick(); osg::notify(osg::NOTICE)<<"done in "<delta_m(startTick, endTick)<<" ms"< 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 ("< maxVertex) maxVertex = *itr; } unsigned int base = _vertices->size(); unsigned int numberNewVertices = _vertexPointers.empty() ? 0 : (maxVertex - minVertex) + 1; // osg::notify(osg::NOTICE)<<"base = "<accept(tc); tc.copyToLocalData(); #if 0 for(Vec3List::iterator vitr = _vertices.begin(); vitr != _vertices.end(); ++vitr) { osg::notify(osg::NOTICE)<<"v "<<*vitr<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(); computeLightDirectionSlihouetteEdges(osg::Vec3(0.0,0.0,1.0f)); osg::Timer_t t45 = osg::Timer::instance()->tick(); computeLightDirectionSlihouetteEdges(osg::Vec3(0.0,0.0,1.0f)); osg::Timer_t t5 = osg::Timer::instance()->tick(); osg::notify(osg::NOTICE)<<"removeDuplicateVertices "<delta_m(t0,t1)<<" ms"<delta_m(t1,t2)<<" ms"<delta_m(t2,t3)<<" ms"<delta_m(t3,t4)<<" ms"<delta_m(t4,t45)<<" ms"<delta_m(t45,t5)<<" ms"<delta_m(t0,t5)<<" ms"<normalize(); } } void OccluderGeometry::buildEdgeMaps() { // osg::notify(osg::NOTICE)<<"OccluderGeometry::buildEdgeMaps()"< 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._p1]) * 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); 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()<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()) ); } if (!_silhouetteIndices.empty()) { glColor4f(1.0f, 0.0f, 0.0f, 1.0f); glDrawElements(GL_LINES, _silhouetteIndices.size(), GL_UNSIGNED_INT, &(_silhouetteIndices.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() { } ShadowVolumeGeometry::ShadowVolumeGeometry(const ShadowVolumeGeometry& oc, const osg::CopyOp& copyop): osg::Drawable(oc,copyop) { } void ShadowVolumeGeometry::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()) ); } else { glNormal3f(0.0f, 0.0f, 0.0f); } glColor4f(0.5f, 1.0f, 1.0f, 1.0f); 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; }