着色器编程入门
一、GLSL简介
GLSL(OpenGL Shading Language)是用于编写着色器的编程语言。它是一种高级编程语言,类似于C语言,但专门用于编写图形硬件(如GPU)上的着色器程序。GLSL是WebGL和OpenGL的核心组成部分,用于实现顶点着色器和片元着色器的功能。
(一)GLSL的基本语法
变量类型:
- 标量类型:
float
(浮点数)、int
(整数)、bool
(布尔值)。 - 向量类型:
vec2
(二维浮点向量)、vec3
(三维浮点向量)、vec4
(四维浮点向量)。 - 矩阵类型:
mat2
(2x2矩阵)、mat3
(3x3矩阵)、mat4
(4x4矩阵)。 - 结构体类型:可以自定义复杂的数据结构。
glslfloat scalar = 1.0; vec3 position = vec3(0.0, 0.5, 0.0); mat4 transformMatrix = mat4(1.0);
- 标量类型:
变量修饰符:
attribute
:用于顶点着色器,表示从顶点数据中接收的输入。varying
:用于顶点着色器和片元着色器之间传递数据。uniform
:用于从JavaScript代码向着色器传递常量数据。
glslattribute vec4 a_position; // 顶点位置 varying vec4 v_color; // 传递给片元着色器的颜色 uniform mat4 u_transform; // 从JavaScript传递的变换矩阵
函数:
- GLSL支持函数的定义和调用,内置了许多数学函数,如
sin
、cos
、dot
(点乘)、cross
(叉乘)等。
glslfloat calculateLength(vec3 v) { return length(v); }
- GLSL支持函数的定义和调用,内置了许多数学函数,如
控制语句:
- GLSL支持
if
、for
、while
等控制语句,但通常不建议在着色器中使用复杂的控制逻辑,因为这会影响性能。
glslif (scalar > 0.5) { scalar = 1.0; }
- GLSL支持
二、顶点着色器
(一)顶点着色器的作用
顶点着色器是着色器程序的第一部分,它对每个顶点进行处理。顶点着色器的主要任务包括:
- 顶点变换:将顶点从模型空间转换到裁剪空间。
- 光照计算:计算顶点的光照属性(如颜色、法线等)。
- 传递数据:将处理后的数据(如颜色、纹理坐标等)传递给片元着色器。
(二)如何将顶点数据传递给着色器
顶点数据通过attribute
变量传递给顶点着色器。在JavaScript中,需要将顶点数据存储到缓冲区中,并绑定到相应的attribute
变量。
javascript
// 创建缓冲区
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// 将顶点数据存储到缓冲区
const positions = [
0.0, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
// 获取attribute变量的位置
const positionLocation = gl.getAttribLocation(program, 'a_position');
// 绑定缓冲区到attribute变量
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
顶点着色器代码示例:
glsl
attribute vec4 a_position; // 顶点位置
uniform mat4 u_transform; // 变换矩阵
varying vec4 v_color; // 传递给片元着色器的颜色
void main() {
gl_Position = u_transform * a_position; // 应用变换
v_color = vec4(1.0, 0.0, 0.0, 1.0); // 设置颜色
}
三、片元着色器
(一)片元着色器的作用
片元着色器是着色器程序的第二部分,它对每个片元(像素)进行处理。片元着色器的主要任务包括:
- 颜色计算:计算每个片元的最终颜色。
- 纹理映射:应用纹理到片元。
- 光照计算:对片元进行光照计算。
(二)如何计算每个像素的颜色
片元着色器接收顶点着色器传递过来的数据(如颜色、纹理坐标等),并计算最终的像素颜色。片元着色器的输出是gl_FragColor
,它决定了屏幕上每个像素的颜色。
片元着色器代码示例:
glsl
precision mediump float; // 精度声明
varying vec4 v_color; // 从顶点着色器接收的颜色
void main() {
gl_FragColor = v_color; // 设置片元颜色
}
四、着色器编译和链接
(一)编写着色器代码
着色器代码通常以字符串的形式存储在JavaScript中。顶点着色器和片元着色器分别负责不同的任务,因此需要分别编写。
javascript
const vertexShaderSource = `
attribute vec4 a_position;
uniform mat4 u_transform;
varying vec4 v_color;
void main() {
gl_Position = u_transform * a_position;
v_color = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
const fragmentShaderSource = `
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
`;
(二)编译着色器
使用WebGL的API将着色器代码编译为着色器对象。
javascript
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('Shader compile failed with: ' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
(三)链接着色器到程序
将顶点着色器和片元着色器链接到一个WebGL程序对象中。
javascript
function createProgram(gl, vertexShader, fragmentShader) {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Program link failed with: ' + gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return null;
}
return program;
}
const program = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(program);
(四)传递数据到着色器
通过uniform
变量将数据从JavaScript传递到着色器。
javascript
// 获取uniform变量的位置
const transformLocation = gl.getUniformLocation(program, 'u_transform');
// 创建变换矩阵
const transformMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
];
// 将变换矩阵传递给着色器
gl.uniformMatrix4fv(transformLocation, false, transformMatrix);
总结
着色器编程是WebGL的核心内容,通过GLSL语言编写顶点着色器和片元着色器,可以实现复杂的图形效果。顶点着色器负责处理顶点数据,片元着色器负责计算每个像素的颜色。通过编译和链接着色器,可以将它们组合成一个WebGL程序,并通过uniform
变量传递数据。掌握这些基础知识后,你可以开始探索更高级的图形技术,如纹理映射、光照计算等。