webgl2 方法解析: getProgramParameter()

118 阅读2分钟

getProgramParameter 是 WebGL2 中的一个方法,用于获取已链接程序对象(program object)的参数信息。

基本用法

gl.getProgramParameter(program, pname);

参数说明

  1. program - 要查询的 WebGL 程序对象

  2. pname - 指定要查询的参数名称,可以是以下值之一:

    • gl.DELETE_STATUS - 返回布尔值,表示程序是否被标记为删除
    • gl.LINK_STATUS - 返回布尔值,表示最后一次链接操作是否成功
    • gl.VALIDATE_STATUS - 返回布尔值,表示最后一次验证操作是否成功
    • gl.ATTACHED_SHADERS - 返回附加到程序的着色器数量
    • gl.ACTIVE_ATTRIBUTES - 返回程序中活动属性变量的数量
    • gl.ACTIVE_UNIFORMS - 返回程序中活动uniform变量的数量
    • gl.TRANSFORM_FEEDBACK_BUFFER_MODE - 返回变换反馈缓冲区模式
    • gl.TRANSFORM_FEEDBACK_VARYINGS - 返回变换反馈varying变量的数量
    • gl.ACTIVE_UNIFORM_BLOCKS - 返回程序中活动uniform块的数量

返回值

根据查询的参数不同,返回不同类型的值:

  • 布尔值(对于状态查询)
  • 数值(对于数量查询)
  • 枚举值(对于模式查询)

使用示例

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

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebGL2 getProgramParameter 示例</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        canvas { border: 1px solid #ccc; }
        pre { background: #f5f5f5; padding: 10px; border-radius: 5px; }
​
        #container {
          display: flex;
          justify-content: space-around;
        }
    </style>
</head>
<body>
  <div id="container">
    <div>
      <h2>WebGL2 getProgramParameter 示例</h2>
      <canvas id="glCanvas" width="400" height="300"></canvas>
    </div>
    <div>
      <h2>程序参数输出:</h2>
      <pre id="output"></pre>
    </div>
  </div>
​
    <script>
        // 顶点着色器代码
        const vsSource = `#version 300 es
          in vec4 aPosition;
          void main() {
            gl_Position = aPosition;
          }
        `;
​
        // 片段着色器代码
        const fsSource = `#version 300 es
          precision highp float;
          out vec4 fragColor;
          void main() {
            fragColor = vec4(1.0, 0.5, 0.2, 1.0);
          }
        `;
​
        // 初始化WebGL2上下文
        const canvas = document.getElementById('glCanvas');
        const gl = canvas.getContext('webgl2');
        if (!gl) {
          alert('您的浏览器不支持WebGL2');
          throw new Error('WebGL2 not supported');
        }
​
        const vertexShader = createShader(gl, vsSource, gl.VERTEX_SHADER);
        const fragmentShader = createShader(gl, fsSource, gl.FRAGMENT_SHADER);
        const program = createProgram(gl, vertexShader, fragmentShader);
​
        // 执行查询
        logAllProgramParameters(gl, program);
​
        render();
​
        // 创建着色器函数
        function createShader(gl, source, type) {
            const shader = gl.createShader(type);
            gl.shaderSource(shader, source);
            gl.compileShader(shader);
            
            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                console.error('着色器编译错误:', gl.getShaderInfoLog(shader));
                gl.deleteShader(shader);
                return null;
            }
            
            return shader;
        }
​
        // 创建程序函数
        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('程序链接错误:', gl.getProgramInfoLog(program));
                gl.deleteProgram(program);
                return null;
            }
            
            return program;
        }
​
        // 查询并输出所有程序参数
        function logAllProgramParameters(gl, program) {
            const outputElement = document.getElementById('output');
            let outputText = '';
​
            // 定义所有可能的pname值
            const parameters = {
                'DELETE_STATUS': gl.DELETE_STATUS,
                'LINK_STATUS': gl.LINK_STATUS,
                'VALIDATE_STATUS': gl.VALIDATE_STATUS,
                'ATTACHED_SHADERS': gl.ATTACHED_SHADERS,
                'ACTIVE_ATTRIBUTES': gl.ACTIVE_ATTRIBUTES,
                'ACTIVE_UNIFORMS': gl.ACTIVE_UNIFORMS,
                'TRANSFORM_FEEDBACK_BUFFER_MODE': gl.TRANSFORM_FEEDBACK_BUFFER_MODE,
                'TRANSFORM_FEEDBACK_VARYINGS': gl.TRANSFORM_FEEDBACK_VARYINGS,
                'ACTIVE_UNIFORM_BLOCKS': gl.ACTIVE_UNIFORM_BLOCKS
            };
​
            // 查询每个参数
            for (const [name, value] of Object.entries(parameters)) {
                try {
                    const paramValue = gl.getProgramParameter(program, value);
                    outputText += `${name}: ${paramValue}\n`;
                    console.log(outputText);
                } catch (e) {
                    outputText += `${name}: 查询失败 (${e.message})\n`;
                }
            }
​
            outputElement.textContent = outputText;
            console.log(outputText);
        }
​
        // 简单的渲染演示
        function render() {
            // 设置视口和清除颜色
            gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
            gl.clearColor(0.2, 0.3, 0.4, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT);
            
            // 使用我们的程序
            gl.useProgram(program);
            
            // 创建顶点缓冲区
            const positionBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
            
            // 设置三角形位置
            const positions = [
                0, 0.5,
                -0.5, -0.5,
                0.5, -0.5
            ];
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
            
            // 获取属性位置并启用
            const positionAttributeLocation = gl.getAttribLocation(program, "aPosition");
            gl.enableVertexAttribArray(positionAttributeLocation);
            gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
            
            // 绘制
            gl.drawArrays(gl.TRIANGLES, 0, 3);
        }
​
    </script>
</body>
</html>

注意事项

  1. 使用此方法前,确保程序对象已经通过gl.linkProgram()进行了链接
  2. 对于失败的情况,可以使用gl.getProgramInfoLog()获取更详细的错误信息
  3. 查询不存在的程序对象会导致WebGL错误