#include "SampleGenerator.h" #include "common.h" using namespace std; using namespace CHCDemoEngine; //HaltonSequence PoissonDiscSampleGenerator2D::sHalton(2); //HaltonSequence RandomSampleGenerator2D::sHalton(2); //HaltonSequence QuadraticDiscSampleGenerator2D::sHalton(2); SampleGenerator::SampleGenerator(int numSamples, float radius): mNumSamples(numSamples), mRadius(radius) {} PoissonDiscSampleGenerator2D::PoissonDiscSampleGenerator2D(int numSamples, float radius): SampleGenerator(numSamples, radius), sHalton(HaltonSequence(2)) {} void PoissonDiscSampleGenerator2D::Generate(float *samples) const { // this is a hacky poisson sampling generator which does random dart-throwing on a disc. // as a savety criterium, the min distance requirement is relaxed if we are not // able to place any dart for a number of tries // the solution is a possion sampling with respect to the adjusted min distance // better solutions have been proposed, i.e., using hierarchical sampling const int maxTries = 1000; const float f_reduction = 0.9f; float r[2]; // generates poisson distribution on disc // start with some threshold. best case: all samples lie on the circumference //const float minDist = 2.0f * mRadius / sqrt((float)mNumSamples); const float eps = 0.2f; const float minDist = 2.0f * mRadius * M_PI * (1.0f - eps) / (float)mNumSamples; float sqrMinDist = minDist * minDist; //cout << "minDist before= " << minDist << endl; Sample2 *s = (Sample2 *)samples; int totalTries = 0; // check if on disc for (int i = 0; i < mNumSamples; ++ i) { int tries = 0; // repeat until valid sample was found while (1) { ++ tries; ++ totalTries; // note: should use halton, but seems somewhat broken sHalton.GetNext(r); // scale to -1 .. 1 const float rx = r[0] * 2.0f - 1.0f; const float ry = r[1] * 2.0f - 1.0f; // check if in disk, else exit early const float distanceSquared = rx * rx + ry * ry; if ((rx * rx + ry * ry > mRadius * mRadius) // also avoid case that sample exactly in center //|| (distanceSquared <= 1e-3f) ) continue; bool sampleValid = true; // check poisson property for (int j = 0; ((j < i) && sampleValid); ++ j) { const float dist = (s[j].x - rx) * (s[j].x - rx) + (s[j].y - ry) * (s[j].y - ry); if (dist < sqrMinDist) sampleValid = false; } if (sampleValid) { s[i].x = rx; s[i].y = ry; break; } if (tries > maxTries) { sqrMinDist *= f_reduction; tries = 0; } } } //cout << "minDist after= " << sqrt(sqrMinDist) << " #tries: " << totalTries << endl; } RandomSampleGenerator2D::RandomSampleGenerator2D(int numSamples, float radius): SampleGenerator(numSamples, radius), sHalton(HaltonSequence(2)) {} void RandomSampleGenerator2D::Generate(float *samples) const { Sample2 *s = (Sample2 *)samples; int numSamples = 0; float r[2]; while (numSamples < mNumSamples) { sHalton.GetNext(r); const float rx = r[0] * 2.0f - 1.0f; const float ry = r[1] * 2.0f - 1.0f; // check if in disk, else exit early if (rx * rx + ry * ry > mRadius * mRadius) continue; s[numSamples].x = rx; s[numSamples].y = ry; ++ numSamples; } } SphericalSampleGenerator3D::SphericalSampleGenerator3D(int numSamples, float radius): SampleGenerator(numSamples, radius) {} void SphericalSampleGenerator3D::Generate(float *samples) const { float r[2]; Sample3 *s = (Sample3 *)samples; for (int i = 0; i < mNumSamples; ++ i) { r[0] = RandomValue(0, 1); r[1] = RandomValue(0, 1); // create stratified samples over sphere const float theta = 2.0f * acos(sqrt(1.0f - r[0])); const float phi = 2.0f * M_PI * r[1]; s[i].x = mRadius * sin(theta) * cos(phi); s[i].y = mRadius * sin(theta) * sin(phi); s[i].z = mRadius * cos(theta); } } QuadraticDiscSampleGenerator2D::QuadraticDiscSampleGenerator2D(int numSamples, float radius): PoissonDiscSampleGenerator2D(numSamples, radius) //SampleGenerator(numSamples, radius), //sHalton(HaltonSequence(2)), //mPoisson(PoissonDiscSampleGenerator2D(numSamples, radius)) {} void QuadraticDiscSampleGenerator2D::Generate(float *samples) const { #if 0 float r[2]; Sample2 *s = (Sample2 *)samples; for (int i = 0; i < mNumSamples; ++ i) { sHalton.GetNext(r); // create samples over disc: the sample density // decreases quadratically with the distance to the origin s[i].x = mRadius * r[1] * sin(2.0f * M_PI * r[0]); s[i].y = mRadius * r[1] * cos(2.0f * M_PI * r[0]); } #else //static PoissonDiscSampleGenerator2D poisson(mNumSamples, 1.0f); //poisson.Generate(samples); PoissonDiscSampleGenerator2D::Generate(samples); Sample2 *s = (Sample2 *)samples; // multiply with lenght to get quadratic dependence on the distance for (int i = 0; i < mNumSamples; ++ i) { Sample2 &spl = s[i]; float len = sqrt(spl.x * spl.x + spl.y * spl.y); spl.x *= len * mRadius; spl.y *= len * mRadius; } #endif }