3D:从极坐标创建球体时避免在极点处挤压

3D: avoid pinching at poles when creating sphere from polar coordinates

我正在使用维基百科的 spherical coordinate system article 创建一个由 Three.js 中的粒子组成的球体。基于这篇文章,我创建了一个小的 Polarizer class 接受极坐标 setPolar(rho, theta, phi) 并且它 returns 对应的 x, y, z

这是 setPolar() 函数:

// Rho: radius
// theta θ: polar angle on Y axis
// phi φ: azimuthal angle on Z axis

Polarizer.prototype.setPolar = function(rho, theta, phi){
  // Limit values to zero
  this.rho = Math.max(0, rho);
  this.theta = Math.max(0, theta);
  this.phi = Math.max(0, phi);

  // Calculate x,y,z
  this.x = this.rho * Math.sin(this.theta) * Math.sin(this.phi);
  this.y = this.rho * Math.cos(this.theta);
  this.z = this.rho * Math.sin(this.theta) * Math.cos(this.phi);

  return this;
}

我用它来定位我的粒子,如下所示:

var tempPolarizer = new Polarizer();

for(var i = 0; i < geometry.vertices.length; i++){
  tempPolarizer.setPolar(
    50,                         // Radius of 50
    Math.random() * Math.PI,    // Theta ranges from 0 - PI
    Math.random() * 2 * Math.PI // Phi ranges from 0 - 2PI
  );

  // Set new vertex positions
  geometry.vertices[i].set(
    tempPolarizer.x,
    tempPolarizer.y,
    tempPolarizer.z
  );
}

它工作得很好,除了我得到高粒子密度,或者在两极 "pinching":

我不知道如何避免这种情况发生。我想过将加权随机数传递给纬度,但我希望在没有经度的情况下为粒子设置动画,同时也会减慢速度并在两极聚集。

是否有不同的公式可以生成一个球体,其中两极的重量不那么大?我应该改用四元数吗?

为了避免两极的高密度,我不得不将 theta(纬度)着陆的可能性降低到接近 0 和 PI。我输入的

Math.random() * Math.PI, 因为 theta 给出了所有值的相同可能性(橙色)。

Math.acos((Math.random() * 2) - 1) 对输出进行完美加权,使 0 和 PI 沿着球体表面(黄色)的可能性降低

现在连两极都分不清了!

  1. 用于随机均匀采样

    在单位立方体中使用随机点,将其作为矢量处理并将其长度设置为球体的半径。例如在 C++ 中是这样的:

    x = 2.0*Random()-1.0; 
    y = 2.0*Random()-1.0; 
    z = 2.0*Random()-1.0; 
    m=r/sqrt(x*x+y*y+z*z);
    x*=m;
    y*=m;
    z*=m;
    

    其中 <0.0,1.0> 中的随机数 return。有关详细信息,请参阅:

    • Procedural generation of stars with skybox
  2. 均匀非随机抽样

    查看相关 QAs:

    • Sphere triangulation by mesh subdivision
    • Make a sphere with equidistant vertices