WebGL、canvas、svg

WebGL、canvas、svg

面试题

canvas

canvas只需要操作一个canvas标签,使用JavaScripy指令进行动态绘图。 Canvas 可以做到像素级操作,例如图片滤镜效果等,由于绘制的是位图,所以缩放会导致失真。

面试题

  • canvas导出图片模糊原因 如何解决,restore和save的区别
  • canvas位图和svg矢量图的区别
  • canvas的绘图原理,canvas 渲染原理
  • canvas.style.width和canvas.width区别
  • canvas怎么进行图片压缩的

canvas位图和svg矢量图的区别

canvassvgwebGL
2D2D3D
不会保留绘制的图形的信息,基于像素点绘制位图,放大会会失真内存中保留绘制的图形的信息,用html标签描绘形状,矢量图放大不会失真
canvas无法对已经绘制的图像进行修改、操作svg中每个图形又对应真实的dom节点、svg可以获取到标签进行操作
高数据量高绘制频率(帧率)的场景,如动画、游戏低数据量低绘制频率的场景,如图形、图表

矢量图为时间换空间,位图为空间换时间
差不多的条件下,矢量图耗费CPU多,位图耗费内存多一点

canvas的绘图原理

canvas.style.width和canvas.width区别

  • canvas.width / canvas.height 表示画布真实大小,其实我们并不可见,canvas绘制是以画布实际大小展开的
  • canvas.style.width / canvas.style.height 表示画布输出到浏览器我们可见的/最终的大小

WebGL

什么是webGL
webGL是一种帮助我们开发3D网页的绘图技术,底层是JavaScript API

WebGL 技术旨在帮助我们在不使用插件的情况下在任何兼容的网页浏览器中开发交互式 2D 和 3D 网页效果

基本概念

WebGL 只关心两件事:裁剪空间中的坐标值和颜色值

WebGL运行在电脑的GPU上,运行在GPU上的代码需要提供成对的方法。每对方法中有 顶点着色器 + 片元着色器

  • 顶点着色器:计算顶点的位置,提供顶点在裁剪空间中的坐标值
  • 片元着色器:计算图元的颜色值,基于顶点着色器的计算结果绘制像素点
着色器获取数据的四种方式
  • 属性和缓冲
    • 缓冲是发送到GPU的一些二进制数据序列。通常缓冲数据包括位置、方向、纹理坐标、顶点颜色值等。
    • 属性说明如何从缓冲中获取所需数据并将它提供给顶点着色器
  • 全局变量:在着色程序运行之前赋值,在运行过程中全局有效。全局变量在一次绘制过程中传递给着色器的值都一样。
  • 纹理是一个数据序列,可以在着色程序运行中随意读取其中的数据。一般情况下我们在纹理中存储的大都是图像数据,但你也可以根据自己喜欢存放除了颜色数据以外的其它数据
  • 可变量是一种顶点着色器给片元着色器传值的方式

案例:原生WebGL API绘制三角形

GPU上的工作:

  1. 先调用三次顶点着色器计算出三角形的3个顶点在裁剪空间坐标系中的对应位置。 通过变量 gl_Position保存在GPU中
  2. 调用片元着色器完成每个顶点颜色值的计算,通过变量gl_FragColor 将对应的颜色值存储在 GPU 中
  3. 完成这些工作后我们已经得到了绘制三角形所需的像素点,最后便是光栅化三角形了。

WebGL 作为一种 3D 绘图技术本身就是依托于 HTML5 中的 canvas 元素而存在的

  1. 首先我们需要创建一个 canvas 元素作为绘制三角形所需的画布,并完成浏览器对 canvas 元素兼容性的测试。
function webglInit () {
  const canvasEl = document.createElement('canvas'); // canvas 元素创建
  canvasEl.width = document.body.clientWidth; // 设置 canvas 画布的宽度
  canvasEl.height = document.body.clientHeight; // 设置 canvas 画布的高度
  document.body.append(canvasEl); // 将创建好的 canvas 画布添加至页面中的 body 元素下
  // 接下来我们需要判断浏览器对于 WebGL 的兼容性,如果浏览器不支持 WebGL 那么我们就不需要再进行下去了
  if(!canvasEl.getContext("webgl") && !canvasEl.getContext("experimental-webgl ")) {
    alert("Your Browser Doesn't Support WebGL");
    return;
  }
  // 如果浏览器支持 WebGL,那么我们就获取 WebGL 的上下文对象并复制给变量 gl
  const context = (canvasEl.getContext("webgl"))
  ? canvasEl.getContext("webgl") 
  : getContext("experimental-webgl");
  /* 
    设置视口 context.viewport(x, y, width, height);
    x: 用来设定视口的左下角水平坐标。默认值:0
    y: 用来设定视口的左下角垂直坐标。默认值:0
    width: 用来设定视口的宽度。默认值:canvas 的宽度
    height: 用来设定视口的高度。默认值:canvas 的高度
    当你第一次创建 WebGL 上下文的时候,视口的大小和 canvas 的大小是匹配的。然而,如果你重新改变了canvas的大小,你需要告诉 WebGL 上下文设定新的视口,因此这里作为初次创建这行代码可以省略
  */
  context.viewport(0, 0, context.canvas.width, context.canvas.height);
  return context;
}
  1. 需要准备画三角形所需的顶点即顶点着色器,以及三角形对应的填充色即片元着色器
