1
\$\begingroup\$

I have a webgl program that sometimes renders textures, but mostly renders triangles or lines. When I am not rendering a texture, webgl gives the warning, "RENDER WARNING: there is no texture bound to the unit 0". Here is some code from my rendering loop:

if (thing.hasOwnProperty('texCoords')) {
    gl.uniform1i(shaderProgram.useTexture, true);
    gl.bindBuffer(gl.ARRAY_BUFFER, thing.texCoords);                                                                       
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, thing.texture);                                                                          
    gl.uniform1i(shaderProgram.tex_uniform, 0);
    gl.enableVertexAttribArray(shaderProgram.vertexPositionTex);
    gl.vertexAttribPointer(shaderProgram.vertexPositionTex, 2, gl.FLOAT, false, 0, 0);                                     
} else {
    gl.uniform1i(shaderProgram.useTexture, false);
    gl.disableVertexAttribArray(shaderProgram.vertexPositionTex);                                                          
}

If a thing doesn't render a texture, there is code to set a flag in my shaders not to consult the sampler2d for texture values and instead just draw polygons.

I suppose "there is no texture bound to the unit 0" is correct: there isn't a texture bound since the last call to drawArrays, but why would that issue a warning when I don't try to access TEXTURE0?

\$\endgroup\$
4
  • \$\begingroup\$ Do you have two separate shader programs, one using samplers, one without? I wouldn't expect that warning, if the shader does sample. Maybe post the shader source? \$\endgroup\$
    – Bram
    Commented Jan 7, 2019 at 23:46
  • \$\begingroup\$ Only one shader program. It only uses the sampler if the "useTexture" uniform is true (in which case a texture is attached). \$\endgroup\$ Commented Jan 8, 2019 at 21:13
  • 1
    \$\begingroup\$ It doesn't matter if it only accesses the texture when useTexture is true. What matters is the shader uses a texture at all. So keep a texture bound or follow best practices and either (a) use two shaders, one that uses a texture and one that does not or (b) multiply the texture by the color gl_FragColor = uniformColor * textureColor; and when you don't want to use one or the other set it it white. If you don't want to use a texture then bind a 1 pixel white texture. If you don't want to use the color set it to white. \$\endgroup\$
    – gman
    Commented Jan 9, 2019 at 0:38
  • \$\begingroup\$ @gman I would accept that answer if it were posited as such. Since it's a comment, I'll take it into consideration ;-) \$\endgroup\$ Commented Jan 10, 2019 at 1:03

1 Answer 1

2
\$\begingroup\$

It doesn't matter if it only accesses the texture when useTexture is true. What matters is the shader uses a texture at all.

So keep a texture bound or follow best practices and either

(a) use two shaders, one that uses a texture and one that does not

or

(b) multiply the texture by the color, eg.

gl_FragColor = uniformColor * textureColor;

and when you don't want to use one or the other set it it white. If you don't want to use a texture then bind a 1 pixel white texture. If you don't want to use the color set it to white.

const vs = `
attribute vec4 position;
void main() {
  gl_Position = position;
  gl_PointSize = 80.0;
}
`;

const fs = `
precision mediump float;
uniform sampler2D tex;
uniform vec4 u_color;
void main() {
  vec4 t_color = texture2D(tex, gl_PointCoord.xy);
  gl_FragColor = u_color * t_color;
}
`;

const gl = document.querySelector('canvas').getContext('webgl');
const prg = twgl.createProgram(gl, [vs, fs]);

const positionLoc = gl.getAttribLocation(prg, "position");
const colorLoc = gl.getUniformLocation(prg, "u_color");
// don't need tex location because only 1 texture and uniform defaults
// to 0

const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
const pixels = new Uint8Array([
  255, 128, 128, 255,
  128, 255, 128, 255,
  128, 128, 255, 255,
  255, 128, 255, 255,
]);
gl.texImage2D(
    gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0,
    gl.RGBA, gl.UNSIGNED_BYTE, pixels);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

const whiteTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, whiteTexture);
gl.texImage2D(
    gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0,
    gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 255, 255, 255]));

gl.useProgram(prg);

// draw with color
gl.bindTexture(gl.TEXTURE_2D, whiteTexture);
gl.uniform4fv(colorLoc, [1, 0, 0, 1]);
gl.vertexAttrib2f(positionLoc, -2 / 3, 0);
gl.drawArrays(gl.POINTS, 0, 1);

// draw with texture
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.uniform4fv(colorLoc, [1, 1, 1, 1]);
gl.vertexAttrib2f(positionLoc, 0, 0);
gl.drawArrays(gl.POINTS, 0, 1);

// draw with both
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.uniform4fv(colorLoc, [1, .5, .5, 1]);
gl.vertexAttrib2f(positionLoc, 2 / 3, 0);
gl.drawArrays(gl.POINTS, 0, 1);
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>

\$\endgroup\$

You must log in to answer this question.

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