首页 > 解决方案 > 在特定的枢轴点旋转

问题描述

我正在尝试转动耳机组。它能够在我的模型(在 Maya 中)中做到这一点。但我似乎无法在 threejs 中弄清楚。

耳机枢轴

我知道我可以通过执行以下操作来旋转我的对象 XY 和 Z:

object.rotateX(THREE.Math.degToRad(degreeX));
object.rotateY(THREE.Math.degToRad(degreeY));
object.rotateZ(THREE.Math.degToRad(degreeZ));

但是,当其余部分旋转/移动时,如何保持枢轴点静止?所以在我的例子中,我希望耳机能够根据你在我的图片中看到的黑色螺丝左右移动。

标签: three.js

解决方案


将您的模型作为父模型,THREE.Object3D但要使其易于使用该SceneUtils.attach功能。

例子:

单击然后拖动,每次单击枢轴对象都会移动到该位置,然后模型(立方体)将通过调用附加到枢轴上THREE.SceneUtils.attach(model, scene, pivot)。当您松开鼠标时,模型将使用 分离THREE.SceneUtils.detach(model, pivot, scene)

'use strict';

/* global THREE */

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas: canvas});

  const fov = 45;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 100;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  // make the camera look down
  camera.position.set(0, 10, 0);
  camera.up.set(0, 0, -1);
  camera.lookAt(0, 0, 0);
  
  const scene = new THREE.Scene();
  scene.background = new THREE.Color('black');

  scene.add(new THREE.GridHelper(40, 40));
     
  let model;
  {
    const cubeSize = 3;
    const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
    const cubeMat = new THREE.MeshBasicMaterial({color: 'red'});
    model = new THREE.Mesh(cubeGeo, cubeMat);
    model.position.set(.5, .5, .5);
    scene.add(model);
  }

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  function render() {

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }
    
    renderer.render(scene, camera);
  }
  render();

  let rotate = false;
  const startPos = {x:0, y:0};
  const raycaster = new THREE.Raycaster();
  const pivot = new THREE.Object3D();  
  scene.add(pivot);
  pivot.add(new THREE.AxesHelper(.5));
  
  function setPivotPoint(e) {
    startPos.x = e.clientX;
    startPos.y = e.clientY;
    const normalizedPosition = {
      x: e.clientX / canvas.clientWidth  *  2 - 1,
      y: e.clientY / canvas.clientHeight * -2 + 1,
    };
    
    // this part is NOT important to the answer. The question
    // is how to rotate from some point. This code is picking
    // a point. Which point to pick was not part of the question
    // but to demo the solution it's important to pick a point
    
    // put the pivot where the mouse was clicked
    raycaster.setFromCamera(normalizedPosition, camera);
     
    const intersection = raycaster.intersectObjects(scene.children)[0];
    if (intersection) {
      if (rotate) {
        removeFromPivot();
      }
      pivot.position.copy(intersection.point);
      pivot.rotation.set(0,0,0);
      pivot.updateMatrixWorld();
      rotate = true;
      
      // this the important part. We're making the cube
      // a child of 'pivot' without it moving in world space
      THREE.SceneUtils.attach(model, scene, pivot);
      render();
    }
  }
  
  function rotatePivot(e) {
    e.preventDefault();
    if (rotate) {
      const dx = e.clientX - startPos.x;
      const dy = e.clientY - startPos.y;
      const maxDelta = Math.abs(dx) > Math.abs(dy) ? dx : dy;
      pivot.rotation.y = maxDelta * 0.01;
      render();
    }
  }
  
  function removeFromPivot() {
    if (rotate) {
      rotate = false;
      THREE.SceneUtils.detach(model, pivot, scene);
      window.removeEventListener('mousemove', rotatePivot);
      window.removeEventListener('mouseup', removeFromPivot);
    }
  }
  
  canvas.addEventListener('mousedown', (e) => {
    e.preventDefault();
    setPivotPoint(e);
    if (rotate) {
      window.addEventListener('mousemove', rotatePivot);
      window.addEventListener('mouseup', removeFromPivot);
    }
  });
}

main();
html, body {
  margin: 0;
  height: 100%;
}
#c {
  width: 100%;
  height: 100%;
  display: block;
}
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r98/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r98/js/utils/SceneUtils.js"></script>


推荐阅读