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

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