首页 > 其他分享 >可视化学习:WebGL实现缩放平移

可视化学习:WebGL实现缩放平移

时间:2024-03-21 12:12:12浏览次数:25  
标签:平移 const 缩放 0.0 WebGL value 可视化 offset patternPracticeRef

前言

在上篇文章中,我们使用WebGL实现了网格背景,当时有提到说使用WebGL来实现的好处之一,是网格背景可以与画布上的其他元素更好地融合,比如一起缩放平移,那么在WebGL中怎么实现缩放和平移呢?现在我们已经实现了网格背景,接下来我们就用网格背景作为例子来了解一下WebGL中的缩放和平移。

这里需要用到我之前学过的变换矩阵,不熟悉变换矩阵的小伙伴可以看我之前的文章《CSS transform与仿射变换》,或者查阅其他相关资料;简单来说就是使用矩阵来表示顶点坐标的变换。

具体实现

接下来我们在代码中来具体实现这个效果。

1. 改造顶点着色器

首先我们先改造顶点着色器的GLSL代码,对顶点应用变换矩阵。

attribute vec2 a_vertexPosition;
attribute vec2 uv;

varying vec2 vUv;

uniform int scale;
uniform vec2 offset;

mat3 translateMatrix = mat3( // 平移矩阵
  1.0, 0.0, 0.0, // 第一列
  0.0, 1.0, 0.0, // 第二列
  offset.x, offset.y, 1.0 // 第三列
);

mat3 scaleMatrix = mat3( // 缩放矩阵
  float(scale), 0.0, 0.0,
  0.0, float(scale), 0.0,
  0.0, 0.0, 1.0
);

void main() {
  gl_PointSize = 1.0;
  vUv = uv;
  vec3 pos = scaleMatrix * translateMatrix * vec3(a_vertexPosition, 1.0);
  gl_Position = vec4(pos, 1.0);
}

代码中我们增加接收两个uniform常量scaleoffset,表示缩放比例和平移的偏移量;并且定义两个矩阵:平移矩阵translateMatrix和缩放矩阵scaleMatrix。需要注意GLSL这里矩阵的写法是列主序的,也就是说这里的第一行其实是平常我们认为的第一列,也就是说假如有平移矩阵乘以原坐标:translateMatrix * vec3(a_vertexPosition, 1.0),我们会得到如下结果:

\[\begin{bmatrix} 1 & 0 & offset.x \\ 0 & 1 & offset.y \\ 0 & 0 & 1 \end{bmatrix} \times \begin{bmatrix} x_0 \\ y_0 \\ 1 \end{bmatrix} = \begin{bmatrix} x_0 + offset.x\\ y_0 + offset.y \\ 1 \end{bmatrix} \]

将两个矩阵相乘表示叠加效果,再与坐标向量相乘后,我们就能得到映射的新顶点坐标。

2. 改造js代码

顶点着色器中增加接收的两个参数需要js代码传递过去,接下来我们就对js代码进行改造。

首先是设置这两个变量的初始值,scale等于1表示原始大小,offset设置的初始偏移量为0,也就是不偏移。

// ...
renderer.uniforms.scale = 1;
renderer.uniforms.offset = [0.0, 0.0];
// ...

然后我们添加对鼠标滚轮事件以及鼠标按下和放开事件的监听。

// ...
const addEvent = () => {
  patternPracticeRef.value.addEventListener('mousewheel', wheelEventHandler);
  patternPracticeRef.value.addEventListener('mouseup', mouseUpHandler);
  patternPracticeRef.value.addEventListener('mousedown', mouseDownHandler);
}
addEvent();
// ...

接下来我们就来完成这三个事件监听的回调函数。

我们先来完成滚轮事件的监听回调,这个比较简单。e.wheelDeltaY > 0表示滚轮向下滚动,实现放大效果,这里我使用了整数表示放大倍数,这是因为之前我有使用浮点数来实现过,但是存在一些问题,比如绘制出来的网格线会有可能粗细不同,甚至会缺少一些线,这估计是由于精度原因导致的,我还没去进一步的研究。

