WebGL曼德博集合程序报错:无有效着色器程序(编译链接验证正常)
WebGL曼德博集合程序报错:drawArrays时无有效着色器程序使用
我在编写一个生成曼德博集合的WebGL程序,使用Chrome浏览器,GPU为GTX 1660 Ti。着色器编译、链接、验证均成功,但调用drawArrays时出现错误:
mandelbrot.js:33 WebGL: INVALID_OPERATION: drawArrays: no valid shader program in use
排查1小时未找到问题,相关代码如下:
顶点着色器
precision mediump float; attribute vec2 position; varying vec2 fragPosition; void main() { gl_Position = vec4(position, 0.0, 1.0); fragPosition = position; }
片元着色器
precision mediump float; #define ITERATIONS 50 varying vec2 fragPosition; vec2 cx_mul(vec2 a, vec2 b) { return vec2(a.x*b.x-a.y*b.y, a.x*b.y+a.y*b.x); } void main() { int itr = 0; vec2 z = fragPosition, c = fragPosition; for(int i = 0; i < 50; i++) { itr = i; z = cx_mul(z, z) + c; if(length(z) > 2.0) break; } gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }
JavaScript代码(mandelbrot.js)
var gl; var canvas; var program; const address = '127.0.0.1'; import {initGL, compileShaders, bindVAO, loadFile} from './util.js'; window.onload = function() { canvas = document.getElementById('canvas'); gl = canvas.getContext('webgl'); if(!gl) gl = canvas.getContext('experimental-webgl'); initGL(gl); var vertexCode = loadFile('http://' + address + '/mandelbrot.vert'); var fragmentCode = loadFile('http://' + address + '/mandelbrot.frag'); var vertexShader = gl.createShader(gl.VERTEX_SHADER); var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(vertexShader, vertexCode); gl.shaderSource(fragmentShader, fragmentCode); compileShaders(vertexShader, fragmentShader); bindVAO(); gl.useProgram(program); update(); } function update() { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); }
工具代码(util.js)
export {initGL, compileShaders, bindVAO, loadFile}; var gl; function initGL(glContext) { gl = glContext; } function compileShaders(vertexShader, fragmentShader) { gl.compileShader(vertexShader); if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) throw ("compilation error: " + gl.getShaderInfoLog(vertexShader)); gl.compileShader(fragmentShader); if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) throw ("compilation error: " + gl.getShaderInfoLog(fragmentShader)); var program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); if(!gl.getProgramParameter(program, gl.LINK_STATUS)) throw ("linking error: " + gl.getProgramInfoLog(program)); gl.validateProgram(program); if(!gl.getProgramParameter(program, gl.VALIDATE_STATUS)) throw ("validation error: " + gl.getProgramInfoLog(program)); return program; } function bindVAO() { var vertices = new Float32Array([-1, 1, -1, -1, 1, 1, 1, -1]); var vao = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vao); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); gl.vertexAttribPointer(0, 2, gl.FLOAT, gl.FALSE, 2 * Float32Array.BYTES_PER_ELEMENT, 0); gl.enableVertexAttribArray(0); } function loadFile(url) { var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", url, false); xmlHttp.send(null); return xmlHttp.responseText; }
问题原因与修复方案
核心错误:着色器程序未赋值给全局变量
util.js中的compileShaders函数会返回编译链接完成的着色器程序,但你在mandelbrot.js中调用该函数时,没有将返回值赋值给全局的program变量,导致gl.useProgram(program)传入的是undefined(无效程序),触发报错。
修复代码:修改mandelbrot.js中的调用逻辑:
// 原代码 compileShaders(vertexShader, fragmentShader); // 修复后 program = compileShaders(vertexShader, fragmentShader);
额外优化建议
- 修正
bindVAO函数名:WebGL 1.0不支持顶点数组对象(VAO),此处创建的是顶点缓冲区对象(VBO),建议将函数名改为bindVertexBuffer,避免概念混淆。 - 使用宏定义的迭代次数:片元着色器中定义了
ITERATIONS宏,但循环硬编码了50,可改为i < ITERATIONS,提升代码可维护性:
for(int i = 0; i < ITERATIONS; i++) {
内容的提问来源于stack exchange,提问作者imlol69420
相关产品推荐
相关产品推荐

