/* -*-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 using namespace osg; typedef std::pair Point; // bool=true signifies a newly created point, false indicates original point. typedef std::vector PointList; typedef std::vector VertexList; // copyVertexListToPointList a vector for Vec3 into a vector of Point's. void copyVertexListToPointList(const VertexList& in,PointList& out) { out.reserve(in.size()); for(VertexList::const_iterator itr=in.begin(); itr!=in.end(); ++itr) { out.push_back(Point(0,*itr)); } } void copyPointListToVertexList(const PointList& in,VertexList& out) { out.reserve(in.size()); for(PointList::const_iterator itr=in.begin(); itr!=in.end(); ++itr) { out.push_back(itr->second); } } // clip the convex hull 'in' to plane to generate a clipped convex hull 'out' // return true if points remain after clipping. unsigned int clip(const Plane& plane,const PointList& in, PointList& out,unsigned int planeMask) { std::vector distance; distance.reserve(in.size()); for(PointList::const_iterator itr=in.begin(); itr!=in.end(); ++itr) { distance.push_back(plane.distance(itr->second)); } out.clear(); for(unsigned int i=0;i=0.0f) { out.push_back(in[i]); if (distance[i_1]<0.0f) { unsigned int mask = (in[i].first & in[i_1].first) | planeMask; float r = distance[i_1]/(distance[i_1]-distance[i]); out.push_back(Point(mask,in[i].second*r+in[i_1].second*(1.0f-r))); } } else if (distance[i_1]>0.0f) { unsigned int mask = (in[i].first & in[i_1].first) | planeMask; float r = distance[i_1]/(distance[i_1]-distance[i]); out.push_back(Point(mask,in[i].second*r+in[i_1].second*(1.0f-r))); } } return out.size(); } // clip the convex hull 'in' to planeList to generate a clipped convex hull 'out' // return true if points remain after clipping. unsigned int clip(const Polytope::PlaneList& planeList,const VertexList& vin,PointList& out) { PointList in; copyVertexListToPointList(vin,in); unsigned int planeMask = 0x1; for(Polytope::PlaneList::const_iterator itr=planeList.begin(); itr!=planeList.end(); ++itr) { if (!clip(*itr,in,out,planeMask)) return false; in.swap(out); planeMask <<= 1; } in.swap(out); return out.size(); } void transform(PointList& points,const osg::Matrix& matrix) { for(PointList::iterator itr=points.begin(); itr!=points.end(); ++itr) { itr->second = itr->second*matrix; } } void transform(const PointList& in,PointList& out,const osg::Matrix& matrix) { for(PointList::const_iterator itr=in.begin(); itr!=in.end(); ++itr) { out.push_back(Point(itr->first,itr->second * matrix)); } } void pushToFarPlane(PointList& points) { for(PointList::iterator itr=points.begin(); itr!=points.end(); ++itr) { itr->second.z() = 1.0f; } } void computePlanes(const PointList& front, const PointList& back, Polytope::PlaneList& planeList) { for(unsigned int i=0;i=3) { // compute the points on the far plane. PointList farPoints; farPoints.reserve(points.size()); transform(points,farPoints,MVP); pushToFarPlane(farPoints); transform(farPoints,invP); // move the occlude points into projection space. transform(points,MV); // use the points on the front plane as reference vertices on the _occluderVolume // so that the vertices can later by used to test for occlusion of the occluder itself. copyPointListToVertexList(points,_occluderVolume.getReferenceVertexList()); // create the front face of the occluder Plane occludePlane = computeFrontPlane(points); _occluderVolume.add(occludePlane); // create the sides of the occluder computePlanes(points,farPoints,_occluderVolume.getPlaneList()); _occluderVolume.setupMask(); // if the front face is pointing away from the eye point flip the whole polytope. if (occludePlane[3]>0.0f) { _occluderVolume.flip(); } _volume = computePolytopeVolume(points,farPoints)/volumeview; for(ConvexPlanarOccluder::HoleList::const_iterator hitr=occluder.getHoleList().begin(); hitr!=occluder.getHoleList().end(); ++hitr) { PointList points; if (clip(cullingset.getFrustum().getPlaneList(),hitr->getVertexList(),points)>=3) { _holeList.push_back(Polytope()); Polytope& polytope = _holeList.back(); // compute the points on the far plane. PointList farPoints; farPoints.reserve(points.size()); transform(points,farPoints,MVP); pushToFarPlane(farPoints); transform(farPoints,invP); // move the occlude points into projection space. transform(points,MV); // use the points on the front plane as reference vertices on the _occluderVolume // so that the vertices can later by used to test for occlusion of the occluder itself. copyPointListToVertexList(points,polytope.getReferenceVertexList()); // create the front face of the occluder Plane occludePlane = computeFrontPlane(points); // create the sides of the occluder computePlanes(points,farPoints,polytope.getPlaneList()); polytope.setupMask(); // if the front face is pointing away from the eye point flip the whole polytope. if (occludePlane[3]>0.0f) { polytope.flip(); } // remove the hole's volume from the occluder volume. _volume -= computePolytopeVolume(points,farPoints)/volumeview; } } //std::cout << "final volume = "<<_volume<& vertices) { if (_occluderVolume.containsAllOf(vertices)) { for(HoleList::iterator itr=_holeList.begin(); itr!=_holeList.end(); ++itr) { PointList points; if (clip(itr->getPlaneList(),vertices,points)>=3) return false; } return true; } return false; } bool ShadowVolumeOccluder::contains(const BoundingSphere& bound) { //std::cout << "Sphere testing occluder "<