0
\$\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\$
  • \$\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 Jan 7 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\$ – Limited Atonement Jan 8 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 Jan 9 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\$ – Limited Atonement Jan 10 at 1:03
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, 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\$

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.