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

2024-03-19

我正在为我们的 THREE.js 应用程序开发正交相机。本质上,该相机将以 2D 方式向用户呈现场景(用户可以选择在 2D 和 3D 相机之间切换)。该相机将允许平移和缩放到鼠标点。我可以进行平移,也可以进行缩放,但不能缩放到鼠标点。这是我的代码:

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;

会发生一些向鼠标点缩放的情况,但似乎不稳定。我想保持 2D 视图,因此当我缩放时,我也会移动相机(而不是使用非垂直目标,这会破坏 2D 效果)。

我从中得到了线索这个问题 https://stackoverflow.com/questions/23994206/zoom-to-object-in-threejs/30514984#30514984。据我所知,我已成功转换为 THREE.js 坐标mouse3D(见答案这个问题 https://stackoverflow.com/questions/11036106/three-js-projector-and-ray-objects).

那么,考虑到这个设置,我怎样才能平滑地缩放到鼠标点(mouse3D)使用正交相机并保持二维视图?提前致谢。


假设您有一个由世界坐标中的位置和观察点(或枢轴点)描述的相机,则缩放(或远离)特定点的核心是非常简单的。

你的表示似乎更简单:只是一个位置/距离对。我没有看到旋转组件,所以我假设你的相机是自上而下的正交相机。

在这种情况下,您的观察点(您不需要)只是(position.x, position.y - distance, position.z).

在一般情况下,您所需要做的就是将相机位置和观察点移向变焦点,同时保持相机法线(即方向)。请注意,无论投影类型或相机旋转如何,这都将起作用。编辑(2020/05/01):使用正交投影时,这不是您需要做的全部(请参阅底部的更新)。

如果您仔细想想,这正是您在 3D 中缩放某个点时所发生的情况。你一直看着同一个方向,但你越来越接近(但从未达到)你的目标。

例如,如果您想要缩放 1.1 倍,您可以想象将连接相机位置和缩放点的矢量缩放 1/1.1。

您可以通过简单地插值来做到这一点:

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;

正如我上面所说,在您的情况下,您实际上不需要更新观察点,然后计算新距离。您的新距离将是:

var newDistance = newPosition.y

应该可以做到这一点。

如果您想在位置/观察点和位置/缩放点对之间设置最小和最大距离限制,它只会变得更加复杂一点(主要是在一般情况下)。

更新(2020/05/01):

我刚刚意识到,上述内容虽然是正确的(除了缺少一个小但非常重要的步骤),但并不是对OP问题的完整答案。在正交模式下更改相机的位置当然不会改变正在渲染的图形的比例。为此,必须更新相机的投影矩阵(即必须更改正交投影的左、右、上、下参数)。

因此,许多图形库在其正交相机类中包含缩放因子,这正是这样做的。我没有使用 ThreeJS 的经验,但我认为该属性称为“缩放”。

所以,总结一下一切:

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

如果您想使用上面的正交相机类代码,您可能必须更改计算左、右、上和下的部分,并在计算中添加缩放因子。这是一个例子:

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)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

THREE.js 正交相机缩放到鼠标点 的相关文章