const wheelEventHandler = e => {
  e.preventDefault();
  if (e.wheelDeltaY > 0) { // 向下滚,放大
    if (renderer.uniforms.scale <= 50) {
      renderer.uniforms.scale += 1;
    }
  } else { // 向上滚,缩小
    if (renderer.uniforms.scale > 1) {
      renderer.uniforms.scale -= 1;
    }
  }
}
const mouseDownHandler = e => {
  // ...
}
const mouseUpHandler = e => {
	// ...
}

此时我们在页面上进行测试一下,就可以看到缩放的效果实现了。
image

接着我们来实现平移的效果,因为偏移量需要根据鼠标的初始位置和移动结束的位置计算得到,所以我们增加一个对象类型的变量lastPos来记录鼠标的初始位置,并在鼠标按下的事件回调中对它赋值。

// ...
const lastPos = {};
// ...
const mouseDownHandler = e => {
  e.preventDefault();
  // 记录初始位置
  lastPos.x = e.offsetX;
  lastPos.y = e.offsetY;
  // 绑定事件
  patternPracticeRef.value.addEventListener('mousemove', mouseMoveHandler);
}

在鼠标按下后,我们对鼠标的移动事件开启监听,便于实时更新位置信息。

const mouseMoveHandler = e => {
  e.preventDefault();
  // 计算坐标差值并转换为Canvas差值
  const { offsetX: x, offsetY: y } = e;
  const translateX = (x - lastPos.x) / patternPracticeRef.value.width;
  const translateY = (lastPos.y - y) / patternPracticeRef.value.height;
  // 设置偏移量
  renderer.uniforms.offset = [translateX, translateY];
}

因为在页面上y轴向下,与WebGL中y轴向上是相反的,所以这里计算y方向的偏移量使用lastPos.y - y。我们通过除以canvas的宽高,就能转换得到偏移量在WebGL里的对应数值。

接着我们在鼠标按键松开事件监听的回调中,对移动监听进行移除。

const mouseDownHandler = e => {
   e.preventDefault();
  // 解绑事件
  patternPracticeRef.value.addEventListener('mousemove', mouseMoveHandler);
}

此时在页面上测试,能看到我们可以对网格进行拖动平移了,但很明显这其中还存在问题,当我们完成第一次平移后,想再点击鼠标来平移,就会发现在按下鼠标的那一刻网格会发生闪烁,这是因为在上一次平移完成后,图片的中心点已经改变了,而在GLSL代码中的偏移矩阵中,偏移量的设置是相对(0, 0)点的,所以会闪烁一下,也就是说我们需要考虑中心点的影响,在第二次平移时要在新的中心点的基础上去进行平移,在这里我使用一个lastCenter变量来存储中心点的位置。

const lastPos = {}, lastCenter = {};

并在鼠标按键松开的事件回调中对画布中心点的信息进行更新。

const mouseUpHandler = e => {
  e.preventDefault();
  // 计算坐标差值并转换为Canvas差值
  const { offsetX: x, offsetY: y } = e;
  const translateX = (x - lastPos.x) / patternPracticeRef.value.width;
  const translateY = (lastPos.y - y) / patternPracticeRef.value.height;
  // 更新新的中心点
  lastCenter.x = translateX + lastCenter.x;
  lastCenter.y = translateY + lastCenter.y;
  // 解除事件绑定
  patternPracticeRef.value.removeEventListener('mousemove', mouseMoveHandler);
}

同时在鼠标移动过程中偏移量的更新我们也要把中心点的坐标考虑进去。

const mouseMoveHandler = e => {
  e.preventDefault();
  // 计算坐标差值并转换为Canvas差值
  const { offsetX: x, offsetY: y } = e;
  const translateX = (x - lastPos.x) / patternPracticeRef.value.width;
  const translateY = (lastPos.y - y) / patternPracticeRef.value.height;
  // 设置偏移量
  renderer.uniforms.offset = [translateX + lastCenter.x, translateY + lastCenter.y];
}

这个时候我们再去测试一下,可以看到就是正常的了。

总结

到这里为止我们就实现了在WebGL中的缩放和平移,这里主要就是借助了鼠标事件的监听和变换矩阵的应用。

完整代码
最终效果

标签:平移,const,缩放,0.0,WebGL,value,可视化,offset,patternPracticeRef
From: https://www.cnblogs.com/beckyyyy/p/18087073

