#include "VssRay.h" #include "Beam.h" #include "Mesh.h" #include "Polygon3.h" namespace GtpVisibilityPreprocessor { void Beam::Construct(const AxisAlignedBox3 &box, const AxisAlignedBox3 &dBox) { // the frustum is defined by set of negative halfspace described by mPlanes // construct Vector3 center = box.Center(); Vector3 dCenter = dBox.Center(); // "back plane" mPlanes.push_back(Plane3(-VssRay::GetDirection(dCenter.x, dCenter.y), center)); Vector3 directions[4]; directions[0] = VssRay::GetDirection(dBox.Min().x, dBox.Min().y); directions[1] = VssRay::GetDirection(dBox.Max().x, dBox.Min().y); directions[2] = VssRay::GetDirection(dBox.Max().x, dBox.Max().y); directions[3] = VssRay::GetDirection(dBox.Min().x, dBox.Max().y); // side planes mPlanes.push_back(Plane3(-CrossProd(directions[0], directions[1]), center)); mPlanes.push_back(Plane3(-CrossProd(directions[1], directions[2]), center)); mPlanes.push_back(Plane3(-CrossProd(directions[2], directions[3]), center)); mPlanes.push_back(Plane3(-CrossProd(directions[3], directions[0]), center)); // now make sure all planes contain the spatial box int i, j; for (i=0; i < mPlanes.size(); i++) { float maxDist = 0; for (j=0; j < 8; j++) { float dist = mPlanes[i].Distance(box.GetVertex(j)); if (dist > maxDist) maxDist = dist; } mPlanes[i].mD -= maxDist; } mBox = box; mDirBox = dBox; SetValid(); } // conservative frustum box intersection // returns // 0 - box intersects the frustum // -1 - box intersects the frustum and is fully inside // 1 - box does not intersect the frustum int Beam::ComputeIntersection(const AxisAlignedBox3 &box) { int i; int result = -1; for (i=0; i < mPlanes.size(); i++) { int side = box.Side(mPlanes[i]); if (side == 1) return 1; if (side > result) result = side; } return result; } Beam::~Beam() { DEL_PTR(mMesh); } void Beam::ComputePerspectiveFrustum(float &left, float &right, float &bottom, float &top, float &near, float &far, const AxisAlignedBox3 &sceneBBox) const { const float xDirRange = mDirBox.Max().x - mDirBox.Min().x; const float yDirRange = mDirBox.Max().y - mDirBox.Min().y; //Debug << "xdir range: " << xDirRange << endl; //Debug << "ydir range: " << yDirRange << endl; near = 0.1f; // NOTE: what is the best value for near and far plane? far = 2.0f * Magnitude(sceneBBox.Diagonal()); right = fabs(near * tan(xDirRange * 0.5f)); left = -right; top = fabs(near * tan(yDirRange * 0.5f)); bottom = -top; } void Beam::ComputeOrthoFrustum(float &left, float &right, float &bottom, float &top, float &near, float &far, const AxisAlignedBox3 &sceneBBox) const { const int vAxis = GetMainDirection().DrivingAxis(); const int axis2 = (vAxis + 1) % 3; const int axis3 = (vAxis + 2) % 3; const float xDirRange = mBox.Max()[axis2] - mDirBox.Min()[axis2]; const float yDirRange = mDirBox.Max()[axis3] - mDirBox.Min()[axis3]; near = 0.1f; // NOTE: what is the best value for near and far plane? far = 2.0f * Magnitude(sceneBBox.Diagonal()); right = xDirRange * 0.5f; left = -right; top = yDirRange * 0.5f; bottom = -top; } Vector3 Beam::GetMainDirection() const { return - mPlanes[0].mNormal; } void BeamSampleStatistics::Print(ostream &app) const { app << "===== Beam sample statistics ===============\n"; app << "#N_PVSSIZE ( size of pvs )\n" << pvsSize << "\n"; app << "#N_RAYS ( Number of rays )\n" << rays << "\n"; app << "#N_RAYCONTRIBUTIONS ( number of ray constributions )\n" << rayContributions << "\n"; app << "#N_RAYLENGHTENTROPY ( Ray lenght entropy )\n" << rayLengthEntropy << "\n"; app << "#N_IMPORTANCE ( importance )\n" << importance << "\n"; app << "#N_CTIME ( Construction time [s] )\n" << Time() << " \n"; app << "===== END OF KdTree statistics ==========\n"; } void Beam::CreateMesh(const float zfar) { if (mMesh) return; mMesh = new Mesh(); // -- compute far plane // box should not never remove part of beam polygons Vector3 bmin = mBox.Min() - Vector3(zfar * 2.0f); Vector3 bmax = mBox.Max() + Vector3(zfar * 2.0f); AxisAlignedBox3 bbox(bmin, bmax); Plane3 fplane; fplane.mNormal = -mPlanes[0].mNormal; // NOTE: beam far plane must not not be culled by gl far plane fplane.mD = mPlanes[0].mD - zfar - 1.0f; mPlanes.push_back(fplane); for (int i = 0; i < mPlanes.size(); ++ i) { Polygon3 *poly = bbox.CrossSection(mPlanes[i]); if (!poly->Valid(Limits::Small)) DEL_PTR(poly); for (int j = 0; (j < mPlanes.size()) && poly; ++ j) { if (j != i) { Polygon3 *front = new Polygon3(); Polygon3 *back = new Polygon3(); poly->Split(mPlanes[j], *front, *back, Limits::Small); DEL_PTR(poly); DEL_PTR(front); if (!back->Valid(Limits::Small)) DEL_PTR(back); poly = back; } } if (poly) { IncludePolyInMesh(*poly, *mMesh); } } // remove far plane mPlanes.pop_back(); } }