canvas只需要操作一个canvas
标签,使用JavaScripy指令进行动态绘图。 Canvas 可以做到像素级操作,例如图片滤镜效果等,由于绘制的是位图,所以缩放会导致失真。
canvas | svg | webGL |
---|---|---|
2D | 2D | 3D |
不会保留绘制的图形的信息,基于像素点绘制位图,放大会会失真 | 内存中保留绘制的图形的信息,用html标签描绘形状,矢量图放大不会失真 | |
canvas无法对已经绘制的图像进行修改、操作 | svg中每个图形又对应真实的dom节点、svg可以获取到标签进行操作 | |
高数据量高绘制频率(帧率)的场景,如动画、游戏 | 低数据量低绘制频率的场景,如图形、图表 |
矢量图为时间换空间,位图为空间换时间
差不多的条件下,矢量图耗费CPU多,位图耗费内存多一点
canvas.width / canvas.height
表示画布真实大小,其实我们并不可见,canvas绘制是以画布实际大小展开的canvas.style.width / canvas.style.height
表示画布输出到浏览器我们可见的/最终的大小什么是webGL
webGL是一种帮助我们开发3D网页的绘图技术,底层是JavaScript API
WebGL 技术旨在帮助我们在不使用插件的情况下在任何兼容的网页浏览器中开发交互式 2D 和 3D 网页效果
WebGL 只关心两件事:裁剪空间中的坐标值和颜色值
WebGL运行在电脑的GPU上,运行在GPU上的代码需要提供成对的方法。每对方法中有 顶点着色器
+ 片元着色器
顶点着色器
GPU上的工作:
gl_Position
保存在GPU中gl_FragColor
将对应的颜色值存储在 GPU 中WebGL 作为一种 3D 绘图技术本身就是依托于 HTML5 中的 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;
}
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) // 编译着色器代码
// 创建一个程序用于连接顶点着色器和片元着色器
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)。片元比像素多了许多信息。
片元处理:该阶段主要是通过片元着色器来计算片元的最终颜色和深度值,同时通过深度测试和模板测试来判断当前片元是否可见,如果片元通过测试,那它就可以被直接绘制到帧缓存中了。