先看效果



还是比较节省性能的,这个还是包含了生成测试数据的性能,实际应用如果是直接通信获得数据应该还能少几毫秒吧!

准备工作

  1. 用了React,但是关系不大
  2. WebGL的基础用法(推荐看一看掘金里的一个教程:WebGL 入门与实践
  3. 有兴趣应该读一读这个的源码GPU.JS,因为一开始偷学了一手flatten2dArrayTo这个方法,后来发现实现上述效果的功能的实现原理和GPU

    .JS的加速原理差不多的
  4. 需要稍微写一个fragmentShader的代码;因为要把大多数耗时的计算扔到这个里面执行

重要代码

  1. 需要将测试数据生成的matrix二维数组通过flatten2dArrayTo转化为Uint8Array
  1. const size = { width: 1400, height: 600 };
  2. const sourceArr = new Float32Array(size.width * size.height).fill(-999.0);
  3. const matrix = []; // 一个二维数组
  4. setInterval(() => {
  5. const res = [];
  6. // TODO 按某些规则生成一行数据放入res
  7. matrix.unshift(res);
  8. if (matrix.length > size.height) {
  9. matrix.pop();
  10. }
  11. flatten2dArrayTo(matrix, sourceArr);
  12. }, 20);
  13. // 二维数组转一维数组
  14. const flatten2dArrayTo = (array, target) => {
  15. let offset = 0;
  16. for (let y = 0; y < array.length; y += 1) {
  17. target.set(array[y], offset);
  18. offset += array[y].length;
  19. }
  20. };
  21. // ...实际给GL使用再将Float32Array转为Uint8Array
  22. const d = sourceArr;
  23. new Uint8Array(d.buffer);
  24. // ...
  1. 需要给GL定义:调色板作为第0个纹理,数据转化为的Uint8Array当作第1个纹理
  1. const drawDance = (palette, data, width, height, l) => {
  2. if (canRef.current) {
  3. const gl = canRef.current.getContext?.('webgl');
  4. if (gl) {
  5. // 这个暂时没用
  6. const lengthHandle = gl.getUniformLocation(gl.program, 'length');
  7. gl.uniform1f(lengthHandle, l);
  8. // 纹理0:一个256*2的调色板
  9. const paletteLoc = gl.getUniformLocation(gl.program, 'u_Palette');
  10. gl.uniform1i(paletteLoc, 0);
  11. // 纹理1:Float32Array转为Uint8Array的数据纹理
  12. const samplerLoc = gl.getUniformLocation(gl.program, 'u_Sampler');
  13. gl.uniform1i(samplerLoc, 1);
  14. // 纹理0放入
  15. gl.activeTexture(gl.TEXTURE0);
  16. const texture1 = gl.createTexture();
  17. gl.bindTexture(gl.TEXTURE_2D, texture1);
  18. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  19. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  20. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  21. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  22. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 256 * 2, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, palette);
  23. // 纹理1放入
  24. gl.activeTexture(gl.TEXTURE1);
  25. const texture2 = gl.createTexture();
  26. gl.bindTexture(gl.TEXTURE_2D, texture2);
  27. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  28. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  29. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  30. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  31. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, bvbv(data));
  32. // canvas那么大的一个网格
  33. drawBuffer(gl, [-1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0], 'a_Position');
  34. // 释放纹理
  35. gl.deleteTexture(texture1);
  36. gl.deleteTexture(texture2);
  37. }
  38. }
  39. };
  1. canvas尺寸变化的时候告诉GL {width,height} 方便在片元着色器中取到对应点的value
  1. const onResize = useCallback(() => {
  2. const { offsetHeight: height, offsetWidth: width } = containerRef.current || {};
  3. const can = React.createElement('canvas', {
  4. width,
  5. height,
  6. style: { background: '#90202020' },
  7. ref: canRef,
  8. });
  9. containerRef.current && render(can, containerRef.current);
  10. const gl = canRef.current.getContext('webgl');
  11. if (gl) {
  12. // 重新设置gl视口,gl的Oxy在canvas的中心
  13. initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
  14. gl.viewport(0, 0, width, height);
  15. const widthHandle = gl.getUniformLocation(gl.program, 'width');
  16. const heightHandle = gl.getUniformLocation(gl.program, 'height');
  17. gl.uniform1f(widthHandle, width);
  18. gl.uniform1f(heightHandle, height);
  19. // 缩放相关的不重要
  20. const x1H = gl.getUniformLocation(gl.program, 'x1');
  21. const x2H = gl.getUniformLocation(gl.program, 'x2');
  22. gl.uniform1f(x1H, 0);
  23. gl.uniform1f(x2H, width);
  24. }
  25. }, []);
  1. 一个fragmentShader,主要是要把通过像素位置获取对应二维的数组中对应的数据值(重点是那个decode32函数,网上找了挺久的How do I convert a vec4 rgba value to a float? ),然后根据最小最大和调色板确定绘制的颜色
  1. precision mediump float;
  2. uniform float width;
  3. uniform float height;
  4. uniform float length;
  5. uniform float x1;
  6. uniform float x2;
  7. uniform sampler2D u_Palette;
  8. uniform sampler2D u_Sampler;
  9. vec2 reslution =vec2(width,height);
  10. highp float decode32(highp vec4 rgba) {
  11. highp float Sign = 1.0 - step(128.0,rgba[0])*2.0;
  12. highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0;
  13. highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000);
  14. highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 ));
  15. return Result;
  16. }
  17. void main(){
  18. // gl_FragColor=vec4(gl_FragCoord.xyx/reslution.xyx,1.0);
  19. if(gl_FragCoord.y < 10.0){
  20. // 简单画个调色板示意图
  21. gl_FragColor=texture2D(u_Palette,gl_FragCoord.xy/reslution.xy);
  22. }
  23. else{
  24. // 绘制数据点
  25. float xx=x1+gl_FragCoord.x/reslution.x*(x2-x1);
  26. vec2 pos = vec2(xx,reslution.y-gl_FragCoord.y)/vec2(reslution.x,reslution.y);
  27. vec4 color=texture2D(u_Sampler,pos)*255.0;
  28. float val=decode32(color.abgr);
  29. if(val < -99.0){
  30. gl_FragColor=vec4(0.0,0.0,0.0,1.0);
  31. }
  32. else{
  33. gl_FragColor=texture2D(u_Palette,vec2((val+20.0)/100.0,1.0));
  34. }
  35. }
  36. }

