我跟着射线追踪一个周末,兰伯特的余弦定律是通过在单位球体表面随机点并向这个方向发射射线来模拟的。
作者使用一种简单的拒绝方法来生成球面上的随机点。因为我已经在使用GLM,所以我认为我会很聪明,并且使用glm::sphericalRand()而不是自己来完成工作。然后,我决定看看这些点实际上是如何均匀分布的,并绘制了它们相对于y方向的正常面的角度:
float buckets[200] = {};
std::srand(time(0)); // Give glm a new seed
for (int i = 0; i < 10000000; i++) {
const glm::vec3 normal = glm::vec3(0.0f, 1.0f, 0.0f);
const glm::vec3 randomVector = glm::sphericalRand(1.0f); // Implicitly normalized (sphere radius of 1)
const float dot = glm::dot(randomVector, normal);
const int bucket = 100 + dot * 100; // Pick a bucket in the range [0, 199]
buckets[bucket]++;
}我用glm::sphericalRand()在单位球面上生成10.000.000个随机向量,并取它们的正态点积。然后,我增加对应于它们的点积值的桶。
每个桶表示与法向在一定角度范围内的向量数。向量的点积在[-1,-0.99>到桶0,[-0.99,-0.98>在桶1,等等。
我期望所有的角度(水桶)的选择大致相等。然而,情况似乎并非如此。我在下面的每个桶中绘制了条目的数目。

显然,每个桶大约有50.000个条目,这对10.000.000个样本和200个桶来说是有意义的。然而,桶99 (对应的点积为0)显示了一个清晰的倾角,大约有一半的样本。
我决定使用此stackexchange注释创建自己的函数,在球面上生成一个随机点。
glm::vec3 sphericalRand(float radius = 1.0f) {
glm::vec3 randomVec = glm::vec3(glm::gaussRand(0.0f, 1.0f), glm::gaussRand(0.0f, 1.0f), glm::gaussRand(0.0f, 1.0f));
return glm::normalize(randomVec) * radius;
}绘制这一图产生了以下结果:

接近点乘积0的倾角不那么明显(尽管确实仍然存在)。然而,现在出现了一些其他的现象:与负点产品的样本(桶0到99)相比,具有正点产品的样本(桶100到199)通常要少。
这是否是std::rand()工作方式的结果(我相信GLM是在引擎盖下使用的)?还是这里还发生了什么事?
发布于 2022-09-22 20:39:21
答案不多,但早在2017年,在我的论文中,我注意到sphericalRand在它为θ和phi生成的范围内是唯一的。

这是在我打开一个问题(问题被核弹)之后,据称被修复的东西。https://github.com/g-truc/glm/pull/708/files
然而,我也提到了linearRand也是独占的,sphericalRand使用它。
当时我的解决方案是只使用std::rand()并自己动手。
float theta = 2 * PI * ((float)rand() / RAND_MAX);
float phi = acos(2.0f * ((float)rand() / RAND_MAX) - 1.0f);
glm::vec3 point = sphereToCartesian(rho, theta, phi);https://stackoverflow.com/questions/71161952
复制相似问题