2
votes

I have a series of textures which stack together (using a mip-map-style resolution pyramid) to arrive at a final image.

Because of the way they stack, it's necessary to initialize them to an unsigned int value of 128 when they have not been populated by meaningful image data. IE, 128 is zero because the render shader will subtract .5 from each texture value, which allows subsequent pyramidal layers to offset the final image by positive or negative values.

I cannot seem to figure out how to initialize a (single-channel GL_LUMINANCE) texture to a value!

I've tried setting it as a renderbuffer target and rendering polys to it, but the FBO seems to be marked as incomplete. I've also tried targeting it as a renderbuffer target and using gl.clear(gl.COLOR_BUFFER_BIT) but again it's considered incomplete.

The obvious thing would be to copy values in using gl.texSubImage2D() but that seems really slow... maybe that's the only way? I was hoping for something more elegant that doesn't require allocating so much memory (at least a frame's worth of a single value) and so slow (because all that data must be written to the buffer when it's all a single value).

The only way to set a texture to a (default) value in WebGL seems to be to resize it, or allocate it, which sets it to all zeroes.

Also, there doesn't seem to be a copy mode like gl.SIGNED_BYTE which would allow zero to be zero (IE, signed values coming in)... but this also doesn't solve the problem of initializing the texture to a single value (in this case, zero).

Any ideas? How does one initialize a WebGL texture to a value aside from just plain old copying the value into it?

2

2 Answers

2
votes

Being able to render to a particular type of texture is unfortunately not guaranteed by the OpenGL ES 2.0 spec on which WebGL is based on. The only way to tell if it works is to create the texture, attach it to a framebuffer and then call checkFramebufferStatus and see if it returns FRAMEBUFFER_COMPLETE. Unfortunately it won't in a lot of cases.

Only 3 combinations off attachments are guaranteed to work

  • COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
  • COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer
  • COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer

So your options are

  1. use an RGBA texture and render 128,128,128,??? to it in an fbo (or gl.clear it)

  2. use a LUMINANCE texture and call texImage2D

  3. use a LUMINANCE texture and call copyTexImage2D using the backbuffer or an fbo of the correct size cleared to the color you want (though there is no guarantee this is fast AFAIK)
0
votes

In my experience (mainly with Chrome in OSX) using Canvas to initialise a texture is fast. I guess it is because the browser allocates the Canvas and draws to it all on the GPU, and its WebGL implementation uses the same GL context as Canvas, so there is no huge CPU-to-GPU memory transfer.

        // Quickly init texture to (128,128,128)
        var canvas = this._canvas = document.createElement("canvas");
        canvas.width = wTex;
        canvas.height = hTex;
        var ctx = this._ctx = canvas.getContext("2d");
        ctx.fillStyle = "#808080";
        ctx.fillRect(0, 0, wTex, hTex);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, canvas);