ThreeJS - 使用不同的旋转中心和lookAt点的OrbitControl

9

我的应用程序中使用了OrbitControl,允许摄像机围绕世界旋转。 最近我尝试增强控件功能,允许摄像机围绕任意点旋转,而不仅仅是摄像机的lookAt点。但我目前没有太大的进展。

如果我在代码中移除这一行:this.object.lookAt( this.target );,它并不能正常工作。有什么想法吗?

以下是一些图片以澄清问题: enter image description here enter image description here

我将摄像机围绕对象(枢轴)中心旋转,但摄像机没有对准中心。


1
你尝试过使用TrackballControl而不是OrbitControl吗? - MacK
你最终解决了这个问题吗?下面的答案会立即重置并将对象放回中心。 - Starfs
你解决过这个问题吗?我也遇到了!@ChrisU - Nicolas
我还想要能够旋转物体,但调整相机位置使其对齐在中心以下。看起来自定义控件方法可能是唯一的方法? https://threejs.org/examples/#misc_lookat https://github.com/mrdoob/three.js/blob/master/examples/misc_lookat.html - Kim T
我已经提出了一个功能请求:https://github.com/mrdoob/three.js/issues/18476 - Kim T
2个回答

7

只需更新controls.target属性,例如:

controls.target.set(1, 5, 7);

或者针对网格进行操作:
controls.target.copy(mesh.position)

1
这将把lookAt设置为目标。我不希望相机看向旋转中心。 - ChrisU

5

OrbitControls旨在用于围绕场景旋转,摄像机视口直接朝向控制旋转目标。它们不适用于处理与相机分离的对象旋转,但有TransformControls,但这些不支持阻尼。

使用轨道控件旋转,将锁定您的相机视口以查看中心(虚线),并围绕中心旋转(红线):

enter image description here

如果移动/平移目标,则相机目标和旋转中心一起移动,如下所示:

enter image description here

您需要独立的旋转中心和相机目标,因此相机围绕对象旋转,同时查看某个点,如下所示:

enter image description here

似乎有两种方法创建自定义相机/旋转功能:

1)修改OrbitControls 将相机.lookAt更改为与controls.target偏移。

OrbitControls所需的视图更改: https://github.com/sciecode/three.js/commit/dccf1578343bb9b7c79bb2eb2004d5ee34a76e6a#diff-ffef32863dd826c87a45cfb28c4ddd83

自定义Orbit Controls演示: https://jsfiddle.net/kmturley/6qxh3zc9/28/

2)修改TransformControls 更改变换控件以允许阻尼、自由旋转和隐藏gizmo叠加。

自定义Transform Controls演示 https://jsfiddle.net/kmturley/2p1v6bcw/18/

3)创建您自己的物体旋转控件

import * as THREE from "https://threejs.org/build/three.module.js";

var mesh, renderer, scene, camera, controls;
var radius = 5;
var group;
var targetRotationX = 0;
var targetRotationOnMouseDownX = 0;
var targetRotationY = 0;
var targetRotationOnMouseDownY = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var mouseY = 0;
var mouseYOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var finalRotationY

init();
animate();

function init() {

  // renderer
  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setPixelRatio(window.devicePixelRatio);
  document.body.appendChild(renderer.domElement);

  // scene
  scene = new THREE.Scene();

  // camera
  camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.set(0, radius * 2, radius * 2);
  camera.lookAt(0, radius, 0)

  // controls
  /*     controls = new OrbitControls( camera, renderer.domElement ); */
  document.addEventListener('mousedown', onDocumentMouseDown, false);
  document.addEventListener('touchstart', onDocumentTouchStart, false);
  document.addEventListener('touchmove', onDocumentTouchMove, false);

  // ambient
  scene.add(new THREE.AmbientLight(0x222222));

  // light
  var light = new THREE.DirectionalLight(0xffffff, 1);
  light.position.set(20, 20, 0);
  scene.add(light);

  // geometry
  var geometry = new THREE.SphereGeometry(radius, 12, 8);

  // material
  var material = new THREE.MeshPhongMaterial({
    color: 0x00ffff,
    flatShading: true,
    transparent: true,
    opacity: 0.7,
  });

  // mesh
  group = new THREE.Object3D();
  mesh = new THREE.Mesh(geometry, material);
  group.add(mesh);
  scene.add(group);
}

function onDocumentMouseDown(event) {
  event.preventDefault();
  document.addEventListener('mousemove', onDocumentMouseMove, false);
  document.addEventListener('mouseup', onDocumentMouseUp, false);
  document.addEventListener('mouseout', onDocumentMouseOut, false);
  mouseXOnMouseDown = event.clientX - windowHalfX;
  targetRotationOnMouseDownX = targetRotationX;
  mouseYOnMouseDown = event.clientY - windowHalfY;
  targetRotationOnMouseDownY = targetRotationY;
}

function onDocumentMouseMove(event) {
  mouseX = event.clientX - windowHalfX;
  mouseY = event.clientY - windowHalfY;
  targetRotationY = targetRotationOnMouseDownY + (mouseY - mouseYOnMouseDown) * 0.02;
  targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDown) * 0.02;
}

function onDocumentMouseUp(event) {
  document.removeEventListener('mousemove', onDocumentMouseMove, false);
  document.removeEventListener('mouseup', onDocumentMouseUp, false);
  document.removeEventListener('mouseout', onDocumentMouseOut, false);
}

function onDocumentMouseOut(event) {
  document.removeEventListener('mousemove', onDocumentMouseMove, false);
  document.removeEventListener('mouseup', onDocumentMouseUp, false);
  document.removeEventListener('mouseout', onDocumentMouseOut, false);
}

function onDocumentTouchStart(event) {
  if (event.touches.length == 1) {
    event.preventDefault();
    mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
    targetRotationOnMouseDownX = targetRotationX;
    mouseYOnMouseDown = event.touches[0].pageY - windowHalfY;
    targetRotationOnMouseDownY = targetRotationY;
  }
}

function onDocumentTouchMove(event) {
  if (event.touches.length == 1) {
    event.preventDefault();
    mouseX = event.touches[0].pageX - windowHalfX;
    targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDown) * 0.05;
    mouseY = event.touches[0].pageY - windowHalfY;
    targetRotationY = targetRotationOnMouseDownY + (mouseY - mouseYOnMouseDown) * 0.05;
  }
}

function animate() {
  requestAnimationFrame(animate);
  rotate();
  renderer.render(scene, camera);
}

function rotate() {
  group.rotation.y += (targetRotationX - group.rotation.y) * 0.1;
  finalRotationY = (targetRotationY - group.rotation.x);
  if (group.rotation.x <= 1 && group.rotation.x >= -1) {
    group.rotation.x += finalRotationY * 0.1;
  }
  if (group.rotation.x > 1) {
    group.rotation.x = 1
  }
  if (group.rotation.x < -1) {
    group.rotation.x = -1
  }
}

定制旋转控件演示:https://jsfiddle.net/kmturley/6317jd95/11/ 另一个人的示例:http://projects.defmech.com/ThreeJSObjectRotationWithQuaternion/ 关于这些方法的讨论在three.js的GitHub项目中:https://github.com/mrdoob/three.js/issues/18476

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