Nori
|
00001 /* 00002 This file is part of Nori, a simple educational ray tracer 00003 00004 Copyright (c) 2012 by Wenzel Jakob and Steve Marschner. 00005 00006 Nori is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License Version 3 00008 as published by the Free Software Foundation. 00009 00010 Nori is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 #if !defined(__DISCRETE_PDF_H) 00020 #define __DISCRETE_PDF_H 00021 00022 #include <nori/common.h> 00023 00024 NORI_NAMESPACE_BEGIN 00025 00026 /** 00027 * \brief Discrete probability distribution 00028 * 00029 * This data structure can be used to transform uniformly distributed 00030 * samples to a stored discrete probability distribution. 00031 * 00032 * \ingroup libcore 00033 */ 00034 struct DiscretePDF { 00035 public: 00036 /// Allocate memory for a distribution with the given number of entries 00037 explicit inline DiscretePDF(size_t nEntries = 0) { 00038 reserve(nEntries); 00039 clear(); 00040 } 00041 00042 /// Clear all entries 00043 inline void clear() { 00044 m_cdf.clear(); 00045 m_cdf.push_back(0.0f); 00046 m_normalized = false; 00047 } 00048 00049 /// Reserve memory for a certain number of entries 00050 inline void reserve(size_t nEntries) { 00051 m_cdf.reserve(nEntries+1); 00052 } 00053 00054 /// Append an entry with the specified discrete probability 00055 inline void append(float pdfValue) { 00056 m_cdf.push_back(m_cdf[m_cdf.size()-1] + pdfValue); 00057 } 00058 00059 /// Return the number of entries so far 00060 inline size_t size() const { 00061 return m_cdf.size()-1; 00062 } 00063 00064 /// Access an entry by its index 00065 inline float operator[](size_t entry) const { 00066 return m_cdf[entry+1] - m_cdf[entry]; 00067 } 00068 00069 /// Have the probability densities been normalized? 00070 inline bool isNormalized() const { 00071 return m_normalized; 00072 } 00073 00074 /** 00075 * \brief Return the original (unnormalized) sum of all PDF entries 00076 * 00077 * This assumes that \ref normalize() has previously been called 00078 */ 00079 inline float getSum() const { 00080 return m_sum; 00081 } 00082 00083 /** 00084 * \brief Return the normalization factor (i.e. the inverse of \ref getSum()) 00085 * 00086 * This assumes that \ref normalize() has previously been called 00087 */ 00088 inline float getNormalization() const { 00089 return m_normalization; 00090 } 00091 00092 /** 00093 * \brief Normalize the distribution 00094 * 00095 * \return Sum of the (previously unnormalized) entries 00096 */ 00097 inline float normalize() { 00098 m_sum = m_cdf[m_cdf.size()-1]; 00099 if (m_sum > 0) { 00100 m_normalization = 1.0f / m_sum; 00101 for (size_t i=1; i<m_cdf.size(); ++i) 00102 m_cdf[i] *= m_normalization; 00103 m_cdf[m_cdf.size()-1] = 1.0f; 00104 m_normalized = true; 00105 } else { 00106 m_normalization = 0.0f; 00107 } 00108 return m_sum; 00109 } 00110 00111 /** 00112 * \brief %Transform a uniformly distributed sample to the stored distribution 00113 * 00114 * \param[in] sampleValue 00115 * An uniformly distributed sample on [0,1] 00116 * \return 00117 * The discrete index associated with the sample 00118 */ 00119 inline size_t sample(float sampleValue) const { 00120 std::vector<float>::const_iterator entry = 00121 std::lower_bound(m_cdf.begin(), m_cdf.end(), sampleValue); 00122 size_t index = (size_t) std::max((ptrdiff_t) 0, entry - m_cdf.begin() - 1); 00123 return std::min(index, m_cdf.size()-2); 00124 } 00125 00126 /** 00127 * \brief %Transform a uniformly distributed sample to the stored distribution 00128 * 00129 * \param[in] sampleValue 00130 * An uniformly distributed sample on [0,1] 00131 * \param[out] pdf 00132 * Probability value of the sample 00133 * \return 00134 * The discrete index associated with the sample 00135 */ 00136 inline size_t sample(float sampleValue, float &pdf) const { 00137 size_t index = sample(sampleValue); 00138 pdf = operator[](index); 00139 return index; 00140 } 00141 00142 /** 00143 * \brief %Transform a uniformly distributed sample to the stored distribution 00144 * 00145 * The original sample is value adjusted so that it can be "reused". 00146 * 00147 * \param[in, out] sampleValue 00148 * An uniformly distributed sample on [0,1] 00149 * \return 00150 * The discrete index associated with the sample 00151 */ 00152 inline size_t sampleReuse(float &sampleValue) const { 00153 size_t index = sample(sampleValue); 00154 sampleValue = (sampleValue - m_cdf[index]) 00155 / (m_cdf[index + 1] - m_cdf[index]); 00156 return index; 00157 } 00158 00159 /** 00160 * \brief %Transform a uniformly distributed sample. 00161 * 00162 * The original sample is value adjusted so that it can be "reused". 00163 * 00164 * \param[in,out] 00165 * An uniformly distributed sample on [0,1] 00166 * \param[out] pdf 00167 * Probability value of the sample 00168 * \return 00169 * The discrete index associated with the sample 00170 */ 00171 inline size_t sampleReuse(float &sampleValue, float &pdf) const { 00172 size_t index = sample(sampleValue, pdf); 00173 sampleValue = (sampleValue - m_cdf[index]) 00174 / (m_cdf[index + 1] - m_cdf[index]); 00175 return index; 00176 } 00177 00178 /** 00179 * \brief Turn the underlying distribution into a 00180 * human-readable string format 00181 */ 00182 QString toString() const { 00183 QString result = QString("DiscretePDF[sum=%1, " 00184 "normalized=%2, pdf = {").arg(m_sum).arg(m_normalized); 00185 00186 for (size_t i=0; i<m_cdf.size(); ++i) { 00187 result += QString("%1").arg(operator[](i)); 00188 if (i != m_cdf.size()-1) 00189 result += QString(", "); 00190 } 00191 return result + QString("}]"); 00192 } 00193 private: 00194 std::vector<float> m_cdf; 00195 float m_sum, m_normalization; 00196 bool m_normalized; 00197 }; 00198 00199 NORI_NAMESPACE_END 00200 00201 #endif /* __DISCRETE_PDF_H */