如何计算球体上几何体的旋转,使它们面向外

How to calculate rotation for geometries on a sphere so that they face outwards

我有一个 sphere 并且我根据从坐标(半径 = 200)转换的点(x,y,z)在表面上添加圆柱体。现在我一直在研究如何单独计算每个圆柱体从球体面向外所需的旋转。

我正在使用 Matrix4(makeRotationX(); 和 Matrix4(makeRotationZ(); 旋转几何图形。

function drawCylinder(x_values, y_values, z_values, scene) {

  var cylinderHeight = 20;
  var rotationX = new THREE.Matrix4().makeRotationX(Math.PI/2);
  var rotationZ = new THREE.Matrix4().makeRotationZ(Math.PI/2);

  var axis = new THREE.Vector3(x_values, y_values, z_values);
  var geometry = new THREE.CylinderGeometry(2, 2, cylinderHeight, 32 );
  geometry.translate(x_values[0], y_values[0], z_values[0]);
  //geometry.applyMatrix4(rotationZ);

  var material = new THREE.MeshBasicMaterial({
    color: 0x5affb5
  });
  var mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  clearArrays();

}

示例(x:– 71.2237692444388,y:– 47.741840449353155,z:– 182.89858218456328)

你的问题中没有说明球心的坐标。让我称他们为(x0, y0, z0)

球体的半径为R = 200,圆柱体的高度为cylinderHeight = 20

圆柱底部的坐标为(x, y, z)

由于您希望圆柱体在地球上“垂直”定向,因此您希望圆柱体的轴处于径向方向;换句话说,您希望球体的中心、圆柱体的底部和圆柱体的顶部对齐。另一种表述方式是,您希望中​​心->底部和中心->顶部这两个向量共线。另一种表述方式是,您希望这两个向量的坐标成比例。

由于您知道所有涉及的长度,因此比例因子必须为 (R + cylinderHeight) / R

最终圆柱体顶部的坐标(xT, yT, zT)由下式给出:

(xT-x0, yT-y0, zT-z0) = (R + cylinderHeight) / R * (x-x0, y-y0, z-z0)

xT = (R + cylinderHeight) * (x-x0) / R + x0
yT = (R + cylinderHeight) * (y-y0) / R + y0
zT = (R + cylinderHeight) * (z-z0) / R + z0

你可以使用quaternion.setFromUnitVectors(),有一个基本向量和一个圆柱位置向量:

body{
  overflow: hidden;
  margin: 0;
}
<script type="module">
import * as THREE from "https://threejs.org/build/three.module.js";
import {OrbitControls} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.setScalar(10);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

let controls = new OrbitControls(camera, renderer.domElement);

let radius = 5;
let s = new THREE.Mesh(new THREE.SphereBufferGeometry(radius, 36, 18), new THREE.MeshNormalMaterial({wireframe: true}));
scene.add(s);

// cylinders
let g = new THREE.CylinderBufferGeometry(0.125, 0.125, 1, 8);
g.translate(0, 0.5, 0);
let m = new THREE.MeshBasicMaterial({color: "orange"});
let baseV = new THREE.Vector3(0, 1, 0);
let dirV = new THREE.Vector3();
for(let i = 0; i < 50; i++){
  let c = new THREE.Mesh(g, m);
  c.position.setFromSphericalCoords(
    radius,
    Math.random() * Math.PI,
    Math.random() * Math.PI * 2
  );
  c.quaternion.setFromUnitVectors(baseV, dirV.copy(c.position).normalize());
  scene.add(c);
}

renderer.setAnimationLoop(()=>{
  renderer.render(scene, camera);
});

</script>