2D 缩放到 webgl 中的点

2024-03-05

我正在尝试使用 WebGL (更具体地说,是 regl)创建 2D 图形可视化。通过我当前的实现,我已经可以看到力布局应用于每个节点,这很好。当我尝试相对于当前鼠标位置进行缩放时,问题就出现了。根据我的研究,要实现这种行为,需要按以下顺序应用矩阵变换:

translate(nodePosition, mousePosition)
scale(scaleFactor)
translate(nodePosition, -mousePosition)

所以,每次wheel触发事件,重新计算鼠标位置,并使用新的鼠标位置信息更新变换矩阵。 目前的行为很奇怪,我似乎不明白出了什么问题。这是一个活生生的例子 https://codesandbox.io/s/922pkr64jw?module=%2Fsrc%2Findex.js.

显然,如果我将鼠标固定在初始位置进行放大和缩小,一切都会正常工作。但是,如果我移动鼠标并尝试将焦点放在另一个节点上,则会失败。

检索鼠标位置的函数是:

const getMousePosition = (event) => {
    var canvas = event.currentTarget
    var rect = canvas.getBoundingClientRect()
    var x = event.clientX - rect.left
    var y = event.clientY - rect.top
    var projection = mat3.create()
    var pos = vec2.fromValues(x,y)
    // this converts the mouse coordinates from 
    // pixel space to WebGL clipspace
    mat3.projection(projection, canvas.clientWidth, canvas.clientHeight)
    vec2.transformMat3(pos, pos, projection)
    return(pos)
}

The wheel事件监听器回调:

var zoomFactor = 1.0
var mouse = vec2.fromValues(0.0, 0.0)
options.canvas.addEventListener("wheel", (event) => {
    event.preventDefault()
    mouse = getMousePosition(event)
    var direction = event.deltaY < 0 ? 1 : -1
    zoomFactor = 1 + direction * 0.1
    updateTransform()
})

以及更新变换的函数:

var transform = mat3.create()
function updateTransform() {
    var negativeMouse = vec2.create()
    vec2.negate(negativeMouse, mouse)
    mat3.translate(transform, transform, mouse)
    mat3.scale(transform, transform, [zoomFactor, zoomFactor])
    mat3.translate(transform, transform, negativeMouse)
}

This transform矩阵在顶点着色器中作为统一变量提供:

  precision highp float;
  attribute vec2 position;

  uniform mat3 transform;

  uniform float stageWidth;
  uniform float stageHeight;

  vec2 normalizeCoords(vec2 position) {
    float x = (position[0]+ (stageWidth  / 2.0));
    float y = (position[1]+ (stageHeight / 2.0));

    return vec2(
        2.0 * ((x / stageWidth ) - 0.5),
      -(2.0 * ((y / stageHeight) - 0.5))
    );
  }

  void main () {
    gl_PointSize = 7.0;
    vec3 final = transform * vec3(normalizeCoords(position), 1);
    gl_Position = vec4(final.xy, 0, 1);
  }

where, position是保存节点位置的属性。

到目前为止我已经尝试过:

  • 我已经尝试更改转换的顺序。结果更奇怪。
  • 当我独立应用平移或缩放时,一切看起来都很好。

这是我第一次与不常见的 SVG/canvas 东西进行交互。解决方案可能很明显,但我真的不知道该去哪里寻找。我究竟做错了什么?

更新 06/11/2018

我遵循@Johan的建议并在现场演示 https://codesandbox.io/s/922pkr64jw?module=%2Fsrc%2Findex.js。虽然解释颇有说服力,但结果却不太符合我的预期。反转变换以获取模型空间中的鼠标位置的想法对我来说很有意义,但我的直觉(可能是错误的)表明直接在屏幕空间上应用变换也应该可行。为什么我不能将节点和鼠标都投影到屏幕空间中并直接在那里应用变换?

更新 07/11/2018