源码

基本上述代码过程就能实现了;直接看源码吧:ctrlcv->AudioDance8 ctrlCV工程师

一个简单利用WebGL绘制频谱瀑布图示例的更多相关文章

  1. 一个简单的AXIS远程调用Web Service示例

    我们通常都将编写好的Web Service发布在Tomcat或者其他应用服务器上,然后通过浏览器调用该Web Service,返回规范的XML文件.但是如果我们不通过浏览器调用,而是通过客户端程序调用 ...

  2. svg绘制一个简单地饼图

    一个简单地svg绘制饼图的demo,代码如下 <!DOCTYPE html> <html> <head> <meta charset="UTF-8& ...

  3. ComplexHeatmap|根据excel表绘制突变景观图(oncoplot)

    本文首发于“生信补给站”:https://mp.weixin.qq.com/s/8kz2oKvUQrCR2_HWYXQT4g 如果有maf格式的文件,可以直接oncoplot包绘制瀑布图,有多种展示和 ...

  4. IOS开发之小实例--使用UIImagePickerController创建一个简单的相机应用程序

    前言:本篇博文是本人阅读国外的IOS Programming Tutorial的一篇入门文章的学习过程总结,难度不大,因为是入门.主要是入门UIImagePickerController这个控制器,那 ...

  5. 一个简单的通讯服务框架(大家发表意见一起研究)JAVA版本

    最近研究下java语言,根据一般使用的情况,写了个连接通讯服务的框架: 框架结构 C-Manager-S; 把所有通讯内容抽取成三个方法接口:GetData,SetData,带返还的Get; 所有数据 ...

  6. 分享:计算机图形学期末作业!!利用WebGL的第三方库three.js写一个简单的网页版“我的世界小游戏”

    这几天一直在忙着期末考试,所以一直没有更新我的博客,今天刚把我的期末作业完成了,心情澎湃,所以晚上不管怎么样,我也要写一篇博客纪念一下我上课都没有听,还是通过强大的度娘完成了我的作业的经历.(当然作业 ...

  7. Quartz2D之绘制一个简单的机器猫

    学习iOS有一段时间了,在博客园也默默的潜水了两个月,见识了很多大神,收获不少. 今天整理笔记,发现忘记的不少,我感觉需要及时的整理一下了,同时也把做的小东西贴上来和大家分享一下. 最近学习了Quar ...

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

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

  9. maftools | 从头开始绘制发表级oncoplot(瀑布图)

    本文首发于微信公众号 **“ 生信补给站 ”** ,期待您的关注!!! 原文链接:https://mp.weixin.qq.com/s/G-0PtaoO6bYuhx_D_Rlrlw 对于组学数据的分析 ...

  10. [Unity]利用Mesh绘制简单的可被遮挡,可以探测的攻击指示器

    最近做一个小游戏的Demo,最终的效果是这样的 主要是利用Mesh绘制三角形作为显示,然后使用后处理来制作探灯,注意,性能一般,仅仅适合小游戏 分为3步 1:利用mesh绘制三角形,原理很简单,利用三 ...

随机推荐

  1. 2021-09-11:给你一个32位的有符号整数x,返回将x中的数字部分反转后的结果。反转后整数超过 32 位的有符号整数的范围就返回0,假设环境不允许存储 64 位整数(有符号或无符号)。

    2021-09-11:给你一个32位的有符号整数x,返回将x中的数字部分反转后的结果.反转后整数超过 32 位的有符号整数的范围就返回0,假设环境不允许存储 64 位整数(有符号或无符号). 福大大 ...

  2. Django笔记四十之运行Django环境的python脚本

    本文首发于公众号:Hunter后端 原文链接:Django笔记四十之运行Django环境的python脚本 这一篇笔记介绍如何在 Django 中运行脚本. 假设说我们要实现一个功能,需要获取 blo ...

  3. Django-4:运行runserver

    Djnago运行.启动 命令:python manage.py runserver 端口号 例如:当前有个项目为ClosedLoop,如果要启动它就进入项目环境,或者直接在PyCharm的终端中运行命 ...

  4. ent M2M模型在pxc集群中的一个大坑

    ent M2M模型在pxc集群中的一个大坑 事故简要分析 PXC集群3个节点,在插入数据时,如果使用数据库自己生成的主键,一般顺序为1,4,7,10- 这里就是坑的源头,在ent底层代码中,在做M2M ...

  5. 【编程日记】搭建PyCharm集成开发环境

    0.相关确定 本教程使用的版本号为专业版PyCharm 2022.3.2,如果您是初学者,为了更好的学习本教程,避免不必要的麻烦,请您下载使用与本教程一致的版本号. 1.PyCharm的下载 官网下载 ...

  6. mysql安装教程【安装版】和Navicat-for-MySQL破解版

    傻瓜式mysql安装教程[安装版]https://blog.csdn.net/qq_59636442/article/details/123058454 Navicat-for-MySQL下载链接:h ...

  7. .NET 创建无边框的跨平台应用

    .NET 创建无边框的跨平台应用 在创建了Photino应用程序以后我们发现它自带了一个标题栏,并且非常丑,我们现在要做的就是去掉这个很丑的自带标题栏,并且自定义一个更好看的,下面我们将用Masa B ...

  8. Java实现Kafka生产者和消费者的示例

    Kafka简介 Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写.Kafka的目标是为处理实时数据提供一个统一.高吞吐.低延迟的平台. 文章持续更新,微信搜索「 ...

  9. 一篇讲懂Java运行类型、编译类型和多态(面向对象语言精髓之一)

    对象:运行类型.编译类型和多态 1.搞清楚面向对象的运行类型和编译类型就掌握了对象的精髓,我们用举个例子 class Father { Father() { System.out.println(&q ...

  10. Java 设计模式实战系列—策略模式

    从优惠打折活动说起 电商平台为了增加销量经常搞一些活动,比如 618.双十一,还有一些节假日活动,根据销量的变化又经常更新不同的活动.最开始为了增加销量,全场都六折: // 打六折 public Bi ...