overte/libraries/voxels/src/ViewFrustum.cpp
2013-05-06 10:59:09 -07:00

240 lines
9.1 KiB
C++

//
// ViewFrustum.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 04/11/13.
//
// Simple view frustum class.
//
//
#include "ViewFrustum.h"
#include "voxels_Log.h"
using voxels_lib::printLog;
ViewFrustum::ViewFrustum() :
_position(glm::vec3(0,0,0)),
_direction(glm::vec3(0,0,0)),
_up(glm::vec3(0,0,0)),
_right(glm::vec3(0,0,0)),
_fieldOfView(0.0),
_aspectRatio(1.0),
_nearClip(0.1),
_farClip(500.0),
_nearHeight(0.0),
_nearWidth(0.0),
_farHeight(0.0),
_farWidth(0.0),
_farCenter(glm::vec3(0,0,0)),
_farTopLeft(glm::vec3(0,0,0)),
_farTopRight(glm::vec3(0,0,0)),
_farBottomLeft(glm::vec3(0,0,0)),
_farBottomRight(glm::vec3(0,0,0)),
_nearCenter(glm::vec3(0,0,0)),
_nearTopLeft(glm::vec3(0,0,0)),
_nearTopRight(glm::vec3(0,0,0)),
_nearBottomLeft(glm::vec3(0,0,0)),
_nearBottomRight(glm::vec3(0,0,0)) { }
/////////////////////////////////////////////////////////////////////////////////////
// ViewFrustum::calculateViewFrustum()
//
// Description: this will calculate the view frustum bounds for a given position
// and direction
//
// Notes on how/why this works:
// http://www.lighthouse3d.com/tutorials/view-frustum-culling/view-frustums-shape/
//
void ViewFrustum::calculate() {
static const double PI_OVER_180 = 3.14159265359 / 180.0; // would be better if this was in a shared location
glm::vec3 front = _direction;
// Calculating field of view.
float fovInRadians = _fieldOfView * PI_OVER_180;
float twoTimesTanHalfFOV = 2.0f * tan(fovInRadians/2.0f);
// Do we need this?
//tang = (float)tan(ANG2RAD * angle * 0.5) ;
float nearClip = _nearClip;
float farClip = _farClip;
_nearHeight = (twoTimesTanHalfFOV * nearClip);
_nearWidth = _nearHeight * _aspectRatio;
_farHeight = (twoTimesTanHalfFOV * farClip);
_farWidth = _farHeight * _aspectRatio;
float farHalfHeight = (_farHeight * 0.5f);
float farHalfWidth = (_farWidth * 0.5f);
_farCenter = _position+front * farClip;
_farTopLeft = _farCenter + (_up * farHalfHeight) - (_right * farHalfWidth);
_farTopRight = _farCenter + (_up * farHalfHeight) + (_right * farHalfWidth);
_farBottomLeft = _farCenter - (_up * farHalfHeight) - (_right * farHalfWidth);
_farBottomRight = _farCenter - (_up * farHalfHeight) + (_right * farHalfWidth);
float nearHalfHeight = (_nearHeight * 0.5f);
float nearHalfWidth = (_nearWidth * 0.5f);
_nearCenter = _position+front * nearClip;
_nearTopLeft = _nearCenter + (_up * nearHalfHeight) - (_right * nearHalfWidth);
_nearTopRight = _nearCenter + (_up * nearHalfHeight) + (_right * nearHalfWidth);
_nearBottomLeft = _nearCenter - (_up * nearHalfHeight) - (_right * nearHalfWidth);
_nearBottomRight = _nearCenter - (_up * nearHalfHeight) + (_right * nearHalfWidth);
// compute the six planes
// The planes are defined such that the normal points towards the inside of the view frustum.
// Testing if an object is inside the view frustum is performed by computing on which side of
// the plane the object resides. This can be done computing the signed distance from the point
// to the plane. If it is on the side that the normal is pointing, i.e. the signed distance
// is positive, then it is on the right side of the respective plane. If an object is on the
// right side of all six planes then the object is inside the frustum.
// the function set3Points assumes that the points are given in counter clockwise order, assume you
// are inside the frustum, facing the plane. Start with any point, and go counter clockwise for
// three consecutive points
_planes[TOP_PLANE ].set3Points(_nearTopRight,_nearTopLeft,_farTopLeft);
_planes[BOTTOM_PLANE].set3Points(_nearBottomLeft,_nearBottomRight,_farBottomRight);
_planes[LEFT_PLANE ].set3Points(_nearBottomLeft,_farBottomLeft,_farTopLeft);
_planes[RIGHT_PLANE ].set3Points(_farBottomRight,_nearBottomRight,_nearTopRight);
_planes[NEAR_PLANE ].set3Points(_nearBottomRight,_nearBottomLeft,_nearTopLeft);
_planes[FAR_PLANE ].set3Points(_farBottomLeft,_farBottomRight,_farTopRight);
}
void ViewFrustum::dump() const {
printLog("position.x=%f, position.y=%f, position.z=%f\n", _position.x, _position.y, _position.z);
printLog("direction.x=%f, direction.y=%f, direction.z=%f\n", _direction.x, _direction.y, _direction.z);
printLog("up.x=%f, up.y=%f, up.z=%f\n", _up.x, _up.y, _up.z);
printLog("right.x=%f, right.y=%f, right.z=%f\n", _right.x, _right.y, _right.z);
printLog("farDist=%f\n", _farClip);
printLog("farHeight=%f\n", _farHeight);
printLog("farWidth=%f\n", _farWidth);
printLog("nearDist=%f\n", _nearClip);
printLog("nearHeight=%f\n", _nearHeight);
printLog("nearWidth=%f\n", _nearWidth);
printLog("farCenter.x=%f, farCenter.y=%f, farCenter.z=%f\n",
_farCenter.x, _farCenter.y, _farCenter.z);
printLog("farTopLeft.x=%f, farTopLeft.y=%f, farTopLeft.z=%f\n",
_farTopLeft.x, _farTopLeft.y, _farTopLeft.z);
printLog("farTopRight.x=%f, farTopRight.y=%f, farTopRight.z=%f\n",
_farTopRight.x, _farTopRight.y, _farTopRight.z);
printLog("farBottomLeft.x=%f, farBottomLeft.y=%f, farBottomLeft.z=%f\n",
_farBottomLeft.x, _farBottomLeft.y, _farBottomLeft.z);
printLog("farBottomRight.x=%f, farBottomRight.y=%f, farBottomRight.z=%f\n",
_farBottomRight.x, _farBottomRight.y, _farBottomRight.z);
printLog("nearCenter.x=%f, nearCenter.y=%f, nearCenter.z=%f\n",
_nearCenter.x, _nearCenter.y, _nearCenter.z);
printLog("nearTopLeft.x=%f, nearTopLeft.y=%f, nearTopLeft.z=%f\n",
_nearTopLeft.x, _nearTopLeft.y, _nearTopLeft.z);
printLog("nearTopRight.x=%f, nearTopRight.y=%f, nearTopRight.z=%f\n",
_nearTopRight.x, _nearTopRight.y, _nearTopRight.z);
printLog("nearBottomLeft.x=%f, nearBottomLeft.y=%f, nearBottomLeft.z=%f\n",
_nearBottomLeft.x, _nearBottomLeft.y, _nearBottomLeft.z);
printLog("nearBottomRight.x=%f, nearBottomRight.y=%f, nearBottomRight.z=%f\n",
_nearBottomRight.x, _nearBottomRight.y, _nearBottomRight.z);
}
//enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE };
const char* ViewFrustum::debugPlaneName (int plane) const {
switch (plane) {
case TOP_PLANE: return "Top Plane";
case BOTTOM_PLANE: return "Bottom Plane";
case LEFT_PLANE: return "Left Plane";
case RIGHT_PLANE: return "Right Plane";
case NEAR_PLANE: return "Near Plane";
case FAR_PLANE: return "Far Plane";
}
return "Unknown";
}
int ViewFrustum::pointInFrustum(const glm::vec3& point) const {
//printf("ViewFrustum::pointInFrustum() point=%f,%f,%f\n",point.x,point.y,point.z);
//dump();
int result = INSIDE;
for(int i=0; i < 6; i++) {
float distance = _planes[i].distance(point);
//printf("plane[%d] %s -- distance=%f \n",i,debugPlaneName(i),distance);
if (distance < 0) {
return OUTSIDE;
}
}
return(result);
}
int ViewFrustum::sphereInFrustum(const glm::vec3& center, float radius) const {
int result = INSIDE;
float distance;
for(int i=0; i < 6; i++) {
distance = _planes[i].distance(center);
if (distance < -radius)
return OUTSIDE;
else if (distance < radius)
result = INTERSECT;
}
return(result);
}
int ViewFrustum::boxInFrustum(const AABox& box) const {
//printf("ViewFrustum::boxInFrustum() box.corner=%f,%f,%f x=%f\n",
// box.getCorner().x,box.getCorner().y,box.getCorner().z,box.getSize().x);
int result = INSIDE;
for(int i=0; i < 6; i++) {
//printf("plane[%d] -- point(%f,%f,%f) normal(%f,%f,%f) d=%f \n",i,
// _planes[i].getPoint().x, _planes[i].getPoint().y, _planes[i].getPoint().z,
// _planes[i].getNormal().x, _planes[i].getNormal().y, _planes[i].getNormal().z,
// _planes[i].getDCoefficient()
//);
glm::vec3 normal = _planes[i].getNormal();
glm::vec3 boxVertexP = box.getVertexP(normal);
float planeToBoxVertexPDistance = _planes[i].distance(boxVertexP);
glm::vec3 boxVertexN = box.getVertexN(normal);
float planeToBoxVertexNDistance = _planes[i].distance(boxVertexN);
//printf("plane[%d] normal=(%f,%f,%f) bVertexP=(%f,%f,%f) planeToBoxVertexPDistance=%f boxVertexN=(%f,%f,%f) planeToBoxVertexNDistance=%f\n",i,
// normal.x,normal.y,normal.z,
// boxVertexP.x,boxVertexP.y,boxVertexP.z,planeToBoxVertexPDistance,
// boxVertexN.x,boxVertexN.y,boxVertexN.z,planeToBoxVertexNDistance
// );
if (planeToBoxVertexPDistance < 0) {
return OUTSIDE;
} else if (planeToBoxVertexNDistance < 0) {
result = INTERSECT;
}
}
return(result);
}
bool ViewFrustum::matches(const ViewFrustum& compareTo) const {
return compareTo._position == _position &&
compareTo._direction == _direction &&
compareTo._up == _up &&
compareTo._right == _right &&
compareTo._fieldOfView == _fieldOfView &&
compareTo._aspectRatio == _aspectRatio &&
compareTo._nearClip == _nearClip &&
compareTo._farClip == _farClip;
}