webgl2 方法解析: getShaderInfoLog()

117 阅读3分钟

在 WebGL2 中,gl.getShaderInfoLog() 是一个非常重要的函数,用于获取着色器编译过程中的日志信息。它通常用于调试着色器代码,帮助开发者了解着色器编译失败的原因。

1. 函数定义

gl.getShaderInfoLog(shader) 是 WebGL2 的一个方法,它的作用是返回一个字符串,其中包含了指定着色器的编译日志信息。

  • 参数

    • shader:一个 WebGLShader 对象,表示要查询日志的着色器。
  • 返回值

    • 返回一个字符串,包含着色器编译过程中的日志信息。如果着色器编译成功,通常返回一个空字符串;如果编译失败,则返回错误信息。

2. 使用场景

当你尝试编译一个着色器时,可能会因为语法错误、变量未定义或其他问题导致编译失败。gl.getShaderInfoLog() 可以帮助你获取这些错误信息,从而快速定位问题。

3. 示例代码

以下是一个完整的示例, 可直接运行:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebGL2 getShaderInfoLog</title>
    <style>
        button {
            margin: 10px;
            padding: 10px;
            font-size: 16px;
        }
​
        #glCanvas {
          width: 800px;
          height: 600px;
        }
    </style>
</head>
<body>
    <h1>WebGL2 getShaderInfoLog Example</h1>
    <div id="container">
      <div id="buttons">
        <button id="compileCorrectShader">shader代码编译正确</button>
        <button id="compileErrorShader">shader代码编译错误</button>
      </div>
      <canvas id="glCanvas"></canvas>
    </div>
​
    <script>
        // 创建 WebGL2 上下文
        const canvas = document.getElementById('glCanvas');
        const gl = canvas.getContext('webgl2');
        if (!gl) {
            throw new Error('WebGL2 is not supported');
        }
​
        // 正确的顶点着色器代码
        const correctVertexShaderSource = `#version 300 es
            in vec4 a_position;
            void main() {
              gl_Position = a_position;
            }
        `;
​
        // 错误的顶点着色器代码(故意拼写错误)
        const errorVertexShaderSource = `#version 300 es
            in vec4 a_position;
            void main() {
                gl_Position = a_positoin; // 错误:变量名拼写错误
            }
        `;
​
        const fragmentShaderSource = `#version 300 es
          precision mediump float;
          out vec4 fragColor;
​
          void main() {
            fragColor = vec4(1.0, 0.0, 0.0, 1.0);
          }
        `;
​
        // 编译着色器的函数
        function compileShader(source, type) {
          const shader = gl.createShader(type);
          gl.shaderSource(shader, source);
          gl.compileShader(shader);
​
          // 检查编译状态
          if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
            const log = gl.getShaderInfoLog(shader);
            // alert('Shader compilation failed:', log);
            throw new Error('Shader compilation failed:', log);
            gl.deleteShader(shader);
            return null;
          }
          return shader;
        }
​
        // 创建program
        function compileProgram(vertexShader, fragmentShader) {
          const program = gl.createProgram();
          gl.attachShader(program, vertexShader);
          gl.attachShader(program, fragmentShader);
          gl.linkProgram(program);
​
          // 检查链接状态
          if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
            const infoLog = gl.getProgramInfoLog(program);
            throw new Error('程序连接失败: ' + infoLog );
          }
​
          return program;
​
        }
​
        function render(vertexShaderSource) {
          const vertexShader = compileShader(vertexShaderSource, gl.VERTEX_SHADER);
          const fragmentShader = compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER);
          const program = compileProgram(vertexShader, fragmentShader);
​
          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.useProgram(program);
​
          // 获取并启用顶点属性
          const positionAttribLoc = gl.getAttribLocation(program, 'a_position');
          gl.enableVertexAttribArray(positionAttribLoc);
          gl.vertexAttribPointer(positionAttribLoc, 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('compileCorrectShader').addEventListener('click', () => {
          render(correctVertexShaderSource);
        });
​
        document.getElementById('compileErrorShader').addEventListener('click', () => {
          render(errorVertexShaderSource);
        });
    
    </script>
</body>
</html>

4. 常见错误信息

  • 语法错误:如果着色器代码中存在语法问题,比如拼写错误、缺少分号等,gl.getShaderInfoLog() 会返回具体的错误信息,指出错误的位置。
  • 变量未定义:如果使用了未声明的变量,日志中会提示变量未定义。
  • 类型不匹配:如果着色器代码中存在类型不匹配的问题,也会在日志中显示。

5. 注意事项

  • 日志内容gl.getShaderInfoLog() 返回的日志内容格式可能因浏览器或显卡驱动的不同而有所差异,但通常会包含错误的行号具体和描述。
  • 性能影响:虽然获取日志信息对性能影响不大,但在生产环境中,建议在调试完成后移除相关代码,以避免不必要的开销。