相关文章

  • R语言神经网络与决策树的银行顾客信用评估模型对比可视化研究
    全文链接:https://tecdat.cn/?p=35403原文出处:拓端数据部落公众号在数字化时代,顾客信用评估成为商业决策中的重要一环。无论是金融机构的信贷审批,还是电商平台的用户信用管理,都需要对顾客的信用状况进行准确评估。随着机器学习技术的不断发展,决策树和神经网络等算法在顾客信用评......
  • 基于python+django+Spark的动漫推荐可视化分析系统
    摘 要近年来,随着互联网的蓬勃发展,企事业单位对信息的管理提出了更高的要求。以传统的管理方式已无法满足现代人们的需求。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,随着各行业的不断发展,基于Spark的国漫推荐系统的建设也逐渐进入了信息化的进程。这个系统......
  • 探索宇宙奥秘,天文馆3D可视化引领未来观星新风尚
    在这个科技日新月异的时代,我们似乎离神秘的宇宙越来越近。 天文馆作为普及天文知识、展示宇宙奥秘的重要场所,一直备受人们的喜爱。然而,传统的天文馆展示方式往往局限于平面图片和简单的模型,无法让人真正感受到宇宙的浩瀚与壮丽。而3D可视化技术的出现,为天文馆带来了革命性的变......
  • 智慧交通三维可视化合集 | 图扑数字孪生
    城市交通作为城市与区域交通体系的核心,其完善程度和发展水平是评价城市现代化水准的关键指标之一。城市交通数字孪生技术正在成为城市交通管理的关键工具,支持系统的高效运行和安全保障。随着互联网、大数据和人工智能技术的进步,城市交通数字孪生应用逐步成熟。图扑软件专注于Web......
  • 在电脑桌面上怎么制作可视化工作计划待办清单?
    对于忙碌的上班族来说,每天都需要处理大量的工作任务,如何在繁杂的工作中保持高效和有序,成为了一个亟待解决的问题。在电脑桌面上制作可视化的工作计划待办清单,就是一个非常实用的方法。通过将工作任务以清单的形式展现在桌面上,我们可以随时了解工作进度,确保每一项任务都能按时完成,......
  • 立体呈现航空风采,3D漫游可视化探索企业文化新境界
    在科技的浪潮中,3D技术日益成熟,为人们带来了前所未有的视觉体验。而今天,我们将借助这一神奇的技术,开启一场别开生面的航空企业文化漫游之旅,全方位地感受航空企业的魅力与风采。 置身3D模型中,眼前的景象变得栩栩如生,仿佛触手可及。我们可以自由地穿梭于各个展区,欣赏到不同区域的......
  • 关于卷积神经网络特征可视化
    卷积神经网络CNN,一个大号/深层的,现代的,黑箱的,信号/图像处理器。简单讲解如何将图像输入到卷积神经网络CNN并显示网络不同层的激活图,并通过将激活图与原始图像进行比较以探索网络学习哪些特征本例来源于Mathworks公司的大佬,需要用到MATLABNeuralNetworkToolbox(TM),Image......
  • 在cifar-10数据集上t-sne可视化效果最好(๑•̀ㅂ•́)و✧
    还是需要在python上面保存模型,加载模型,然后提取特征保存为mat文件就行了(但我现在只加载了64维特征,4096维特征还没试过,估计也可以但应该会又慢又不好看)①先放matlab可视化t-sne的代码%加载特征数据data=load('10_157_ckpt.pth.mat');features=data.features;labels=dat......
  • 火箭升空,震撼来袭!三维可视化技术揭秘宇宙探索之旅
    在浩瀚无垠的宇宙中,人类对于未知的探索从未停止。每一次火箭发射,都是对宇宙的一次深情告白,都是人类迈向星辰大海的坚定步伐。如今,借助三维可视化技术,我们得以更加直观、生动地感受火箭发射的震撼场景,仿佛置身于那激动人心的瞬间,与火箭一同冲破大气层,探索宇宙的奥秘。 想象一下,......
  • 智慧乡村,数字物联,大数据信息可视化管控平台
    通过打造数据中台,实现模型算法、业务组件、工具组件、地图服务和数据服务等应用支撑服务;以“互联互通、以用促建、共建共享”为原则,应用业界成熟的大数据中台产品,贯穿目录编制、治理、归集、入仓、采集、分析等六大环节,提高数据存储能力、数据处理能力,实现聚数、看数和用数......