I have been working through WebGL tutorials like webglfundamentals and have run into a stumbling point - I believe that I will need to use a texture that I create to pass information directly to the fragment shader, but I can't seem to index the texture properly.
The goal is to pass information about light sources (location and color) that will be factored into the fragment color. Ideally this information is dynamic in both value and length.
Reproduction
I've created a simplified version of the problem in this fiddle: WebGL - Data Texture Testing
Here's some of the code.
In a one-time setup we create a texture, fill it with data, and apply what seem to be the most fool-proof settings on that texture (no mips, no byte packing issues[?])
// lookup uniforms
var textureLocation = gl.getUniformLocation(program, "u_texture");
// Create a texture.
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// fill texture with 1x3 pixels
const level = 0;
const internalFormat = gl.RGBA; // I've also tried to work with gl.LUMINANCE
// but it feels harder to debug
const width = 1;
const height = 3;
const border = 0;
const type = gl.UNSIGNED_BYTE;
const data = new Uint8Array([
// R, G, B, A (unused) // : 'texel' index (?)
64, 0, 0, 0, // : 0
0, 128, 0, 0, // : 1
0, 0, 255, 0, // : 2
]);
const alignment = 1; // should be uneccessary for this texture, but
gl.pixelStorei(gl.UNPACK_ALIGNMENT, alignment); // I don't think this is hurting
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, width, height, border,
internalFormat, type, data);
// set the filtering so we don't need mips and it's not filtered
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);
In the draw sequence (which only happens once but conceivably could repeat) we reinforce that the program should use our texture
// Tell the shader to use texture unit 0 for u_texture
gl.activeTexture(gl.TEXTURE0); // added this and following line to be extra sure which texture is being used...
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.uniform1i(textureLocation, 0);
Finally, in the fragment shader, we are trying to just reliably use one 'texel' as a means of conveying information. I can't seem to make heads or tails of how to retrieve the values that I stored in the texture reliably.
precision mediump float;
// The texture.
uniform sampler2D u_texture;
void main() {
vec4 sample_00 = texture2D(u_texture, vec2(0, 0));
// This sample generally appears to be correct.
// Changing the provided data for the B channel of texel
// index 0 seems to add blue as expected
vec4 sample_01 = texture2D(u_texture, vec2(0, 1));
vec4 sample_02 = texture2D(u_texture, vec2(0, 2));
// These samples are how I expected this to work since
// the width of the texture is set to 1
// For some reason 01 and 02 both show the same color
vec4 sample_10 = texture2D(u_texture, vec2(1, 0));
vec4 sample_20 = texture2D(u_texture, vec2(2, 0));
// These samples are just there for testing - I don't think
// that they should work
// choose which sample to display
vec4 sample = sample_00;
gl_FragColor = vec4(sample.x, sample.y, sample.z, 1);
}
Question(s)
Is using a texture the best way to do this? I have heard of the ability to pass arrays of vectors as well, but textures seem to be more common.
How are you supposed to create the texture? (particularly when I specify 'width' and 'height' should I be referring to resulting texel dimensions or the number of gl.UNSIGNED_BYTE elements that I will use to construct the texture?? texImage2D documentation)
How are you supposed to index into the texture in a fragment shader when not using 'varying' types? (i.e. I just want the value of one or more particular texels - no interpolation [having little to nothing to do with vertices])
Other Resources
I've read as much as I can about this for the time being. Here's a non-exhaustive list:
- JMI Madison suggests that they have figured it out, but the solution is buried in a mountain of project-specific code
- The webglfundamentals tutorials get close - using a 3x2 data texture - but it uses interpolation and doesn't seem to translate well to my use case
- Here's someone talking about trying to use vec3 arrays
- And of course I've been trying to compare my work with some OpenGL documentation (texImage2D and texture2d)
Edit Here's another resource I just found: Hassles with array access in WebGL, and a couple of workarounds. Makes me hopeful.
This is really bugging me.
Thanks in advance!
uniform vec3 lights[4];
Also looking up texture pixels is via unit coords not pixel coords. egtexture2D(tex, vec2(0,2))
should betexture2D(tex, vec2(0,0.5))
– Blindman67