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

WebGL使用drawArraysInstanced时纹理无法显示的求助

OpenGL实例化绘制纹理异常问题

我正在开发一款浏览器小游戏学习OpenGL,尝试用drawArraysInstanced做实例化绘制渲染纹理。现有一张85×44带透明通道的PNG纹理,单次绘制时显示正常,但切换到实例化绘制后无法正常显示。调整片段着色器的alpha阈值后,画布对应位置只会出现白色块(如图)。尝试调整glBindTexture调用顺序,绘制内容会在白色和黑色间切换,但不确定方向是否正确。

显示白色块的画布

片段着色器(FS)

// #version 300 es
// #pragma vscode_glsllint_stage: frag

precision mediump float;

// our texture
uniform sampler2D u_image;

// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;

void main() {
   gl_FragColor = texture2D(u_image, v_texCoord);
   if(gl_FragColor.a < 0.9) discard;
}

顶点着色器(VS)

// #version 300 es
// #pragma vscode_glsllint_stage: vert

attribute vec2 a_Position;

uniform mat3 u_matrix;

varying vec2 v_texCoord;

void main() {
   gl_Position = vec4(u_matrix * vec3(a_Position, 1), 1);

   // because we're using a unit quad we can just use
   // the same data for our texcoords.
   v_texCoord = a_Position;  
}

initVertexBuffer.ts

import { ProgramInfo } from "../../../compileShaders";

export function initVertexBuffers({
  gl,
  programInfo,
  array,
  rgba, // note not in use in this file
  texture, // note not in use in this file
}: {
  gl: WebGL2RenderingContext;
  programInfo: ProgramInfo;
  array: number[];
  rgba: [number, number, number, number] | number[];
  texture: WebGLTexture;
}) {
  const dim = 2;
  const vertices = new Float32Array(array);

  // Assign the vertices in buffer object to a_Position variable
  // let positionLocation = gl.getAttribLocation(program, "a_position");
  const a_Position = gl.getAttribLocation(programInfo.program, "a_Position");
  const u_imageLoc = gl.getUniformLocation(programInfo.program, "u_image");
  const u_matrixLoc = gl.getUniformLocation(programInfo.program, "u_matrix");

  const vertexBuffer = gl.createBuffer();
  if (!vertexBuffer) {
    console.log("Failed to create the buffer object");
    return { n: -1 };
  }
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

  if (a_Position < 0) {
    console.log("Failed to get the storage location of a_Position");
    return { n: -2 };
  }
  gl.enableVertexAttribArray(a_Position);
  gl.vertexAttribPointer(a_Position, dim, gl.FLOAT, false, 0, 0);

  // use texture
  gl.activeTexture(gl.TEXTURE0);

  // Return number of vertices
  return { n: vertices.length / dim, u_imageLoc, u_matrixLoc };
}

createRect.ts

export const createRect = ({
  array,
  gl,
  position,
  size,
  cameraLoc,
  color = [],
}: {
  gl: WebGL2RenderingContext;
  array: number[];
  position: XY;
  size: Dimensions;
  cameraLoc: XY;
  color?: number[] | [number, number, number, number];
}) => {
  const { width: canvasWidth, height: canvasHeight } = gl.canvas;
  const { x, y } = position;
  const { width, height } = size;
  const { x: cameraX, y: cameraY } = cameraLoc;

  const clipX = ((x - cameraX) / canvasWidth) * 2 - 1;
  const clipY = ((y - cameraY) / canvasHeight) * -2 + 1;
  const clipWidth = width / canvasWidth;
  const clipHeight = height / canvasHeight;

  // minimum of 12 numbers per rect
  array.push(
    // first triangle
    clipX,
    clipY,
    clipX + clipWidth,
    clipY,
    clipX,
    clipY - clipHeight,
    // second triangle
    clipX + clipWidth,
    clipY,
    clipX,
    clipY - clipHeight,
    clipX + clipWidth,
    clipY - clipHeight,
    ...color
  );
};

draw.ts

import { RootState } from "../../../../store";
import { glBindTexture } from "../../shaders/textures/terrain/grass1/glBindTexture";
import { ProgramInfo } from "../../shaders/compileShaders";
import { initVertexBuffers } from "../../shaders/textures/terrain/grass1/initVertexBuffers";
import { gray } from "../../colors";
import { createRect } from "../../shaders/textures/terrain/grass1/createRect";

interface Props {
  gl: WebGL2RenderingContext;
  state: RootState;
  shaders: {
    grass1Shader: ProgramInfo;
  };
}
const images = {} as Record<string, HTMLImageElement>;
export const terrain = ({ gl, state, shaders: { grass1Shader } }: Props) => {
  if (!grass1Shader) return;
  const cameras = state.game.cameras["main"].position;
  if (!images["grass1.png"]) {
    const img = document.getElementById("grass1.png") as HTMLImageElement;
    if (!img) return;
    images["grass1.png"] = img;
  }
  images["grass1.png"].width = 85;
  images["grass1.png"].height = 40;
  if (!images["grass1.png"]) return;

  const array = [] as number[];
  createRect({
    array,
    gl,
    position: {
      x: 0,
      y: 0,
    },
    cameraLoc: cameras,
    size: {
      width: 85,
      height: 44,
    },
  });
  createRect({
    array,
    gl,
    position: {
      x: 100,
      y: 100,
    },
    cameraLoc: cameras,
    size: {
      width: 85,
      height: 44,
    },
  });
  gl.useProgram(grass1Shader.program);
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
  const texture = glBindTexture(gl, grass1Shader, images["grass1.png"]);

  const { n, u_matrixLoc } = initVertexBuffers({
    gl,
    programInfo: grass1Shader,
    array,
    rgba: gray,
    texture,
  });

  if (n < 0) {
    console.log(n);
    console.log("Failed to set the positions of the vertices");
    return;
  }
  // identity matrix spanning full screen
  gl.uniformMatrix3fv(u_matrixLoc, false, [1, 0, 0, 0, 1, 0, 0, 0, 1]);
  // console.log(n, array.length / 12);
  gl.drawArraysInstanced(gl.TRIANGLES, 0, n, array.length / 12);
  // gl.drawElementsInstanced(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0, 1);

  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:45:53