WebGL 着色器中的数据传递

156 阅读4分钟

一、WebGL 着色器中的数据类型

在 WebGL 中,着色器的数据传递主要通过两类变量进行:属性(Attributes)统一变量(Uniforms) 。此外,还有变换变量(Varyings) ,它们用于在着色器之间传递数据。

1. 顶点属性(Attributes)

顶点属性是传递给顶点着色器的输入数据。每个属性都代表一个数据集,例如顶点位置、颜色、法线或纹理坐标等。顶点着色器通过这些属性来计算每个顶点的位置或其他属性。

  • 使用场景:用于传递每个顶点的具体信息。
  • 数据类型:通常是 vec3vec4float 等。
示例:
// 顶点着色器中的属性声明
attribute vec3 aPosition;  // 顶点位置
attribute vec4 aColor;     // 顶点颜色

2. 统一变量(Uniforms)

统一变量是可以在所有顶点和片段着色器中使用的常量值,它们通常用于传递全局信息,如模型矩阵、视图矩阵、光源位置、材质属性等。统一变量的值在渲染过程中不会改变。

  • 使用场景:用于传递常量数据,且这些数据在每个绘制调用中都保持不变。
  • 数据类型:支持多种类型,包括 mat4vec4float 等。
示例:
// 顶点着色器中的统一变量声明
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;
}