经过一番挣扎后,我决定采取不同的方法并调整解决方案这个答案 https://stackoverflow.com/a/42437153/5288378对于我的用例。尽管缩放功能按预期工作(还添加了平移),但我仍然相信有些解决方案根本不依赖于 d3-zoom。也许隔离视图矩阵并独立控制它以实现预期的行为,如评论中所建议的。要查看我当前的解决方案,请检查下面我的答案。


好吧,在原始方法失败后,我设法使这个解决方案 https://stackoverflow.com/a/42437153/5288378适合我的用例。

The updateTransform现在的功能是:

var transform = mat3.create();
function updateTransform(x, y, scale) {
    mat3.projection(transform, options.canvas.width, options.canvas.height);
    mat3.translate(transform, transform, [x,y]);
    mat3.scale(transform, transform, [scale,scale]);
    mat3.translate(transform, transform, [
      options.canvas.width / 2,
      options.canvas.height / 2
    ]);
    mat3.scale(transform, transform, [
      options.canvas.width / 2,
      options.canvas.height / 2
    ]);
    mat3.scale(transform, transform, [1, -1]);
}

并由 d3-zoom 调用:

import { zoom as d3Zoom } from "d3-zoom";
import { select } from "d3-selection";

var zoom = d3Zoom();

d3Event = () => require("d3-selection").event;

select(options.canvas)
      .call(zoom.on("zoom", () => {
          var t = d3Event().transform
          updateTransform(t.x, t.y, t.k)
       }));

Here https://codesandbox.io/s/x2wzn3v1yz是该解决方案的现场演示。

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

2D 缩放到 webgl 中的点 的相关文章

