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

WebGL无报错但无法渲染三角形问题求助

WebGL三角形无法渲染问题排查与修复

我尝试用WebGL绘制三角形,程序没有报错,但三角形始终显示不出来。我试过调整输入顺序、重写着色器代码,以下是相关代码片段:

顶点着色器

attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 v_color;

void main()
{
    v_color = a_color;
    gl_Position = a_position;
}

片元着色器(初始错误版本)

attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 v_color;

void main()
{
    v_color = a_color;
    gl_Position = a_position;
}

绘制函数

function drawTri(x1,y1,x2,y2,x3,y3){
    const a_position = new Float32Array([x1,y1,0,1,x2,y2,0,1,x3,y3,0,1]);

    const a_color = new Float32Array([
      testColor[0],testColor[1],testColor[2],testColor[3],
      testColor[0],testColor[1],testColor[2],testColor[3],
      testColor[0],testColor[1],testColor[2],testColor[3]
    ]);

    gl.useProgram(myShaders.untextured.ProgramInf.program);
    gl.viewport(0, 0, 630, 360);

    // Bind Positional Data
    gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer);

    gl.bufferData(gl.ARRAY_BUFFER, a_position, gl.STATIC_DRAW);

    gl.enableVertexAttribArray(a_position_Location);

    gl.vertexAttribPointer(a_position_Location, 4, gl.FLOAT, false, 0, 0);

    // Bind Color Data
    gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer);

    gl.bufferData(gl.ARRAY_BUFFER, a_color, gl.STATIC_DRAW);

    gl.enableVertexAttribArray(a_color_Location);

    gl.vertexAttribPointer(a_color_Location, 4, gl.FLOAT, false, 0, 0);

    gl.drawArrays(gl.TRIANGLES, 0, 3);
}

testColor 定义

const testColor = [0,0,1,1];

完整示例代码

const canvas = document.createElement("canvas"); 
const gl =
  canvas.getContext("webgl2") ||
  canvas.getContext("experimental-webgl") ||
  canvas.getContext("webgl");
canvas.width = 480;
canvas.height = 360;

gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);

//Get Shaders
const myShaders = {
  untextured: {
    Shaders: {
      vert: `
                precision highp float;
                attribute vec4 a_position;
                attribute vec4 a_color;
                varying vec4 v_color;

                void main()
                {
                  v_color = a_color;
                  gl_Position = a_position;
                }
            `,
      frag: `
                precision highp float;
                varying vec4 v_color;

                void main()
                {
                  gl_FragColor = vec4(0,0,1,1);
                }
            `,
    },
    ProgramInf: null,
  },
  createAndCompileShaders: (vert, frag) => {
    // compile vertex Shader
    const vertShader = gl.createShader(gl.VERTEX_SHADER);
    try {
      gl.shaderSource(vertShader, vert.trim());
      gl.compileShader(vertShader);
      if (!gl.getShaderParameter(vertShader, gl.COMPILE_STATUS)) {
        throw gl.getShaderInfoLog(vertShader);
      }
    } catch (error) {
      console.error(error);
    }

    // compile fragment Shader
    const fragShader = gl.createShader(gl.FRAGMENT_SHADER);
    try {
      gl.shaderSource(fragShader, frag.trim());
      gl.compileShader(fragShader);
      if (!gl.getShaderParameter(fragShader, gl.COMPILE_STATUS)) {
        throw gl.getShaderInfoLog(fragShader);
      }
    } catch (error) {
      console.error(error);
    }

    // compile program
    const program = gl.createProgram();
    try {
      gl.attachShader(program, vertShader);
      gl.attachShader(program, fragShader);
      gl.linkProgram(program);
      if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
        throw gl.getProgramInfoLog(program);
      }

      gl.validateProgram(program);
      if (!gl.getProgramParameter(program, gl.VALIDATE_STATUS)) {
        throw gl.getProgramInfoLog(program);
      }
    } catch (error) {
      console.error(error);
    }

    return {
      program: program,
      vert: vertShader,
      frag: fragShader,
    };
  },
};

myShaders.untextured.ProgramInf = myShaders.createAndCompileShaders(
  myShaders.untextured.Shaders.vert,
  myShaders.untextured.Shaders.frag
);

const a_position_Location = gl.getAttribLocation(
  myShaders.untextured.ProgramInf.program,
  "a_position"
);
const a_color_Location = gl.getAttribLocation(
  myShaders.untextured.ProgramInf.program,
  "a_color"
);

console.log(a_position_Location, a_color_Location);

document.body.appendChild(canvas);

const positionBuffer = gl.createBuffer();

//predefine penColor's postion so we don't have to call it as much.
const penColor = [0, 0, 1, 1];

