threejs - как повернуть объект относительно мыши на градус от его текущей центральной точки

У меня есть модель threejs в сцене, точка 0,0,0 которой находится в ее конце. Мне пришлось повернуть его так, чтобы его положение покоя находилось под нужным мне углом, и анимировать его в сцене, чтобы ни положение, ни поворот не были на 0,0,0. Кроме того, камера размещена и настроена так, чтобы смотреть на объект, поэтому ее положение и поворот были изменены.

Я хочу получить координаты мыши пользователя и просто повернуть модель вокруг своей центральной точки на мировой оси Y на определенное количество максимальных и минимальных градусов. Я знаю, как сопоставить координаты мыши с желаемым углом в градусах / радианах, но как мне сказать модели, что она должна вращаться?

Я пробовал model.rotation.y = [radians], и я предполагаю, что он вращается на основе той матрицы вращения, которая у него есть в настоящее время (или, по крайней мере, не так, как я ожидал). И если я сделаю rotateOnWorldAxis, он повернется из точки 0,0,0, в которую он был импортирован, а не там, где я хочу, чтобы он был, и, кроме того, не является абсолютным числом градусов (т.е. он поворачивается на 30 градусов от того места, где он находится. в настоящее время каждое движение мыши, а не на 30 градусов по исходной точке мира.

Как мне заставить его повернуться в его центральной точке на определенный угол относительно мировой оси Y?

Положение модели - {_x: 0, _y: -0.3, _z: -2}, ее вращение - {x: -2, y: 2.4, z: 0}. Положение камеры - {x: 0, y: 0, z: 5}, а вращение - {_x: 0.3926990816987242, _y: 0, _z: -0}.

Текущий код:

const target = this.mouseTarget;
const mouseX = clientX - this.halfWidth; //halfWidth is half the screen width, client X is the mouse e.clientX
const mouseY = clientY - this.halfHeight;
target.x += (mouseX - target.x) * 0.02;
target.y += (-mouseY - target.y) * 0.02;
target.z = this.camera.position.z; // assuming the camera is located at ( 0, 0, z );
const maxRotDeg = 30;
const maxRot = this.degToRad(maxRotDeg);
const rotVal = this.mapValue(
  target.x,
  -this.halfWidth,
  this.halfWidth,
  -maxRot,
  maxRot,
); //works to give me the radians that I want for rotation
//this.modelGroup.rotateOnWorldAxis(this.rotationAxisY, rotVal); //doesn't work
//this.modelGroup.lookAt(target); //doesn't work

person mheavers    schedule 12.05.2020    source источник


Ответы (1)


Самый простой общий способ повернуть любой объект в любом месте иерархии сцены вокруг произвольного центра вращения - это создать Object3D там, где вы хотите, чтобы этот центр вращения находился. Назовем это «точкой поворота». Затем возьмите вещь, которую хотите повернуть, attach ее в точку поворота. поверните pivotPoint, затем верните объект на место (повторно прикрепите его к предыдущему родительскому элементу). Другими словами

const pivotPoint = new THREE.Object3D();
pivotPoint.position.set(...);  // optional
pivotPoint.rotation.set(...);  // optional
someParent.add(pivotPoint)     

Затем, чтобы повернуть что-то другое вокруг этой точки

const parent = thingToRotate.parent;
pivotPoint.attach(thingToRotate);
pivotPoint.rotation.set( ... );    // do the rotation
parent.attach(thingToRotate);

Это наиболее общий способ поворота вокруг любой точки в любой ориентации, независимо от того, насколько глубоко в иерархии сцены находится thingToRotate.

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

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 50;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.set(0, 3, 3);
  camera.lookAt(0, 1, 0);

  const scene = new THREE.Scene();
  scene.background = new THREE.Color('white');

  [[-1, 2, 4], [1, 2, -3]].forEach(pos => {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(...pos);
    scene.add(light);
  });

  const boxWidth = 1;
  const boxHeight = 1;
  const boxDepth = 1;
  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);

  function makeInstance(parent, pos, rot, scale) {
    const material = new THREE.MeshPhongMaterial({color: Math.random() * 0xFFFFFF | 0});

    const mesh = new THREE.Mesh(geometry, material);
    parent.add(mesh);
    mesh.position.set(...pos);
    mesh.rotation.set(...rot);
    return mesh;
  }
  
  const m1 = makeInstance(scene, [0, 0, 0], [0, 0.7, 0]);
  const m2 = makeInstance(m1, [1, 1, 0], [0.3, 0.5, 0]); 
  const m3 = makeInstance(m1, [-1, 1, 0], [-0.9, 0.5, 0]); 
  const m4 = makeInstance(m2, [1, 1, 0], [-0.4, 1.3, 0.8]); 
  
  let thingToRotate = m3;

  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;
  }
  
  const pivotPoint = new THREE.Object3D();
  scene.add(pivotPoint);

  let then = 0;
  function render(now) {
    now *= 0.001;
    delta = now - then;
    then = now;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }
    
    {
       // put pivotPoint at origin of thingToRotate in world space
       // note: an object's origin might not be its center. If oyu
       // want its center you need to compute its center
       thingToRotate.getWorldPosition(pivotPoint.position);
       // reset rotation for pivotPoint
       pivotPoint.rotation.set(0, 0, 0);
       
       // rotate thingToRotate around pivotPoint's yAxis
       const parent = thingToRotate.parent;
       pivotPoint.attach(thingToRotate);
       pivotPoint.rotation.y = delta;
       parent.attach(thingToRotate);
    }
    
    m1.rotation.y -= delta * 0.1;

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  function setClick(selector, thing) {
    document.querySelector(selector).addEventListener('input', () => {
      thingToRotate = thing;
    });
  }
  setClick('#m1', m1);
  setClick('#m2', m2);
  setClick('#m3', m3);
  setClick('#m4', m4);
  
  requestAnimationFrame(render);
}

