Further work on Occlusion Culling. Most of work is complete, just debugging

required now.
This commit is contained in:
Robert Osfield
2002-06-13 16:21:00 +00:00
parent 8dcb26967c
commit 0ebe473eb5
13 changed files with 335 additions and 55 deletions

View File

@@ -103,18 +103,26 @@ void CollectOccludersVisitor::apply(osg::OccluderNode& node)
if (isCulled(node)) return;
std::cout<<"CollectOccludersVisitor:: We have found an Occlusion node in frustum"<<&node<<std::endl;
// std::cout<<"CollectOccludersVisitor:: We have found an Occlusion node in frustum"<<&node<<std::endl;
// push the culling mode.
pushCurrentMask();
if (node.getOccluder()&& !isCulled(node.getOccluder()->getOccluder().getVertexList()))
if (node.getOccluder())
{
// need to test occluder against view frustum.
std::cout << " adding in Occluder"<<std::endl;
_occluderList.push_back(ShadowVolumeOccluder(_nodePath, *node.getOccluder(), getModelViewMatrix(),getProjectionMatrix()));
// computeOccluder will check if the occluder is the view frustum,
// if it ins't then the it will return false, when in it will
// clip the occluder's polygons in clip space, then create occluder
// planes, all with their normals facing inward towards the volume,
// and then transform them back into projection space.
ShadowVolumeOccluder svo;
if (svo.computeOccluder(_nodePath, *node.getOccluder(), *this))
{
// need to test occluder against view frustum.
// std::cout << " adding in Occluder"<<std::endl;
_occluderList.push_back(svo);
}
}
traverse(node);

View File

@@ -109,13 +109,28 @@ void CullStack::pushProjectionMatrix(Matrix* matrix)
_projectionStack.push_back(matrix);
osg::CullingSet* cullingSet = osgNew osg::CullingSet();
// set up view frustum.
cullingSet->getFrustum().setToUnitFrustumWithoutNearFar();
cullingSet->getFrustum().transformProvidingInverse(*matrix);
// set the small feature culling.
cullingSet->setSmallFeatureCullingPixelSize(_smallFeatureCullingPixelSize);
_projectionCullingStack.push_back(cullingSet);
// set up the relevant occluders which a related to this projection.
for(ShadowVolumeOccluderList::iterator itr=_occluderList.begin();
itr!=_occluderList.end();
++itr)
{
//std::cout << " ** testing occluder"<<std::endl;
if (itr->matchProjectionMatrix(*matrix))
{
//std::cout << " ** activating occluder"<<std::endl;
cullingSet->addOccluder(*itr);
}
}
//_projectionCullingStack.push_back(osgNew osg::CullingSet(*_clipspaceCullingStack.back(),*matrix));
_projectionCullingStack.push_back(cullingSet);
pushCullingSet();

View File

@@ -12,3 +12,21 @@ CullingSet::CullingSet()
CullingSet::~CullingSet()
{
}
void CullingSet::disableOccluder(NodePath& nodePath)
{
//std::cout<<" trying to disable occluder"<<std::endl;
for(OccluderList::iterator itr=_occluderList.begin();
itr!=_occluderList.end();
++itr)
{
if (itr->getNodePath()==nodePath)
{
//std::cout<<" ++ disabling occluder"<<std::endl;
// we have trapped for the case an occlude potentially occluding itself,
// to prevent this we disable the results mask so that no subsequnt
// when the next pushCurrentMask calls happens this occluder is switched off.
itr->disableResultMasks();
}
}
}

View File

