WebGL实现带纹理开放圆柱体遇glmatrix 'out is null'错误求助
解决WebGL中glMatrix的"out is null"错误
问题根源
你遇到的"out is null"错误,核心原因是**worldMatrix、viewMatrix、projectionMatrix这些矩阵变量只做了声明,但没有初始化**。glMatrix库的mat4方法(比如mat4.identity、mat4.lookAt、mat4.perspective)要求第一个参数(输出矩阵)必须是一个已创建的mat4实例,不能是null,否则就会抛出这个错误。
另外,你代码里的xRotationMatrix和identityMatrix也存在同样的未初始化问题,会导致后续旋转逻辑报错。
修复步骤
1. 初始化所有矩阵变量
在全局变量声明处,把矩阵变量初始化为mat4.create()创建的实例:
var mat4 = glMatrix.mat4; var segments = 64; var cylVertices=[]; //sidevertices var positionAttribLocation = null; var gl = null; var program = null; var cylVertexBufferObject = null; var matWorldUniformLocation =null; var matViewUniformLocation =null; var matProjectionUniformLocation =null; // 初始化矩阵实例 var worldMatrix = mat4.create(); var viewMatrix = mat4.create(); var projectionMatrix = mat4.create(); var xRotationMatrix = mat4.create(); var identityMatrix = mat4.create(); mat4.identity(identityMatrix); // 初始化单位矩阵 var canvas = null; // ... 其他代码保持不变
2. 修正setCamera()函数
确保所有mat4方法都使用已初始化的矩阵作为输出参数,同时可以调整相机的上方向([0,10,0]改成[0,1,0]更符合常规3D空间设定):
function setCamera(){ mat4.identity(worldMatrix); // 修正lookAt的上方向为[0,1,0](可选,但更合理) mat4.lookAt(viewMatrix, [0,1,-8], [0,0,0], [0,1,0]); mat4.perspective(projectionMatrix, glMatrix.glMatrix.toRadian(45), canvas.width/canvas.height, 0.1, 1000.0); gl.uniformMatrix4fv(matWorldUniformLocation, gl.FALSE, worldMatrix); gl.uniformMatrix4fv(matViewUniformLocation, gl.FALSE, viewMatrix); gl.uniformMatrix4fv(matProjectionUniformLocation, gl.FALSE, projectionMatrix); };
3. 修复顶点生成逻辑
你当前的顶点生成代码有逻辑错误,theta的计算不正确,会导致圆柱体顶点排列混乱,修正如下:
// 替换原来的顶点生成代码 var thetaStep = (2 * Math.PI) / segments; // 每个分段的弧度 for (i = 0; i <= segments; i++){ var theta = i * thetaStep; var x = Math.cos(theta); var z = Math.sin(theta); var s = i / segments; // 纹理坐标S分量从0到1 cylVertices.push(x, 0, z, s, 0); // 底部顶点 cylVertices.push(x, 2, z, s, 1); // 顶部顶点(纹理T分量改成1更合理) } cylArray = new Float32Array(cylVertices);
4. 优化渲染循环中的重复操作
你的drawCylSide()函数在每次渲染循环里都会创建新的Buffer和Texture,这会严重影响性能,建议把Buffer和Texture的创建移到initDemo()中:
// 在initDemo()中添加Buffer和Texture的初始化 var cylVertexBufferObject; var boxTexture; var initDemo = function () { // ... 原有代码(WebGL初始化、着色器创建等) // 初始化顶点Buffer cylVertexBufferObject = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, cylVertexBufferObject); gl.bufferData(gl.ARRAY_BUFFER, cylArray, gl.STATIC_DRAW); // 初始化纹理 boxTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, boxTexture); gl.texParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameter(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, document.getElementById('wall-img') ); gl.bindTexture(gl.TEXTURE_2D, null); // 获取uniform位置(这一步也应该移到initDemo里,不用每次循环获取) matWorldUniformLocation = gl.getUniformLocation(program, 'mWorld'); matViewUniformLocation = gl.getUniformLocation(program, 'mView'); matProjectionUniformLocation = gl.getUniformLocation(program, 'mProjection'); // ... 渲染循环部分 }; // 修改drawCylSide()为只做绘制操作 function drawCylSide(){ gl.useProgram(program); gl.bindBuffer(gl.ARRAY_BUFFER, cylVertexBufferObject); setPointer(5); var texCoordAttribLocation = gl.getAttribLocation(program,'vertTexCoord'); gl.vertexAttribPointer( texCoordAttribLocation, 2, gl.FLOAT, gl.FALSE, 5 * Float32Array.BYTES_PER_ELEMENT, 3 * Float32Array.BYTES_PER_ELEMENT, ); gl.enableVertexAttribArray(positionAttribLocation); gl.enableVertexAttribArray(texCoordAttribLocation); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, boxTexture); gl.drawArrays(gl.TRIANGLE_STRIP, 0, cylVertices.length / 5); // 使用正确的顶点数量 };
额外建议
- 确保你的纹理图片
wall-img在DOM中存在,并且加载完成后再初始化WebGL(可以用img.onload触发initDemo()),避免纹理加载失败。 - 检查着色器中的uniform和attribute名称是否和JS代码中的一致,避免拼写错误。
内容的提问来源于stack exchange,提问作者Ebrahim Adams
相关产品推荐
相关产品推荐