const gl =  webglInit();
// 创建顶点着色器 语法 gl.createShader(type) 此处 type 为枚举型值为 gl.VERTEX_SHADER 或 gl.FRAGMENT_SHADER 两者中的一个
const vShader = gl.createShader(gl.VERTEX_SHADER) 
// 编写顶点着色器的 GLSL 代码 语法 gl.shaderSource(shader, source); shader - 用于设置程序代码的 webglShader(着色器对象) source - 包含 GLSL 程序代码的字符串
gl.shaderSource(vShader, `
  attribute vec4 v_position;

  void main() {
    gl_Position = v_position; // 设置顶点位置
  }
`)
gl.compileShader(vShader) // 编译着色器代码

const fShader = gl.createShader(gl.FRAGMENT_SHADER) 
gl.shaderSource(fShader, `
  precision mediump float;
  uniform vec4 f_color;
  void main() {
    gl_FragColor = f_color; // 设置片元颜色
  }
`) // 编写片元着色器代码 
gl.compileShader(fShader) // 编译着色器代码
  1. 就需要创建一个程序用来连接我们的顶点着色器和片元着色器完成最终的三角形绘制工作。
// 创建一个程序用于连接顶点着色器和片元着色器
const program = gl.createProgram() 
gl.attachShader(program, vShader) // 添加顶点着色器
gl.attachShader(program, fShader) // 添加片元着色器
gl.linkProgram(program) // 连接 program 中的着色器

gl.useProgram(program) // 告诉 WebGL 用这个 program 进行渲染

const color = gl.getUniformLocation(program, 'f_color') 
// 获取 f_color 变量位置
gl.uniform4f(color, 0.93, 0, 0.56, 1) // 设置它的值

const position = gl.getAttribLocation(program, 'v_position') 
// 获取 v_position 位置
const pBuffer = gl.createBuffer() 
// 创建一个顶点缓冲对象,返回其 id,用来放三角形顶点数据,
gl.bindBuffer(gl.ARRAY_BUFFER, pBuffer) 
// 将这个顶点缓冲对象绑定到 gl.ARRAY_BUFFER
// 后续对 gl.ARRAY_BUFFER 的操作都会映射到这个缓存
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    0, 0.5,
    0.5, 0,
    -0.5, -0.5
]),  // 三角形的三个顶点
     // 因为会将数据发送到 GPU,为了省去数据解析,这里使用 Float32Array 直接传送数据
gl.STATIC_DRAW // 表示缓冲区的内容不会经常更改
)
// 将顶点数据加入的刚刚创建的缓存对象

gl.vertexAttribPointer( // 告诉 OpenGL 如何从 Buffer 中获取数据
    position, // 顶点属性的索引
    2, // 组成数量,必须是 1,2,3 或 4。我们只提供了 x 和 y
    gl.FLOAT, // 每个元素的数据类型
    false, // 是否归一化到特定的范围,对 FLOAT 类型数据设置无效
    0, // stride 步长 数组中一行长度,0 表示数据是紧密的没有空隙,让 OpenGL 决定具体步长
    0 // offset 字节偏移量,必须是类型的字节长度的倍数。
)
gl.enableVertexAttribArray(position);
// 开启 attribute 变量额,使顶点着色器能够访问缓冲区数据

gl.clearColor(0, 1, 1, 1) // 设置清空颜色缓冲时的颜色值
gl.clear(gl.COLOR_BUFFER_BIT) // 清空颜色缓冲区,也就是清空画布
// 语法 gl.drawArrays(mode, first, count); mode - 指定绘制图元的方式 first - 指定从哪个点开始绘制 count - 指定绘制需要使用到多少个点
gl.drawArrays( gl.TRIANGLES, 0, 3 )

作者:政采云前端团队
链接:https://juejin.cn/post/6994940475459731463
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

图形绘制流水线 渲染管线

GPU 接收 CPU 的指令进行图形的绘制,通过顶点处理和片元处理等操作,生成像素阵列输入到帧缓存。

图形的渲染流程,称为渲染管线。
渲染管线主要包括两个功能
1.将物体3D坐标转变为屏幕空间2D坐标
2.为屏幕每个像素点进行着色

几何顶点被组合为图元(点,线段或多边形),然后图元被合成片元,最后片元被转换为帧缓存中的象素数据。
在这里插入图片描述
顶点处理:对顶点进行坐标变化
在这里插入图片描述
图元组装和裁剪:图元组装是指将顶点组合生成一个个图元(点/线/三角形),裁剪是指将视口之外的对象进行裁剪,裁剪针对的是逐个片元而不是逐个顶点。
在这里插入图片描述

光栅化:光栅化是将几何图元变为二维图像的过程。
该过程包含了两部分的工作。
第一部分工作:决定窗口坐标中的哪些整型栅格区域被基本图元占用;
第二部分工作:分配一个颜色值和一个深度值到各个区域。光栅化过程产生的是片元。

二维图象上每个点都包含了颜色、深度和纹理数据。将该点和相关信息叫做一个 片元(fragment)。片元比像素多了许多信息。
在这里插入图片描述
片元处理:该阶段主要是通过片元着色器来计算片元的最终颜色和深度值,同时通过深度测试和模板测试来判断当前片元是否可见,如果片元通过测试,那它就可以被直接绘制到帧缓存中了。
在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值