您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

内卷年代,是该学学 WebGL 了

时间:2023-03-16 11:52:45  来源:微信公众号  作者:前端YUE

​前言

大部分公司的都会有可视化的需求,但是用echarts,antv等图表库,虽然能快速产出成果,但是还是要知道他们底层其实用canvas或svg来做渲染,canvas浏览器原生支持,h5天然支持的接口,而svg相比矢量化,但是对大体量的点的处理没有canvas好,但是可以操作dom等优势。canvas和svg我们一般只能做2d操作,当canvas.getContext('webgl')我们就能获取webgl的3d上下文,通过glsl语言操作gpu然后渲染了。理解webgl,可以明白h5的很多三维的api底层其实都是webgl实现,包括对canvas和svg也会有新的认知。

canvas和webgl的区别

canvas和webgl都可以做二维三维图形的绘制。底层都会有对应的接口获取。cancvas一般用于二维canvas.getContext("2d")​,三维一般可以通过canvas.getContext('webgl')

窥探WebGL

理解建模

如果你有建模软件基础的话,相信3dmax、maya、su等软件你一定不会陌生,本质其实就是点、线、面来组成千变万化的事物。打个比方球体就是无数个点连成线然后每三根线形成面,当然有常见的四边形,其实也是两个三边形组成,为什么不用四边形,因为三边形更稳定、重心可计算、数据更容易测算。

所以核心也就是点、线、三角面

了解WebGL

WebGL可以简单理解为是openGL的拓展,让web端通过js可以有强大的图形处理能力。当然为了与显卡做交互你必须得会glsl语言。

GLSL

glsl着色器语言最重要的就是顶点着色器和片元着色器。简单理解为一个定位置一个添颜色。

简单绘制一个点

webgl会有大量的重复性前置工作,也就是创建着色器 -> 传入着色器源码 -> 编译着色器 -> 创建着色器程序 -> 绑定、连接、启用着色器 -> 可以绘制了!

一般而言我们是不会重复写这个东西,封装好了直接调用就行。

function initShader (gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE) {
    const vertexShader = gl.createShader(gl.VERTEX_SHADER);

    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

    gl.shaderSource(vertexShader, VERTEX_SHADER_SOURCE);
    gl.shaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE);

    //编译着色器
    gl.compileShader(vertexShader);
    gl.compileShader(fragmentShader);

    //创建程序对象
    const program = gl.createProgram();

    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);

    gl.linkProgram(program);
    gl.useProgram(program);

    return program;
}
 
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="./initShader.js"></script>
</head>

<body>
  <canvas id="canvas" width="300" height="400">
    不支持canvas
  </canvas>
</body>

<script>
  const ctx = document.getElementById('canvas')
  const gl = ctx.getContext('webgl')

  //着色器: 通过程序用固定的渲染管线,来处理图像的渲染,着色器分为两种,顶点着色器:顶点理解为坐标,片元着色器:像素

  //顶点着色器源码
  const VERTEX_SHADER_SOURCE = `
    void mAIn() {
      gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
      gl_PointSize = 10.0;
    }  
  `
  //片元着色器源码
  const FRAGMENT_SHADER_SOURCE = `
    void main() {
      gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }   
  `
  //创建着色器
  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  //执行绘制
  gl.drawArrays(gl.POINTS, 0, 1)
  //gl.drawArrays(gl.LINES, 0, 1)
  //gl.drawArrays(gl.TRIANGLES, 0, 1)

</script>

</html>

绘制效果如下:

图片

相信看了上面有段代码会有疑惑

图片

gl_position代表坐标,vec4就一个存放个4个float的浮点数的容量,定义坐标, 分别对应x、y、z、w,也就是三维坐标,但是w就等于比例缩放xyz而已,一般在开发中,我们的浏览器的坐标要跟这个做个转换对应上,gl_POintSize是点的大小,注意是浮点数

 

图片

 

gl_flagColor渲染的像素是红色,是因为这类似于比例尺的关系需要做个转换, (R值/255,G值/255,B值/255,A值/1) ->(1.0, 0.0, 0.0, 1.0)

绘制动态点

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="./initShader.js"></script>
</head>

<body>
  <canvas id="canvas" width="300" height="400">
    不支持canvas
  </canvas>
</body>

