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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/91586.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记忆化搜索,901. 滑雪

901. 滑雪 - AcWing题库 给定一个 R 行 C 列的矩阵&#xff0c;表示一个矩形网格滑雪场。 矩阵中第 i行第 j 列的点表示滑雪场的第 i 行第 j列区域的高度。 一个人从滑雪场中的某个区域内出发&#xff0c;每次可以向上下左右任意一个方向滑动一个单位距离。 当然&#xff0…

数据结构--栈的实现

数据结构–栈的实现 1.栈的概念和结构&#xff1a; 栈的概念&#xff1a;栈是一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Las…

SpringMVC 学习(三)注解开发

4. 注解开发 4.1 环境搭建 (1) 新建 maven 模块 springmvc-03-annotation (2) 确认依赖 确认方法同 3(2)&#xff0c;手动导入发布依赖见3(11) <!--资源过滤--> <build><resources><resource><directory>src/main/java</directory>&…

PostMan的学习

PostMan的学习 目录 环境变量和全局变量接口关联内置动态参数以及自定义动态参数实现业务闭环Postman断言批量运行collection数据驱动之CSV文件和JSON文件测试必须带请求头的接口Mock Serviers 服务器Cookie鉴权NewmanPostManNewManjenkins实现接口测试持续集成 参考资料&am…

Kerberos常见报错汇总

一.kdb5_util: Password mismatch while reading master key from keyboard 1>.错误复现 2>.错误原因分析 在初始化Kerberos数据库时需要输入密码&#xff0c;2次密码输入不一致就会导致该错误。 3>.解决方案 重新执行"kdb5_util -r YINZHENGJIE.COM create -s…

Mendix中的依赖管理:npm和Maven的应用

序言 在传统java开发项目中&#xff0c;我们可以利用maven来管理jar包依赖&#xff0c;但在mendix项目开发Custom Java Action时&#xff0c;由于目录结构有一些差异&#xff0c;我们需要自行配置。同样的&#xff0c;在mendix项目开发Custom JavaScript Action时&#xff0c;…

数据集笔记:旧金山共享单车OD数据

数据地址&#xff1a;System Data | Bay Wheels | Lyft

使用不同尺寸的传感器拍照时,怎么保证拍出同样视场范围的照片?

1、问题背景 使用竞品机做图像效果对比时&#xff0c;我们通常都会要求拍摄的照片要视场范围一致&#xff0c;这样才具有可比性。之前我会考虑用同样焦距、同样分辨率的设备去拍照对比就可以了&#xff0c;觉得相机的视场范围只由镜头焦距来决定。 但如果对于不同尺寸的传感器…

Spring修炼之旅(3)自动装配与注解开发

一、自动装配说明 1.1概述 自动装配是使用spring满足bean依赖的一种方法 spring会在应用上下文中为某个bean寻找其依赖的bean。 1.2装配机制 Spring中bean有三种装配机制&#xff0c;分别是&#xff1a; 在xml中显式配置&#xff1b; 在java中显式配置&#xff1b; 隐式…

【Java 进阶篇】MySQL 数据控制语言(DCL):管理用户权限

MySQL 是一个强大的关系型数据库管理系统&#xff0c;提供了丰富的功能和选项来管理数据库和用户。数据库管理员&#xff08;DBA&#xff09;通常使用数据控制语言&#xff08;Data Control Language&#xff0c;简称 DCL&#xff09;来管理用户的权限和访问。 本文将详细介绍…

定义现代化实时数据仓库,SelectDB 全新产品形态全面发布

导读&#xff1a;9 月 25 日&#xff0c;2023 飞轮科技产品发布会在线上正式召开&#xff0c;本次产品发布会以 “新内核、新图景” 为主题&#xff0c;飞轮科技 CEO 马如悦全面解析了现代化数据仓库的演进趋势&#xff0c;宣布立足于多云之上的 SelectDB Cloud 云服务全面开放…

数据结构——堆(C语言)

本篇会解决一下几个问题&#xff1a; 1.堆是什么&#xff1f; 2.如何形成一个堆&#xff1f; 3.堆的应用场景 堆是什么&#xff1f; 堆总是一颗完全二叉树堆的某个节点总是不大于或不小于父亲节点 如图&#xff0c;在小堆中&#xff0c;父亲节点总是小于孩子节点的。 如图&a…

华为ensp单臂路由及OSPF实验

单臂路由及OSPF实验 1.1实验背景 在这个实验中&#xff0c;我们模拟了一个复杂的网络环境&#xff0c;该网络环境包括多个子网和交换机。这个实验旨在帮助网络工程师和管理员了解如何配置单臂路由和使用开放最短路径优先&#xff08;OSPF&#xff09;协议来实现不同子网之间的…

从 低信噪比陆上地震记录 解决办法收集 到 走时层析反演中的折射层析调研

目录 (前言1) 关于背景的回答:(前言2) 现有的降低噪声, 提高信噪比的一些特有方法的论文资料 (传统策略):1. 关于波形反演与走时层析反演2. 折射层析3. 用一个合成数据来解释折射层析反演的思路4. 其他层析反演方法:5. 关于层析反演的一些TIPS (可补充)参考文献: 降噪有关资料参…

MySQL系统架构设计

MySQL 一、MySQL整体架构1.1 SQL接口1.2 解析器 Parser1.3 查询优化器 Optimizer1.3.1 逻辑优化1.3.2 物理优化1.3.3 explain1.4 缓存 Cache1.5 存储引擎 Stroage Management1.6 一条查询SQL的执行流程二、缓存池(Buffer Pool)2.1 Buffer Pool 预读机制2.2 Buffer Pool free链…

SpringBoot使用Docker并上传至DockerHub

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版&#xff0c;欢迎购买。点击进入详情 文章目录 1.系列文章2.构建docker镜像的方式3.docker操作3.1 安装docker3.2 查看docker镜像3.3 本地运行docker3.4 修改tag3.5 推送docker镜像3.6 远端server拉取d…

FOC控制算法

目录 一、FOC介绍 二、FOC基本概念 1、为什么是三相&#xff1f; 2、FOC矢量控制总体算法简述 3、为什么FOC不一定需要电流采样&#xff1f;参考链接 4、FOC的分类 &#xff08;1&#xff09;有感FOC与无感FOC 三、FOC中电流采样 参考链接 1、高端采样 2、低端采样 …

AI项目十三:PaddleOCR训练自定义数据集

若该文为原创文章&#xff0c;转载请注明原文出处。 续上一篇&#xff0c;PaddleOCR环境搭建好了&#xff0c;并测试通过&#xff0c;接下来训练自己的检测模型和识别模型。 paddleocr检测模型训练 1、准备数据集 在PaddleOCR目录下新建文件夹&#xff1a;train_data, 这个…

Xilinx FPGA 7系列 GTX/GTH Transceivers (5)-- Aurora 8b10b 信号传输实战--小试牛刀

第一节:Xilinx FPGA 7系列 GTX/GTH Transceivers (1)–了解了GTX硬件的基础知识 第二节:IBERT GTX --通过Ibert IP测试链路通信 第三节:aurora 8b10b single lane 4byte–学习官方历程 第四节:aurora 8b10b single lane 4byte–修改官方例子,发收递增数。 GTX/GTH Transc…

深度学习:模型训练过程中Trying to backward through the graph a second time解决方案

1 问题描述 在训练lstm网络过程中出现如下错误&#xff1a; Traceback (most recent call last):File "D:\code\lstm_emotion_analyse\text_analyse.py", line 82, in <module>loss.backward()File "C:\Users\lishu\anaconda3\envs\pt2\lib\site-packag…