Occlusion culling optimizations, added minimum polygon area, and only calculate projection matrix once

This commit is contained in:
ZappoMan 2013-06-19 11:46:22 -07:00
parent 01ae437343
commit 6755dfd8e4
6 changed files with 69 additions and 19 deletions

View file

@ -13,6 +13,35 @@
int CoverageMap::_mapCount = 0;
const BoundingBox CoverageMap::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-2.f,-2.f), glm::vec2(4.f,4.f));
// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space.
//
// (0,0) (windowWidth, 0)
// -1,1 1,1
// +-----------------------+
// | | |
// | | |
// | -1,0 | |
// |-----------+-----------|
// | 0,0 |
// | | |
// | | |
// | | |
// +-----------------------+
// -1,-1 1,-1
// (0,windowHeight) (windowWidth,windowHeight)
//
// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide
// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically
// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough"
// then we can calculate a reasonable polygon area
const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500;
const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10;
const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS);
const float CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) *
(TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS);
CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygons) :
_isRoot(isRoot), _myBoundingBox(boundingBox), _managePolygons(managePolygons) {
_mapCount++;
@ -51,9 +80,10 @@ void CoverageMap::erase() {
}
}
/**
/** Kee this debugging code for now....
if (_isRoot) {
printLog("CoverageMap last to be deleted...\n");
printLog("MINIMUM_POLYGON_AREA_TO_STORE=%f\n",MINIMUM_POLYGON_AREA_TO_STORE);
printLog("_mapCount=%d\n",_mapCount);
printLog("_maxPolygonsUsed=%d\n",_maxPolygonsUsed);
printLog("_totalPolygons=%d\n",_totalPolygons);
@ -63,7 +93,6 @@ void CoverageMap::erase() {
_mapCount = 0;
}
**/
}
void CoverageMap::init() {
@ -143,6 +172,13 @@ void CoverageMap::storeInArray(VoxelProjectedPolygon* polygon) {
// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT
CoverageMap::StorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, bool storeIt) {
// short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is
// not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later.
if (!polygon->getAllInView()) {
return DOESNT_FIT;
}
if (_isRoot || _myBoundingBox.contains(polygon->getBoundingBox())) {
// check to make sure this polygon isn't occluded by something at this level
for (int i = 0; i < _polygonCount; i++) {
@ -157,8 +193,13 @@ CoverageMap::StorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon,
// want to report our inserted one as occluded, but we do want to add our inserted one.
if (polygonAtThisLevel->getDistance() >= polygon->getDistance()) {
if (storeIt) {
storeInArray(polygon);
return STORED;
if (polygon->getBoundingBox().area() > MINIMUM_POLYGON_AREA_TO_STORE) {
//printLog("storing polygon of area: %f\n",polygon->getBoundingBox().area());
storeInArray(polygon);
return STORED;
} else {
return NOT_STORED;
}
} else {
return NOT_STORED;
}
@ -183,8 +224,13 @@ CoverageMap::StorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon,
// if we got this far, then the polygon is in our bounding box, but doesn't fit in
// any of our child bounding boxes, so we should add it here.
if (storeIt) {
storeInArray(polygon);
return STORED;
if (polygon->getBoundingBox().area() > MINIMUM_POLYGON_AREA_TO_STORE) {
//printLog("storing polygon of area: %f\n",polygon->getBoundingBox().area());
storeInArray(polygon);
return STORED;
} else {
return NOT_STORED;
}
} else {
return NOT_STORED;
}

View file

@ -18,6 +18,7 @@ public:
static const bool NOT_ROOT=false;
static const bool IS_ROOT=true;
static const BoundingBox ROOT_BOUNDING_BOX;
static const float MINIMUM_POLYGON_AREA_TO_STORE;
CoverageMap(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, bool managePolygons = true);
~CoverageMap();

View file

@ -115,6 +115,14 @@ void ViewFrustum::calculate() {
_planes[NEAR_PLANE ].set3Points(_nearBottomRight,_nearBottomLeft,_nearTopLeft);
_planes[FAR_PLANE ].set3Points(_farBottomLeft,_farBottomRight,_farTopRight);
// Also calculate our projection matrix in case people want to project points...
// Projection matrix : Field of View, ratio, display range : near to far
glm::mat4 projection = glm::perspective(_fieldOfView, _aspectRatio, _nearClip, _farClip);
glm::vec3 lookAt = _position + _direction;
glm::mat4 view = glm::lookAt(_position, lookAt, _up);
// Our ModelViewProjection : multiplication of our 3 matrices (note: model is identity, so we can drop it)
_ourModelViewProjectionMatrix = projection * view; // Remember, matrix multiplication is the other way around
}
//enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE };
@ -425,18 +433,10 @@ void ViewFrustum::printDebugDetails() const {
_eyeOffsetOrientation.w );
}
glm::vec2 ViewFrustum::projectPoint(glm::vec3 point, bool& pointInView) const {
// Projection matrix : Field of View, ratio, display range : near to far
glm::mat4 projection = glm::perspective(_fieldOfView, _aspectRatio, _nearClip, _farClip);
glm::vec3 lookAt = _position + _direction;
glm::mat4 view = glm::lookAt(_position, lookAt, _up);
// Our ModelViewProjection : multiplication of our 3 matrices (note: model is identity, so we can drop it)
glm::mat4 VP = projection * view; // Remember, matrix multiplication is the other way around
glm::vec4 pointVec4 = glm::vec4(point,1);
glm::vec4 projectedPointVec4 = VP * pointVec4;
glm::vec4 pointVec4 = glm::vec4(point,1) ;
glm::vec4 projectedPointVec4 = _ourModelViewProjectionMatrix * pointVec4;
pointInView = (projectedPointVec4.w > 0); // math! If the w result is negative then the point is behind the viewer
// what happens with w is 0???

View file

@ -137,6 +137,8 @@ private:
const char* debugPlaneName (int plane) const;
// Used to project points
glm::mat4 _ourModelViewProjectionMatrix;
};

View file

@ -48,7 +48,7 @@ void VoxelProjectedPolygon::setVertex(int vertex, const glm::vec2& point) {
};
bool VoxelProjectedPolygon::occludes(const VoxelProjectedPolygon& occludee) const {
bool VoxelProjectedPolygon::occludes(const VoxelProjectedPolygon& occludee, bool checkAllInView) const {
// if we are completely out of view, then we definitely don't occlude!
// if the occludee is completely out of view, then we also don't occlude it
@ -56,7 +56,7 @@ bool VoxelProjectedPolygon::occludes(const VoxelProjectedPolygon& occludee) cons
// this is true, but unfortunately, we're not quite handling projects in the
// case when SOME points are in view and others are not. So, we will not consider
// occlusion for any shadows that are partially in view.
if (!getAllInView() || !occludee.getAllInView() ) {
if (checkAllInView && (!getAllInView() || !occludee.getAllInView())) {
return false;
}

View file

@ -20,6 +20,7 @@ public:
glm::vec2 corner;
glm::vec2 size;
bool contains(const BoundingBox& box) const;
float area() const { return size.x * size.y; };
void printDebugDetails(const char* label=NULL) const;
};
@ -48,7 +49,7 @@ public:
bool getAllInView() const { return _allInView; };
void setAllInView(bool allInView) { _allInView = allInView; };
bool occludes(const VoxelProjectedPolygon& occludee) const;
bool occludes(const VoxelProjectedPolygon& occludee, bool checkAllInView = false) const;
bool pointInside(const glm::vec2& point) const;
float getMaxX() const { return _maxX; }