Search code examples
glslwebgltextures

How does data get laid out in am RGBA WebGL texture?


I'm trying to pass a list of integers to the fragment shader and need random access to any of its positions. I can't use uniforms since index must be a constant, so I'm using the usual technique of passing the data through a texture.

Things seem to work, but calling texture2D to obtain specific pixels is not behaving as I'd expect.

My data looks like this:

this.textureData = new Uint8Array([
    0,  0,  0,  10,    0,  0,  0,  20,    0,  0,  0,  30,    0,  0,  0,  40,                                   
    0,  0,  0,  50,    0,  0,  0,  60,    0,  0,  0,  70,    0,  0,  0,  80,
]);

I then copy that over through a texture:

            this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
            this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
            this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
            this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);

            this.gl.texImage2D(
                this.gl.TEXTURE_2D,
                0,
                this.gl.RGBA,
                4,  // width: using 4 since its 4 bytes per pixel
                2,  // height 
                0,
                this.gl.RGBA,
                this.gl.UNSIGNED_BYTE,
                this.textureData);

So this texture is 4x2 pixels.

When I call texture2D(uTexture, vec2(0,0)); I get a vec4 pixel with the correct values (0,0,0,10).

However, when I call with locations such as (1,0), (2,0), (3,0), (4,0), etc they all return a pixel with (0,0,0,30).

Same for the second row. If I call with (0,1) I get the first pixel of the second row.

Any number greater than 1 for the X coordinate returns the last pixel of the second row.

I'd expect the coordinates to be:

this.textureData = new Uint8Array([
    // (0,0)                (1,0)              (2,0)              (3,0)
    0,  0,  0,  10,    0,  0,  0,  20,    0,  0,  0,  30,    0,  0,  0,  40,     
    // (0,1)                (1,1)              (2,1)              (3,1)                              
    0,  0,  0,  50,    0,  0,  0,  60,    0,  0,  0,  70,    0,  0,  0,  80,
]);

What am I missing? How can I correctly access the pixels?

Thanks!


Solution

  • Texture coordinates are not integral, they are in the range [0.0, 1.0]. They map the vertices of the geometry to a point in the texture image. The texture coordinates specifies which part of the texture is placed on an specific part of the geometry and together with the texture parameters (see gl.texParameteri) it specifies how the geometry is wrapped by the texture. In general, the lower left point of the texture is addressed by the texture coordinate (0.0, 0.0) and the upper right point of the texture is addressed by (1.0, 1.0).
    Texture coordinates work the same in OpenGL, OpenGL Es and WebGL. See How do opengl texture coordinates work?