0
\$\begingroup\$

I have a bunch of texture IDs that each correspond to an image, I would like an integer to be passed in as an attribute, and then just get a uniform sampler2D <integer> You cannot do this in glsl, since sampler2D has to be a uniform, so I took the approach of just activating a uniform based on a provided integer. Is there a way to directly get a sampler2D based on a textureId without if statements?

Code

precision mediump float;

uniform sampler2D bedrock;
uniform sampler2D dirt;
uniform sampler2D grass;
uniform sampler2D gravel;
uniform sampler2D sand;
uniform sampler2D snow;
uniform sampler2D stone;

varying float vTextureId;
varying vec2 vUv;
varying float vBrightness;

int bedrockId = 0;
int stoneId = 1;
int dirtId = 2;
int sandId = 4;
int grassId = 5;
int gravelId = 6;
int snowId = 7;

void main() {
  int textureId = int(vTextureId);
  vec4 texel;

  if (textureId == bedrockId) {
    texel = texture2D(bedrock, vUv);
  } else if (textureId == stoneId) {
    texel = texture2D(stone, vUv);
  } else if (textureId == dirtId) {
    texel = texture2D(dirt, vUv);
  } else if (textureId == sandId) {
    texel = texture2D(sand, vUv);
  } else if (textureId == grassId) {
    texel = texture2D(grass, vUv);
  } else if (textureId == gravelId) {
    texel = texture2D(gravel, vUv);
  } else if (textureId == snowId) {
    texel = texture2D(snow, vUv);
  };

  gl_FragColor = vec4(texel.xyz * vBrightness, 1);
}
\$\endgroup\$
2
  • \$\begingroup\$ Use a sampler2D array, or make a texture atlas. \$\endgroup\$
    – Theraot
    Aug 12, 2021 at 18:56
  • \$\begingroup\$ Thanks, I will look into this! \$\endgroup\$ Aug 13, 2021 at 6:45

1 Answer 1

0
\$\begingroup\$

We bind the sampler2D array to a list of textureIds, then we access them using a for loop in the shader (we cant use variables since glsl doesn't accept variable indices)

const textureIds = [];

function bindTexture(image, textureId) {
  const texture = gl.createTexture();
  gl.activeTexture(gl.TEXTURE0 + textureId);
  gl.bindTexture(gl.TEXTURE_2D, texture);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
  gl.generateMipmap(gl.TEXTURE_2D);
};

for (let i = 0; i < numberOfTextures; i++) {
  const textureName = textures[i];
  const image = document.querySelector(`.${textureName}`);

  bindTexture(image, i);
  textureIds.push(i);
};

const program = createProgram(`
  precision highp float;

  uniform mat4 matrix;

  attribute vec3 position;
  attribute float textureId;
  attribute vec2 uv;
  attribute vec3 normal;

  varying float vTextureId;
  varying vec2 vUv;
  varying float vBrightness;

  void main() {
    gl_Position = matrix * vec4(position, 1);

    vec3 lightDirection = vec3(0, 1, 0);
    vTextureId = textureId;
    vUv = uv;
    vBrightness = max(0.0, dot(normal, lightDirection));
  }
  `, `
  precision highp float;

  uniform sampler2D samplerArray[4];

  varying float vTextureId;
  varying vec2 vUv;
  varying float vBrightness;

  void main() {
    int textureId = int(vTextureId);
    vec4 texel;

    for (int i = 0; i < 4; i++) {
      if (i == textureId) {
        texel = texture2D(samplerArray[i], vUv);
        break;
      }
    }

    gl_FragColor = vec4(texel.xyz * vBrightness, 1);
  }
`);

const samplerArrayLocation = gl.getUniformLocation(program, "samplerArray");

gl.uniform1iv(samplerArrayLocation, textureIds);
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .