【问题标题】:How to rotate the object the same regardless of the direction of the camera?无论相机的方向如何,如何旋转相同的对象?
【发布时间】:2021-12-04 12:45:09
【问题描述】:

我需要在考虑相机方向的情况下沿世界轴旋转对象,以便在改变相机方向时旋转保持不变。

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

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);

但是我不明白如何使用这个方向向量来修复相机方向变化时的轴变化

【问题讨论】:

  • @Rabbid76 因为在第一个问题中,最初的描述都很糟糕。在您提出的问题中,用户想要沿世界轴旋转对象,我还需要考虑相机的坐标和方向

标签: javascript three.js quaternions


【解决方案1】:

我不知道自己想要达到什么目标。我认为您想在视图空间中围绕 x 轴旋转,而不是在世界空间中围绕 x 轴旋转。使用相机对象和.localToWorld 将向量从世界空间转换为视图空间:

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>

【讨论】:

  • 哦,是的,这就是我需要的。我正在写一个简单的游戏,并试图整天这样做,但你的解决方案结果很简单。非常感谢。
猜你喜欢
  • 1970-01-01
  • 2019-01-26
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多