/* -*-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 using namespace osg; CollectOccludersVisitor::CollectOccludersVisitor(): NodeVisitor(COLLECT_OCCLUDER_VISITOR,TRAVERSE_ACTIVE_CHILDREN) { setCullingMode(VIEW_FRUSTUM_CULLING| NEAR_PLANE_CULLING| FAR_PLANE_CULLING| SMALL_FEATURE_CULLING); _minimumShadowOccluderVolume = 0.005f; _maximumNumberOfActiveOccluders = 10; _createDrawables = false; } CollectOccludersVisitor::~CollectOccludersVisitor() { } void CollectOccludersVisitor::reset() { CullStack::reset(); _occluderSet.clear(); } float CollectOccludersVisitor::getDistanceToEyePoint(const Vec3& pos, bool withLODScale) const { if (withLODScale) return (pos-getEyeLocal()).length()*getLODScale(); else return (pos-getEyeLocal()).length(); } float CollectOccludersVisitor::getDistanceToViewPoint(const Vec3& pos, bool withLODScale) const { if (withLODScale) return (pos-getViewPointLocal()).length()*getLODScale(); else return (pos-getViewPointLocal()).length(); } float CollectOccludersVisitor::getDistanceFromEyePoint(const Vec3& pos, bool withLODScale) const { const Matrix& matrix = *_modelviewStack.back(); float dist = -(pos[0]*matrix(0,2)+pos[1]*matrix(1,2)+pos[2]*matrix(2,2)+matrix(3,2)); if (withLODScale) return dist*getLODScale(); else return dist*getLODScale(); } void CollectOccludersVisitor::apply(osg::Node& node) { if (isCulled(node)) return; // push the culling mode. pushCurrentMask(); handle_cull_callbacks_and_traverse(node); // pop the culling mode. popCurrentMask(); } void CollectOccludersVisitor::apply(osg::Transform& node) { if (isCulled(node)) return; // push the culling mode. pushCurrentMask(); ref_ptr matrix = createOrReuseMatrix(*getModelViewMatrix()); node.computeLocalToWorldMatrix(*matrix,this); pushModelViewMatrix(matrix.get(), node.getReferenceFrame()); handle_cull_callbacks_and_traverse(node); popModelViewMatrix(); // pop the culling mode. popCurrentMask(); } void CollectOccludersVisitor::apply(osg::Projection& node) { if (isCulled(node)) return; // push the culling mode. pushCurrentMask(); ref_ptr matrix = createOrReuseMatrix(node.getMatrix()); pushProjectionMatrix(matrix.get()); handle_cull_callbacks_and_traverse(node); popProjectionMatrix(); // pop the culling mode. popCurrentMask(); } void CollectOccludersVisitor::apply(osg::Switch& node) { apply((Group&)node); } void CollectOccludersVisitor::apply(osg::LOD& node) { if (isCulled(node)) return; // push the culling mode. pushCurrentMask(); handle_cull_callbacks_and_traverse(node); // pop the culling mode. popCurrentMask(); } void CollectOccludersVisitor::apply(osg::OccluderNode& node) { // need to check if occlusion node is in the occluder // list, if so disable the appropriate ShadowOccluderVolume disableAndPushOccludersCurrentMask(_nodePath); if (isCulled(node)) { popOccludersCurrentMask(_nodePath); return; } // std::cout<<"CollectOccludersVisitor:: We have found an Occlusion node in frustum"<<&node<_minimumShadowOccluderVolume) { // need to test occluder against view frustum. //std::cout << " adding in Occluder"<(*occludeeItr); ShadowVolumeOccluder::HoleList& holeList = occludee.getHoleList(); for(ShadowVolumeOccluderSet::iterator occluderItr=_occluderSet.begin(); occluderItr!=occludeeItr; ++occluderItr) { // cast away constness of the std::set element since ShadowVolumeOccluder::contains() is non const, // and the std::set is a const, just for the invariance of the operator (&(*occluderItr)); if (occluder->contains(occludee.getOccluder().getReferenceVertexList())) { // erase occluder from set. // take a copy of the iterator then rewind it one element so to prevent invalidating the occludeeItr. ShadowVolumeOccluderSet::iterator eraseItr = occludeeItr--; _occluderSet.erase(eraseItr); break; } // now check all the holes in the occludee against the occluder, // do so in reverse order so that the iterators remain valid. for(ShadowVolumeOccluder::HoleList::reverse_iterator holeItr=holeList.rbegin(); holeItr!=holeList.rend(); ) { if (occluder->contains((*holeItr).getReferenceVertexList())) { holeList.erase((++holeItr).base()); } else { ++holeItr; } } } } if (_occluderSet.size()<=_maximumNumberOfActiveOccluders) return; // move the iterator to the _maximumNumberOfActiveOccluders th occluder. occludeeItr = _occluderSet.begin(); for(unsigned int i=0;i<_maximumNumberOfActiveOccluders;++i) ++occludeeItr; // discard last occluders. _occluderSet.erase(occludeeItr,_occluderSet.end()); }