简体   繁体   English

THREE.js 正交相机缩放到鼠标点

[英]THREE.js orthographic camera zoom to mouse point

I'm working on an orthographic camera for our THREE.js app.我正在为我们的 THREE.js 应用程序开发正交相机。 Essentially, this camera will present the scene to the user in 2D (users have the option of switching between the 2D and 3D camera).本质上,该相机将以 2D 形式向用户呈现场景(用户可以选择在 2D 和 3D 相机之间切换)。 This camera will allow for panning and zooming to mouse point.该相机将允许平移和缩放到鼠标点。 I have the panning working, and I have zooming working, but not zooming to mouse point.我有平移工作,我有缩放工作,但没有缩放到鼠标点。 Here's my code:这是我的代码:

import React from 'react';
import T from 'three';

let panDamper = 0.15;

let OrthoCamera = React.createClass({
  getInitialState: function () {
    return {
      distance: 150,
      position: { x: 8 * 12, y: 2 * 12, z: 20 * 12 },
    };
  },
  getThreeCameraObject: function () {
    return this.camera;
  },
  applyPan: function (x, y) { // Apply pan by changing the position of the camera
    let newPosition = {
      x: this.state.position.x + x * -1 * panDamper,
      y: this.state.position.y + y * panDamper,
      z: this.state.position.z
    };

    this.setState({position: newPosition});
  },
  applyDirectedZoom: function(x, y, z) {
    let zoomChange = 10;
    if(z < 0) zoomChange *= -1;
    let newDistance = this.state.distance + zoomChange;

    let mouse3D = {
      x: ( x / window.innerWidth ) * 2 - 1,
      y: -( y / window.innerHeight ) * 2 + 1
    };

    let newPositionVector = new T.Vector3(mouse3D.x, mouse3D.y, 0.5);
    newPositionVector.unproject(this.camera);
    newPositionVector.sub(this.camera.position);

    let newPosition = {
      x: newPositionVector.x,
      y: newPositionVector.y,
      z: this.state.position.z
    };

    this.setState({
      distance: newDistance,
      position: newPosition
    });
  },
  render: function () {
    let position = new T.Vector3(this.state.position.x, this.state.position.y, this.state.position.z);

    let left = (this.state.distance / -2) * this.props.aspect + this.state.position.x;
    let right = (this.state.distance / 2) * this.props.aspect + this.state.position.x;
    let top = (this.state.distance / 2) + this.state.position.y;
    let bottom = (this.state.distance / -2) + this.state.position.y;

    // Using react-three-renderer
    // https://github.com/toxicFork/react-three-renderer
    return <orthographicCamera
      {...(_.pick(this.props, ['near', 'far', 'name']))}
      position={position}
      left={left}
      right={right}
      top={top}
      bottom={bottom}
      ref={(camera) => this.camera = camera}/>
  }
});

module.exports = OrthoCamera;

Some zooming towards the mouse point happens but it seems erratic.向鼠标点进行了一些缩放,但似乎不稳定。 I want to keep a 2D view, so as I zoom, I also move the camera (rather than having a non-perpendicular target, which kills the 2D effect).我想保持 2D 视图,因此在缩放时,我也会移动相机(而不是使用非垂直目标,这会破坏 2D 效果)。

I took cues from this question .我从这个问题中得到了提示。 As far as I can tell, I am successfully converting to THREE.js coordinates in mouse3D (see the answer to this question ).至于我可以告诉大家,我成功地转换为three.js所坐标mouse3D (见回答这个问题)。

So, given this setup, how can I smoothly zoom to the mouse point ( mouse3D ) using the orthographic camera and maintaining a two dimensional view?那么,鉴于此设置,如何使用正交相机平滑缩放到鼠标点 ( mouse3D ) 并保持二维视图? Thanks in advance.提前致谢。

Assuming you have a camera that is described by a position and a look-at (or pivot) point in world coordinates, zooming at (or away from) a specific point is quite simple at its core.假设您有一个由世界坐标中的位置和观察(或枢轴)点描述的相机,缩放(或远离)特定点的核心非常简单。

Your representation seems to be even simpler: just a position/distance pair.您的表示似乎更简单:只是一个位置/距离对。 I didn't see a rotation component, so I'll assume your camera is meant to be a top-down orthographic one.我没有看到旋转组件,所以我假设你的相机是一个自上而下的正交相机。

