3

So, I'm struggling with 1D textures. What I'm trying to achieve is passing 3 float values to a fragment shader as a uniform. They represent a light's color, in an attempt to reuse the same shader for n lights, with all their info -color and position- stored in the texture. For now, I'm trying to pass only the color for a single light to test things out. So in the fragment shader I have this:

uniform sampler1D lightColor;
...
vec3 lc = vec3(texelFetch(lightColor, 0, 0)); // all zeroes
vec3 lc = vec3(texture(lightColor, 0, 0));    // same

I've tried to achieve it both with texelFetch and texture calls within the shader (either one or the other), in both cases to no avail. Please note that if I hardcode the value in the shader like this:

vec3 lc = vec3(0.0f, 0.0f, 0.8f);

then I get the expected results (which are non-zero values in lc), so I'm positive that, at least in the shader, the problem may be in either the texelFetch or texture calls.

Back in C++ land, the code (executed once when my lightManager initializes) is as follows:

GLfloat lightValues[] = { 0.8f, 0.8f, 0.8f };
GLuint lightID; // member, not a local variable.
glGenTextures(1, &lightID);
glBindTexture(GL_TEXTURE_1D, lightID);
glActiveTexture(GL_TEXTURE0 + lightID);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage1D(GL_TEXTURE_1D, 1, GL_RGB32F, 1);
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 3 * sizeof(GLfloat), GL_RGB, GL_FLOAT, lightValues);
glUniform1i(glGetUniformLocation(shader->program, "light"), lightID);

Nothing extremely fancy going here (although definitely wrong). After going through table 6.2 of the OpenGL doc, for glTexStorage1D I chose 1 for levels (no MipMaps) and GL_RGB32F for internalFormat (since I'm trying to pass 3 floats). width is 1, since there is a single value. That should take care of the allocation.

Now, on to filling the buffers up with glTexSubImage1D, for which I choose level 0 (again, no MipMaps), 0 for xoffset, for width thrice the size of a GLfloat, GL_RGB as the format and GLfloat as the type. Finally, the actual data.

A few things about the c++ code: I correctly set the filters to GL_NEAREST (so that's not to blame) and I would say the uniform location/connection to the sader is correct (via glUniform1i and glGetUniformLocation).

So here come my questions:

  • First and obvious, does this make sense, passing lights info via a texture? Shaders are blatantly unable to do stuff like lights[n], since n needs to be known at compile time, so textures came naturally to mind as a way to trick this.
  • Second, is my assumption correct that the size of the data may be the culprit? I've read about completeness in textures, but to be honest, it was rather brief. A size of 1 texel smells definitely fishy, though.
  • Third, do you see anything else wrong? Particularly with the internalFormat, format and type?
  • Fourth, any ideas in general why lc keeps being populated with zeroes?

Thanks!!

EDIT: I do not want to use techniques like multiple passing, or defining a hard limit on the number of lights passed to the shader (making n constant). I read too about some feature in OpenGL 4.2, I believe, which does not interest me either. I'm just trying to learn with the tools at hand (but it's 100% guaranteed in the future I will come back with questions about those topics, once I figure this out (: )

Carlos Romero
  • 698
  • 8
  • 18

1 Answers1

1

Okay, figured it out together with https://stackoverflow.com/users/1774414/raistmaj

Turns out width is both in glTexStorage and glTexSubImage the number of elements in the array, so 1, regardless of the number of components.

Also, glActiveTexture must be called before glBindTexture (duh!!)

Community
  • 1
  • 1
Carlos Romero
  • 698
  • 8
  • 18
  • You're also misusing glActiveTexture with the texture ID. OpenGL will generate an error and ignore that call. – datenwolf Dec 13 '16 at 19:58
  • What do you mean by misusing? Because of the sum? AFAIK that's a pretty standard way, how would you know which texture unit to activate otherwise, if `lightID` value is unknown till runtime? – Carlos Romero Dec 13 '16 at 20:14
  • 1
    What you do wrong there is adding the *texture name* to GL_TEXTURE_0. *That's not how it goes!* There's a certain number of texture units (0 to N, N being a figure you can query with `glGetInteger( GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)` and it's valid to call `glActiveTexture(GL_TEXTURE_0 + i)' where i is in the range 0 to N. What you generate with `glGenTextures` and bind with `glBindTexture` is a so called *texture name* and everything in the range 1 to 2^32-1 may be used as a texture name. – datenwolf Dec 13 '16 at 22:11
  • 1
    Regarding your question "how to know which texture unit to activate": It's up to your discretion. Think of texture units like hose fed paint guns. An OpenGL implementation gives you a certain number of paint guns, which you have to work with. But you can put a (nearly) unlimited number of dye canisters into your shop, which you can freely connect with your limited number of paint guns. `glActiveTexture(GL_TEXTURE_0 + paint_gun_number)` selects the paint gun `glBindTexture(…, name_of_dye)` connects the hose. And `glUniform(sampler_location, paint_gun_number)` assigns paint guns to the shader. – datenwolf Dec 13 '16 at 22:15
  • A great explanation and analogy, danke vielmals. I see now how I was mixing things up. I find myself wondering smth related, which I post in the next comment due to size limitations. – Carlos Romero Dec 14 '16 at 17:33
  • Say I connect `M` paintguns, +1 for my lighting calculations. That value `m` changes from surface to surface, and will have a maximum of `N - 1`, correct? In other words, for drawing a complete model (composed of many surfaces), the restriction on the number of available textures is applied individually to each surface, not the model as a whole. Even more - rendering my scene completely could very well require a number of paint guns beyond `N`, as long as each of the individual surfaces does not require more than `N` paint guns. Is anything I said not true, or I understood this correctly? – Carlos Romero Dec 14 '16 at 17:33
  • 1
    Replace "surface" with "drawing batches" and you're spot on. In the old-and-busted legacy API a glBegin/glEnd block would denote a "drawing batch". These days you can recognize a cohesive drawing batch as calls to functions named `glDraw…`. Between these calls you can change the texture binding for each texture unit. – There's also an extension (and this not yet a standard feature so don't rely on it) that allows to use an arbitrary number of textures within a drawing batch, without having to bind them; that extension is called "bindless textures". I just want to pique your interest there… – datenwolf Dec 14 '16 at 23:37
  • I read in passing about these bindless textures. Very enlightening (pun intended) question this has been. Thank you very much. – Carlos Romero Dec 15 '16 at 07:44