source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/SampleGenerator.cpp @ 2955

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