In that case, your look-at point (which you won't need) is simply (position.x, position.y - distance, position.z) .在这种情况下,您的观察点(您不需要)只是(position.x, position.y - distance, position.z)

In the general case, all you need to do is move both the camera position and the look-at point towards the zoom-at point while preserving the camera normal (ie direction).在一般情况下,您需要做的就是将相机位置和观察点移向缩放点,同时保持相机法线(即方向)。 Note that this will work regardless of projection type or camera rotation.请注意,无论投影类型或相机旋转如何,这都将起作用。 EDIT (2020/05/01): When using an orthographic projection, this is not all you need to do (see update at the bottom).编辑(2020/05/01):使用正交投影时,这不是您需要做的全部(请参阅底部的更新)。

If you think about it, this is exactly what happens when you're zooming at a point in 3D.如果您仔细想想,这正是在 3D 中缩放某个点时会发生的情况。 You keep looking at the same direction, but you move ever closer (without ever reaching) your target.你一直在看同一个方向,但你离目标越来越近(从未达到)。

If you want to zoom by a factor of 1.1 for example, you can imagine scaling the vector connecting your camera position to your zoom-at point by 1/1.1.例如,如果您想放大 1.1 倍,您可以想象将连接相机位置和放大点的矢量放大 1/1.1。

You can do that by simply interpolating:你可以通过简单的插值来做到这一点:

var newPosition = new THREE.Vector3();
newPosition.x = (orgPosition.x - zoomAt.x) / zoomFactor + zoomAt.x;
newPosition.y = (orgPosition.y - zoomAt.y) / zoomFactor + zoomAt.y;
newPosition.z = (orgPosition.z - zoomAt.z) / zoomFactor + zoomAt.z;

As I said above, in your case you won't really need to update a look-at point and then calculate the new distance.正如我上面所说,在您的情况下,您实际上不需要更新观察点然后计算新距离。 Your new distance will simply be:您的新距离将是:

var newDistance = newPosition.y

That should do it.那应该这样做。

It only gets a little bit more sophisticated (mainly in the general case) if you want to set minimum and maximum distance limits both between the position/look-at and position/zoom-at point pairs.如果您想在位置/观察点和位置/缩放点对之间设置最小和最大距离限制,它只会变得更加复杂(主要是在一般情况下)。

UPDATE (2020/05/01):更新(2020/05/01):

I just realized that the above, although correct (except for missing one minor but very important step) is not a complete answer to OP's question.我刚刚意识到,以上虽然是正确的(除了遗漏了一个次要但非常重要的步骤)并不是对 OP 问题的完整答案。 Changing the camera's position in orthographic mode won't of course change the scale of graphics being rendered.在正交模式下更改相机的位置当然不会更改正在渲染的图形的比例。 For that, the camera's projection matrix will have to be updated (ie the left, right, top and bottom parameters of the orthographic projection will have to be changed).为此,必须更新相机的投影矩阵(即必须更改正交投影的左、右、上和下参数)。

For this reason, many graphics libraries include a scaling factor in their orthographic camera class, which does exactly that.出于这个原因,许多图形库在它们的正交相机类中包含一个缩放因子,这正是这样做的。 I don't have experience with ThreeJS, but I think that property is called 'zoom'.我没有使用 ThreeJS 的经验,但我认为该属性称为“缩放”。

So, summing everything up:所以,总结一下:

var newPosition = new THREE.Vector3();
newPosition.x = (orgPosition.x - zoomAt.x) / zoomFactor + zoomAt.x;
newPosition.y = (orgPosition.y - zoomAt.y) / zoomFactor + zoomAt.y;
newPosition.z = (orgPosition.z - zoomAt.z) / zoomFactor + zoomAt.z;
myCamera.zoom = myCamera.zoom * zoomFactor
myCamera.updateProjectionMatrix()

If you want to use your orthographic camera class code above instead, you will probably have to change the section that computes left, right, top and bottom and add a scaling factor in the calculation.如果您想改用上面的正交相机类代码,您可能需要更改计算左、右、上和下的部分,并在计算中添加缩放因子。 Here's an example:下面是一个例子:

var aspect = this.viewportWidth / this.viewportHeight
var dX     = (this.right - this.left)
var dY     = (this.top   - this.bottom) / aspect
var left   = -dX / (2 * this.scale)
var right  =  dX / (2 * this.scale)
var bottom = -dY / (2 * this.scale)
var top    =  dY / (2 * this.scale)
mat4.ortho(this.mProjection, left, right, bottom, top, this.near, this.far)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM