#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; _createDrawables = false; } CollectOccludersVisitor::~CollectOccludersVisitor() { } void CollectOccludersVisitor::reset() { CullStack::reset(); } float CollectOccludersVisitor::getDistanceToEyePoint(const Vec3& pos, bool withLODBias) const { if (withLODBias) return (pos-getEyeLocal()).length()*getLODBias(); else return (pos-getEyeLocal()).length(); } float CollectOccludersVisitor::getDistanceFromEyePoint(const Vec3& pos, bool withLODBias) 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 (withLODBias) return dist*getLODBias(); else return dist*getLODBias(); } 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.getLocalToWorldMatrix(*matrix,this); pushModelViewMatrix(matrix.get()); 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; } } } } }