webgl片段着色器

2023/8/22 webgl3D

🌙 片段着色器-Fragment Shader

一个片段着色器的工作是为当前光栅化的像素提供颜色值,通常是以下的形式:

// 片段着色器没有默认精度,所以我们需要设置一个精度
// mediump是一个不错的默认值,代表“medium precision”(中等精度)
precision mediump float;
 
void main() {
    // gl_FragColor是一个片段着色器主要设置的变量
   gl_FragColor = doMathToMakeAColor;
}
1
2
3
4
5
6
7
8

每个像素都将调用一次片段着色器,每次调用需要从你设置的特殊全局变量gl_FragColor中获取颜色信息。

片段着色器所需的数据,可以通过以下三种方式获取

🌙 Uniforms 全局变量 (opens new window)

gl.uniform1f (floatUniformLoc, v);                 // float
gl.uniform1fv(floatUniformLoc, [v]);               // float 或 float array
gl.uniform2f (vec2UniformLoc,  v0, v1);            // vec2
gl.uniform2fv(vec2UniformLoc,  [v0, v1]);          // vec2 或 vec2 array
gl.uniform3f (vec3UniformLoc,  v0, v1, v2);        // vec3
gl.uniform3fv(vec3UniformLoc,  [v0, v1, v2]);      // vec3 或 vec3 array
gl.uniform4f (vec4UniformLoc,  v0, v1, v2, v4);    // vec4
gl.uniform4fv(vec4UniformLoc,  [v0, v1, v2, v4]);  // vec4 或 vec4 array
 
gl.uniformMatrix2fv(mat2UniformLoc, false, [  4x element array ])  // mat2 或 mat2 array
gl.uniformMatrix3fv(mat3UniformLoc, false, [  9x element array ])  // mat3 或 mat3 array
gl.uniformMatrix4fv(mat4UniformLoc, false, [ 16x element array ])  // mat4 或 mat4 array
 
gl.uniform1i (intUniformLoc,   v);                 // int
gl.uniform1iv(intUniformLoc, [v]);                 // int 或 int array
gl.uniform2i (ivec2UniformLoc, v0, v1);            // ivec2
gl.uniform2iv(ivec2UniformLoc, [v0, v1]);          // ivec2 或 ivec2 array
gl.uniform3i (ivec3UniformLoc, v0, v1, v2);        // ivec3
gl.uniform3iv(ivec3UniformLoc, [v0, v1, v2]);      // ivec3 or ivec3 array
gl.uniform4i (ivec4UniformLoc, v0, v1, v2, v4);    // ivec4
gl.uniform4iv(ivec4UniformLoc, [v0, v1, v2, v4]);  // ivec4 或 ivec4 array
 
gl.uniform1i (sampler2DUniformLoc,   v);           // sampler2D (textures)
gl.uniform1iv(sampler2DUniformLoc, [v]);           // sampler2D 或 sampler2D array
 
gl.uniform1i (samplerCubeUniformLoc,   v);         // samplerCube (textures)
gl.uniform1iv(samplerCubeUniformLoc, [v]);         // samplerCube 或 samplerCube array
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

还有一些类型 bool, bvec2, bvec3, and bvec4。它们可用gl.uniform?f?或gl.uniform?i?。

🌙 Textures 纹理(片段着色器中)

在着色器中获取纹理信息,可以先创建一个sampler2D类型全局变量,然后用GLSL方法texture2D 从纹理中提取信息。

precision mediump float;
 
uniform sampler2D u_texture;
 
void main() {
   vec2 texcoord = vec2(0.5, 0.5);  // 获取纹理中心的值
   gl_FragColor = texture2D(u_texture, texcoord);
}
1
2
3
4
5
6
7
8

创建并给纹理填充数据:

var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
var level = 0;
var width = 2;
var height = 1;
var data = new Uint8Array([
   255, 0, 0, 255,   // 一个红色的像素
   0, 255, 0, 255,   // 一个绿色的像素
]);
gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
1
2
3
4
5
6
7
8
9
10
11

在初始化时找到全局变量的地址:

var someSamplerLoc = gl.getUniformLocation(someProgram, "u_texture");

// 在渲染的时候WebGL要求纹理必须绑定到一个纹理单元上
var unit = 5;  // 挑选一个纹理单元
gl.activeTexture(gl.TEXTURE0 + unit);
gl.bindTexture(gl.TEXTURE_2D, tex);

// 告诉着色器你要使用的纹理在那个纹理单元
gl.uniform1i(someSamplerLoc, unit);
1
2
3
4
5
6
7
8
9

🌙 Varyings 可变量

可变量是一种顶点着色器给片段着色器传值的方式。

为了使用可变量,要在两个着色器中定义同名的可变量。 给顶点着色器中可变量设置的值,会作为参考值进行内插,在绘制像素时传给片段着色器的可变量。

顶点着色器

attribute vec4 a_position;

uniform vec4 u_offset;

varying vec4 v_positionWithOffset; // 定义同名变量

void main() {
gl_Position = a_position + u_offset;
v_positionWithOffset = a_position + u_offset;
}
1
2
3
4
5
6
7
8
9
10

片段着色器

precision mediump float;

varying vec4 v_positionWithOffset; // 定义同名变量

void main() {
// 从裁剪空间 (-1 <-> +1) 转换到颜色空间 (0 -> 1).
vec4 color = v_positionWithOffset * 0.5 + 0.5;
gl_FragColor = color;
}
1
2
3
4
5
6
7
8
9

通常情况下直接将裁剪空间的值传给片段着色器当作颜色值是没有意义的, 虽然它可以运行并且可以生成颜色值。上面只是一个示例。