Three.js - 如何围绕一个Vector3点旋转相机?

6
好的,我会尽可能简明扼要地解释。我不太擅长数学,对你来说显而易见的东西对我来说可能就像火箭科学一样难以理解。
我正在使用带有CSS3DRenderer的Three.js创建虚拟画廊空间。
我需要一个第一人称视角,就像FPS游戏一样。
我已经成功地让相机前进、后退、向左和向右移动了。
然而,当我尝试旋转相机时,我得到了这个结果pictured here 相机正在旋转它的本地轴,但是我需要的是视口而不是相机旋转,就像下面这样pictured here 因此,我需要让相机围绕一个枢轴点/向量旋转,然后使用Object3d.lookAt()重新聚焦。
我知道我可以通过将相机作为另一个对象的子对象来解决问题,然后旋转对象的轴。然而,我宁愿自己做数学计算。
简而言之,我想了解如何围绕另一个向量点旋转一个向量点,并如何在数学上表示这种关系。
不想使用脚本,例如three.js指针锁定控件,来完成工作。我想亲自动手做实际的数学计算。
任何建议或教程链接都将不胜感激!

当您将相机向左或向右移动时,您是否会旋转相机(lookAt)以保持指向同一点?您想要围绕此点旋转相机吗? - dcromley
当我向左/右看时,我希望摄像机的vector3位置围绕一个vector3枢轴点逐渐旋转。在每次围绕枢轴点增量后,我将调用Object3d.lookAt()。否则,我的相机会围绕枢轴旋转,但始终面向同一方向,这不符合我希望实现的FPS视角模拟。 另外,我应该提到,每当相机向前、向后、向左或向右移动时,我的枢轴点也会向前、向后、向左或向右移动相同的距离。因此,枢轴点是动态的,而不是世界空间中的固定坐标。 - pandakub
你需要学习的是极坐标系 - yomotsu
如果枢轴点是动态的,那么它就不是一个枢轴点。枢轴是固定的。如果你把相机向右移动10个单位,枢轴点会怎样移动?目标是否在移动?什么是固定的(如果有的话)? - dcromley
枢轴点只是固定在处理相机前进、后退、左右移动的功能中,这些功能与处理旋转/向左或向右转动的功能是分开的,并且这些功能与处理旋转/向左或向右转动的功能是分开的。也许它并没有固定,因为它(枢轴)从不移动,但从我的相机始终保持完全相同的距离意义上来说是固定的。如果我的相机向左移动两个单位的距离,那么枢轴点也会向左移动两个单位的距离。 - pandakub
2个回答

9
以下是一个相机围绕一个盒子旋转的示例。
它的工作原理在于应用旋转矩阵总是围绕着原点旋转一个对象。这与仅修改“rotation”属性不同,后者会将对象围绕其自身中心旋转,正如您所发现的那样。这里的诀窍是将相机移动200个单位远离原点,这样当我们应用旋转矩阵时,它就会在一个圆周上围绕原点旋转。
由于盒子位于原点处,因此这将使相机围绕盒子旋转。然后使用“lookAt”将相机指向盒子。
如果您想了解更多关于此主题的低级别解释,请参阅以下链接:http://webglfundamentals.org/webgl/lessons/webgl-scene-graph.html

var canvas = document.getElementById('canvas');
var scene = new THREE.Scene();
var renderer = new THREE.WebGLRenderer({canvas: canvas, antialias: true});
var camera = new THREE.PerspectiveCamera(45, canvas.clientWidth / canvas.clientWidth, 1, 1000);

var geometry = new THREE.BoxGeometry(50, 50, 50);
var material = new THREE.MeshBasicMaterial({color: '#f00'});
var box = new THREE.Mesh(geometry, material);
scene.add(box);

// important, otherwise the camera will spin on the spot.
camera.position.z = 200;

var period = 5; // rotation time in seconds
var clock = new THREE.Clock();
var matrix = new THREE.Matrix4(); // Pre-allocate empty matrix for performance. Don't want to make one of these every frame.
render();

function render() {
  requestAnimationFrame(render);
  if (canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight) {
    // This stuff in here is just for auto-resizing.
    renderer.setSize(canvas.clientWidth, canvas.clientHeight, false);
    camera.aspect = canvas.clientWidth /  canvas.clientHeight;
    camera.updateProjectionMatrix();
  }

  // Create a generic rotation matrix that will rotate an object
  // The math here just makes it rotate every 'period' seconds.
  matrix.makeRotationY(clock.getDelta() * 2 * Math.PI / period);

  // Apply matrix like this to rotate the camera.
  camera.position.applyMatrix4(matrix);

  // Make camera look at the box.
  camera.lookAt(box.position);

  // Render.
  renderer.render(scene, camera);
}
html, body, #canvas {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.js"></script>
<canvas id="canvas"></canvas>


谢谢!这看起来很有用。告诉我,makeRotationY() Matrix4方法是否总是相对于原点/世界空间旋转对象?您无法将此特定方法应用于更改对象的本地轴吗? - pandakub
一个旋转矩阵总是围绕原点旋转。然而,有一个技巧可以使物体围绕空间中的另一点旋转。1.将对象平移,使要围绕的点位于原点处。2.然后应用旋转矩阵。3.撤销步骤1中的平移。这将使它看起来像是你只是围绕一个特定点而不是原点旋转。这被称为“基变换”。 - Brendan Annable
@pandakub 不是的,因为这个解决方案基本上是个坏主意。为什么呢?我在下面的答案中解释了。 - Martin

3
标准的方法是创建一个与对象位置相同的var camera_pivot = new object3D()。将相机作为子级,向后移动相机以实现可观察距离并旋转对象。
您可以按照需要移动object3D()和旋转它。这是易于编写代码和优化性能的最佳解决方案。
在object3D上,您可以使用camera_pivot.translateX()、camera_pivot.rotateX()、camera_pivot.lookAt(obj)等功能。
另一种方式很难在不影响场景中其他对象的情况下执行任何操作。

-1. OP特别说明:“我知道可以通过将相机作为另一个对象的子节点来解决我的问题,然后旋转该对象的轴。但是,我宁愿自己计算数学问题。” - Brendan Annable
1
相机始终是另一个对象的子级。如果您仅为相机定义了单独的对象,则可以像使用相机一样使用此对象的操作。这是最佳实践和解决问题的常规方法。THREE JS旨在更有可能使用对象而不是在渲染中使用自己的计算。例如,无法根据需要更改相机动画,使用TWEEN等... - Martin
1
+1. 这是从谷歌搜索“three.js pivot camera”目前排名第三的结果。原帖作者可能关心数学,但我只想要一个干净实用的解决方案。 - Kaivosukeltaja
我喜欢这两种解决方案。里面有更多低级数学,这很好。 - Arnaldo Capo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接