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

查看:168
本文介绍了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 是屏幕宽度的一半,客户端 X 是鼠标 e.clientXconst mouseY = clientY - this.halfHeight;target.x += (mouseX - target.x) * 0.02;target.y += (-mouseY - target.y) * 0.02;target.z = this.camera.position.z;//假设相机位于 ( 0, 0, z );const maxRotDeg = 30;const maxRot = this.degToRad(maxRotDeg);const rotVal = this.mapValue(目标.x,-this.halfWidth,this.halfWidth,-maxRot,最大旋转,);//工作给我我想要旋转的弧度//this.modelGroup.rotateOnWorldAxis(this.rotationAxisY, rotVal);//不起作用//this.modelGroup.lookAt(目标);//不起作用

解决方案

最简单的通用方法是围绕某个任意旋转中心旋转场景层次结构中任何位置的任何对象的Object3D 您希望旋转中心所在的位置.我们称之为枢轴点".然后把你想旋转的东西,attach 放到pivotPoint 上.旋转pivotPoint,然后将对象放回原来的位置(将其重新附加到它之前的父对象).换句话说

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

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

const parent = thingToRotate.parent;pivotPoint.attach(thingToRotate);pivotPoint.rotation.set( ... );//进行旋转parent.attach(thingToRotate);

无论 thingToRotate 在场景层次结构中的深度如何,这是以任何方向围绕任何点旋转的最通用方式.

function main() {const canvas = document.querySelector('#c');const renderer = new THREE.WebGLRenderer({canvas});常量 fov = 75;常量方面 = 2;//画布默认常量接近 = 0.1;常量远 = 50;const camera = new THREE.PerspectiveCamera(fov,aspect,near,far);相机位置设置(0、3、3);相机.lookAt(0, 1, 0);const 场景 = 新的 THREE.Scene();Scene.background = new THREE.Color('white');[[-1, 2, 4], [1, 2, -3]].forEach(pos => {常量颜色 = 0xFFFFFF;常量强度 = 1;const light = new THREE.DirectionalLight(颜色,强度);light.position.set(...pos);场景.添加(光);});const boxWidth = 1;const boxHeight = 1;const boxDepth = 1;const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);功能makeInstance(父,位置,腐烂,规模){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);返回网格;}const m1 = makeInstance(场景, [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]);让 thingToRotate = m3;函数 resizeRendererToDisplaySize(renderer) {const canvas = renderer.domElement;const width = canvas.clientWidth;常量高度 = canvas.clientHeight;const needResize = canvas.width !== width ||canvas.height !== 高度;如果(需要调整大小){renderer.setSize(width, height, false);}返回需要调整大小;}const pivotPoint = new THREE.Object3D();场景.添加(枢轴点);让然后= 0;函数渲染(现在){现在 *= 0.001;delta = 现在 - 然后;然后=现在;如果(resizeRendererToDisplaySize(渲染器)){const canvas = renderer.domElement;camera.aspect = canvas.clientWidth/canvas.clientHeight;相机.updateProjectionMatrix();}{//将 pivotPoint 置于世界空间中 thingToRotate 的原点//注意:对象的原点可能不是它的中心.如果 oyu//想要它的中心,你需要计算它的中心thingToRotate.getWorldPosition(pivotPoint.position);//重置枢轴点的旋转pivotPoint.rotation.set(0, 0, 0);//围绕pivotPoint的y轴旋转thingToRotateconst parent = thingToRotate.parent;pivotPoint.attach(thingToRotate);pivotPoint.rotation.y = delta;parent.attach(thingToRotate);}m1.rotation.y -= delta * 0.1;renderer.render(场景,相机);请求动画帧(渲染);}函数 setClick(选择器,事物){document.querySelector(selector).addEventListener('input', () => {thingToRotate = 东西;});}setClick('#m1', m1);setClick('#m2', m2);setClick('#m3', m3);setClick('#m4', m4);请求动画帧(渲染);}main();

body {边距:0;}#C {宽度:100vw;高度:100vh;显示:块;}#ui {位置:绝对;左:0;顶部: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>

还有很多其他快捷方式,但每一种都需要准确了解您的场景设置方式.

例如,如果您唯一想做的就是围绕世界 Y 轴旋转事物,但这些事物本身具有旋转性,然后将它们作为其他 Object3D 的父对象,请在 Object3D 上设置位置code>Object3D 和物体的旋转.

示例:想象一下你有一些像这样定向和旋转的东西

scene.add(thing);thing.position.set(100, 200, 300);//一些任意位置thing.rotation.set(1, 2, 3);//一些任意旋转

改成这个

const helper = new THREE.Object3D();场景添加(助手);helper.position.set(100, 200, 300);//helper 上的一些任意位置thing.rotation.set(1, 2, 3);//对事物进行一些任意旋转

现在您可以旋转 helper.rotation.y 并且物体将在世界 Y 轴上围绕其原点旋转.

如果你想围绕某个对象的中心旋转,那么你需要计算它的中心(中心!=原点,尽管它们通常是相同的)并添加其他助手.请参阅这篇文章的底部,它使 3d 文本围绕其中心旋转,因为它的原点在文本的左边.

这篇文章还介绍了通过添加如上的助手来移动旋转点.

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.

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?

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.

How do I get it to rotate on its center point to a certain degree angle on the world Y axis?

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}.

Current code is:

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

解决方案

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

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.

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

Change it to this

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

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

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天全站免登陆