一、WebGL 着色器中的数据类型
在 WebGL 中,着色器的数据传递主要通过两类变量进行:属性(Attributes)和统一变量(Uniforms) 。此外,还有变换变量(Varyings) ,它们用于在着色器之间传递数据。
1. 顶点属性(Attributes)
顶点属性是传递给顶点着色器的输入数据。每个属性都代表一个数据集,例如顶点位置、颜色、法线或纹理坐标等。顶点着色器通过这些属性来计算每个顶点的位置或其他属性。
- 使用场景:用于传递每个顶点的具体信息。
- 数据类型:通常是
vec3
、vec4
或float
等。
示例:
// 顶点着色器中的属性声明
attribute vec3 aPosition; // 顶点位置
attribute vec4 aColor; // 顶点颜色
2. 统一变量(Uniforms)
统一变量是可以在所有顶点和片段着色器中使用的常量值,它们通常用于传递全局信息,如模型矩阵、视图矩阵、光源位置、材质属性等。统一变量的值在渲染过程中不会改变。
- 使用场景:用于传递常量数据,且这些数据在每个绘制调用中都保持不变。
- 数据类型:支持多种类型,包括
mat4
、vec4
、float
等。
示例:
// 顶点着色器中的统一变量声明
uniform mat4 uModelViewMatrix; // 模型视图矩阵
uniform mat4 uProjectionMatrix; // 投影矩阵
3. 变换变量(Varyings)
变换变量用于在顶点着色器和片段着色器之间传递数据。顶点着色器可以计算和输出这些变量,而片段着色器则读取它们。Varying 变量通常用于传递从顶点计算出的值(如颜色、法线、纹理坐标等)。
- 使用场景:用于将顶点着色器中的输出传递给片段着色器。
- 数据类型:与顶点着色器中的输出数据类型相匹配。
示例:
// 顶点着色器中的 Varying 变量声明
varying vec4 vColor; // 从顶点着色器传递到片段着色器的颜色
void main() {
vColor = aColor; // 将顶点颜色传递给片段着色器
}
4. 片段着色器中的输入变量(Fragment Shader Inputs)
片段着色器接收来自顶点着色器通过 Varying 变量传递的数据。在片段着色器中,这些变量通常用于计算最终的像素颜色或进行其他图像处理。
- 使用场景:在片段着色器中处理像素级别的数据。
- 数据类型:与顶点着色器的 Varying 变量匹配。
示例:
// 片段着色器中的输入变量声明
precision mediump float;
varying vec4 vColor; // 来自顶点着色器的颜色
void main() {
gl_FragColor = vColor; // 设置片段的最终颜色
}
二、在 WebGL 中传递数据给着色器
WebGL 提供了一些方法和 API,允许开发者从 JavaScript 代码向着色器传递数据。以下是常见的数据传递方法。
1. 向着色器传递顶点数据
顶点数据通常存储在一个数组中,并通过 WebGL 的顶点缓冲区(Vertex Buffer)传递给着色器。下面是传递顶点数据的基本步骤:
- 创建缓冲区并绑定数据。
- 使用
gl.getAttribLocation()
获取属性位置。 - 使用
gl.vertexAttribPointer()
定义数据格式并启用顶点属性。
示例代码:
// 顶点数据:位置和颜色
var vertices = new Float32Array([
0.0, 1.0, 0.0, 1.0, 0.0, 0.0, // 顶部红色
-1.0, -1.0, 0.0, 0.0, 1.0, 0.0, // 左下绿色
1.0, -1.0, 0.0, 0.0, 0.0, 1.0 // 右下蓝色
]);
// 创建缓冲区并传递数据
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// 获取属性位置并启用顶点属性
var positionAttribLocation = gl.getAttribLocation(shaderProgram, "aPosition");
var colorAttribLocation = gl.getAttribLocation(shaderProgram, "aColor");
gl.vertexAttribPointer(positionAttribLocation, 3, gl.FLOAT, false, 6 * 4, 0);
gl.vertexAttribPointer(colorAttribLocation, 3, gl.FLOAT, false, 6 * 4, 3 * 4);
gl.enableVertexAttribArray(positionAttribLocation);
gl.enableVertexAttribArray(colorAttribLocation);
// 绘制三角形
gl.drawArrays(gl.TRIANGLES, 0, 3);
2. 向着色器传递统一变量
统一变量通常用于传递不会改变的全局数据,如矩阵、光源信息等。可以通过 gl.getUniformLocation()
获取统一变量的存储位置,然后使用 gl.uniformMatrix4fv()
、gl.uniform4fv()
等方法传递具体的数据。
示例代码:
// 获取统一变量位置
var uModelViewMatrixLoc = gl.getUniformLocation(shaderProgram, "uModelViewMatrix");
var uProjectionMatrixLoc = gl.getUniformLocation(shaderProgram, "uProjectionMatrix");
// 设置统一变量的值
var modelViewMatrix = new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, -5,
0, 0, 0, 1
]);
var projectionMatrix = new Float32Array([
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, -1.0, -2.0,
0.0, 0.0, -1.0, 0.0
]);
gl.uniformMatrix4fv(uModelViewMatrixLoc, false, modelViewMatrix);
gl.uniformMatrix4fv(uProjectionMatrixLoc, false, projectionMatrix);
3. 向着色器传递变换变量
变换变量用于在顶点着色器和片段着色器之间传递数据。顶点着色器计算并输出这些数据,片段着色器接收并使用它们。
示例代码:
// 顶点着色器
varying vec4 vColor;
void main() {
// 将顶点颜色传递给片段着色器
vColor = aColor;
}
// 片段着色器
precision mediump float;
varying vec4 vColor;
void main() {
// 输出颜色
gl_FragColor = vColor;
}