在具有Three.js的椭圆体PointCloud中重新分配点

时间:2015-08-19 13:56:23

标签: javascript random three.js distribution

我最近开始尝试使用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,如果您的浏览器看起来不一样,我就制作了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;

颗粒分布更均匀。更有趣的是,它不会形成轴的“十字形孔”,我期望这是因为Math.random()+ 0.1不会产生低于0.1的任何值。所以这个小技巧解决了我的问题,即使我仍然对一个好的答案感兴趣。

3 个答案:

答案 0 :(得分:2)

角度分布明显不均匀。你看到的相当于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)

进行相应缩放

答案 1 :(得分:0)

您想要创建一个均匀分布在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

答案 2 :(得分:0)

我最终使用了@ 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://raw.github.com/替换http://rawgit.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的有趣贡献。