Three.js将球体旋转到任意位置

Three.js Rotate sphere to arbitrary position

本文关键字:任意 位置 旋转 js Three      更新时间:2023-09-26

使用Three.js,我有一个球体(地球仪)和几个附在火山点上的精灵。我可以旋转(旋转)球体,精灵保持在它们的位置,因为它们是作为一个组添加到球体中的。

现在,我希望能够使用按钮将地球旋转到任意位置。我该怎么做?例如,如果我想旋转到的点在地球仪的后面,我如何旋转地球仪使其在前面?

这个代码基本上就是我现在所拥有的。我添加精灵到的主网格。

 <html>
<head></head>
<body>

<script src="three.min.js"></script>
<script>
  var scene, camera, renderer;
  var geometry, material, mesh;
  init();
  animate();
  function init() {
      scene = new THREE.Scene();
      camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
      camera.position.z = 1000;
      material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: false } );
      geometry = new THREE.SphereGeometry( 159, 32, 32 );
      mesh = new THREE.Mesh( geometry, material );
      scene.add( mesh );
      var map = THREE.ImageUtils.loadTexture( "sprite1.png" );
      var material2 = new THREE.SpriteMaterial( { map:map, color:0x00ff00 } );
      var sprite1 = new THREE.Sprite( material2 );
      sprite1.position.set(100,100,100);
      sprite1.scale.set(40,40,40);
      mesh.add(sprite1);
      var sprite2 = new THREE.Sprite( material2);
      sprite2.position.set(-100,-100,-100);
      sprite2.scale.set(30,30,30);
      mesh.add(sprite2);
      var sprite3 = new THREE.Sprite(material2);
      sprite3.position.set(100,-100,100);
      sprite3.scale.set(20,20,20);
      mesh.add(sprite3);
      renderer = new THREE.WebGLRenderer({alpha:true});
      renderer.setSize( window.innerWidth, window.innerHeight );
      document.body.appendChild( renderer.domElement );
  }
  function animate() {
      requestAnimationFrame( animate );
      mesh.rotation.y += 0.01;
      renderer.render( scene, camera );
  }
 </script>
</body>
</html>

图表示例

这将是我的方法:

// as sprite is a child of mesh get world position
var spritePos = new THREE.Vector3().setFromMatrixPosition(sprite.matrixWorld);
// get the vectors for calculating angle
var cv3 = new THREE.Vector3().subVectors(camera.position, mesh.position);
var sv3 = new THREE.Vector3().subVectors(spritePos, mesh.position);
// we only want to rotate around y-axis, so only the angle in x-z-plane is relevant
var cv2 = new THREE.Vector2(cv3.x, cv3.z);
var sv2 = new THREE.Vector2(sv3.x, sv3.z);
// normalize Vectors
cv2.normalize();
sv2.normalize();
// dot product
var dot = cv2.dot(sv2);
// angle to between sprite and camera in radians
// cosinus is from 1 to -1, so we need to normalize and invert it and multiply it with PI to get proper angle
var angle = (1 - (dot + 1) / 2) * Math.PI;
// is sprite left or right from camera?
if(spritePos.x < 0)
  mesh.rotation += angle;
else
  mesh.rotation -= angle;

现在,我做了一个Plunker。

它似乎有点不准确,因为它总是向左或向右旋转一点到最前面的位置。也许是由于余弦在某些特定角度附近。

还要记住,如果摄影机或网格位于场景中的其他位置,则确定精灵是在摄影机的左侧还是右侧会有点困难。

点积后的解释:

点积将两个向量的角度表示为余弦。所以我们得到一个介于-1和1之间的值。例如cos(0) = 1 cos(PI/2) = 0 cos(PI) = -1此时So为0°=1和180°=-1。

我们想要得到以弧度为单位的角度来旋转网格。因此,首先我们将其标准化为(dot + 1) / 2,因此0°=1,180°=0。

然后将其反转(0°=0,180°=1)并乘以PI(0°=0,180°=PI)。

现在,我们有了旋转的角度,但我们不知道是需要向左还是向右旋转,这就是为什么我从相机中检查精灵是向左还是向右。

我不知道这是足够的解释,还是完全可以理解?