main();
body {
  margin: 0;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}
#ui {
  position: absolute;
  left: 0;
  top: 0;
}
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.min.js"></script>
<div id="ui">
<div><input type="radio" name="thing" id="m1"><label for="m1">m1</label></div>
<div><input type="radio" name="thing" id="m2"><label for="m2">m2</label></div>
<div><input type="radio" name="thing" id="m3" checked><label for="m3">m3</label></div>
<div><input type="radio" name="thing" id="m4"><label for="m4">m4</label></div>
</div>

Есть много других ярлыков, но для каждого из них нужно точно знать, как у вас настроена сцена.

Например, если вы единственное, что вам когда-либо захочется, это вращать объекты вокруг мировой оси Y, но сами эти объекты имеют вращение, затем родите их какому-нибудь другому Object3D, установите положение на Object3D и вращение объекта.

Пример: представьте, что у вас есть что-то ориентированное и вращающееся вот так

scene.add(thing);
thing.position.set(100, 200, 300);  // some arbitrary position
thing.rotation.set(1, 2, 3);        // some arbitrary rotation

Измените это на это

const helper = new THREE.Object3D();
scene.add(helper);
helper.position.set(100, 200, 300);  // some arbitrary position on helper
thing.rotation.set(1, 2, 3);         // some arbitrary rotation on thing

Теперь вы можете вращать helper.rotation.y, и объект будет вращаться вокруг своей исходной точки на мировой оси Y.

Если вы хотите повернуть объект вокруг центра, вам нужно вычислить его центр (center! = Origin, хотя они часто бывают одинаковыми) и добавить других помощников. См. эту статью в нижней части, где 3D-текст вращается вокруг своего центра, потому что его источник находится слева от текста.

В этой статье также рассматривается перемещение точек вращения путем добавления помощников, как указано выше.

person gman    schedule 12.05.2020