用 Three.js 重新划分椭圆点云中的点

Repartition of points in an ellipsoid PointCloud with Three.js

我最近开始尝试 Three.js。 我尝试使用 PointCloud 对象创建椭圆体粒子云。

我使用椭圆体的参数方程生成随机点,如下所示:

    var vertex = new THREE.Vector3();
    u = Math.random() * 2 * Math.PI;
    v = Math.random() * Math.PI;
    vertex.x = Math.random() * a * Math.cos(u) * Math.sin(v);
    vertex.y = Math.random() * b * Math.sin(u) * Math.sin(v);
    vertex.z = Math.random() * c * Math.cos(v);

但是当我渲染云时,我注意到异常数量的粒子聚集在椭圆体的轴周围。

我想知道这是否与 Math.random() 函数的分布有关,还是我遗漏了什么?请帮助我理解这一点。

您可以看看它 here and I made a screenshot 以防它在您的浏览器上看起来不一样。

编辑:代码已按照@severin-pappadeux 的友好建议进行了修改,以避免错误分布的点,但问题仍然存在。

编辑: 我修改了使用 Math.random() 设置顶点长度的部分,即:

vertex.x = Math.random() * a * wx;
vertex.y = Math.random() * b * wy;
vertex.z = Math.random() * c * wz;

至:

vertex.x = (Math.random() + 0.1) * a * wx;
vertex.y = (Math.random() + 0.1) * b * wy;
vertex.z = (Math.random() + 0.1) * c * wz;

而且颗粒分布更均匀。更有趣的是,它不会在轴所在的位置形成 "cross-like hole",这是我所期望的,因为 Math.random() + 0.1 不会产生任何低于 0.1 的值。所以这个小技巧解决了我的问题,尽管我仍然对好的答案感兴趣。

角度分布明显不均匀。你看到的效果相当于http://mathworld.wolfram.com/SpherePointPicking.html的效果。可以尝试建立单位统一的球体矢量,并将其与椭圆相交以产生顶点。沿线的东西

phi   = 2.0 * Math.PI * Math.random();
csth  = 2.0 * Math.random() - 1.0;
snth  = Math.sqrt((1.0 - csth)*(1.0 + csth));
wx = snth * Math.sin(phi);
wy = snth * Math.cos(phi);
wz = csth;

(wx,wy,wz) 是单位向量。构建距离为 s*(wx,wy,wz) 的射线。将来自 (0,0,0) 的这条光线与椭圆相交,找到你的顶点

更新

没有意识到问题是关于给定卷中的制服。无论如何要在单位球体中获得均匀,必须添加半径采样:

r = Math.pow( Math.random(), 1.0/3.0 ); // is there cubic root sqrt3() function?

那么球体内的点将是 (r*wx, r*wy, r*wz) 并且可以相应地缩放 (a, b, c)

您想创建一个均匀分布在 3D 椭球体内的随机点云。

首先,在立方体内部生成一个随机点,忽略嵌入球体之外的点。

vertex.x = 2 * Math.random() - 1;
vertex.y = 2 * Math.random() - 1;
vertex.z = 2 * Math.random() - 1;
if ( vertex.length() < 1 ) geometry.vertices.push( vertex );

您现在将在一个球体内有均匀的点。要创建椭圆体,请在创建点云后对其进行缩放。

var pointCloud = new THREE.Points( geometry, material );
pointCloud.scale.set( a, b, c );

three.js r.86

我最终使用了@WestLangley 的解决方案,它是这样实现的(正如@Atrahasis 所建议的):

while(geometry.vertices.length < 20000) {
    var vertex = new THREE.Vector3();
    vertex.x = 2 * Math.random() - 1;
    vertex.y = 2 * Math.random() - 1;
    vertex.z = 2 * Math.random() - 1;
    if(vertex.length() < 1) geometry.vertices.push(vertex);
}

您可以看到完整的代码 here(据我所见,它在 Firefox 上看起来比在 Chrome 上更好)

额外提示:从 Github 导入 Codepen/JSFiddle 等中的原始 js 文件在 Chrome 上不起作用,因为文件的 MIME 类型是 'text/plain',因此浏览器可以不执行它。诀窍是用 http://rawgit.com/ 替换 http://raw.github.com/ 部分,所以对于 OrbitControls.js,我将 https://raw.githubusercontent.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js 更改为 https://rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js 并且有效!

感谢@SeverinPappadeux 的有趣贡献。