1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
#ifndef RANDOM_H
#define RANDOM_H
#include "rand.h"
#include "Runtime/Math/Vector2.h"
#include "Runtime/Math/Quaternion.h"
#include "Runtime/Math/FloatConversion.h"
inline float RangedRandom (Rand& r, float min, float max)
{
float t = r.GetFloat ();
t = min * t + (1.0F - t) * max;
return t;
}
inline float Random01 (Rand& r)
{
return r.GetFloat ();
}
inline int RangedRandom (Rand& r, int min, int max)
{
int dif;
if (min < max)
{
dif = max - min;
int t = r.Get () % dif;
t += min;
return t;
}
else if (min > max)
{
dif = min - max;
int t = r.Get () % dif;
t = min - t;
return t;
}
else
{
return min;
}
}
inline Vector3f RandomUnitVector (Rand& rand)
{
float z = RangedRandom (rand, -1.0f, 1.0f);
float a = RangedRandom (rand, 0.0f, 2.0F * kPI);
float r = sqrt (1.0f - z*z);
float x = r * cos (a);
float y = r * sin (a);
return Vector3f (x, y, z);
}
inline Vector2f RandomUnitVector2 (Rand& rand)
{
float a = RangedRandom (rand, 0.0f, 2.0F * kPI);
float x = cos (a);
float y = sin (a);
return Vector2f (x, y);
}
inline Quaternionf RandomQuaternion (Rand& rand)
{
Quaternionf q;
q.x = RangedRandom (rand, -1.0f, 1.0f);
q.y = RangedRandom (rand, -1.0f, 1.0f);
q.z = RangedRandom (rand, -1.0f, 1.0f);
q.w = RangedRandom (rand, -1.0f, 1.0f);
q = NormalizeSafe (q);
if (Dot (q, Quaternionf::identity ()) < 0.0f)
return -q;
else
return q;
}
inline Quaternionf RandomQuaternionUniformDistribution (Rand& rand)
{
const float two_pi = 2.0F * kPI;
// Employs Hopf fibration to uniformly distribute quaternions
float u1 = RangedRandom( rand, 0.0f, 1.0f );
float theta = RangedRandom( rand, 0.0f, two_pi );
float rho = RangedRandom( rand, 0.0f, two_pi );
float i = sqrt( 1.0f - u1 );
float j = sqrt( u1 );
// We do not need to normalize the generated quaternion, because the probability density corresponds to the Haar measure.
// This means that a random rotation is obtained by picking a point at random on S^3, and forming the unit quaternion.
Quaternionf q( i * sin(theta), i * cos(theta), j * sin(rho), j * cos(rho) );
if (Dot (q, Quaternionf::identity ()) < 0.0f)
return -q;
else
return q;
}
inline Vector3f RandomPointInsideCube (Rand& r, const Vector3f& extents)
{
return Vector3f ( RangedRandom (r, -extents.x, extents.x),
RangedRandom (r, -extents.y, extents.y),
RangedRandom (r, -extents.z, extents.z));
}
inline Vector3f RandomPointBetweenCubes (Rand& r, const Vector3f& min, const Vector3f& max)
{
Vector3f v;
int i;
for (i=0;i<3;i++)
{
float x = r.GetFloat () * 2.0F - 1.0F;
if (x > 0.0f)
v[i] = min[i] + x * (max[i] - min[i]);
else
v[i] = -min[i] + x * (max[i] - min[i]);
}
return v;
}
inline Vector3f RandomPointInsideUnitSphere (Rand& r)
{
Vector3f v = RandomUnitVector (r);
v *= pow (Random01 (r), 1.0F / 3.0F);
return v;
}
inline Vector3f RandomPointInsideEllipsoid (Rand& r, const Vector3f& extents)
{
return Scale (RandomPointInsideUnitSphere (r), extents);
}
inline Vector3f RandomPointBetweenSphere (Rand& r, float minRadius, float maxRadius)
{
Vector3f v = RandomUnitVector (r);
// As the volume of the sphere increases (x^3) over an interval we have to increase range as well with x^(1/3)
float range = pow (RangedRandom (r, 0.0F, 1.0F), 1.0F / 3.0F);
return v * (minRadius + (maxRadius - minRadius) * range);
}
inline Vector2f RandomPointInsideUnitCircle (Rand& r)
{
Vector2f v = RandomUnitVector2 (r);
// As the volume of the sphere increases (x^3) over an interval we have to increase range as well with x^(1/3)
v *= pow (RangedRandom (r, 0.0F, 1.0F), 1.0F / 2.0F);
return v;
}
inline Vector3f RandomPointBetweenEllipsoid (Rand& r, const Vector3f& maxExtents, float minRange)
{
Vector3f v = Scale (RandomUnitVector (r), maxExtents);
// As the volume of the sphere increases (x^3) over an interval we have to increase range as well with x^(1/3)
float range = pow (RangedRandom (r, minRange, 1.0F), 1.0F / 3.0F);
return v * range;
}
/// Builds a random Barycentric coordinate which can be used to generate random points on a triangle:
/// Vector3f point = v0 * barycentric.x + v1 * barycentric.y + v2 * barycentric.z;
inline Vector3f RandomBarycentricCoord (Rand& rand)
{
// Was told that this leads to bad distribution because of the 1.0F - s
// float s = gRand.GetFloat ();
// float t = RangedRandom (gRand, 0.0F, 1.0F - s);
// float r = (1.0F - s - t);
// Vector3f positionOnMesh = r * vertices[face.v1] + s * vertices[face.v2] + t * vertices[face.v3];
// return positionOnMesh;
float u = rand.GetFloat ();
float v = rand.GetFloat ();
if (u + v > 1.0F)
{
u = 1.0F - u;
v = 1.0F - v;
}
float w = 1.0F - u - v;
return Vector3f (u, v, w);
}
#endif
|