threejs-如何将与鼠标有关的对象从其当前中心点旋转到一个度设置 [英] threejs - how to rotate an object in relation to mouse to a degree setting from its current center point

查看:183
本文介绍了threejs-如何将与鼠标有关的对象从其当前中心点旋转到一个度设置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在一个场景中有一个threejs模型,其终点是0,0,0点.我必须旋转它,以便它的静止位置处于我想要的角度,并将其设置为场景动画,因此该位置和旋转均不为0,0,0.此外,已将相机定位并设置为注视对象,因此其位置和旋转已更改.

I have a threejs model in a scene whose 0,0,0 point is at its end. I've had to rotate it so that its resting position is at the angle I want, and animate it into the scene, so neither the position nor the rotation is at 0,0,0. Furthermore, the camera has been positioned and set to look at the object, so its position and rotation have been changed.

我想获取用户的鼠标坐标,只是让模型围绕其在世界Y轴上的中心点旋转一定数量的最大和最小度数.我知道如何将鼠标坐标映射到所需的度数/弧度角,但是如何告诉模型旋转?

I want to get the user's mouse coordinates, and just have the model rotate around its center point on a world Y axis a certain number of max and min degrees. I know how to map the mouse coordinates to the degree / radian angle I want, but how do I tell the model to rotate?

我已经尝试过 model.rotation.y = [弧度] ,并且我假设它根据当前具有的旋转矩阵旋转(或者至少不是我期望的方式).如果我执行 rotateOnWorldAxis ,它会从导入它的0,0,0点开始旋转,这不是我想要的位置,而且不是绝对的度数(即每次鼠标移动时从当前位置旋转30度,而不是在世界原点上旋转30度.

I've tried model.rotation.y = [radians], and it rotates, I'm assuming, based on whatever rotation matrix it currently has (or at the very least, not the way I expect it to). And if I do rotateOnWorldAxis it rotates from its 0,0,0 point at which it was imported, which not where I want it to be, and furthermore isn't an absolute number of degrees (i.e. it rotates 30 degrees from where it's at currently each mouse move, rather than to 30 degrees on the world origin.

如何使其在世界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} .

Model position is at {_x: 0, _y: -0.3, _z: -2} and its rotation is at {x: -2, y: 2.4, z: 0} Camera position is {x: 0, y: 0, z: 5} and rotation {_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

推荐答案

在场景层次结构中围绕任意旋转中心旋转任何对象的最简单的 generic 方法是制作一个 Object3D您希望旋转中心位于的位置.我们称其为"pivotPoint".然后拿起您想旋转的东西,将其附加到pivotPoint.旋转pivotPoint,然后将对象放回原处(将其重新附加到先前的父对象).换句话说

The simplest generic way to rotate any object anywhere in the scene hierarchy around some arbitrary rotation center is to make an Object3D where you want that rotation center to be. Let's call it the "pivotPoint". Then take the thing you want to rotate, attach it to the pivotPoint. rotate the pivotPoint, then put the object back where it was (re-attach it to it's previous parent). In other words

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

然后围绕该点旋转其他东西

Then to rotate some other thing around that point

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

这是在任何方向上绕任意点旋转的最通用的方法,而不管thingToRotate在场景层次结构中有多深.

That is the most generic way to rotate around any point in any orientation regardless of how deep in the scene hierarchy the thingToRotate is.

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>

还有许多其他快捷方式,但是每个快捷方式都需要确切了解场景设置.

There are lots other shortcuts but each one requires knowing exactly how you have your scene setup.

例如,如果您唯一想做的就是绕着世界Y轴旋转物体,但是这些物体本身具有旋转能力,然后将它们作为其他 Object3D 的父元素,则在 Object3D 和事物上的旋转.

For example if you the only thing you ever want to do is rotate things around the world Y axis but those things themselves have rotation then parent them to some other Object3D, set the position on the Object3D and the rotation on the thing.

示例:假设您有一些东西像这样定向和旋转

Example: Imagine you had some thing oriented and rotated like this

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轴上旋转.

Now you can rotate helper.rotation.y and thing will rotate around its origin at the world Y axis.

如果要围绕某个对象的中心旋转,则需要计算其中心(尽管中心常常是相同的!=原始点)并添加其他辅助对象.请参阅这篇文章,使底部3d文字围绕其中心旋转,因为它的起源在文本的左侧.

If you want to rotate around the center of some object then you need to compute its center (center != origin though they are often the same) and add other helpers. See this article toward the bottom where it makes 3d text rotate around its center because its origin is on the left off the text.

本文还介绍了通过添加上述辅助对象来移动旋转点的方法.

This article also covers moving rotation points by adding helpers like above.

这篇关于threejs-如何将与鼠标有关的对象从其当前中心点旋转到一个度设置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