linkProgram() 是 WebGL2 中的一个重要方法,用于链接已附加了着色器的程序对象。
功能描述
linkProgram() 方法将一个包含顶点着色器和片段着色器的程序对象进行链接,生成可执行的 WebGL 程序。在链接的过程中会将vs和fs代码联合起来检查, 看两个在传输过程中有没有出错。(注: 与attachShader()不同, attachShader只检查当前的shader的语法是否错误)。
详细说明
-
链接过程:这个方法将检查附加到程序对象的着色器之间的兼容性,并创建可执行代码。
-
验证链接状态:链接完成后,可以使用
gl.getProgramParameter(program, gl.LINK_STATUS)检查链接是否成功。 -
获取链接信息:如果链接失败,可以使用
gl.getProgramInfoLog(program)获取错误信息。 -
典型使用流程:
- 创建程序对象 (
gl.createProgram()) - 附加着色器 (
gl.attachShader()) - 链接程序 (
gl.linkProgram()) - 检查链接状态
- 使用程序 (
gl.useProgram())
- 创建程序对象 (
使用方法
gl.linkProgram(program);
program:要链接的WebGLProgram对象
与attachShader的区别
attachShader只检查当前的shader的语法是否错误,比如下方的两个shader, attachShader()不会报错,因为它们的语法并没有错
#version 300 es
in vec4 aPosition;
void main() {
gl_Position = aPosition;
}
#version 300 es
precision highp float;
in vec4 color;
out vec4 fragColor;
void main() {
fragColor = color;
}
但是它们配合起来工作就会发生错误, 因为vs中没有out, 但是fs中却in了, 所以linkProgram()阶段会报错
示例代码
下方是一个可以直接运行的示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL2 linkProgram() 示例</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
canvas { border: 1px solid #000; margin-top: 10px; }
button { margin: 5px; padding: 8px 15px; }
.container { margin-bottom: 20px; }
</style>
</head>
<body>
<h1>WebGL2 linkProgram() 示例</h1>
<div class="container">
<button id="successBtn">测试链接成功</button>
<button id="failBtn">测试链接失败</button>
</div>
<canvas id="glCanvas" width="400" height="300"></canvas>
<div id="status">状态: 未初始化</div>
<script>
// 获取Canvas和WebGL2上下文
const canvas = document.getElementById('glCanvas');
const gl = canvas.getContext('webgl2');
const statusDiv = document.getElementById('status');
if (!gl) {
statusDiv.textContent = '状态: 您的浏览器不支持WebGL2';
throw new Error('WebGL2 not supported');
}
// 顶点着色器源码 - 成功案例
const vsSourceSuccess = `#version 300 es
in vec4 aPosition;
out vec4 vColor;
void main() {
gl_Position = aPosition;
vColor = vec4(1.0, 0.0, 0.0, 1.0);
}`;
// 片段着色器源码 - 成功案例
const fsSourceSuccess = `#version 300 es
precision highp float;
in vec4 vColor;
out vec4 fragColor;
void main() {
fragColor = vColor;
}`;
// 片段着色器源码 - 失败案例(故意写错)
const fsSourceFail = `#version 300 es
precision highp float;
in vec4 color;
out vec4 fragColor;
void main() {
fragColor = color;
}`;
// 创建着色器函数
function createShader(gl, sourceCode, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, sourceCode);
gl.compileShader(shader);
// 检查编译状态
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('着色器编译错误:', gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgram(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('程序链接错误:', gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return null;
}
// 可以删除着色器了,它们已经链接到程序中
gl.deleteShader(vertexShader);
gl.deleteShader(fragmentShader);
return program;
}
// 渲染函数
function render(program) {
if (!program) return;
gl.useProgram(program);
// 设置顶点数据
const positionAttributeLocation = gl.getAttribLocation(program, "aPosition");
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);
// 启用并设置顶点属性指针
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);
// 清空画布并绘制
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
// 按钮事件处理
document.getElementById('successBtn').addEventListener('click', () => {
statusDiv.textContent = '状态: 尝试链接成功案例...';
const vertexShader = createShader(gl, vsSourceSuccess, gl.VERTEX_SHADER);
const fragmentShader = createShader(gl, fsSourceSuccess, gl.FRAGMENT_SHADER);
const program = createProgram(vertexShader, fragmentShader);
statusDiv.textContent = '状态: 链接成功 - 显示橙色三角形';
render(program);
});
document.getElementById('failBtn').addEventListener('click', () => {
statusDiv.textContent = '状态: 尝试链接失败案例...';
const vertexShader = createShader(gl, vsSourceSuccess, gl.VERTEX_SHADER);
const fragmentShader = createShader(gl, fsSourceFail, gl.FRAGMENT_SHADER);
const program = createProgram(vertexShader, fragmentShader);
if (program === null){
statusDiv.textContent = '状态: 链接失败(如预期) - 错误信息已输出到控制台';
// 清除画布
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
}
});
// 初始状态
statusDiv.textContent = '状态: 点击按钮测试链接成功或失败案例';
</script>
</body>
</html>
注意事项
- 在链接前必须确保所有需要的着色器都已正确附加
- 链接失败通常是由于着色器代码错误或着色器间不兼容导致的
- 链接成功后,可以删除着色器对象以释放资源