在特定的枢轴点旋转

时间:2018-11-27 16:12:18

标签: three.js

我正在尝试旋转耳机的一部分。它可以在我的模型(在Maya中)中做到这一点。但是我似乎无法在threejs中弄清楚。

headphone pivot

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

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

但是,当其余部分旋转/移动时,如何使枢轴点保持静止?因此,在我的示例中,我希望听筒能够根据您在图片中看到的黑色螺丝在左右移动。

2 个答案:

答案 0 :(得分:1)

您可以将耳机网格嵌套在另一个THREE.Group内,将耳机重新放置在该组中,以使轴心位于所需位置,然后旋转父对象。

// You take your headphones and nest them inside a Group
var headphones = new THREE.Mesh(geom, material);
var parent = new THREE.Group();
parent.add(headphones);

// Then you move your headphones to the desired pivot position
headphones.position.set(-5, 0.1, 0);

// Parent is going to rotate around it origin
parent.rotateX(THREE.Math.degToRad(degreeX));

请注意,如果您希望将轴心放在(5, -0.1, 0)上,则应沿相反方向移动耳机:(-5, 0.1, 0)

答案 1 :(得分:1)

将您的模型与另一个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>