使用WebGL绘制流动虚线

上文中介绍了如何在片元着色器中绘制虚线,通过计算屏幕像素到折线的距离和屏幕像素投影到折线的长度可以绘制折线。

接下来尝试使用WebGL2在canvas中绘制流动的折线。

需解决的问题

顶点数据传输

shader中使用的折线顶点数据需要从外部传入,最开始考虑使用uniform vec2[]数组方式传入,但是GPU中数组上限太低,很容易就不够用了,而且数组个数声明必须使用常量,无法从外部传入数组个数,动态的构造数组。

因此,我采用纹理方式传入顶点数据,采用纹理方式存储顶点数据明显优于数组方式。而且WebGL2支持了更多类型的纹理格式,数据存储更方便。

目前先考虑2D的情况,即一个顶点包含x,y两个属性,一条折线包含多个顶点,一次可以绘制多条折线。即WebGL中对应的纹理可以采用RGB32F格式,纹理存储数据如下:

纹理 顶点
R x
G y
B 线段分割符,0,1

纹理中B通道存储折线的分割符,即最后一个折线的顶点的B通道存储为0,用于同下个折线断开。否则,所有顶点将连成一条折线。

画布

由于完全采用shader进行绘制,顶点仅需要构造两个三角形即可,覆盖当前的canvas即可

具体流程

准备画布

初始化WebGL此处不再赘述。vertexshader中传入的顶点数据,仅为canvas四个顶点即可,顶点及顶点索引如下:

const canvs_pts=new Float32Array([-1,-1,-1,1,1,1,1,-1
]);
const canvas_pts_idx=new Uint16Array([0,2,1,0,3,2
]);

通过in方式传入顶点,gl.drawElements绘制两个三角形即可。

构造纹理数据

定义如下的折线数据格式:

let testline_data=[[[30,100],[600,200],[700,300],[50,50]],[[40,410],[500,500],[600,700]]
];

折线包含顶点数组,一个顶点为一个两个要素的数组。可以同时绘制多条折线。

纹理数据可以理解为2D格式的数组,因此需要将顶点数据格式化为mxn格式的形式。数据存储以此为R\G\B。这里格式化顶点格式通过顶点数量开根号的方式得到列数,再计算总行数,多余的像素用0补齐。最终需要返回ArrayBufferView,和纹理对应的宽高。