<script>
  const canvas = document.getElementById('canvas')
  const gl = canvas.getContext('webgl')
    
  const VERTEX_SHADER_SOURCE = `
    precision mediump float;
    attribute vec2 a_Position;
    attribute vec2 a_Screen_Size;
    void main(){
      vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0; 
      position = position * vec2(1.0, -1.0);
      gl_Position = vec4(position, 0, 1);
      gl_PointSize = 10.0;
    }  
  `
  const FRAGMENT_SHADER_SOURCE = `
   precision mediump float;
   uniform vec4 u_Color;
   void main() {
    vec4 color = u_Color / vec4(255, 255, 255, 1);
    gl_FragColor = color; 
   }
  `
  //前置工作,着色器可以渲染了!
  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  //获取glsl的变量对应的属性做修改
  var a_Position = gl.getAttribLocation(program, 'a_Position');
  var a_Screen_Size = gl.getAttribLocation(program, 'a_Screen_Size');
  var u_Color = gl.getUniformLocation(program, 'u_Color');
  gl.vertexAttrib2f(a_Screen_Size, canvas.width, canvas.height); //给glsl的属性赋值两个浮点数
  
  //给个默认背景颜色
  gl.clearColor(0, 0, 0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);

  //存储点击位置的数组。
  var points = [];
  canvas.addEventListener('click', e => {
    var x = e.pageX;
    var y = e.pageY;
    var color = { r: Math.floor(Math.random() * 256), g: Math.floor(Math.random() * 256), b: Math.floor(Math.random() * 256), a: 1 };
    points.push({ x: x, y: y, color: color })
        
    gl.clearColor(0, 0, 0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);
    
    for (let i = 0; i < points.length; i++) {
      var color = points[i].color;
      gl.uniform4f(u_Color, color.r, color.g, color.b, color.a);
      gl.vertexAttrib2f(a_Position, points[i].x, points[i].y);
      gl.drawArrays(gl.POINTS, 0, 1);
    }
  })
</script>

</html>

vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0; 注意这里的坐标转换,从canvas转为ndc坐标,其实就是看范围就行,[0, 1] -> [0, 2] -> [-1, 1]。上面总体的流程总结下就是,定义着色器,定义glsl着色器源码 -> 通过api获取canvas的信息转换坐标系 -> 监听点击事件传递变量到glsl中 -> 通过pointer缓存 -> drawArrays绘制。但是这种方法,很明显有大量的重复渲染,每次遍历都要把之前渲染的重复执行。

大致效果

 

图片

 

总结

通过简单的webgl入门,已经有了初步的认知,大致的流程为:着色器初始化 -> 着色器程序对象 -> 控制变量 -> 绘制,为了更好的性能,后面会使用缓冲区来解决重复渲染的问题,这样我们的顶点不会一个一个设置而直接会被缓存,包括后面一些动态效果会涉及到矩阵的转换,如平移、缩放、旋转、复合矩阵。



Tags:WebGL   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
内卷年代,是该学学 WebGL 了
​前言大部分公司的都会有可视化的需求,但是用echarts,antv等图表库,虽然能快速产出成果,但是还是要知道他们底层其实用canvas或svg来做渲染,canvas浏览器原生支持,h5天然支持的接...【详细内容】
2023-03-16  Search: WebGL  点击:(105)  评论:(0)  加入收藏
如何使用 WebGL 进行实时视频处理
这是我最近在 CodePen 上制作的 WebGL 演示案例。它可以捕获网络摄像头的数据(或在无法访问网络摄像头时,从 placekitten 获取备用图像),并将其实时转换为 ASCII 图像艺术。 为...【详细内容】
2020-09-02  Search: WebGL  点击:(598)  评论:(0)  加入收藏
新技术来了,你没必要继续折腾WebGL了
我在前面的文章中提到过目前基于WebGL的前端三维可视化存在的一些问题:1、前端浏览体验和数据量有很大关系,需要花费大量的数据进行数据的轻量化以及切片处理,但是同样要忍受切...【详细内容】
2020-06-15  Search: WebGL  点击:(1427)  评论:(0)  加入收藏
▌简易百科推荐
Netflix 是如何管理 2.38 亿会员的
作者 | Surabhi Diwan译者 | 明知山策划 | TinaNetflix 高级软件工程师 Surabhi Diwan 在 2023 年旧金山 QCon 大会上发表了题为管理 Netflix 的 2.38 亿会员 的演讲。她在...【详细内容】
2024-04-08    InfoQ  Tags:Netflix   点击:(0)  评论:(0)  加入收藏
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(6)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(13)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(9)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(11)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(9)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
站内最新
站内热门
站内头条