WebGL笔记:使用鼠标绘制多个线条应用及绘制动感线性星座
使用鼠标绘制多个线条
- 多个线条,肯定不是一笔画过的,而是多次画的线条
- 既然是多线,那就需要有个容器来管理它们
1 )建立容器对象
建立一个 lineBox 对象,作为承载多边形的容器
// lineBox.js
export default class lineBox {constructor(gl) {this.gl = glthis.children = []}add(obj) {obj.gl = this.glthis.children.push(obj)}updateVertices(params) {this.children.forEach(ele => {ele.updateVertices(params)})}draw() {this.children.forEach(ele => {ele.init()ele.draw()})}
}
-
属性
- gl webgl上下文对象
- children 子级
-
方法
- add() 添加子对象
- updateVertices() 更新子对象的顶点数据
- draw() 遍历子对象绘图,每个子对象对应一个buffer 对象,所以在子对象绘图之前要先初始化
2 )场景应用
场景:鼠标点击画布,绘制多边形路径,鼠标右击,取消绘制,鼠标再次点击,绘制新的多边形
import LineBox from './lineBox'
import Poly from './poly'// 容器
const lb = new LineBox(gl)
// 当前正在绘制的多边形
let poly = null// 取消右击提示
canvas.oncontextmenu = function() {return false
}// 鼠标点击事件
canvas.addEventListener("mousedown", (event) => {if(event.button === 2) {popVertice()} else {const { x, y } = getMousePosInWebgl(event, canvas)poly ? poly.addVertice(x,y) : crtPoly(x,y)}render()
})// 鼠标移动
canvas.addEventListener("mousemove", (event) => {if (poly) {const { x, y } = getMousePosInWebgl(event, canvas)poly.setVertice(poly.count - 1, x, y)render()}
})// 删除最后一个顶点
function popVertice() {poly.popVertice()poly = null
}// 创建多边形
function crtPoly(x,y) {poly = new Poly({vertices:[x,y,x,y],types:['POINTS','LINE_STRIP']})lb.add(poly)
}// 渲染方法
function render() {gl.clear(gl.COLOR_BUFFER_BIT)lb.draw()
}
3 )场景应用
- 画一个星座
- 鼠标第1次点击画布时
- 创建多边形
- 绘制2个点
- 鼠标移动时
- 当前多边形最后一个顶点随鼠标移动
- 鼠标接下来点击画布时
- 新建一个点
- 鼠标右击时
- 删除最后一个随鼠标移动的点
- 顶点要有闪烁动画
- 建立顶点的时候,如果鼠标点击了其它顶点,就不要再显示新的顶点
3.1 )建立顶点着色器
<script id="vertexShader" type="x-shader/x-vertex">attribute vec4 a_Attr;varying float v_Alpha;void main() {gl_Position = vec4(a_Attr.x, a_Attr.y, 0.0, 1.0);gl_PointSize = a_Attr.z;v_Alpha = a_Attr.w;}
</script>
- a_Attr() 是一个4维向量,其参数结构为(x, y, z, w)
- x,y代表位置
- z代表顶点尺寸
- w代表顶点透明度,w会通过 varying 变量 v_Alpha 传递给片元
3.2 )建立片元着色器
<script id="fragmentShader" type="x-shader/x-fragment">precision mediump float;varying float v_Alpha;void main() {float dist = distance(gl_PointCoord, vec2(0.5,0.5));if(dist < 0.5) {gl_FragColor = vec4(0.87, 0.91, 1.0, v_Alpha);} else {discard;}}
</script>
- 通过v_Alpha接收透明度,然后设置片元的颜色
3.3 )建立夜空对象,用于承载多边形
const lb = new lineBox(gl)
3.4 )建立合成对象,用于对顶点数据做补间运算
const compose = new Compose();
3.5 )声明两个变量,用于表示当前正在绘制的多边形和鼠标划上的点
// 当前正在绘制的多边形
let poly = null
// 鼠标划上的点
let point = null
3.6 )取消右击提示
// 取消右击提示
canvas.oncontextmenu = function() {return false;
}
3.7 )鼠标按下事件
// 鼠标按下事件
canvas.addEventListener("mousedown", (event) => {if(event.button === 2) {// 右击删除顶点poly && popVertice()} else {const {x,y} = getMousePosInWebgl(event, canvas)if(poly) {// 连续添加顶点addVertice(x,y)} else {// 建立多边形crtPoly(x, y)}}
});
-
getMousePosInWebgl() 方法是用于获取鼠标在webgl 画布中的位置,我们之前说过。
-
crtPoly() 创建多边形
function crtPoly(x, y) {let o1 = point ? point : { x, y, pointSize: random(), alpha: 1 }const o2 = { x, y, pointSize: random(), alpha: 1 }poly = new Poly({size: 4,attrName: 'a_Attr',geoData: [o1,o2],types: ['POINTS','LINE_STRIP']})lb.add(poly)crtTrack(o1)crtTrack(o2) } -
建立两个顶点数据o1,o2,如果鼠标点击了其它顶点,o1的数据就是此顶点的数据
-
顶点的尺寸是一个随机数random()
function random() {return Math.random() * 8.0 + 3.0 } -
基于两个顶点数据,建立多边形对象和两个时间轨对象
-
crtTrack() 建立时间轨
function crtTrack(obj) {const { pointSize } = objconst track = new Track(obj)track.start = new Date()track.timeLen = 2000track.loop = truetrack.keyMap = new Map([["pointSize",[[500, pointSize],[1000, 0],[1500, pointSize],],],["alpha",[[500, 1],[1000, 0],[1500, 1],],],]);compose.add(track) } -
addVertice() 添加顶点
function addVertice(x, y) {const { geoData } = polyif(point) {geoData[geoData.length-1] = point}let obj = { x, y, pointSize:random(), alpha: 1 }geoData.push(obj)crtTrack(obj) } -
如果鼠标点击了其它顶点,就让多边形的最后一个顶点数据为此顶点
-
建立下一个顶点的顶点数据,添加新的顶点,建立新的时间轨
-
popVertice() 删除最后一个顶点
function popVertice() {poly.geoData.pop()compose.children.pop()poly = null }
3.8 )鼠标移动事件
canvas.addEventListener("mousemove", (event) => {const { x, y } = getMousePosInWebgl(event, canvas)point = hoverPoint(x, y)if(point) {canvas.style.cursor = 'pointer'} else {canvas.style.cursor = 'default'}if(poly) {const obj = poly.geoData[poly.geoData.length-1]obj.x = xobj.y = y}
});
-
基于鼠标是否划上顶点,设置鼠标的视觉状态
-
设置正在绘制的多边形的最后一个顶点点位
-
hoverPoint() 检测所有顶点的鼠标划入,返回顶点数据
function hoverPoint(mx, my) {for(let { geoData } of lb.children) {for(let obj of geoData) {if(poly && obj === poly.geoData[poly.geoData.length-1]) {continue}const delta = {x: mx - obj.x,y: my - obj.y}const { x,y } = glToCssPos(delta, canvas)const dist = x * x + y * y;if(dist < 100) {return obj}}}return null } -
遍历 lb 中的所有顶点数据,忽略绘图时随鼠标移动的点,获取鼠标和顶点的像素距离,若此距离小于10像素,返回此点;否则,返回null
-
glToCssPos() webgl坐标系转css坐标系,将之前说过的getMousePosInWebgl() 方法逆向思维即可
function glToCssPos({x,y},{width,height}){const [halfWidth, halfHeight] = [width / 2, height / 2]return {x:x*halfWidth,y:-y*halfHeight} }
2.9 )连续渲染方法
!(function animate() {compose.update(new Date())lb.updateVertices(['x', 'y', 'pointSize', 'alpha'])render()requestAnimationFrame(animate)
})();
- 更新动画数据
- 更新Vertices 数据
- render() 渲染
function render(){gl.clear(gl.COLOR_BUFFER_BIT)lb.draw() }
相关文章:
WebGL笔记:使用鼠标绘制多个线条应用及绘制动感线性星座
使用鼠标绘制多个线条 多个线条,肯定不是一笔画过的,而是多次画的线条既然是多线,那就需要有个容器来管理它们 1 )建立容器对象 建立一个 lineBox 对象,作为承载多边形的容器 // lineBox.js export default class …...
nodejs+vue 汽车销售系统elementui
第三章 系统分析 10 3.1需求分析 10 3.2可行性分析 10 3.2.1技术可行性:技术背景 10 3.2.2经济可行性 11 3.2.3操作可行性: 11 3.3性能分析 11 3.4系统操作流程 12 3.4.1管理员登录流程 12 3.4.2信息添加流程 12 3.4.3信息删除流程 13 第四章 系统设计与…...
leetcode76 Minimum Window Substring
给定两个字符串s和t, 找到s的一个子串,使得t的每个字符都出现在子串中,求最短的子串 由于要每个字符出现,所以顺序其实没有关系 因此我们可以定义一个map,统计t中字符出现次数 然后在s中慢慢挪动滑动窗口,…...
简单工厂模式~
我们以生产手机作为应用场景展开讲解! 手机是一个抽象的概念,它包含很多的品牌,例如华为,苹果,小米等等,因此我们可将其抽象为一个接口,如下所示: public interface tel {void pro…...
基于Java的会员管理系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…...
数据结构 图 并查集 遍历方法 最短路径算法 最小生成树算法 简易代码实现
文章目录 前言并查集图遍历方法广度优先遍历深度优先遍历 最小生成树算法Kruskal算法Prim算法 最短路径算法Dijkstra算法BellmanFord算法FloydWarshall算法 全部代码链接 前言 图是真的难,即使这些我都学过一遍,再看还是要顺一下过程;说明方…...
idea Springboot 教师标识管理系统开发mysql数据库web结构java编程计算机网页源码maven项目
一、源码特点 springboot 教师标识管理系统是一套完善的信息系统,结合springboot框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用springboot框架(MVC模式开发),系统 具有完整的源代码和数据库&…...
2023-9-30 JZ36 二叉搜索树与双向链表
题目链接:二叉搜索树与双向链表 import java.util.*; /** public class TreeNode {int val 0;TreeNode left null;TreeNode right null;public TreeNode(int val) {this.val val;}} */ public class Solution {TreeNode pre null;public TreeNode Convert(Tree…...
在windows的ubuntu LTS中安装及使用EZ-InSAR进行InSAR数据处理
EZ-InSAR(曾被称为MIESAR,即Matlab界面用于易于使用的合成孔径雷达干涉测量)是一个用MATLAB编写的工具箱,用于通过易于使用的图形用户界面(GUI)进行干涉合成孔径雷达(InSAR)数据处理…...
腾讯mini项目-【指标监控服务重构】2023-08-25
今日已办 traefik proxy jaeger Prometheus prometheus | Prometheus 配置完依然无法实现 web-url的前缀访问【待解决】 Set span storage type : elasticsearch services:elasticsearch:image: elasticsearch:7.17.12container_name: elasticsearchnetworks:- backend # …...
数据挖掘(1)概述
一、数据仓库和数据挖掘概述 1.1 数据仓库的产生 数据仓库与数据挖掘: 数据仓库和联机分析处理技术(存储)。数据挖掘:在大量的数据中心挖掘感兴趣的知识、规则、规律、模式、约束(分析)。数据仓库用于决策分析: 数据仓库:是在数…...
YApi Pro
1.介绍 说明:YApi Pro 是一款高效、易用、功能强大的 API 管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。它可以帮助开发者轻松创建、发布、维护 API,同时为用户提供了优秀的交互体验,开发人员可以更加高效地完…...
AUTOSAR RTE介绍(更新版230925)
RTE是什么 AUTOSAR RTE(Run Time Environment)实现了AUTOSAR系统中的虚拟功能总线(VFB),提供了SWC(Software Component)之间的访问接口和SWC对于BSW资源的访问接口。RTE为SWC中的Runnable提供与其他SWC或者BSW模块通信的接口,RTE将Runnable映射到OS Task中,并且管理Runna…...
深度学习笔记_1、定义神经网络
1、使用了PyTorch的nn.Module类来定义神经网络模型;使用nn.Linear来创建全连接层。(CPU) import torch.nn as nn import torch.nn.functional as F from torchsummary import summary# 定义神经网络模型 class Net(nn.Module):def __init__(self):super(Net, self).__init__()…...
【Java 进阶篇】MySQL 事务详解
在数据库管理中,事务是一组SQL语句的执行单元,它们被视为一个整体。事务的主要目标是保持数据库的一致性和完整性,即要么所有SQL语句都成功执行,要么所有SQL语句都不执行。在MySQL中,事务起到了非常重要的作用…...
Spring修炼之旅(3)自动装配与注解开发
一、自动装配说明 1.1概述 自动装配是使用spring满足bean依赖的一种方法 spring会在应用上下文中为某个bean寻找其依赖的bean。 1.2装配机制 Spring中bean有三种装配机制,分别是: 在xml中显式配置; 在java中显式配置; 隐式…...
嵌入式Linux应用开发-基础知识-第十六章GPIO和Pinctrl子系统的使用
嵌入式Linux应用开发-基础知识-第十六章GPIO和Pinctrl子系统的使用 第十六章 GPIO 和 Pinctrl 子系统的使用16.1 Pinctrl 子系统重要概念16.1.1 引入16.1.2 重要概念16.1.3 示例16.1.4 代码中怎么引用pinctrl 16.2 GPIO子系统重要概念16.2.1 引入16.2.2 在设备树中指定引脚16.2…...
Ubuntu系统下使用apt-get安装Mysql8
记录一下在Ubuntu20.04 64位系统下面使用apt-get方式安装mysql8关系型数据库 Centos下使用yum安装Mysql8(Mysql5.7)以及常见的配置和使用 首先肯定是检查下当前Ubuntu系统是否已经安装过mysql数据库 一般拿到新的云服务器是没有安装的 rootmyw:~# whe…...
jenkins联动显示或隐藏参数
1. 添加组件 Active Choices Plug-in 如jenkins无法联网,可在以下两个地址中下载插件,然后放到/home/jenkins/.jenkins/plugin下面重启jenkins即可 Active Choices Active Choices | Jenkins plugin 2. 效果如下: sharding为空时…...
Error: Activity class {xxx.java} does not exist
git切换到不同的branch之后,报下面的错误: Error: Activity class {xxx.java} does not exist 解决方案: 首先clean 然后会删除build目录 然后点击:Invalidate Caches Android Studio重启,然后重新build即可。...
python基于微信小程序的家政服务与互助平台
目录技术栈选择功能模块设计数据库设计接口开发小程序前端部署与测试安全与合规项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作技术栈选择 后端采用Python的Django或Flask框架,提供RESTful API接口。数据库使用MyS…...
人工智能毕业设计2026方向集合
0 选题推荐 - 人工智能篇 毕业设计是大家学习生涯的最重要的里程碑,它不仅是对四年所学知识的综合运用,更是展示个人技术能力和创新思维的重要过程。选择一个合适的毕业设计题目至关重要,它应该既能体现你的专业能力,又能满足实际…...
lite-avatar形象库入门:如何查找、预览并下载心仪的数字人形象
lite-avatar形象库入门:如何查找、预览并下载心仪的数字人形象 1. 数字人形象库简介 在数字人项目开发中,一个合适的虚拟形象往往能让用户体验大幅提升。lite-avatar形象库正是为解决这一需求而生的专业资源库。 这个基于HumanAIGC-Engineering/LiteA…...
告别‘阴阳屏’:深入MTK平台PQ底层,教你用代码实现多供应商屏幕色彩统一
MTK平台屏幕色彩统一实战:从Gamma参数调试到自动化加载 当你的项目同时采用三家不同供应商的屏幕模组时,用户滑动屏幕时可能看到三种截然不同的白色——这种"阴阳屏"现象在硬件采购多元化的今天越来越普遍。作为深耕显示领域多年的工程师&…...
深度学习标量、向量、矩阵与张量(三)
1. 定位导航 线性代数是深度学习最核心的数学工具——没有之一。神经网络的前向传播本质上就是矩阵乘法加非线性激活;反向传播本质上就是链式法则在矩阵/向量上的应用;PCA、SVD、特征分解等工具贯穿从数据预处理到模型分析的全过程。 本篇是最基础的一篇…...
VitePress 博客主题定制与美化实战
1. VitePress主题美化的核心思路 很多开发者在使用VitePress搭建博客时,都会遇到一个共同的问题:默认主题虽然简洁,但缺乏个性。我在实际项目中发现,通过CSS变量覆盖、自定义组件和插件扩展这三个维度,可以打造出极具辨…...
3大突破:重新定义Revit插件开发流程
3大突破:重新定义Revit插件开发流程 【免费下载链接】RevitAddInManager Revit AddinManager update .NET assemblies without restart Revit for developer. 项目地址: https://gitcode.com/gh_mirrors/re/RevitAddInManager 引言:Revit插件开发…...
给嵌入式新手的Cortex-M0内核超详细图解:从寄存器到中断,一篇搞定STM32/GD32入门
给嵌入式新手的Cortex-M0内核超详细图解:从寄存器到中断,一篇搞定STM32/GD32入门 刚拿到STM32开发板时,看着密密麻麻的引脚和上百页的芯片手册,我完全不知道从哪里开始。直到导师指着原理图说:"把芯片想象成一个忙…...
Revit插件开发效率革命:热重载技术如何彻底改变你的开发流程
Revit插件开发效率革命:热重载技术如何彻底改变你的开发流程 【免费下载链接】RevitAddInManager Revit AddinManager update .NET assemblies without restart Revit for developer. 项目地址: https://gitcode.com/gh_mirrors/re/RevitAddInManager RevitA…...
FastAPI 2.0 AI流式响应性能瓶颈分析与突破方案(源码级内存泄漏定位实录)
第一章:FastAPI 2.0 AI流式响应性能瓶颈分析与突破方案(源码级内存泄漏定位实录)在高并发AI推理服务场景下,FastAPI 2.0 的 StreamingResponse 在持续返回大模型 token 流时,常出现 RSS 内存持续增长、GC 延迟升高、最…...
