WebGL 变量

向 shader 中传值

  • attribute: 属性,存放与顶点相关的数据,只能在顶点着色器中使用。
  • uniform: 一致变量,每次绘制像素点时都会调用且一直保持一致。传递与顶点无关的数据,在顶点着色器和片元着色器中都可以使用。
  • varying: 多变变量,从顶点着色器往片段着色器中传递的值,需要在顶点着色器和片段着色器中均设置匹配的多变变量。当 WebGL 绘制像素时,它会 栅格化 该值,然后传递到片段着色器中相对应的片段着色器。

向 attribute 中传值

1
2
var a_PointSize = gl.getAttribLocation(shaderProgram, "a_PointSize");
gl.vertexAttrib1f(a_PointSize, 10.0);

向 uniform 中传值

1
2
3
4
5
var u_Width = gl.getUniformLocation(gl.program, "u_Width");
// uniform[1234][fi][v]
gl.uniform1f(u_Width, gl.drawingBufferWidth);
// uniformMatrix[234]fv()
gl.uniformMatrix2fv(u_Width, false, [2,1, 2,2]);

使用 varying 变量再着色器间传值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var vertexShaderSrc = `
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
void main(){
gl_Position = a_Position;
v_Color = a_Color;
}`;

var fragmentShaderSrc = `
precision mediump float;
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}`;

评论和共享

WebGL 初探

WebGL 初探

基本原理

WebGL 是基于光栅化的 API ,而不是基于 3D 的 API。WebGL 程序的任务就是实现具有投影矩阵坐标和颜色的 WebGL 对象即可。

无论要实现的图形尺寸有多大,其投影矩阵的坐标的范围始终是从 -1 到 1。

GPU 有两个基础任务,第一个就是将点处理为投影矩阵。第二部分就是基于第一部分将相应的像素点描绘出来。

顶点着色器

上图左侧的是用户自己提供的数据。定点着色器就是用户在 GLSL 中写的函数。处理每个定点时,均会被调用一次。用户可以将投影矩阵的值存储在特定的变量 gl_Position 中。GPU 会处理这些值,并将他们存储在其内部。

假设用户希望绘制三角形 TRIANGLES, 那么每次绘制时,上述的第一部分就会产生三个顶点,然后 GPU 会使用他们来绘制三角形。首先 GPU 会将三个顶点对应的像素绘制出来,然后将三角形光栅化,或者说是使用像素点绘制出来。对每一个像素点,GPU 都会调用用户定义的片段着色器来确定该像素点该涂成什么颜色。当然,用户定义的片段着色器必须在 gl_FragColor 变量中设置对应的值。

WebGL 将会连接顶点着色器中的变量和片段着色器中的相同名字和类型的变量。

我们仅仅计算三个顶点。我们的顶点着色器被调用了三次,因此,仅仅计算了三个颜色。而我们的三角形可以有好多颜色,这就是为何被称为 varying

例子

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
53
54
55
56
57
58
const canvas = document.getElementById("canvas")
const gl = canvas.getContext("webgl")
if (!gl) {
console.log('浏览器不支持 WebGL')
}

// 顶点着色器
const VSHADER_SOURCE = `
attribute vec2 a_position;

void main() {
gl_Position = vec4(a_position, 0, 1);
}
`
// 片元着色器
const FSHADER_SOURCE = `
void main() {
gl_FragColor = vec4(0, 1, 0, 1); // green
}
`

// 编译着色器
const vertShader = gl.createShader(gl.VERTEX_SHADER)
gl.shaderSource(vertShader, VSHADER_SOURCE)
gl.compileShader(vertShader)

const fragShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(fragShader, FSHADER_SOURCE)
gl.compileShader(fragShader)

// 合并程序
const shaderProgram = gl.createProgram()
this.shaderProgram = shaderProgram
gl.attachShader(shaderProgram, vertShader)
gl.attachShader(shaderProgram, fragShader)
gl.linkProgram(shaderProgram)
gl.useProgram(shaderProgram)

const positionLocation = gl.getAttribLocation(shaderProgram, "a_position")
const buffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
-1.0, -1.0,
1.0, -1.0,
-1.0, 1.0,
-1.0, 1.0,
1.0, -1.0,
1.0, 1.0
]),
gl.STATIC_DRAW
)
gl.enableVertexAttribArray(positionLocation)
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0)

// draw
gl.drawArrays(gl.TRIANGLES, 0, 6)

评论和共享

  • 第 1 页 共 1 页
作者的图片

Archie Shi

Nothing to say


Front-End Development Engineer