[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 |
|
---|
| 8 |
|
---|
| 9 | SampleGenerator::SampleGenerator(int numSamples, float radius):
|
---|
| 10 | mNumSamples(numSamples), mRadius(radius)
|
---|
[3230] | 11 | {
|
---|
| 12 | mHalton = new HaltonSequence(2);
|
---|
| 13 | }
|
---|
[2853] | 14 |
|
---|
| 15 |
|
---|
[3230] | 16 | SampleGenerator::~SampleGenerator()
|
---|
| 17 | {
|
---|
| 18 | DEL_PTR(mHalton);
|
---|
| 19 | }
|
---|
| 20 |
|
---|
| 21 |
|
---|
[3227] | 22 | PoissonDiscSampleGenerator2D::PoissonDiscSampleGenerator2D(int numSamples, float radius):
|
---|
[3230] | 23 | SampleGenerator(numSamples, radius)
|
---|
[2853] | 24 | {}
|
---|
| 25 |
|
---|
| 26 |
|
---|
[3227] | 27 | void PoissonDiscSampleGenerator2D::Generate(float *samples) const
|
---|
[2853] | 28 | {
|
---|
[3233] | 29 | // Poisson disc sampling generator using relaxation
|
---|
| 30 | // dart-throwing as proposed by McCool et al.
|
---|
| 31 | // the min distance requirement is relaxed if we are not
|
---|
[2930] | 32 | // able to place any dart for a number of tries
|
---|
[3233] | 33 | // the solution is a possion sampling with respect
|
---|
| 34 | // to the adjusted min distance
|
---|
| 35 | // this sampling scheme has the benefit that it is hierarchical
|
---|
| 36 | int maxTries = 1000;
|
---|
[3234] | 37 | const float f_reduction = 0.95f;
|
---|
[3233] | 38 |
|
---|
[2853] | 39 | float r[2];
|
---|
| 40 |
|
---|
[3234] | 41 | // the maximal possible radius: our radius is a fraction of this radius
|
---|
| 42 | // this is used as a measure of the quality of distribution of the point samples
|
---|
[3343] | 43 | //const float rmax = 2.0f * mRadius * sqrt(1.0f / (2.0f * sqrt(3.0f) * mNumSamples));
|
---|
| 44 | float rmax = 0.5f; //mRadius * sqrt(1.0f / (2.0f * sqrt(3.0f) * mNumSamples));
|
---|
[3234] | 45 |
|
---|
[2853] | 46 | // generates poisson distribution on disc
|
---|
[3234] | 47 | // start with some thresholds: all samples lie on the circumference of circle
|
---|
[3233] | 48 |
|
---|
[3343] | 49 | //float minDist = 2.0f * rmax;
|
---|
| 50 | float minDist = rmax;
|
---|
[2930] | 51 | float sqrMinDist = minDist * minDist;
|
---|
[2853] | 52 |
|
---|
[3234] | 53 | int tries = 0;
|
---|
| 54 |
|
---|
[3343] | 55 | //cout << "minDist before= " << minDist / rmax << endl;
|
---|
| 56 | cout << "minDist before= " << rmax << endl;
|
---|
| 57 |
|
---|
[2900] | 58 | Sample2 *s = (Sample2 *)samples;
|
---|
[2853] | 59 |
|
---|
[2930] | 60 | // check if on disc
|
---|
[2853] | 61 | for (int i = 0; i < mNumSamples; ++ i)
|
---|
| 62 | {
|
---|
| 63 | // repeat until valid sample was found
|
---|
| 64 | while (1)
|
---|
| 65 | {
|
---|
[3234] | 66 | // q: should we use halton or does it conflict with the poisson disc properties?
|
---|
[3355] | 67 | //r[0] = RandomValue(0, 1); r[1] = RandomValue(0, 1);
|
---|
| 68 | mHalton->GetNext(r);
|
---|
[2853] | 69 |
|
---|
[3338] | 70 | #if 0
|
---|
[2930] | 71 | // scale to -1 .. 1
|
---|
[2853] | 72 | const float rx = r[0] * 2.0f - 1.0f;
|
---|
| 73 | const float ry = r[1] * 2.0f - 1.0f;
|
---|
| 74 |
|
---|
| 75 | // check if in disk, else exit early
|
---|
[3103] | 76 | const float distanceSquared = rx * rx + ry * ry;
|
---|
[3338] | 77 | if (rx * rx + ry * ry > mRadius * mRadius)
|
---|
| 78 | // also avoid case that sample exactly in center
|
---|
[3227] | 79 | //|| (distanceSquared <= 1e-3f)
|
---|
[3338] | 80 | {
|
---|
[2853] | 81 | continue;
|
---|
[3338] | 82 | }
|
---|
| 83 | #else
|
---|
| 84 | const float rx = r[0];
|
---|
| 85 | const float ry = r[1];
|
---|
| 86 | #endif
|
---|
[2853] | 87 |
|
---|
| 88 | bool sampleValid = true;
|
---|
| 89 |
|
---|
| 90 | // check poisson property
|
---|
| 91 | for (int j = 0; ((j < i) && sampleValid); ++ j)
|
---|
| 92 | {
|
---|
| 93 | const float dist =
|
---|
[2930] | 94 | (s[j].x - rx) * (s[j].x - rx) +
|
---|
| 95 | (s[j].y - ry) * (s[j].y - ry);
|
---|
[2853] | 96 |
|
---|
[3339] | 97 | if (dist < sqrMinDist) sampleValid = false;
|
---|
[2853] | 98 | }
|
---|
| 99 |
|
---|
| 100 | if (sampleValid)
|
---|
| 101 | {
|
---|
[2900] | 102 | s[i].x = rx;
|
---|
| 103 | s[i].y = ry;
|
---|
[2853] | 104 | break;
|
---|
| 105 | }
|
---|
| 106 |
|
---|
[3234] | 107 | ++ tries;
|
---|
| 108 |
|
---|
[2873] | 109 | if (tries > maxTries)
|
---|
[2853] | 110 | {
|
---|
[3234] | 111 | minDist *= f_reduction;
|
---|
| 112 | sqrMinDist = minDist * minDist;
|
---|
| 113 |
|
---|
| 114 | maxTries += 1000;
|
---|
[2853] | 115 | }
|
---|
| 116 | }
|
---|
| 117 | }
|
---|
| 118 |
|
---|
[3338] | 119 | for (int i = 0; i < mNumSamples; ++ i)
|
---|
| 120 | {
|
---|
| 121 | const float a = 2.0f * M_PI * s[i].x;
|
---|
| 122 | const float r = sqrt(s[i].y);
|
---|
| 123 |
|
---|
| 124 | const float rad = mRadius * r;
|
---|
| 125 |
|
---|
| 126 | s[i].x = rad * cos(a);
|
---|
| 127 | s[i].y = rad * sin(a);
|
---|
| 128 | }
|
---|
| 129 |
|
---|
[3343] | 130 | rmax = mRadius * sqrt(1.0f / (2.0f * sqrt(3.0f) * mNumSamples));
|
---|
| 131 | cout << "minDist after= " << (float)minDist * mNumSamples << " #tries: " << tries << " samples: " << mNumSamples << endl;
|
---|
| 132 | cout << "minDist after= " << (float)minDist / rmax << " #tries: " << tries << endl;
|
---|
[2898] | 133 | }
|
---|
| 134 |
|
---|
| 135 |
|
---|
[3227] | 136 | RandomSampleGenerator2D::RandomSampleGenerator2D(int numSamples, float radius):
|
---|
[3230] | 137 | SampleGenerator(numSamples, radius)
|
---|
[2898] | 138 | {}
|
---|
| 139 |
|
---|
| 140 |
|
---|
[3322] | 141 | #if 0
|
---|
[3227] | 142 | void RandomSampleGenerator2D::Generate(float *samples) const
|
---|
[2898] | 143 | {
|
---|
[2900] | 144 | Sample2 *s = (Sample2 *)samples;
|
---|
| 145 |
|
---|
[2903] | 146 | int numSamples = 0;
|
---|
[2898] | 147 |
|
---|
[2930] | 148 | float r[2];
|
---|
| 149 |
|
---|
[2903] | 150 | while (numSamples < mNumSamples)
|
---|
[2898] | 151 | {
|
---|
[3230] | 152 | mHalton->GetNext(r);
|
---|
[2930] | 153 |
|
---|
| 154 | const float rx = r[0] * 2.0f - 1.0f;
|
---|
| 155 | const float ry = r[1] * 2.0f - 1.0f;
|
---|
[2898] | 156 |
|
---|
[2903] | 157 | // check if in disk, else exit early
|
---|
| 158 | if (rx * rx + ry * ry > mRadius * mRadius)
|
---|
| 159 | continue;
|
---|
[2898] | 160 |
|
---|
[2903] | 161 | s[numSamples].x = rx;
|
---|
| 162 | s[numSamples].y = ry;
|
---|
[2898] | 163 |
|
---|
[2903] | 164 | ++ numSamples;
|
---|
| 165 | }
|
---|
[2899] | 166 | }
|
---|
| 167 |
|
---|
[3322] | 168 | #else
|
---|
[2899] | 169 |
|
---|
[3322] | 170 | void RandomSampleGenerator2D::Generate(float *samples) const
|
---|
| 171 | {
|
---|
| 172 | Sample2 *s = (Sample2 *)samples;
|
---|
| 173 |
|
---|
| 174 | int numSamples = 0;
|
---|
| 175 | float x[2];
|
---|
| 176 |
|
---|
| 177 | static float total1 = 0;
|
---|
| 178 | static float total2 = 0;
|
---|
| 179 | static int totalSamples = 0;
|
---|
| 180 |
|
---|
| 181 | for (int i = 0; i < mNumSamples; ++ i)
|
---|
| 182 | {
|
---|
[3371] | 183 | //x[0] = RandomValue(0, 1); x[1] = RandomValue(0, 1);
|
---|
| 184 | mHalton->GetNext(x);
|
---|
[3322] | 185 |
|
---|
| 186 | const float a = 2.0f * M_PI * x[0];
|
---|
| 187 | const float r = mRadius * sqrt(x[1]);
|
---|
| 188 |
|
---|
| 189 | s[i].x = r * cos(a);
|
---|
| 190 | s[i].y = r * sin(a);
|
---|
| 191 |
|
---|
[3323] | 192 | /*total1 += x[0];
|
---|
[3322] | 193 | total2 += x[1];
|
---|
| 194 | totalSamples ++;
|
---|
| 195 |
|
---|
| 196 | if (totalSamples % 1000 == 1)
|
---|
| 197 | {
|
---|
| 198 | float n1 = (float)total1 / totalSamples;
|
---|
| 199 | float n2 = (float)total2 / totalSamples;
|
---|
| 200 |
|
---|
| 201 | cout << "here3 " << n1 << " " << n2 << endl;
|
---|
[3323] | 202 | }*/
|
---|
[3322] | 203 | }
|
---|
| 204 | }
|
---|
| 205 |
|
---|
| 206 | #endif
|
---|
| 207 |
|
---|
[3227] | 208 | SphericalSampleGenerator3D::SphericalSampleGenerator3D(int numSamples, float radius):
|
---|
[2899] | 209 | SampleGenerator(numSamples, radius)
|
---|
| 210 | {}
|
---|
| 211 |
|
---|
| 212 |
|
---|
[3227] | 213 | void SphericalSampleGenerator3D::Generate(float *samples) const
|
---|
[2899] | 214 | {
|
---|
| 215 | float r[2];
|
---|
[2900] | 216 | Sample3 *s = (Sample3 *)samples;
|
---|
| 217 |
|
---|
[2899] | 218 | for (int i = 0; i < mNumSamples; ++ i)
|
---|
| 219 | {
|
---|
[2903] | 220 | r[0] = RandomValue(0, 1);
|
---|
| 221 | r[1] = RandomValue(0, 1);
|
---|
[2930] | 222 |
|
---|
[2900] | 223 | const float theta = 2.0f * acos(sqrt(1.0f - r[0]));
|
---|
| 224 | const float phi = 2.0f * M_PI * r[1];
|
---|
[2901] | 225 |
|
---|
| 226 | s[i].x = mRadius * sin(theta) * cos(phi);
|
---|
| 227 | s[i].y = mRadius * sin(theta) * sin(phi);
|
---|
| 228 | s[i].z = mRadius * cos(theta);
|
---|
| 229 | }
|
---|
[2930] | 230 | }
|
---|
[2899] | 231 |
|
---|
[2930] | 232 |
|
---|
[3343] | 233 | QuadraticDiscSampleGenerator2D::QuadraticDiscSampleGenerator2D(int numSamples,
|
---|
| 234 | float radius):
|
---|
[3313] | 235 | //PoissonDiscSampleGenerator2D(numSamples, radius)
|
---|
| 236 | RandomSampleGenerator2D(numSamples, radius)
|
---|
[3343] | 237 | {
|
---|
| 238 | }
|
---|
[2930] | 239 |
|
---|
| 240 |
|
---|
[3227] | 241 | void QuadraticDiscSampleGenerator2D::Generate(float *samples) const
|
---|
[2930] | 242 | {
|
---|
| 243 | Sample2 *s = (Sample2 *)samples;
|
---|
| 244 |
|
---|
[3329] | 245 | int numSamples = 0;
|
---|
| 246 | float x[2];
|
---|
[2930] | 247 |
|
---|
[2954] | 248 | for (int i = 0; i < mNumSamples; ++ i)
|
---|
| 249 | {
|
---|
[3372] | 250 | //x[0] = RandomValue(0, 1); x[1] = RandomValue(0, 1);
|
---|
| 251 | mHalton->GetNext(x);
|
---|
[3329] | 252 |
|
---|
| 253 | const float a = 2.0f * M_PI * x[0];
|
---|
| 254 | const float r = sqrt(x[1]);
|
---|
[3372] | 255 |
|
---|
| 256 | const float rad = mRadius * r;
|
---|
[2954] | 257 |
|
---|
[3329] | 258 | s[i].x = rad * cos(a);
|
---|
| 259 | s[i].y = rad * sin(a);
|
---|
[2930] | 260 | }
|
---|
[2853] | 261 | } |
---|