无论相机的方向如何,如何旋转相同的物体?

How to rotate the object the same regardless of the direction of the camera?

我需要根据相机的方向沿世界轴旋转对象,以便在改变相机方向时旋转保持不变。

在下面的代码中,您可以沿世界轴旋转球体,但是当相机旋转时,旋转将是相同的,这不是我需要的。旋转球体时如何考虑相机的方向?

const viewport = { width: window.innerWidth, height: window.innerHeight };

// scene preparation
let canvas, renderer, camera, scene, controls;

{
  renderer = new THREE.WebGLRenderer();
  renderer.setSize(viewport.width, viewport.height);
  renderer.setPixelRatio(window.devicePixelRatio);
  canvas = renderer.domElement;
  document.body.appendChild(canvas);
  document.body.style.margin = '0px';
}

{
  const fov = 45;
  const aspect = viewport.width / viewport.height;
  const near = 1;
  const far = 100;
  camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.lookAt(0, 0, 0);
  camera.position.z = 10;
}

{
  scene = new THREE.Scene();
}

{
  controls = new THREE.OrbitControls(camera, canvas);
  controls.enableDamping = false;
  controls.enableZoom = true;
  controls.enableRotate = false;
  controls.enablePan = false;
  controls.autoRotate = true;
}

// adding scene objects
let axesHelper, light, light1, light2, sphere, texture;

{
  axesHelper = new THREE.AxesHelper(10);
  scene.add(axesHelper);
}

{
  light = new THREE.HemisphereLight(0xffffff, 0x000000);
  light1 = new THREE.PointLight(0xffffff);
  light1.position.set(10, 0, 0);
  light2 = new THREE.PointLight(0xffffff);
  light2.position.set(-10, 0, 0);
  scene.add(light);
  scene.add(light1);
  scene.add(light2);
}

{
  texture = new THREE.TextureLoader().load('https://threejs.org/manual/examples/resources/images/wall.jpg');
  const geometry = new THREE.SphereBufferGeometry(5, 32, 16);
  const material = new THREE.MeshPhongMaterial({ color: 0xff0000, map: texture });
  sphere = new THREE.Mesh(geometry, material);
  scene.add(sphere);
}

// sphere rotation
const prevCoords = new THREE.Vector2();
const deltaCoords = new THREE.Vector2();
function handleEvent(event) {
  const isFirst = event.type === 'mousedown';
  const isLast = event.type === 'mouseup';
  if(isFirst) {
    this.moving = true;
    prevCoords.set(event.clientX, event.clientY);
  }
  else if(isLast) {
    this.moving = false;
  }
  else if(!this.moving) {
    return;
  }
  deltaCoords.set(event.clientX - prevCoords.x, event.clientY - prevCoords.y);
  rotateSphere();
  prevCoords.set(event.clientX, event.clientY);
}
const vector = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
let axis, angle;
function rotateSphere() {
  // camera.getWorldDirection(vector);
  // quaternion.setFromAxisAngle(vector, deltaCoords.x * 0.01);
  // sphere.quaternion.premultiply(quaternion);
  
  sphere.rotateOnWorldAxis(new THREE.Vector3(1, 0, 0), deltaCoords.y * 0.001);
  sphere.rotateOnWorldAxis(new THREE.Vector3(0, 1, 0), deltaCoords.x * 0.001);
}
window.addEventListener('mousedown', handleEvent);
window.addEventListener('mousemove', handleEvent);
window.addEventListener('mouseup', handleEvent);

// scene rendering
function loop(time) {
  controls.update();
  renderer.render(scene, camera);
  window.requestAnimationFrame(loop);
}
window.requestAnimationFrame(loop);
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

我找到了如何获取相机方向:

camera.getWorldDirection(vector);

但是我不明白当相机方向改变时如何使用这个方向向量来固定轴变化

我不知道我到底想达到什么目的。我认为您想围绕视图 space 中的 x 轴而不是世界 space 中的 x 轴旋转。使用相机对象和 .localToWorld 转换矢量形式的世界 space 以查看 space:

let xAxis = camera.localToWorld(new THREE.Vector4(1, 0, 0, 0));
sphere.rotateOnWorldAxis(xAxis, deltaCoords.y * 0.001);

const viewport = { width: window.innerWidth, height: window.innerHeight };

// scene preparation
let canvas, renderer, camera, scene, controls;

{
    renderer = new THREE.WebGLRenderer();
    renderer.setSize(viewport.width, viewport.height);
    renderer.setPixelRatio(window.devicePixelRatio);
    canvas = renderer.domElement;
    document.body.appendChild(canvas);
    document.body.style.margin = '0px';
}

{
    const fov = 45;
    const aspect = viewport.width / viewport.height;
    const near = 1;
    const far = 100;
    camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
    camera.lookAt(0, 0, 0);
    camera.position.z = 10;
}

{
    scene = new THREE.Scene();
}

{
    controls = new THREE.OrbitControls(camera, canvas);
    controls.enableDamping = false;
    controls.enableZoom = true;
    controls.enableRotate = false;
    controls.enablePan = false;
    controls.autoRotate = true;
}

// adding scene objects
let axesHelper, light, light1, light2, sphere, texture;

{
    axesHelper = new THREE.AxesHelper(10);
    scene.add(axesHelper);
}

{
    light = new THREE.HemisphereLight(0xffffff, 0x000000);
    light1 = new THREE.PointLight(0xffffff);
    light1.position.set(10, 0, 0);
    light2 = new THREE.PointLight(0xffffff);
    light2.position.set(-10, 0, 0);
    scene.add(light);
    scene.add(light1);
    scene.add(light2);
}

{
    texture = new THREE.TextureLoader().load('https://threejs.org/manual/examples/resources/images/wall.jpg');
    const geometry = new THREE.SphereBufferGeometry(5, 32, 16);
    const material = new THREE.MeshPhongMaterial({ color: 0xff0000, map: texture });
    sphere = new THREE.Mesh(geometry, material);
    scene.add(sphere);
}

// sphere rotation
const prevCoords = new THREE.Vector2();
const deltaCoords = new THREE.Vector2();
function handleEvent(event) {
    const isFirst = event.type === 'mousedown';
    const isLast = event.type === 'mouseup';
    if (isFirst) {
        this.moving = true;
        prevCoords.set(event.clientX, event.clientY);
    }
    else if (isLast) {
        this.moving = false;
    }
    else if (!this.moving) {
        return;
    }
    deltaCoords.set(event.clientX - prevCoords.x, event.clientY - prevCoords.y);
    rotateSphere();
    prevCoords.set(event.clientX, event.clientY);
}
const vector = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
let axis, angle;
function rotateSphere() {
    // camera.getWorldDirection(vector);
    // quaternion.setFromAxisAngle(vector, deltaCoords.x * 0.01);
    // sphere.quaternion.premultiply(quaternion);

    let xAxis = camera.localToWorld(new THREE.Vector4(1, 0, 0, 0));
    sphere.rotateOnWorldAxis(xAxis, deltaCoords.y * 0.001);
    sphere.rotateOnWorldAxis(new THREE.Vector3(0, 1, 0), deltaCoords.x * 0.001);
}
window.addEventListener('mousedown', handleEvent);
window.addEventListener('mousemove', handleEvent);
window.addEventListener('mouseup', handleEvent);

// scene rendering
function loop(time) {
    controls.update();
    renderer.render(scene, camera);
    window.requestAnimationFrame(loop);
}
window.requestAnimationFrame(loop);
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>