function PatchLineData(lines){let points=[];for(let i=0;i<lines.length;i++){let lastpoint_idx=lines[i].length-1;for(let j=0;j<lastpoint_idx;j++){points.push(lines[i][j][0]);points.push(lines[i][j][1]);points.push(1);}points.push(lines[i][lastpoint_idx][0]);points.push(lines[i][lastpoint_idx][1]);points.push(0);//折线最后一个顶点的B存储为0,用于同其他折线断开}//数据补齐为nxn形式,多余的数据用0补充let pixel_count=points.length / 3;let pixel_col=Math.ceil(Math.sqrt(pixel_count));let pixel_row=Math.ceil(pixel_count/pixel_col);let additional_datacount=pixel_col*pixel_row-pixel_count;for(let i=0;i<additional_datacount;i++){points.push(0);points.push(0);points.push(0);}let line_data=new Float32Array(points);return {"linedata":line_data,"texturewidth":pixel_col,"textureheight":pixel_row};
}

使用纹理数据

纹理数据传入此处不再赘述。

vertexshader中仅接受顶点数据即可,无需其他数据,如下:

#version 300 es
in vec2 a_position;
void main(){gl_Position=vec4(a_position,0.0,1.0);
}

fragmentshader中需要做对应的修改,shadertoy中顶点数据为预先写好的,这里需要修改为通过纹理获取顶点数据,再计算对应的折线范围和投影距离。sdLine_t不做修改,仍旧计算距离场和投影距离。

新增方法getPixelCoord用来计算对应的纹理坐标位置,获取像素值通过texelFetch来获取,可以避免计算归一化的纹理坐标,直接使用行列来获取像素。

重点修改cDistance_t方法,通过for循环获取出入的顶点数据,并计算对应的显示范围。

#version 300 es
precision highp float;const float ELIPSE=0.5;uniform float LINEWIDTH;
uniform float dash_size;
uniform float iTime;
uniform sampler2D line_data;ivec2 texture_size;float sdLine_t(in vec2 p,in vec2 a, in vec2 b){vec2 pa=p-a,ba=b-a;float t=dot(pa,ba)/dot(ba,ba);float t_lxs=t*length(ba);float c=length(pa-ba*clamp(t,0.0,1.0));c=1.-smoothstep(LINEWIDTH,LINEWIDTH+ELIPSE,c);return c*mod(t_lxs-iTime*2.,dash_size)/dash_size;
}ivec2 getPixelCoord(int i){return ivec2(i/texture_size.x,int(mod(float(i),float(texture_size.x)))).yx;
}//计算纹理中每个顶点最终颜色
float cDistance_t( in vec2 v )
{//像素总数,WebGL2中可以通过textureSize方法直接获取纹理尺寸int pixelcount=texture_size.x*texture_size.y-1;float max_ini=0.0;//图片左下角为坐标原点for(int i=0;i<pixelcount;i+=1){//获取两个顶点计算显示范围ivec2 pixel_cur=getPixelCoord(i);ivec2 pixel_next=getPixelCoord(i+1);vec4 texel_cur=texelFetch(line_data,pixel_cur,0);vec4 texel_next=texelFetch(line_data,pixel_next,0);float t=sdLine_t(v,texel_cur.xy,texel_next.xy);//计算结果乘线段分隔符,用来打断当前折线和下一条折线t*=texel_cur.z;max_ini=max(max_ini,t);}return max_ini;
}out vec4 fragColor;void main(){texture_size=textureSize(line_data,0);float c_lxs=cDistance_t(gl_FragCoord.xy);fragColor=vec4(vec3(c_lxs),1.0);
}

TODO

  • 反走样
  • 组件化,预期以leaflet插件方式

PS:欢迎提问题。。。

使用WebGL绘制流动虚线相关推荐

  1. 利用javascript和WebGL绘制地球 【翻译】

    利用javascript和WebGL绘制地球 [翻译] 原翻译:利用javascript和WebGL绘制地球 [翻译] 在我们所有已知的HTML5API中,WebGL可能是最有意思的一个,利用这个AP ...

  2. 【视觉高级篇】20 # 如何用WebGL绘制3D物体?

    说明 [跟月影学可视化]学习笔记. 如何用 WebGL 绘制三维立方体 我们知道立方体有8个顶点,6个面,在 WebGL 中,需要用 12 个三角形来绘制它.把每个面的顶点分开,需要 24 个顶点. ...

  3. WebGL 绘制Line的bug(一)

    插播一则广告(长期有效) MONO哥需要在武汉招JavaScript工程师若干 要求:对前端技术(JavasScript.HTML.CSS),对可视化技术(Canvas.WebGL)有浓厚的兴趣 基础 ...

  4. 用webgl绘制一个彩色旋转立方体

    #用webgl绘制一个旋转立方体 ** 学习交流欢迎加群:789723098,博主会将一些demo整理共享 ** 今天给大家分享一个用webgl写的简单的三维场景:转动的交互式彩色立方体,其六个面的颜 ...

  5. webgl绘制客厅房间的家具+座椅板凳床

    一.开发环境说明 开发软件:webstorm 浏览器 : 火狐firefox 编程语言:webgl 二.内容说明 1.内容要求 实现一个小型的3D客厅环境,包括对象建模.照明.摄像机设置:必须使用纯的 ...

  6. 【图形基础篇】04 # GPU与渲染管线:如何用WebGL绘制最简单的几何图形?

    说明 [跟月影学可视化]学习笔记. 图形系统是如何绘图的? 一个通用计算机图形系统主要包括 6 个部分,分别是: 输入设备 中央处理单元:首先,数据经过 CPU 处理,成为具有特定结构的几何信息. 图 ...

  7. WebGL绘制立方体-每个面一种颜色

    WebGL绘制立方体-每个面一种颜色 本文是WebGL电子书的1.8节内容 思路很简单,在线框模式的立方体源码基础上直接进行更改,添加varying变量,引入顶点数据颜色,立方体6个面,每个面可以分为 ...

  8. WebGL绘制带箭头贴图的线

    示例 在讲述本文内容之前,我希望读者先具备以下知识点: 了解WebGL的基本知识,懂得调用自定义的Shader程序: 基本的数学基础和空间几何知识: 明白GPU的渲染管线流程: 因为,本文内容主要讲述 ...

  9. ThreeJS绘制流动的虚线效果

    Threejs绘制等距流动线 three.js flow line Three中LineMaterial中支持将线渲染为虚线样式,通过在LineMaterial中引入时间,可以使虚线动起来,产生流动效 ...

最新文章

  1. Java面向对象知识概括归纳与总结
  2. ABP(现代ASP.NET样板开发框架)系列之2、ABP入门教程
  3. 南邮计算机学院是211,南京邮电大学是211还是985
  4. 判断字符串出栈合法性
  5. iperf测试带宽linux,iperf3-网络带宽性能测试工具
  6. Oracle 查看 表 存储过程 触发器 函数 等对象定义语句的方法
  7. php百度语音合成,Drupal 与百度云语音合成(PHP SDK)的集成
  8. IDEA导入Gradle项目后,重现构建项目并导入jar包后但是External Libraries目录中无任何引入的jar包
  9. php电子邮箱表单,带邮件发送功能的表单(form.php)
  10. php ActiveMQ的安装与使用
  11. 【LeetCode】【字符串】题号:242. 有效的字母异位词
  12. 读书笔记_打开量化投资的黑箱05
  13. excel vb连接mysql数据库教程视频教程_VB6.0与Access数据库关联、VB6.0与Excel数据导入导出案例...
  14. VMware虚拟机安装Ubuntu 2022最新版详细图文安装教程(VMware虚拟机安装+Ubuntu下载+VMware虚拟机配置运行)
  15. 领导力包括哪些能力?如何提升领导力?
  16. String Permutation
  17. KVM安装+vlan配置(超详细)
  18. 给我5分钟,手把手带你学会定时任务!
  19. 排序函数qsort和sort那点事
  20. 三分钟搭建开源的工单系统ferry

热门文章

  1. 计算机默认应用程序怎么取消,如何取消默认打开的QQ浏览器
  2. 10月更新!又一波新功能上线,升级后的EasyOps®简直神了!
  3. 一名网络工程师尴尬的现状?
  4. 你要找的cocos面试答案都在这里了!
  5. 《浪潮之巅》——吴军
  6. 两个电阻的并联与串联
  7. 忍者必须死3突然服务器维修,《忍者必须死3》3月25日停服维护公告
  8. 秒杀Excel的动态可视化报表,不用学python,用它仅需10分钟
  9. 后台管理系统【登录页面】
  10. 教你一起来做一下SpringBoot蓝天幼儿园管理系统