#ifndef __PVS_H #define __PVS_H #include #include namespace GtpVisibilityPreprocessor { class KdNode; class BspNode; class Ray; class Intersectable; class ViewCell; template struct LtSample { bool operator()(const T a, const T b) const { return a < b; } }; /** Information stored with a PVS entry. Consists of the number the object was seen from the view cell. */ template struct PvsData { // int mVisibleSamples; // sum of probability density of visible sample rays float mSumPdf; PvsData() {} PvsData(const float sumPdf): mSumPdf(sumPdf) {} // $$JB in order to return meaningfull values // it assumes that the sum pdf has been normalized somehow!!! float GetVisibility() { return mSumPdf; } }; /** Template class representing the Potentially Visible Set (PVS) mainly from a view cell, but also e.g., from objects. */ template class Pvs { public: Pvs(): /*mSamples(0), */mEntries() {} //int mSamples; /** Compresses PVS lossless or lossy. */ int Compress() {return 0;} int GetSize() const {return (int)mEntries.size();} bool Empty() const {return mEntries.empty();} /** Normalize the visibility of entries in order to get comparable results */ void NormalizeMaximum(); /** Merges pvs of a into this pvs. */ void Merge(const Pvs &a); /** Difference of pvs to pvs b. @returns number of different entries. */ int Diff(const Pvs &b); /** Finds sample in PVS. @returns sample if found, NULL otherwise. */ PvsData *Find(T sample); bool GetSampleContribution(T sample, const float pdf, float &contribution); /** Adds sample to PVS. @contribution contribution of sample (0 or 1) @returns true if sample was not already in PVS. */ bool AddSample(T sample, const float pdf, float &contribution); /** Adds sample to PVS. @returns contribution of sample (0 or 1) */ float AddSample(T sample, const float pdf); /** Adds one pvs to another one. @returns new pvs size */ int AddPvs(const Pvs &pvs); /** Subtracts one pvs from another one. WARNING: could contains bugs @returns new pvs size */ int SubtractPvs(const Pvs &pvs); /** Returns PVS data, i.e., how often it was seen from the view cell, and the object itsef. */ void GetData(const int index, T &entry, PvsData &data); /** Collects the PVS entries and returns them in the vector. */ void CollectEntries(std::vector &entries); /** Removes sample from PVS if reference count is zero. @param visibleSamples number of references to be removed */ bool RemoveSample(T sample, const float pdf); /** Compute continuous PVS difference */ void ComputeContinuousPvsDifference(Pvs &pvs, float &pvsReduction, float &pvsEnlargement); /** Clears the pvs. */ void Clear(); /** Compute continuous PVS difference */ float GetPvsHomogenity(Pvs &pvs) { float pvsReduction, pvsEnlargement; ComputeContinuousPvsDifference(pvs, pvsReduction, pvsEnlargement); return pvsReduction + pvsEnlargement; } /// Map of PVS entries std::map, LtSample > mEntries; }; /** Compute continuous PVS difference of 'b' with respect to the base PVS (*this). Provides separatelly PVS reduction from PVS enlargement. */ template void Pvs::ComputeContinuousPvsDifference(Pvs &b, float &pvsReduction, float &pvsEnlargement) { pvsReduction = 0.0f; pvsEnlargement = 0.0f; // Uses sum of log differences, which corresponds to entropy std::map, LtSample >::iterator it; for (it = b.mEntries.begin(); it != b.mEntries.end(); ++ it) { float bSumPdf = (*it).second.mSumPdf; float aSumPdf = 0.0f; PvsData *data = Find((*it).first); if (data) { aSumPdf = data->mSumPdf; // mark this entry as processed to avoid double counting data->mSumPdf = -aSumPdf; } #if 0 float diff = bSumPdf - aSumPdf; if (diff > 0.0f) { pvsEnlargement += diff; } else { pvsReduction += -diff; } #else if (!data) pvsEnlargement += 1.0f; #endif } for (it = mEntries.begin(); it != mEntries.end(); ++ it) { float aSumPdf = (*it).second.mSumPdf; float bSumPdf = 0.0f; if (aSumPdf < 0.0f) { // this entry was already accounted for! // just revert it back (*it).second.mSumPdf = -aSumPdf; } else { PvsData *data = b.Find((*it).first); if (data) { bSumPdf = data->mSumPdf; } #if 0 float diff = bSumPdf - aSumPdf; if (diff > 0.0f) { pvsEnlargement += diff; } else { pvsReduction += -diff; } #else if (!data) pvsReduction += 1.0f; #endif } } } template int Pvs::Diff(const Pvs &b) { int dif = 0; std::map, LtSample >::const_iterator it; for (it = b.mEntries.begin(); it != b.mEntries.end(); ++ it) { PvsData *data = Find((*it).first); if (!data) ++ dif; } return dif; } template void Pvs::Merge(const Pvs &a) { std::map, LtSample >::const_iterator it; for (it = a.mEntries.begin(); it != a.mEntries.end(); ++ it) { PvsData *data = Find((*it).first); if (data) data->mSumPdf += (*it).second.mSumPdf; else mEntries.insert(*it); } } template void Pvs::Clear() { mEntries.clear(); } template PvsData *Pvs::Find(T sample) { std::map, LtSample >::iterator i = mEntries.find(sample); if (i != mEntries.end()) { return &(*i).second; } else return NULL; } template void Pvs::GetData(const int index, T &entry, PvsData &data) { std::map, LtSample >::iterator i = mEntries.begin(); for (int k = 0; k != index && i != mEntries.end(); i++, k++); entry = (*i).first; data = (*i).second; } template float Pvs::AddSample(T sample, const float pdf) { PvsData *data = Find(sample); if (data) { data->mSumPdf += pdf; return data->mSumPdf; } else { mEntries[sample] = PvsData(pdf); return pdf; } } template bool Pvs::AddSample(T sample, const float pdf, float &contribution) { PvsData *data = Find(sample); if (data) { data->mSumPdf += pdf; contribution = pdf/data->mSumPdf; return false; } else { mEntries[sample] = PvsData(pdf); contribution = 1.0f; return true; } } template bool Pvs::GetSampleContribution(T sample, const float pdf, float &contribution) { PvsData *data = Find(sample); if (data) { contribution = pdf/(data->mSumPdf + pdf); return false; } else { contribution = 1.0f; return true; } } template bool Pvs::RemoveSample(T sample, const float pdf) { std::map, LtSample >:: iterator it = mEntries.find(sample); if (it == mEntries.end()) return false; PvsData *data = &(*it).second; data->mSumPdf -= pdf; if (data->mSumPdf <= 0.0f) mEntries.erase(it); return true; } template int Pvs::AddPvs(const Pvs &pvs) { std::map, LtSample >:: const_iterator it, it_end = pvs.mEntries.end(); float contri; // output PVS of view cell for (it = pvs.mEntries.begin(); it != it_end; ++ it) AddSample((*it).first, (*it).second.mSumPdf, contri); return GetSize(); } template int Pvs::SubtractPvs(const Pvs &pvs) { std::map, LtSample >:: const_iterator it, it_end = pvs.mEntries.end(); // output PVS of view cell for (it = pvs.mEntries.begin(); it != it_end; ++ it) RemoveSample((*it).first, (*it).second.mSumPdf); return GetSize(); } template void Pvs::CollectEntries(std::vector &entries) { std::map, LtSample >:: const_iterator it, it_end = mEntries.end(); // output PVS of view cell for (it = mEntries.begin(); it != it_end; ++ it) entries.push_back((*it)->first); } template void Pvs::NormalizeMaximum() { std::map, LtSample >:: const_iterator it, it_end = mEntries.end(); float maxPdfSum = -1.0f; // output PVS of view cell for (it = mEntries.begin(); it != it_end; ++ it) { float sum = (*it)->second.sumPdf; if (sum > maxSum) maxSum = sum; } maxSum = 1.0f/maxSum; for (it = mEntries.begin(); it != it_end; ++ it) { (*it)->second.sumPdf *= maxSum; } } /** Class instantiating the Pvs template for kd tree nodes. */ class KdPvs: public Pvs { int Compress(); }; //-- typedefs typedef std::map, LtSample > KdPvsMap; typedef std::map, LtSample > ObjectPvsMap; typedef std::map, LtSample > ViewCellPvsMap; typedef PvsData ObjectPvsData; typedef PvsData KdPvsData; typedef Pvs ObjectPvs; typedef Pvs ViewCellPvs; } #endif