webgl 01 入门

webgl 01 入门

hellow world

一个最简单的 canvas 实例

1
2
3
4
const ctx = document.getElementById('canvas')
const c = ctx.getContext('2d')
c.fillStyle = 'red'
c.fillRect(10,10,100,100)

一个最简单的 webgl 实例

1
2
3
4
5
6
7
8
9
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
//gl.clearColor(r,g,b,a) 取值区间为 0.0~1.0
gl.clearColor(1.0,0.0,0.0,1.0) // red 1.0 green 0.0 blue 0.0 alpha 1.0
//gl.clear(buffer) 清空canvas
//gl.COLOR_BUFFER_BIT 清空颜色缓存 ✅常用
//gl.DEPTH_BUFFER_BIT 清空深度缓冲区
//gl.STENCIL_BUFFER_BIT 清空模板缓冲区
gl.clear(gl.COLOR_BUFFER_BIT)

着色器

着色器就是让开发者自己去编写一段程序,用来代替固定渲染管线,来处理图像的渲染。2d 的渲染比较简单,3d 的渲染需要着色器的帮助。

1
2
3
4
5
---
title: 顶点着色器
---
flowchart LR
顶点着色器-- 用来描述顶点的特性 -->通过计算获取位置信息

顶点是指⼆维三维空间中的⼀个点,可以理解为一个个坐标。

1
2
3
4
5
---
title: 片元着色器
---
flowchart LR
片元着色器-- 进行逐片元处理程序 -->通过计算获取颜色信息

片元可以理解为一个个像素。

特点

  • 区分大小写
  • 结尾;必须
  • 入口 main 函数
  • 强语言类型
    • 不能以 gl_, webgl_开头

工作流程

JavaScript 读取相关着色器信息,传递给 webgl 并进行使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
flowchart TB
subgraph 浏览器
渲染成功
end
subgraph WebGL程序
subgraph 片元着色器
颜色
end
subgraph 顶点着色器
坐标系
end
end
subgraph JavaScript程序
着色器源码
end
JavaScript程序 --> WebGL程序
WebGL程序 --> 浏览器
1
2
3
4
5
6
7
8
flowchart TB
subgraph 初始化着色器Shader
direction LR
创建顶点着色器 --> 创建片元着色器 --> 关联着色器和着色器源码 --> 编译着色器 --> 创建program --> 关联着色器和program --> 使用program
end
开始 --> 获得canvas元素 --> 获取WebGL绘图上下文 --> 初始化顶点着色器源程序 --> 初始化片元着色器源程序
初始化片元着色器源程序 --> 创建顶点着色器
使用program --> 绘图渲染

DEMO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
// 创建着色器源码
// 顶点着色器源码
const VERTEX_SHADER_SOURCE = `
// 必须要存在 main 函数
void main() {
// 要绘制的点的坐标
gl_Position = vec4(0.0,0.0,0.0,1.0);
// 点的大小
gl_PointSize = 30.0;
}
`;
// gl_Position vec4(0.0,0.0,0.0,1.0) x, y, z, w齐次坐标 (x/w, y/w, z/w)
// gl_FragColor vec4(1.0,0.0,0.0,1.0) r, g, b, a
// 片元着色器源码
const FRAGMENT_SHADER_SOURCE = `
void main() {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
`;
//初始化着色器Shader
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;
}
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); // 3个点
// 3个顶点
// 0.0, 0.0, 0.0
// 0.2, 0.0, 0.0
// 0.4, 0.0, 0.0
gl.drawArrays(gl.POINTS, 0, 1);
gl.drawArrays(gl.LINES, 1, 2);

坐标系

!330
与 canvas 的坐标系不同
webgl三维坐标系类似下图
!344
!391
有个左手坐标系和右手坐标系的争论

通过attribute变量绘制一个点

声明 attribute 变量

存储限定符 类型 变量名 分号
attribute vec4 aPosition ;
attribute 变量只能在顶点着色器中使用,不能在片元着色器中使用

使用

vertexAttrib4f

流程

实战

通过鼠标点击绘制点

改变点的颜色