202 lines
5.8 KiB
C++
202 lines
5.8 KiB
C++
|
#include <mitsuba/render/sampler.h>
|
||
|
|
||
|
MTS_NAMESPACE_BEGIN
|
||
|
|
||
|
/**
|
||
|
* Adapted version of the low discrepancy sampler in PBRT.
|
||
|
* Provides samples up to a specified depth, after which independent
|
||
|
* sampling takes over.
|
||
|
*/
|
||
|
class LowDiscrepancySampler : public Sampler {
|
||
|
public:
|
||
|
LowDiscrepancySampler() : Sampler(Properties()) {
|
||
|
}
|
||
|
|
||
|
LowDiscrepancySampler(Stream *stream, InstanceManager *manager)
|
||
|
: Sampler(stream, manager) {
|
||
|
m_depth = stream->readInt();
|
||
|
m_random = static_cast<Random *>(manager->getInstance(stream));
|
||
|
|
||
|
m_samples1D = new Float*[m_depth];
|
||
|
m_samples2D = new Point2*[m_depth];
|
||
|
for (int i=0; i<m_depth; i++) {
|
||
|
m_samples1D[i] = new Float[(size_t) m_sampleCount];
|
||
|
m_samples2D[i] = new Point2[(size_t) m_sampleCount];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LowDiscrepancySampler(const Properties &props) : Sampler(props) {
|
||
|
/* Number of samples per pixel when used with a sampling-based integrator */
|
||
|
m_sampleCount = (uint64_t) props.getLong("sampleCount", 4);
|
||
|
|
||
|
/* Depth, up to which which low discrepancy samples are guaranteed to be available. */
|
||
|
m_depth = props.getInteger("depth", 3);
|
||
|
|
||
|
if (!isPowerOfTwo((int) m_sampleCount)) {
|
||
|
m_sampleCount = roundToPowerOfTwo((int) m_sampleCount);
|
||
|
Log(EWarn, "Sample count should be a power of two - rounding to %i", m_sampleCount);
|
||
|
}
|
||
|
|
||
|
m_samples1D = new Float*[m_depth];
|
||
|
m_samples2D = new Point2*[m_depth];
|
||
|
|
||
|
for (int i=0; i<m_depth; i++) {
|
||
|
m_samples1D[i] = new Float[(size_t) m_sampleCount];
|
||
|
m_samples2D[i] = new Point2[(size_t) m_sampleCount];
|
||
|
}
|
||
|
|
||
|
m_random = new Random();
|
||
|
}
|
||
|
|
||
|
virtual ~LowDiscrepancySampler() {
|
||
|
for (int i=0; i<m_depth; i++) {
|
||
|
delete[] m_samples1D[i];
|
||
|
delete[] m_samples2D[i];
|
||
|
}
|
||
|
delete[] m_samples1D;
|
||
|
delete[] m_samples2D;
|
||
|
}
|
||
|
|
||
|
void serialize(Stream *stream, InstanceManager *manager) const {
|
||
|
Sampler::serialize(stream, manager);
|
||
|
stream->writeInt(m_depth);
|
||
|
manager->serialize(stream, m_random.get());
|
||
|
}
|
||
|
|
||
|
ref<Sampler> clone() {
|
||
|
ref<LowDiscrepancySampler> sampler = new LowDiscrepancySampler();
|
||
|
|
||
|
sampler->m_sampleCount = m_sampleCount;
|
||
|
sampler->m_depth = m_depth;
|
||
|
sampler->m_random = new Random(m_random);
|
||
|
sampler->m_samples1D = new Float*[m_depth];
|
||
|
sampler->m_samples2D = new Point2*[m_depth];
|
||
|
for (int i=0; i<m_depth; i++) {
|
||
|
sampler->m_samples1D[i] = new Float[(size_t) m_sampleCount];
|
||
|
sampler->m_samples2D[i] = new Point2[(size_t) m_sampleCount];
|
||
|
}
|
||
|
for (size_t i=0; i<m_req1D.size(); ++i)
|
||
|
sampler->request2DArray(m_req1D[i]);
|
||
|
for (size_t i=0; i<m_req2D.size(); ++i)
|
||
|
sampler->request2DArray(m_req2D[i]);
|
||
|
|
||
|
return sampler.get();
|
||
|
}
|
||
|
|
||
|
inline Float vanDerCorput(uint32_t n, uint32_t scramble) {
|
||
|
n = (n << 16) | (n >> 16);
|
||
|
n = ((n & 0x00ff00ff) << 8) | ((n & 0xff00ff00) >> 8);
|
||
|
n = ((n & 0x0f0f0f0f) << 4) | ((n & 0xf0f0f0f0) >> 4);
|
||
|
n = ((n & 0x33333333) << 2) | ((n & 0xcccccccc) >> 2);
|
||
|
n = ((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >> 1);
|
||
|
n ^= scramble;
|
||
|
return (Float) n / (Float) 0x100000000LL;
|
||
|
}
|
||
|
|
||
|
inline Float sobol2(uint32_t n, uint32_t scramble) {
|
||
|
for (uint32_t v = 1 << 31; n != 0; n >>= 1, v ^= v >> 1)
|
||
|
if (n & 0x1) scramble ^= v;
|
||
|
return (Float) scramble / (Float) 0x100000000LL;
|
||
|
}
|
||
|
|
||
|
inline void sample02(uint32_t n, uint32_t scramble[2], Point2 &sample) {
|
||
|
sample.x = vanDerCorput(n, scramble[0]);
|
||
|
sample.y = sobol2(n, scramble[1]);
|
||
|
}
|
||
|
|
||
|
inline void generate1D(Float *samples, unsigned int sampleCount) {
|
||
|
uint32_t scramble = m_random->nextLong() & 0xFFFFFFFF;
|
||
|
for (unsigned int i = 0; i < sampleCount; ++i)
|
||
|
samples[i] = vanDerCorput(i, scramble);
|
||
|
m_random->shuffle(samples, samples + sampleCount);
|
||
|
}
|
||
|
|
||
|
inline void generate2D(Point2 *samples, unsigned int sampleCount) {
|
||
|
union {
|
||
|
uint64_t qword;
|
||
|
uint32_t dword[2];
|
||
|
} scramble;
|
||
|
scramble.qword = m_random->nextLong();
|
||
|
for (unsigned int i = 0; i < sampleCount; ++i)
|
||
|
sample02(i, scramble.dword, samples[i]);
|
||
|
m_random->shuffle(samples, samples + sampleCount);
|
||
|
}
|
||
|
|
||
|
void generate() {
|
||
|
for (int i=0; i<m_depth; ++i) {
|
||
|
generate1D(m_samples1D[i], (unsigned int) m_sampleCount);
|
||
|
generate2D(m_samples2D[i], (unsigned int) m_sampleCount);
|
||
|
}
|
||
|
|
||
|
for (size_t i=0; i<m_req1D.size(); i++)
|
||
|
generate1D(m_sampleArrays1D[i], (unsigned int) m_sampleCount * m_req1D[i]);
|
||
|
|
||
|
for (size_t i=0; i<m_req2D.size(); i++)
|
||
|
generate2D(m_sampleArrays2D[i], (unsigned int) m_sampleCount * m_req2D[i]);
|
||
|
|
||
|
m_sampleIndex = 0;
|
||
|
m_sampleDepth1D = m_sampleDepth2D = 0;
|
||
|
m_sampleDepth1DArray = m_sampleDepth2DArray = 0;
|
||
|
}
|
||
|
|
||
|
void advance() {
|
||
|
m_sampleIndex++;
|
||
|
m_sampleDepth1D = m_sampleDepth2D = 0;
|
||
|
m_sampleDepth1DArray = m_sampleDepth2DArray = 0;
|
||
|
}
|
||
|
|
||
|
void setSampleIndex(uint64_t sampleIndex) {
|
||
|
m_sampleIndex = sampleIndex;
|
||
|
m_sampleDepth1D = m_sampleDepth2D = 0;
|
||
|
m_sampleDepth1DArray = m_sampleDepth2DArray = 0;
|
||
|
}
|
||
|
|
||
|
Float next1D() {
|
||
|
Assert(m_sampleIndex < m_sampleCount);
|
||
|
if (m_sampleDepth1D < m_depth)
|
||
|
return m_samples1D[m_sampleDepth1D++][m_sampleIndex];
|
||
|
else
|
||
|
return m_random->nextFloat();
|
||
|
}
|
||
|
|
||
|
Point2 next2D() {
|
||
|
Assert(m_sampleIndex < m_sampleCount);
|
||
|
if (m_sampleDepth2D < m_depth)
|
||
|
return m_samples2D[m_sampleDepth2D++][m_sampleIndex];
|
||
|
else
|
||
|
return Point2(m_random->nextFloat(), m_random->nextFloat());
|
||
|
}
|
||
|
|
||
|
Float independent1D() {
|
||
|
return m_random->nextFloat();
|
||
|
}
|
||
|
|
||
|
Point2 independent2D() {
|
||
|
return Point2(
|
||
|
m_random->nextFloat(),
|
||
|
m_random->nextFloat()
|
||
|
);
|
||
|
}
|
||
|
|
||
|
std::string toString() const {
|
||
|
std::ostringstream oss;
|
||
|
oss << "LowDiscrepancySampler[" << std::endl
|
||
|
<< " sampleCount = " << m_sampleCount << "," << std::endl
|
||
|
<< " depth = " << m_depth << std::endl
|
||
|
<< "]";
|
||
|
return oss.str();
|
||
|
}
|
||
|
|
||
|
MTS_DECLARE_CLASS()
|
||
|
private:
|
||
|
ref<Random> m_random;
|
||
|
int m_depth;
|
||
|
int m_sampleDepth1D, m_sampleDepth2D;
|
||
|
Float **m_samples1D;
|
||
|
Point2 **m_samples2D;
|
||
|
};
|
||
|
|
||
|
MTS_IMPLEMENT_CLASS_S(LowDiscrepancySampler, false, Sampler)
|
||
|
MTS_EXPORT_PLUGIN(LowDiscrepancySampler, "Low discrepancy sampler");
|
||
|
MTS_NAMESPACE_END
|