const drawTri = (x1, y1, x2, y2, x3, y3) => {
  const a_position = new Float32Array([
    x1,
    y1,
    1,
    1,
    penColor[0],
    penColor[1],
    penColor[2],
    penColor[3],
    x2,
    y2,
    1,
    1,
    penColor[0],
    penColor[1],
    penColor[2],
    penColor[3],
    x3,
    y3,
    1,
    1,
    penColor[0],
    penColor[1],
    penColor[2],
    penColor[3],
  ]);

  gl.useProgram(myShaders.untextured.ProgramInf.program);
  gl.viewport(0, 0, 480, 360);

  // Bind Positional Data

  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.bufferData(
    gl.ARRAY_BUFFER,
    a_position,
    gl.STATIC_DRAW
  );

  gl.vertexAttribPointer(
    a_position_Location,
    4,
    gl.FLOAT,
    false,
    4 * Float32Array.BYTES_PER_ELEMENT,
    0
  );
  gl.vertexAttribPointer(
    a_color_Location,
    4,
    gl.FLOAT,
    false,
    4 * Float32Array.BYTES_PER_ELEMENT,
    4 * Float32Array.BYTES_PER_ELEMENT
  );

  gl.enableVertexAttribArray(a_position_Location);
  gl.enableVertexAttribArray(a_color_Location);

  gl.useProgram(myShaders.untextured.ProgramInf.program);
  console.log(
    gl.getProgramInfoLog(myShaders.untextured.ProgramInf.program)
  );
  gl.drawArrays(gl.TRIANGLES, 0, 3);
};

drawTri(0, 0, 0.5, 0.5, 0, 0.5);

问题排查与修复

  1. 片元着色器初始错误:你最初提供的片元着色器复制了顶点着色器代码,片元着色器不允许使用attribute变量或赋值gl_Position,不过完整代码中已修正此问题,这不是当前渲染失败的原因。

  2. 顶点数据步长(stride)错误:在完整代码的drawTri函数中,你将位置和颜色数据交错存储(每个顶点占8个float:4个位置+4个颜色),但vertexAttribPointer的stride参数设置为4 * Float32Array.BYTES_PER_ELEMENT,导致WebGL读取顶点属性时跳过的字节数不足,无法正确解析每个顶点的完整数据。

    修正后的vertexAttribPointer调用:

    const vertexSize = 8 * Float32Array.BYTES_PER_ELEMENT; // 每个顶点的总字节数
    gl.vertexAttribPointer(
      a_position_Location,
      4,
      gl.FLOAT,
      false,
      vertexSize,
      0
    );
    gl.vertexAttribPointer(
      a_color_Location,
      4,
      gl.FLOAT,
      false,
      vertexSize,
      4 * Float32Array.BYTES_PER_ELEMENT
    );
    
  3. 顶点坐标适配裁剪空间:WebGL裁剪空间的x轴范围是-1(左)到1(右),y轴范围是-1(下)到1(上)。你当前使用的(0,0)、(0.5,0.5)、(0,0.5)仅在画布右半区域可见,若想让三角形居中,可调整为(-0.5,-0.5)、(0.5,0.5)、(-0.5,0.5)这类坐标。

  4. 冗余代码清理:drawTri中重复调用gl.useProgram无意义,第一次调用已激活目标程序。

修复后的drawTri函数

const drawTri = (x1, y1, x2, y2, x3, y3) => {
  const vertexData = new Float32Array([
    x1, y1, 0, 1, penColor[0], penColor[1], penColor[2], penColor[3],
    x2, y2, 0, 1, penColor[0], penColor[1], penColor[2], penColor[3],
    x3, y3, 0, 1, penColor[0], penColor[1], penColor[2], penColor[3],
  ]);

  gl.useProgram(myShaders.untextured.ProgramInf.program);
  gl.viewport(0, 0, canvas.width, canvas.height); // 使用画布实际尺寸

  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);

  const vertexSize = 8 * Float32Array.BYTES_PER_ELEMENT;
  gl.vertexAttribPointer(a_position_Location, 4, gl.FLOAT, false, vertexSize, 0);
  gl.vertexAttribPointer(a_color_Location, 4, gl.FLOAT, false, vertexSize, 4 * Float32Array.BYTES_PER_ELEMENT);

  gl.enableVertexAttribArray(a_position_Location);
  gl.enableVertexAttribArray(a_color_Location);

  gl.drawArrays(gl.TRIANGLES, 0, 3);
};

// 调用时使用裁剪空间内的居中坐标
drawTri(-0.5, -0.5, 0.5, 0.5, -0.5, 0.5);

内容的提问来源于stack exchange,提问作者ObviousAlexC.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 17:02:51