随机推荐

  • 数列识别

    从另一个问题发展而来 识别R中重复数字的序列 https stackoverflow com questions 7509381 identifying sequences of repeated numbers in r 15328802
  • 根据运行时条件在 Azure Pipeline 中执行或不执行模板

    我已经运行了 Azure Pipeline 现在 我想仅当运行时某个条件成立时才执行一系列步骤 Example steps template steps checkout yml some more steps here bash if s
  • 如何使用Nodejs从上传的ppt文件中获取幻灯片数量?

    我们可以从文件的属性中看到文件详细信息 如下图所示 我需要使用 Nodejs 或 Angularjs 以编程方式获得相同的细节 我不认为 Angularjs 可以完成文件操作 是否可以在节点中获取文件的相同信息 我猜 shellsjs 会支
  • ruby 中的三向比较

    确保 ruby 中三个变量全部相等的最简洁方法是什么 例如 dog animal cat animal chicken animal shoe clothing Something like this which doesn t work
  • 创建一个闭包

    我想创建一个闭包 函数生成器 来计算数字的幂 而不使用特定的 Clojure 库来完成此任务 现在 我可以用循环 重复来做到这一点 defn exp1 in num in exp multi loop num in num exp mult
  • 在 Shiny 应用程序中包含一个 javascript 文件

    我需要将 js 库包含到我的 Shiny 应用程序中 目前我使用 includeHTML 将脚本直接包含到 html 代码中 例如 includeHTML URL js 如果我使用tags script 例如 当我尝试浏览js文件时 浏览器
  • 如何将 JointJS 与使用 Angular CLI 构建的应用程序一起使用?

    我已经通过 npm 安装了 jointjs 并安装了 types 并且代码编译 构建良好 Code import Component from angular core import as joint from node modules j
  • 辅音和元音 Swift

    我是 Swift 的新手 谁能向我解释一下为什么我总是遇到这个问题 我正在使用 Xcode 6 4 但这是我的问题 我希望我能解决它 但我需要我的函数接受大字符串 然后返回 Tuple numVowels numConsonants 计算以
  • Virtualenv 没有名为 zlib 的模块

    我正在尝试在 Python2 6 下创建 Python 2 7 虚拟环境 我只是运行 virtualenv python python27 python27 correctly leads to my python installation
  • 仅解压缩特定扩展名

    我有一个包含 jpg png gif 图像的 zip 存档目录 我想解压缩每个存档 仅获取图像并将它们放入具有存档名称的文件夹中 So files archive1 zip files archive2 zip files archive3
  • JSF 2.0 注入不同范围的托管 bean

    我有一个无状态的控制器 负责处理表单 这被定义为ApplicationScoped 在我的页面上 我有一个与支持 bean 关联的表单 定义为ViewScoped 当我想处理表单时出现错误 serverError class com sun
  • 如何在 Blazor 客户端应用程序中使用 Bootstrap 模式?

    我正在尝试显示引导模式然后绑定其按钮 但我无法通过显示模式的第一步 我正在使用 net core 3 1 的 Blazor 客户端模板 我有一个名为 Modal razor 的页面 其中包含我从 getbootstrap com 找到的引导
  • 无法解决依赖关系 - Laravel

    照亮 合同 容器 BindingResolutionException 无法解析 App Jobs BudgetFetch 类中的依赖关系 参数 0 customerId namespace App Http Controllers use
  • 如何在ionic 3中进行水平滚动

    look at my 我在离子卷轴中有 10 个名字 但它像段落一样进入下一行 这是我的 html 代码
  • Cypress 在请求正文中使用文件进行 HTTP POST 时出错

    我从 Cypress 6 8 0 升级到 7 0 1 升级后 当 Cypress 测试之一调用此函数时 async saveTask task file const requestBody new FormData requestBody
  • 更新由 NSFetchedResultsController 管理且在第一部分有 1 个额外单元格的 UITableView

    主详细信息申请 我有一个UITableViewController由一个NSFetchedResultsController及其委托方法 我在表格视图的第一部分还有一个额外的单元格 其中有一个UIWebView其中显示嵌入视频 该单元格不属
  • 获取数组的一部分而不创建新副本

    我正在尝试找到一种解决方案 解决方法来切片非常大的数组而不创建新副本 这是我的问题 假设我有一个大小为 1 亿或更多的 double int 大型数组 我将代表不同事物的许多不同数组存储在一个非常大的数组中 以显着节省内存使用量 因此 我没
  • 如何为 wkwebview 使用 iOS 13 深色模式

    我正在使用 Xcode 11 beta 开发 iOS 13 有什么办法可以在网页视图上支持暗模式吗 我已经为除 WKWebviews 之外的所有其他视图创建了颜色集 如何更改深色模式的网页视图背景和文本颜色 假设您的问题是询问如何根据浅色模
  • 创建专用函数模板的最佳方法是什么?

    有更好的方法来执行以下操作吗 include
  • THREE.js 正交相机缩放到鼠标点

    我正在为我们的 THREE js 应用程序开发正交相机 本质上 该相机将以 2D 方式向用户呈现场景 用户可以选择在 2D 和 3D 相机之间切换 该相机将允许平移和缩放到鼠标点 我可以进行平移 也可以进行缩放 但不能缩放到鼠标点 这是我的