#ifndef __PVS_H #define __PVS_H #include #include #include "common.h" 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. */ class PvsData { public: // 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; } }; class MailablePvsData { //////////////////////////// // Mailing stuff protected: int mMailbox; public: // last mail id -> warning not thread safe! // both mailId and mailbox should be unique for each thread!!! static int sMailId; static int sReservedMailboxes; static void NewMail(const int reserve = 1) { sMailId += sReservedMailboxes; sReservedMailboxes = reserve; } void Mail() { mMailbox = sMailId; } bool Mailed() const { return mMailbox == sMailId; } void Mail(const int mailbox) { mMailbox = sMailId + mailbox; } bool Mailed(const int mailbox) const { return mMailbox == sMailId + mailbox; } int IncMail() { return ++ mMailbox - sMailId; } ////////////////////////////////////////// // sum of probability density of visible sample rays float mSumPdf; int mCounter; MailablePvsData() {} MailablePvsData(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() {} //virtual ~Pvs(); /** 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. */ S *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 sample to PVS. @returns PvsData */ S *AddSample2(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, S &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 > 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 >::iterator it; for (it = b.mEntries.begin(); it != b.mEntries.end(); ++ it) { float bSumPdf = (*it).second.mSumPdf; float aSumPdf = 0.0f; S *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 { S *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 >::const_iterator it; for (it = b.mEntries.begin(); it != b.mEntries.end(); ++ it) { S data = Find((*it).first); if (!data) ++ dif; } return dif; } template void Pvs::Merge(const Pvs &a) { std::map >::const_iterator it; for (it = a.mEntries.begin(); it != a.mEntries.end(); ++ it) { AddSample((*it).first, (*it).second.mSumPdf); } } template void Pvs::Clear() { mEntries.clear(); } template S *Pvs::Find(T sample) { std::map >::iterator i = mEntries.find(sample); if (i != mEntries.end()) { return &(*i).second; } else { return NULL; } } template void Pvs::GetData(const int index, T &entry, S &data) { std::map >::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) { S *data = Find(sample); if (data) { data->mSumPdf += pdf; return data->mSumPdf; } else { mEntries[sample] = S(pdf); return pdf; } } template S * Pvs::AddSample2(T sample, const float pdf) { S *data = Find(sample); if (data) { data->mSumPdf += pdf; } else { mEntries[sample] = S(pdf); data = Find(sample); } return data; } template bool Pvs::AddSample(T sample, const float pdf, float &contribution) { S *data = Find(sample); if (data) { data->mSumPdf += pdf; contribution = pdf / data->mSumPdf; return false; } else { mEntries[sample] = S(pdf); contribution = 1.0f; return true; } } template bool Pvs::GetSampleContribution(T sample, const float pdf, float &contribution) { S *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 >:: iterator it = mEntries.find(sample); if (it == mEntries.end()) return false; S *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 >:: 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 >:: 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 >:: 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 >:: 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 { public: int Compress(); }; class ObjectPvs: public Pvs { public: /** Counts object int the pvs. Different to method "GetSize", not only the raw container size is returned, but the individual contributions of the entries are summed up. */ int CountObjectsInPvs() const; }; //////////// //-- typedefs typedef std::map > KdPvsMap; typedef std::map > ObjectPvsMap; typedef std::map > ViewCellPvsMap; typedef Pvs ViewCellPvs; } #endif