生成球面上点的方法

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;
}

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值