// ================================================================ // $Id$ // **************************************************************** // // Initial coding by /** @author Jiri Bittner */ #ifndef __RSSTREE_H__ #define __RSSTREE_H__ // Standard headers #include #include #include #include // User headers #include "VssRay.h" #include "AxisAlignedBox3.h" #include "Halton.h" #include "Beam.h" #include "Statistics.h" #include "Ray.h" #include "Containers.h" #include "SamplingStrategy.h" namespace GtpVisibilityPreprocessor { #define USE_KDNODE_VECTORS 1 #define _RSS_STATISTICS #define _RSS_TRAVERSAL_STATISTICS // -------------------------------------------------------------- // Static statistics for kd-tree search // -------------------------------------------------------------- class RssStatistics : public StatisticsBase { public: // total number of nodes int nodes; // number of leaves int leaves; // number of splits along each of the axes int splits[7]; // totals number of rays int rays; // initial size of the pvs int initialPvsSize; // total number of query domains int queryDomains; // total number of ray references int rayRefs; // max depth nodes int maxDepthNodes; // max depth nodes int minPvsNodes; int minRaysNodes; // max ray contribution nodes int maxRayContribNodes; // max depth nodes int minSizeNodes; int maxCostRatioNodes; // max number of rays per node int maxRayRefs; // number of dynamically added ray refs int addedRayRefs; // number of dynamically removed ray refs int removedRayRefs; // dynamically updated values float avgPvsSize; float avgRays; float avgRayContribution; float avgPvsEntropy; float avgRayLengthEntropy; float avgImportance; float avgWeightedRayContribution; // Constructor RssStatistics() { Reset(); } int Nodes() const {return nodes;} int Interior() const { return nodes/2; } int Leaves() const { return Nodes() - Interior(); } void Reset() { nodes = 0; for (int i=0; i<7; i++) splits[i] = 0; rays = queryDomains = 0; rayRefs = 0; maxDepthNodes = 0; minPvsNodes = 0; minRaysNodes = 0; maxRayRefs = 0; addedRayRefs = removedRayRefs = 0; initialPvsSize = 0; maxRayContribNodes = 0; minSizeNodes = 0; maxCostRatioNodes = 0; } void Print(ostream &app) const; friend ostream &operator<<(ostream &s, const RssStatistics &stat) { stat.Print(s); return s; } }; class RssTreeInterior; // -------------------------------------------------------------- // KD-tree node - abstract class // -------------------------------------------------------------- class RssTreeNode { public: struct RayInfo { // pointer to the actual ray VssRay *mRay; RayInfo():mRay(NULL) {} RayInfo(VssRay *r):mRay(r) {} enum { SOURCE_RAY = 0, TERMINATION_RAY, PASSING_RAY, CONTAINED_RAY }; int GetRayClass() const { return SOURCE_RAY; } friend bool operator<(const RayInfo &a, const RayInfo &b) { return a.mRay < b.mRay; } #define USE_ORIGIN 1 Vector3 GetOrigin() const { #if USE_ORIGIN return mRay->GetOrigin(); #else return mRay->GetTermination(); #endif } Vector3 GetTermination() const { #if USE_ORIGIN return mRay->GetTermination(); #else return mRay->GetOrigin(); #endif } float GetOrigin(const int axis) const { #if USE_ORIGIN return mRay->GetOrigin(axis); #else return mRay->GetTermination(axis); #endif } Vector3 GetDir() const { #if USE_ORIGIN return mRay->GetDir(); #else return -mRay->GetDir(); #endif } float GetDirParametrization(const int axis) const { #if USE_ORIGIN return mRay->GetDirParametrization(axis); #else return mRay->GetOpositeDirParametrization(axis); #endif } // Vector3 GetTermination() const { // return mRay->GetOrigin(); // } // float GetTermination(const int axis) const { // return mRay->GetTermination(axis); // } Intersectable *GetObject() const { #if USE_ORIGIN return mRay->mTerminationObject; #else return mRay->mOriginObject; #endif } Intersectable *GetSourceObject() const { #if USE_ORIGIN return mRay->mOriginObject; #else return mRay->mTerminationObject; #endif } // Vector3 Extrap(const float t) const { // return mRay->Extrap(t); // } int ComputeRaySide(const int axis, const float position ) const { // only compare the side of the origin float rpos = (axis < 3) ? GetOrigin(axis) : GetDirParametrization(axis - 3); return (rpos <= position) ? -1 : 1; } static bool GreaterWeightedPvsContribution(const RayInfo &a, const RayInfo &b) { return a.mRay->mWeightedPvsContribution > b.mRay->mWeightedPvsContribution; } static float Distance(const RayInfo &a, const RayInfo &b) { if (a.mRay->mTerminationObject == b.mRay->mTerminationObject) return MAX_FLOAT; return Min(a.mRay->SqrDistance(b.GetTermination()), b.mRay->SqrDistance(a.GetTermination())); } static float SqrDistance5D(const RayInfo &a, const RayInfo &b, const Vector3 &spatialDerivative, const Vector3 &directionalDerivative ) { Vector3 spatialDiff = b.GetOrigin() - a.GetOrigin(); Vector3 directionalDiff = b.GetDir() - a.GetDir(); return DotProd(spatialDiff, spatialDerivative) + DotProd(directionalDiff, directionalDerivative); } }; struct SilhouetteRays { RayInfo *a; RayInfo *b; SilhouetteRays() {} SilhouetteRays(RayInfo *_a, RayInfo *_b):a(_a), b(_b) { } }; typedef vector RayInfoContainer; enum { EInterior, ELeaf }; ///////////////////////////////// // The actual data goes here // link to the parent RssTreeInterior *parent; enum {SPLIT_X=0, SPLIT_Y, SPLIT_Z, SPLIT_DIRX, SPLIT_DIRY, SPLIT_DIRZ}; // splitting axis char axis; // depth unsigned char depth; // short depth; // ///////////////////////////////// // the bbox of the node AxisAlignedBox3 bbox; // the bbox of the node AxisAlignedBox3 dirBBox; // evaluated importance of this node float mImportance; // importance requires update //bool mRequiresUpdate; inline RssTreeNode(RssTreeInterior *p); virtual ~RssTreeNode() {}; virtual int Type() const = 0; bool IsLeaf() const { return axis == -1; } virtual void Print(ostream &s) const = 0; virtual int GetAccessTime() { return 0x7FFFFFF; } float GetImportance() const; }; // -------------------------------------------------------------- // KD-tree node - interior node // -------------------------------------------------------------- class RssTreeInterior : public RssTreeNode { public: // plane in world coordinates float position; // pointers to children RssTreeNode *back, *front; // data for caching long accesses; long lastAccessTime; RssTreeInterior(RssTreeInterior *p):RssTreeNode(p), back(NULL), front(NULL), accesses(0), lastAccessTime(-1) { } virtual int GetAccessTime() { return lastAccessTime; } float GetRelativePosition() const { if (axis < 3) return (position - bbox.Min(axis))/bbox.Size(axis); else return (position - dirBBox.Min(axis-3))/dirBBox.Size(axis-3); } void SetupChildLinks(RssTreeNode *b, RssTreeNode *f) { back = b; front = f; b->parent = f->parent = this; } void ReplaceChildLink(RssTreeNode *oldChild, RssTreeNode *newChild) { if (back == oldChild) back = newChild; else front = newChild; } virtual int Type() const { return EInterior; } virtual ~RssTreeInterior() { if (back) delete back; if (front) delete front; } virtual void Print(ostream &s) const { if (axis == 0) s<<"x "; else if (axis == 1) s<<"y "; else s<<"z "; s<Print(s); front->Print(s); } int ComputeRaySide(const RayInfo &rayData ) { return rayData.ComputeRaySide(axis, position); } }; // -------------------------------------------------------------- // KD-tree node - leaf node // -------------------------------------------------------------- class RssTreeLeaf : public RssTreeNode { private: int mPvsSize; public: static int mailID; int mailbox; RayInfoContainer rays; int mTotalRays; float mTotalContribution; bool mValidPvs; Beam mBeam; RssTreeLeaf(RssTreeInterior *p, const int nRays ):RssTreeNode(p), rays(), mPvsSize(0), mTotalRays(0), mTotalContribution(0.0f), mValidPvs(false) { rays.reserve(nRays); } virtual ~RssTreeLeaf() { } virtual int Type() const { return ELeaf; } virtual void Print(ostream &s) const { s<< "L: rays="<<(int)rays.size()<< " pvs="<