如何获得P5.js的球体交点?

How to get sphere intersection points with P5.js?

我正在使用 p5.js 创建一个 sphere

我感兴趣的是获取用于对球体建模的形状的点坐标。

可以吗?

基本上,我想获得用于绘制对球体建模的三角形的一系列点。

您可以使用 spherical coordinates(两个角度和半径)到笛卡尔坐标 (x,y,z) 的转换公式来计算球体上的点:


(图片来源:维基百科)

如果你把这两个角度想象成我们地球上的纬度(lat)、经度(lon)角度和一个恒定的半径,在JS中你可以把这个公式看成:

var x = radius * cos(lat) * sin(lon);
var y = radius * sin(lat) * sin(lon);
var z = radius * cos(lon);

这里有一个基本的草图来说明这个想法:

var radius    = 120;
var latDetail = 0.243;
var lonDetail = 0.15;

function setup() {
  createCanvas(300, 300, WEBGL);
  strokeWeight(9);
}

function draw() {
  background(255);
  
  orbitControl();
  beginShape(POINTS);
  
  // iterate through lat, lon angles (in radians)
  for(var lat = 0; lat <= PI; lat += latDetail){
    for(var lon = 0; lon <= TWO_PI; lon += lonDetail){
      
      // for each sperical coordinate (lat, lon angles, radius)
      // convert to cartesian (x, y, z)
      
      var x = radius * cos(lat) * sin(lon);
      var y = radius * sin(lat) * sin(lon);
      var z = radius * cos(lon);
      // render each point
      vertex(x, y, z);
    }
  }
  
  endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>

玩一玩 latDetail, lonDetail 变量,这些变量定义 dense/sparse 球体的 parallels/meridians 将如何。

在线快速查看 UV 球体,Daniel Sieger's Generating Spheres article 非常棒!

虽然是c++的代码,但是语法很相似,可以看懂:

// generate vertices per stack / slice
  for (int i = 0; i < n_stacks - 1; i++)
  {
    auto phi = M_PI * double(i + 1) / double(n_stacks);
    for (int j = 0; j < n_slices; j++)
    {
      auto theta = 2.0 * M_PI * double(j) / double(n_slices);
      auto x = std::sin(phi) * std::cos(theta);
      auto y = std::cos(phi);
      auto z = std::sin(phi) * std::sin(theta);
      mesh.add_vertex(Point(x, y, z));
    }
  }

几乎相同的公式(没有 radius 标量)和每个角度上的段数的计数器(而不是角度增量)。

这是一个 p5.js 端口:

var radius    = 120;
var uSegments = 12;
var vSegments = 12;

// sliders
var uSegmentsSlider;
var vSegmentsSlider;

function setup() {
  createCanvas(300, 300, WEBGL);
  strokeWeight(9);
  uSegmentsSlider = createSlider(3, 36, 12, 1);
  vSegmentsSlider = createSlider(3, 36, 12, 1);
  uSegmentsSlider.position(10, 10);
  vSegmentsSlider.position(10, 30);
  createP('U').position(145, -3);
  createP('V').position(145, 17);
}

function draw() {
  // read slider values
  uSegments = uSegmentsSlider.value();
  vSegments = vSegmentsSlider.value();
  background(255);
  
  orbitControl();
  beginShape(POINTS);
  
  // iterate through u, v segments
  for(var u = 0; u < uSegments; u++){
    var phi = PI * (u + 1) / uSegments;
    for(var v = 0; v < vSegments; v++){
      var theta = TWO_PI * v / vSegments;
      // for each sperical coordinate (lat, lon angles, radius)
      // convert to cartesian (x, y, z)
      
      var x = radius * cos(theta) * sin(phi);
      var y = radius * sin(theta) * sin(phi);
      var z = radius * cos(phi);
      // render each point
      vertex(x, y, z);
    }
  }
  
  endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>