WebGL drawArraysInstanced texture not displaying

50 Views Asked by At

I am creating a little browser game to learn OpenGL and trying to instance draw calls for textures. I have a texture that is an 85x44 png with transparency. I am having trouble getting the texture to display. I had it showing up previously when using single draw calls, but something started going wrong when I switched to drawArraysInstanced. If I mess with the alphas in the fragment shader I can get white blocks to appear on the canvas in the correct spots as seen below in the image.

I have been messing with the order of gl bind texture which makes the draws go from white to black. I don't know if I was on to something doing that.

Here is my code:

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);
};

enter image description here

1

There are 1 best solutions below

0
On

I solved this by using properly, 2^n, sized textures. Something must have been wrong with my code allowing for any sized textures. once I started using 64x64 pixel images it all began working.