[2853] | 1 | #include "SampleGenerator.h"
|
---|
[2903] | 2 | #include "common.h"
|
---|
[2853] | 3 |
|
---|
[2901] | 4 |
|
---|
[2853] | 5 | using namespace std;
|
---|
[2903] | 6 | using namespace CHCDemoEngine;
|
---|
[2853] | 7 |
|
---|
[3229] | 8 | //HaltonSequence PoissonDiscSampleGenerator2D::sHalton(2);
|
---|
| 9 | //HaltonSequence RandomSampleGenerator2D::sHalton(2);
|
---|
| 10 | //HaltonSequence QuadraticDiscSampleGenerator2D::sHalton(2);
|
---|
[2853] | 11 |
|
---|
[2901] | 12 |
|
---|
[2853] | 13 | SampleGenerator::SampleGenerator(int numSamples, float radius):
|
---|
| 14 | mNumSamples(numSamples), mRadius(radius)
|
---|
| 15 | {}
|
---|
| 16 |
|
---|
| 17 |
|
---|
[3227] | 18 | PoissonDiscSampleGenerator2D::PoissonDiscSampleGenerator2D(int numSamples, float radius):
|
---|
[3229] | 19 | SampleGenerator(numSamples, radius), sHalton(HaltonSequence(2))
|
---|
[2853] | 20 | {}
|
---|
| 21 |
|
---|
| 22 |
|
---|
[3227] | 23 | void PoissonDiscSampleGenerator2D::Generate(float *samples) const
|
---|
[2853] | 24 | {
|
---|
[2930] | 25 | // this is a hacky poisson sampling generator which does random dart-throwing on a disc.
|
---|
| 26 | // as a savety criterium, the min distance requirement is relaxed if we are not
|
---|
| 27 | // able to place any dart for a number of tries
|
---|
[2873] | 28 | // the solution is a possion sampling with respect to the adjusted min distance
|
---|
| 29 | // better solutions have been proposed, i.e., using hierarchical sampling
|
---|
[3221] | 30 | const int maxTries = 1000;
|
---|
[2873] | 31 | const float f_reduction = 0.9f;
|
---|
| 32 |
|
---|
[3227] | 33 |
|
---|
[2853] | 34 | float r[2];
|
---|
| 35 |
|
---|
| 36 | // generates poisson distribution on disc
|
---|
[2930] | 37 | // start with some threshold. best case: all samples lie on the circumference
|
---|
| 38 | //const float minDist = 2.0f * mRadius / sqrt((float)mNumSamples);
|
---|
| 39 | const float eps = 0.2f;
|
---|
| 40 | const float minDist = 2.0f * mRadius * M_PI * (1.0f - eps) / (float)mNumSamples;
|
---|
| 41 | float sqrMinDist = minDist * minDist;
|
---|
[2853] | 42 |
|
---|
| 43 | //cout << "minDist before= " << minDist << endl;
|
---|
[2900] | 44 | Sample2 *s = (Sample2 *)samples;
|
---|
[2853] | 45 |
|
---|
[2930] | 46 | int totalTries = 0;
|
---|
| 47 |
|
---|
| 48 | // check if on disc
|
---|
[2853] | 49 | for (int i = 0; i < mNumSamples; ++ i)
|
---|
| 50 | {
|
---|
[2930] | 51 | int tries = 0;
|
---|
[2853] | 52 |
|
---|
| 53 | // repeat until valid sample was found
|
---|
| 54 | while (1)
|
---|
| 55 | {
|
---|
| 56 | ++ tries;
|
---|
| 57 | ++ totalTries;
|
---|
| 58 |
|
---|
[2930] | 59 | // note: should use halton, but seems somewhat broken
|
---|
[3227] | 60 | sHalton.GetNext(r);
|
---|
[2853] | 61 |
|
---|
[2930] | 62 | // scale to -1 .. 1
|
---|
[2853] | 63 | const float rx = r[0] * 2.0f - 1.0f;
|
---|
| 64 | const float ry = r[1] * 2.0f - 1.0f;
|
---|
| 65 |
|
---|
| 66 | // check if in disk, else exit early
|
---|
[3103] | 67 | const float distanceSquared = rx * rx + ry * ry;
|
---|
| 68 |
|
---|
| 69 | if ((rx * rx + ry * ry > mRadius * mRadius)
|
---|
[3162] | 70 | // also avoid case that sample exactly in center
|
---|
[3227] | 71 | //|| (distanceSquared <= 1e-3f)
|
---|
[3103] | 72 | )
|
---|
[2853] | 73 | continue;
|
---|
| 74 |
|
---|
| 75 | bool sampleValid = true;
|
---|
| 76 |
|
---|
| 77 | // check poisson property
|
---|
| 78 | for (int j = 0; ((j < i) && sampleValid); ++ j)
|
---|
| 79 | {
|
---|
| 80 | const float dist =
|
---|
[2930] | 81 | (s[j].x - rx) * (s[j].x - rx) +
|
---|
| 82 | (s[j].y - ry) * (s[j].y - ry);
|
---|
[2853] | 83 |
|
---|
[2930] | 84 | if (dist < sqrMinDist)
|
---|
[2853] | 85 | sampleValid = false;
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | if (sampleValid)
|
---|
| 89 | {
|
---|
[2900] | 90 | s[i].x = rx;
|
---|
| 91 | s[i].y = ry;
|
---|
[2853] | 92 | break;
|
---|
| 93 | }
|
---|
| 94 |
|
---|
[2873] | 95 | if (tries > maxTries)
|
---|
[2853] | 96 | {
|
---|
[2930] | 97 | sqrMinDist *= f_reduction;
|
---|
[2853] | 98 | tries = 0;
|
---|
| 99 | }
|
---|
| 100 | }
|
---|
| 101 | }
|
---|
| 102 |
|
---|
[2930] | 103 | //cout << "minDist after= " << sqrt(sqrMinDist) << " #tries: " << totalTries << endl;
|
---|
[2898] | 104 | }
|
---|
| 105 |
|
---|
| 106 |
|
---|
[3227] | 107 | RandomSampleGenerator2D::RandomSampleGenerator2D(int numSamples, float radius):
|
---|
[3229] | 108 | SampleGenerator(numSamples, radius), sHalton(HaltonSequence(2))
|
---|
[2898] | 109 | {}
|
---|
| 110 |
|
---|
| 111 |
|
---|
[3227] | 112 | void RandomSampleGenerator2D::Generate(float *samples) const
|
---|
[2898] | 113 | {
|
---|
[2900] | 114 | Sample2 *s = (Sample2 *)samples;
|
---|
| 115 |
|
---|
[2903] | 116 | int numSamples = 0;
|
---|
[2898] | 117 |
|
---|
[2930] | 118 | float r[2];
|
---|
| 119 |
|
---|
[2903] | 120 | while (numSamples < mNumSamples)
|
---|
[2898] | 121 | {
|
---|
[3227] | 122 | sHalton.GetNext(r);
|
---|
[2930] | 123 |
|
---|
| 124 | const float rx = r[0] * 2.0f - 1.0f;
|
---|
| 125 | const float ry = r[1] * 2.0f - 1.0f;
|
---|
[2898] | 126 |
|
---|
[2903] | 127 | // check if in disk, else exit early
|
---|
| 128 | if (rx * rx + ry * ry > mRadius * mRadius)
|
---|
| 129 | continue;
|
---|
[2898] | 130 |
|
---|
[2903] | 131 | s[numSamples].x = rx;
|
---|
| 132 | s[numSamples].y = ry;
|
---|
[2898] | 133 |
|
---|
[2903] | 134 | ++ numSamples;
|
---|
| 135 | }
|
---|
[2899] | 136 | }
|
---|
| 137 |
|
---|
| 138 |
|
---|
[3227] | 139 | SphericalSampleGenerator3D::SphericalSampleGenerator3D(int numSamples, float radius):
|
---|
[2899] | 140 | SampleGenerator(numSamples, radius)
|
---|
| 141 | {}
|
---|
| 142 |
|
---|
| 143 |
|
---|
[3227] | 144 | void SphericalSampleGenerator3D::Generate(float *samples) const
|
---|
[2899] | 145 | {
|
---|
| 146 | float r[2];
|
---|
[2900] | 147 | Sample3 *s = (Sample3 *)samples;
|
---|
| 148 |
|
---|
[2899] | 149 | for (int i = 0; i < mNumSamples; ++ i)
|
---|
| 150 | {
|
---|
[2903] | 151 | r[0] = RandomValue(0, 1);
|
---|
| 152 | r[1] = RandomValue(0, 1);
|
---|
[2930] | 153 |
|
---|
[2899] | 154 | // create stratified samples over sphere
|
---|
[2900] | 155 | const float theta = 2.0f * acos(sqrt(1.0f - r[0]));
|
---|
| 156 | const float phi = 2.0f * M_PI * r[1];
|
---|
[2901] | 157 |
|
---|
| 158 | s[i].x = mRadius * sin(theta) * cos(phi);
|
---|
| 159 | s[i].y = mRadius * sin(theta) * sin(phi);
|
---|
| 160 | s[i].z = mRadius * cos(theta);
|
---|
| 161 | }
|
---|
[2930] | 162 | }
|
---|
[2899] | 163 |
|
---|
[2930] | 164 |
|
---|
[3227] | 165 | QuadraticDiscSampleGenerator2D::QuadraticDiscSampleGenerator2D(int numSamples, float radius):
|
---|
[3229] | 166 | PoissonDiscSampleGenerator2D(numSamples, radius)
|
---|
| 167 | //SampleGenerator(numSamples, radius),
|
---|
| 168 | //sHalton(HaltonSequence(2)),
|
---|
| 169 | //mPoisson(PoissonDiscSampleGenerator2D(numSamples, radius))
|
---|
[2930] | 170 | {}
|
---|
| 171 |
|
---|
| 172 |
|
---|
[3227] | 173 | void QuadraticDiscSampleGenerator2D::Generate(float *samples) const
|
---|
[2930] | 174 | {
|
---|
[2954] | 175 | #if 0
|
---|
[2930] | 176 | float r[2];
|
---|
| 177 | Sample2 *s = (Sample2 *)samples;
|
---|
| 178 |
|
---|
| 179 | for (int i = 0; i < mNumSamples; ++ i)
|
---|
| 180 | {
|
---|
[3227] | 181 | sHalton.GetNext(r);
|
---|
[2930] | 182 |
|
---|
| 183 | // create samples over disc: the sample density
|
---|
| 184 | // decreases quadratically with the distance to the origin
|
---|
| 185 | s[i].x = mRadius * r[1] * sin(2.0f * M_PI * r[0]);
|
---|
| 186 | s[i].y = mRadius * r[1] * cos(2.0f * M_PI * r[0]);
|
---|
[2954] | 187 | }
|
---|
| 188 | #else
|
---|
[2930] | 189 |
|
---|
[3229] | 190 | //static PoissonDiscSampleGenerator2D poisson(mNumSamples, 1.0f);
|
---|
| 191 | //poisson.Generate(samples);
|
---|
[2954] | 192 |
|
---|
[3229] | 193 | PoissonDiscSampleGenerator2D::Generate(samples);
|
---|
| 194 |
|
---|
[2954] | 195 | Sample2 *s = (Sample2 *)samples;
|
---|
| 196 |
|
---|
| 197 | // multiply with lenght to get quadratic dependence on the distance
|
---|
| 198 | for (int i = 0; i < mNumSamples; ++ i)
|
---|
| 199 | {
|
---|
[2955] | 200 | Sample2 &spl = s[i];
|
---|
[2954] | 201 |
|
---|
| 202 | float len = sqrt(spl.x * spl.x + spl.y * spl.y);
|
---|
| 203 | spl.x *= len * mRadius;
|
---|
| 204 | spl.y *= len * mRadius;
|
---|
[2930] | 205 | }
|
---|
[2954] | 206 | #endif
|
---|
[2853] | 207 | } |
---|