1.生成完全随机的方向,先获取随机数,生成球面坐标对应的两个角度
//生成完全随机的且不重复的方向
vector<glm::vec3> Operate::genRandDir(int number) {
vector<glm::vec3> dirs;
//间隔
float thetaInterval = PI / number;
float fiInterval = 2 * PI / number;
//生成伪随机数的种子
srand(time(NULL));
//生成不重复的随机数对
set<vector<int>> s;
pair<set<vector<int>>::iterator, bool> p;
vector<int> v;
for (int i = 0; i < number; i++) {
int m = rand() % (number + 1);
int n = rand() % (number + 1);
v.clear();
v.push_back(m);
v.push_back(n);
p = s.insert(v);
// 插入失败时重新生成随机数
if (!p.second) {
i--;
continue;
}
float theta = m * thetaInterval;
float fi = n * fiInterval;
//生成随机方向
glm::vec3 dir = glm::vec3(sin(theta)*sin(fi), cos(theta), sin(theta)*cos(fi));
dirs.push_back(dir);
}
return dirs;
}
2.生成球面均匀分布的方向,每隔一定角度取一个方向。
//生成均匀分布的方向
vector<glm::vec3> Operate::genAverDir(int number) {
//srand(time(NULL));
float rangeTheta = PI;
vector<glm::vec3> dirs;
//球面坐标系
float thetaInterval = rangeTheta / number;
for (int i = 0; i <= number; i++) {
float theta = i * thetaInterval;
int m = std::max(floor(number * sin(theta)), 1.0f);
float fiInterval = 2 * PI / m;
for (int j = 0; j < m; j++) {
float fi = j * fiInterval;
//对theta和fi加入小随机扰动
theta += theta * parameter.dirBlur * getUnitRand();
fi += fi * parameter.dirBlur * getUnitRand();
//生成随机方向
glm::vec3 dir = glm::vec3(sin(theta)*sin(fi), cos(theta), sin(theta)*cos(fi));
dirs.push_back(dir);
}
}
return dirs;
}
3.三维球面上的Marsaglia 方法,这是一种基于变换抽样的方法。
step1: 随机抽样产生一对均匀分布的随机数 u ,v ;这里u,v 在[-1,1] 范围内
step2 :计算 r^2 = u^2+v^2;
如果 r^2 > 1 则重新抽样,直到满足 r^2 < 1 .
step3 :x=2*u*sqrt(1-r2);
y=2*v*sqrt(1-r2);
z=1-2*r2;
class cRandom {
public:
cRandom(int x, double y) :seed(x), random(y) {};
cRandom() :seed(0), random(0) {};
int seed;
double random;
};
cRandom my_random(int z) {
const int m = pow(2, 31) - 1;
const int a = 16807;
const int q = 127773;
const int r = 2836;
int temp = a * (z % q) - r * (z / q);
if (temp < 0) {
temp = temp + m;
}
z = temp;
double t = z * 1.0 / m;
cRandom cr;
cr.random = t;
cr.seed = z;
return cr;
}
//获取一个球面的上位置
vector<glm::vec3> getSpherePoint(int num) {
vector<glm::vec3> ans;
srand(time(0));
int z1 = rand();
int z2 = rand();
cRandom sita(z1, 0.0);
cRandom pesi(z2, 0.0);
for (int i = 0; i < num; ++i) {
sita = my_random(pesi.seed);
pesi = my_random(sita.seed);
double u = 2 * sita.random - 1.0;
double v = 2 * pesi.random - 1.0;
double r2 = pow(u, 2) + pow(v, 2);
if (r2 < 1) {
double x = 2 * u * sqrt(1 - r2);
double y = 2 * v * sqrt(1 - r2);
double z = 1 - 2 * r2;
ans.push_back(glm::vec3(x, y, z));
}
else {
i--;
}
}
return ans;
}