随机推荐

  • 启用自定义键盘 iOS8 的应用内购买

    我正在为 iOS 构建自定义键盘 我想知道如何启用应用内购买 该文档指出我可以通过包含的应用程序启用应用程序内购买 但我不确定这意味着什么 技术上 有没有人通过应用内购买构建了 iPhone 扩展 可以给我一些指导 扩展程序与应用程序捆绑在
  • 您认识 16 位时间戳吗?

    我正在使用 Google 书签 它返回 16 位时间戳 我似乎无法在 C 中识别该时间戳以将其转换为真实日期 有什么想法吗 如何转动这个时间戳 1278276905502403在 C 中有意义的东西 这看起来就像以微秒为单位的 UNIX 时
  • 为什么 getQueryString() 在带有 h:commandButton 的 jsf 支持 bean 中不起作用

    我已经在菜单栏顶部构建了一个登录代码片段 如果用户通过导航进入任何页面并突然按下登录按钮 我希望看到该人经过身份验证 同时停留在他最初来自的页面上 所以我在支持 bean 上使用了这个 HttpServletRequest request
  • 等待 Kubernetes 或 Google Container Engine 中的作业/Pod 完成

    在 Kubernetes 或 Google Container Engine 中 脚本中等待作业或 Pod 完成的最佳方式是什么 特别是 最好得到通知而不是轮询状态kubectl 但我会很高兴有一个相当有效的循环 并且裂缝之间没有任何滑动
  • 了解 matplotlib 事件处理:什么是 event 和 mpl_connect?

    我希望能够在按下散点图中的点时显示值 解决方案在这里找到 当鼠标悬停在 matplotlib 中的某个点上时可以显示标签吗 https stackoverflow com questions 7908636 possible to make
  • .NET Core 2.2 迁移生成器无法删除索引

    我正在尝试从 IdentityUserRole 表中名为 UserRole 的列中删除索引 外键 UserRole 有 2 列 用户 ID 和角色 ID 两者都是主键 protected override void OnModelCreat
  • 在*某些* WebAPI 控制器上禁用 SSL 客户端证书?

    为未来的读者编辑 不幸的是 赏金奖励答案 不起作用 我现在对此无能为力 但请阅读我自己的答案 下面 通过测试 确认可以使用最少的代码更改 我们有一个完全采用 ASP NET WebAPI 2 2 的 Azure 云服务 WebRole 无
  • Maven Jetty 插件中的 Jetty JNDI 错误

    我正在尝试配置一个可通过调用 Maven Jetty 插件使用的 JNDI 数据源 我试图在 WAR 文件外部执行此操作 以便以后使用 Jetty 部署我们的 web 应用程序的任何人都不必编辑 WAR 的 WEB INF 目录内的配置文件
  • Android:ViewPager - PagerSlidingTabStrip,state_selected 上的自定义选项卡背景

    当每个选项卡都在时 我需要为每个选项卡使用自定义背景状态选择模式 但当我选择一个选项卡时仍然没有任何反应 我使用这样的选择器 tab selector xml
  • PHP 中的超链接自动生成图像

    我正在为我的第一个客户建立一个网站 使用WordPress 的 Simplicity Lite 主题 http wordpress org themes simplicity lite 我想以某种方式改变主题 以便在特色框位置 幻灯片放映的
  • 在 CSS Bootstrap jquery modal 中将元素暴露在 modal-backdrop 之外

    我正在使用 CSS Bootstrap 的 Modal 功能 它运行得很好 但是 我想添加一项功能 当模式对话框打开并且网页的其余部分被 modal backdrop 覆盖时 来自页面结构范围内不同位置的外部元素之一可以是暴露在背景之上 d
  • 使用中继现代 graphql 添加突变

    我正在尝试使用中继添加用户 下面是我的架构文件 schema graphql createUser input CreateUserInput UserPayload input CreateUserInput clientMutation
  • 如何判断点击了表格中的哪一行号?

    我有一个如下表 table tr td 1 td td 1 td td 1 td tr tr td 2 td td 2 td td 2 td tr tr td 3 td td 3 td td 3 td tr table 当用户单击表时 如何
  • 核心数据问题 - 选择分组依据/具有最大值

    假设我有两个实体 每个消息都属于一个消息线程 如何获取所有消息线程以及该线程上相应的最后一条消息 通常 在 SQL 中 我会这样做 按时间戳 max timeStamp 的线程从消息组中选择 其一 我认为 Core Data 不允许在其谓词
  • C++ Builder vs Delphi vs MFC

    我正在学习MFC 发现它不太好用 我听说过很多关于 Delphi 的事 对 Delphi 的研究让我接触到了 C Builder C Builder 是否提供了 C MFC 的严肃且良好的替代方案 C Builder 比 MFC 更好吗 C
  • Chrome扩展:从popup.js访问background.js的变量

    如果我正在使用chrome extension getBackgroundPage https developer chrome com extensions extension html method getBackgroundPage
  • 如何关闭窗口.打开

    我知道你可以用 window close 关闭 window open 但还有其他方法吗 我有一个打开 facebook 连接的弹出窗口 我想在用户连接到 facebook 时关闭弹出窗口 然后刷新父窗口 我认为过去我使用过 TARGET
  • 一元 & 运算符并在 Ruby 中将过程作为参数传递

    我无法理解下面的这段代码 我了解一元与运算符并将过程作为参数传递给方法的想法 但我实在无法接受过去的事self to the language call 我是这样理解的 我们正在过去self作为 proc block 语言的参数 这对我来说
  • GNU Smalltalk 80 调试器。如何调试smallcode代码?启动调试器?

    在 GNU Smalltalk 80 中 可以用您自己的普通代码编写 Smalltalk 代码 个人选择的文本编辑器 因此 调试代码非常重要 首先 将文件另存为 txt 文件 然后 您可以使用 工具 从程序员文本编辑器中打开该文件 这里的工
  • 2D 缩放到 webgl 中的点

    我正在尝试使用 WebGL 更具体地说 是 regl 创建 2D 图形可视化 通过我当前的实现 我已经可以看到力布局应用于每个节点 这很好 当我尝试相对于当前鼠标位置进行缩放时 问题就出现了 根据我的研究 要实现这种行为 需要按以下顺序应用