You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:44:02