Three.js - 如何围绕球体(globe)定位物体

Three.js - How to position objects around a sphere (globe)

我有一个 json 国家边界文件,用于在 three.js (mbostock example) 中构建地图。
我想要的是将每个圆柱体的位置映射到其各自的国家 - 如下所示:

请查看以下代码段。目前我正在取每个几何体的边界框的中心,它工作得很好,但圆柱体并不像图像中那样指向外。我试过使用 lookAt() 但效果不佳。还有一个 for 循环可以旋转我的国家和圆柱体,但它们没有按应有的方式移动(取消注释以进行测试)。

如何正确定位气缸?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id='my_dataviz'></div>
<script src="https://d3js.org/d3.v6.js"></script>
<script src="https://unpkg.com/topojson-client@3"></script>
<script src="https://unpkg.com/d3-array@1"></script>
<script src="https://unpkg.com/d3-collection@1"></script>
<script src="https://unpkg.com/d3-dispatch@1"></script>
<script src="https://unpkg.com/d3-request@1"></script>
<script src="https://unpkg.com/d3-timer@1"></script>
<script type='module'>
import * as THREE from "https://unpkg.com/three@0.127.0/build/three.module.js";
import {OrbitControls} from "https://unpkg.com/three@0.127.0/examples/jsm/controls/OrbitControls.js";

var width1 = 860,
    height1 = 860,
    radius = 168,
    mesh,
    graticule,
    scene = new THREE.Scene,
    camera = new THREE.PerspectiveCamera(70, width1 / height1, 1, 1000),
    renderer = new THREE.WebGLRenderer({alpha: true}),
    container = document.getElementById( 'my_dataviz' ),
    controls;

    camera.position.z = 400;
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(width1, height1);
    container.appendChild(renderer.domElement);

const geometry = new THREE.SphereGeometry(98, 52, 36 );
const material = new THREE.MeshBasicMaterial( { color: "rgb(220,229,229)", opacity:0.7, transparent: true} );
const sphere = new THREE.Mesh( geometry, material );

d3.json("https://cdn.jsdelivr.net/npm/world-atlas@2/countries-50m.json", function(error, topology) {
  if (error) throw error;
  var countries = []
  var cones = []
  for (var i = 0; i < topology.objects.countries.geometries.length; i++) {
    var rgb = [];
    var newcolor;
    for(var j = 0; j < 3; j++){
      rgb.push(Math.floor(Math.random() * 255));
      newcolor = 'rgb('+ rgb.join(',') +')';
    }
    var mesh = wireframe(topojson.mesh(topology, topology.objects.countries.geometries[i]), new THREE.LineBasicMaterial({color:newcolor, linewidth: 5}))
    countries.push(mesh);
    scene.add(mesh);

    mesh.geometry.computeBoundingBox()
var center = new THREE.Vector3();
mesh.geometry.boundingBox.getCenter(center)

const geometry = new THREE.BoxGeometry( 1, i/10, 1 );
const material = new THREE.MeshBasicMaterial( {color: newcolor} );
const cone = new THREE.Mesh( geometry, material );
cone.position.x = center.x;
cone.position.y = center.y;
cone.position.z = center.z;

// cone.lookAt(mesh.position);
cones.push(cone);
scene.add( cone );
  }
  console.log(sphere.position)

  scene.add(sphere);
  controls = new OrbitControls( camera, renderer.domElement );
  d3.timer(function(t) {
    for (var i = 0; i < countries.length; i++) {
      // countries[i].rotation.x = Math.sin(t / 21000) * Math.PI / 3 - Math.PI / 2;
      // countries[i].rotation.z = t / 20000;
      // cones[i].rotation.x = Math.sin(t / 21000) * Math.PI / 3 - Math.PI / 2;
      // cones[i].rotation.z = t / 20000;
    }
    renderer.render(scene, camera)
  });
});

// Converts a point [longitude, latitude] in degrees to a THREE.Vector3.
function vertex(point) {
  var lambda = point[0] * Math.PI / 180,
      phi = point[1] * Math.PI / 180,
      cosPhi = Math.cos(phi);
  return new THREE.Vector3(
    radius * cosPhi * Math.cos(lambda),
    radius * cosPhi * Math.sin(lambda),
    radius * Math.sin(phi)
  );
}

// Converts a GeoJSON MultiLineString in spherical coordinates to a THREE.LineSegments.
function wireframe(multilinestring, material) {
  var geometry = new THREE.BufferGeometry;
  var pointsArray = new Array();
  multilinestring.coordinates.forEach(function(line) {
    d3.pairs(line.map(vertex), function(a, b) {
      pointsArray.push(a,b);
    });
  });
  geometry.setFromPoints(pointsArray);
  return new THREE.LineSegments(geometry, material);
}
</script>
</body>

群!!

圆柱体没有围绕正确的原点旋转。

let earthPivot = new THREE.Group(); //this is what matters
    mesh.add( earthPivot ); //'mesh' is the globe
      const geometry = new THREE.BoxGeometry( 1, 1+i/10, 1 );
      const material = new THREE.MeshBasicMaterial( {color: newcolor} );
      const cone = new THREE.Mesh( geometry, material );
      cone.position.x = center.x;
      cone.position.y = center.y;
      cone.position.z = center.z;

      cones.push(cone);
      earthPivot.add( cone ); //this is what matters

将您的对象分组并将该组添加到您希望对象围绕其旋转的网格中。