@@ -1,11 +1,161 @@
#include <osg/ShadowVolumeOccluder>
#include <osg/CullStack>
using namespace osg;
void ShadowVolumeOccluder::computeOccluder(const NodePath& nodePath,const ConvexPlanerOccluder& occluder,const Matrix& MV,const Matrix& P)
typedef std::pair<bool,Vec3> Point; // bool=true signifies a newly created point, false indicates original point.
typedef std::vector<Point> PointList;
typedef std::vector<Vec3> VertexList;
// convert a vector for Vec3 into a vector of Point's.
void convert(const VertexList& in,PointList& out)
{
std::cout<<" Computing Occluder"<<std::endl;
out.reserve(in.size());
for(VertexList::const_iterator itr=in.begin();
itr!=in.end();
++itr)
{
out.push_back(Point(false,*itr));
}
}
// 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)
{
std::vector<float> 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<in.size();++i)
{
unsigned int i_1 = (i+1)%in.size(); // do the mod to wrap the index round back to the start.
if (distance[i]>=0.0f)
{
out.push_back(in[i]);
if (distance[i_1]<0.0f)
{
float r = distance[i_1]/(distance[i_1]-distance[i]);
out.push_back(Point(true,in[i].second*r+in[i_1].second*(1.0f-r)));
}
}
else if (distance[i_1]>0.0f)
{
float r = distance[i_1]/(distance[i_1]-distance[i]);
out.push_back(Point(true,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;
convert(vin,in);
for(Polytope::PlaneList::const_iterator itr=planeList.begin();
itr!=planeList.end();
++itr)
{
if (!clip(*itr,in,out)) return false;
in.swap(out);
}
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<front.size();++i)
{
unsigned int i_1 = (i+1)%front.size(); // do the mod to wrap the index round back to the start.
if (!front[i].first || !front[i_1].first)
{
planeList.push_back(Plane(front[i].second,front[i_1].second,back[i].second));
}
}
}
Plane computeFrontPlane(const PointList& front)
{
return Plane(front[2].second,front[1].second,front[0].second);
}
bool ShadowVolumeOccluder::computeOccluder(const NodePath& nodePath,const ConvexPlanerOccluder& occluder,CullStack& cullStack)
{
// std::cout<<" Computing Occluder"<<std::endl;
CullingSet& cullingset = cullStack.getCurrentCullingSet();
const Matrix& MV = cullStack.getModelViewMatrix();
const Matrix& P = cullStack.getProjectionMatrix();
// take a reference to the NodePath to this occluder.
_nodePath = nodePath;
// take a reference to the projection matrix.
_projectionMatrix = &P;
// compute the inverse of the projection matrix.
Matrix invP;
invP.invert(P);
// compute the transformation matrix which takes form local coords into clip space.
Matrix MVP(MV);
MVP *= P;
// for the occluder polygon and each of the holes do
// first transform occluder polygon into clipspace by multiple it by c[i] = v[i]*(MV*P)
@@ -15,7 +165,52 @@ void ShadowVolumeOccluder::computeOccluder(const NodePath& nodePath,const Convex
// compute volume (quality) betwen front polygon in projection space and back polygon in projection space.
const VertexList& vertices_in = occluder.getOccluder().getVertexList();
PointList points;
if (clip(cullingset.getFrustum().getPlaneList(),vertices_in,points)>=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);
// create the sides of the occluder
computePlanes(points,farPoints,_occluderVolume.getPlaneList());
// create the front face of the occluder
Plane occludePlane = computeFrontPlane(points);
_occluderVolume.add(occludePlane);
// if the front face is pointing away from the eye point flip the whole polytope.
if (occludePlane[3]>0.0f)
{
// std::cout << " flipping polytope"<<std::endl;
_occluderVolume.flip();
}
for(Polytope::PlaneList::const_iterator itr=_occluderVolume.getPlaneList().begin();
itr!=_occluderVolume.getPlaneList().end();
++itr)
{
// std::cout << " compute plane "<<*itr<<std::endl;
}
return true;
}
else
{
// std::cout << " occluder clipped out of frustum."<<points.size()<<std::endl;
return false;
}
}
bool ShadowVolumeOccluder::contains(const std::vector<Vec3>& vertices)

View File

@@ -546,7 +546,7 @@ void CullVisitor::apply(osg::OccluderNode& node)
// list, if so disable the appropriate ShadowOccluderVolume
disableOccluder(_nodePath);
std::cout<<"CullVisitor:: We are in an Occlusion node"<<&node<<std::endl;
// std::cout<<"CullVisitor:: We are in an Occlusion node"<<&node<<std::endl;
if (isCulled(node)) return;

View File

@@ -310,7 +310,8 @@ void SceneView::cullStage(osg::Matrix* projection,osg::Matrix* modelview,osgUtil
// collect any occluder in the view frustum.
if (_sceneData->containsOccluderNodes())
{
std::cout << "Scene graph contains occluder nodes, searching for them"<<std::endl;
//std::cout << "Scene graph contains occluder nodes, searching for them"<<std::endl;
osg::CollectOccludersVisitor cov;
cov.setFrameStamp(_frameStamp.get());
@@ -331,8 +332,10 @@ void SceneView::cullStage(osg::Matrix* projection,osg::Matrix* modelview,osgUtil
cov.popModelViewMatrix();
cov.popProjectionMatrix();
cov.popViewport();
std::cout << "finished searching for occluder"<<std::endl;
// std::cout << "finished searching for occluder"<<std::endl;
cullVisitor->setOccluderList(cov.getCollectedOccluderList());
}