Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I am confused about textures and cubemaps in OpenGL.
Let's say I want basic texture mapping. I do:
GLuint texture0;
glGenTextures(1, &texture0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
and then I set up glTexImage2D and call glUniform1i(glGetUniformLocation(shader_program, "texture_sampler"), GL_TEXTURE0) and all is well.
Now, I also want to use a cubemap for environment mapping. I thought, also using this post as reference, that I should do like this:
GLuint texture1;
glGenTextures(1, &texture1);
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_CUBE_MAP, texture1);
and then glUniform1i(glGetUniformLocation(shader_program, "cubemap_sampler"), GL_TEXTURE0+1).
However, this does not work, and only renders a black object.
On the other hand, if I do not run glActiveTexture(GL_TEXTURE0+1) but instead stick to GL_TEXTURE0 everything is fine.
According to my understanding, this is not how it should be...
Can anyone shed some light as to what is going on?
I am using GLSL #version 440.
glUniform1i(glGetUniformLocation(shader_program, "texture_sampler"), GL_TEXTURE0+1) is a strange idea.
The texture unit is the integral binding point between the texture object and the texture sampler.
GL_TEXTURE0 is an enumerator constant for the use with glActiveTexture. GL_TEXTURE0 address the texture unit 0.
The value you need to set on the texture sampler uniform is the texture unit not, the "name" of the texture unit. Hence you have to set 0 rather then GL_TEXTURE0:
glUniform1i(glGetUniformLocation(shader_program, "texture_sampler"), GL_TEXTURE0+1)
glUniform1i(glGetUniformLocation(shader_program, "texture_sampler"), 1)
Note that the sampler bind point is 0 by default. The instruction glUniform1i(..., GL_TEXTURE0+1) causes an INVALID_VALUE error and does not change the binding point at all.
See OpenGL Shading Language 4.60 Specification - 7.6.1 Loading Uniform Variables In The Default Uniform Block
An INVALID_VALUE error is generated if Uniform1i{v} is used to set a
sampler uniform to a value less than zero or greater than or equal to the value
of MAX_COMBINED_TEXTURE_IMAGE_UNITS.
Related
I'm learning openGL texture from leanrnOpenGL : Textures
I can distinguish between glGetUniformLocation and "texture unit.
glGetUniformLocation : an integer that represents the location of a specific uniform variable within a program object.
texture unit : the location of a texture is known as a texture unit.
The pages has the following sentences:
We also have to tell OpenGL to which texture unit each shader sampler belongs to
by setting each sampler using `glUniform1i`.
The corresponding code is as follows :
ourShader.use();
glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 0); // set it manually
ourShader.setInt("texture2", 1); // or with shader class
I made some wrong changes as follows :
assigned the texture unit value of texture1 to 3, and texture2 to 4.
glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 3);
ourShader.setInt("texture2", 4);
The program can be executed, but show a COMPLETELY PURE black texture(or nothing?)
Does the value of texture unit have to start from 0 ? and why?
Why assigning 3 or 4 cause a wrong effect ?
Under the guidance of #Rabbid76, I got the answer.
In the original text of learnOpenGL : Texture, there is a sentence that caused my confusion:
This location of a texture is more commonly known as a texture unit.
#Rabbid76 correct me:
The binding point between the texture object and the sampler uniform is the `texture unit`.
Does the value of texture unit have to start from 0 ?
A: No.
We can specify it by 0~15 at least.
OpenGL should have a at least a minimum of 16 texture units for you to use
which you can activate using GL_TEXTURE0 to GL_TEXTURE15.
Corresponding, when drawing,
invoke glActiveTexture by specify GL_TEXTURE0 to GL_TEXTURE15.
The following is the correct code aftet my correction:
// set `3` `4` as texture unit value
glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 3);
ourShader.setInt("texture2", 4);
// bind textures on corresponding texture units
glActiveTexture(GL_TEXTURE3); // replace GL_TEXTURE0 with GL_TEXTURE3
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE4); // replace GL_TEXTURE1 with GL_TEXTURE4
glBindTexture(GL_TEXTURE_2D, texture2);
The code run normally and show the correct overlay effect(no longer a black view).
I have a functioning OpenGL ES 3 program (iOS), but I've having a difficult time understanding OpenGL textures. I'm trying to render several quads to the screen, all with different textures. The textures are all 256 color images with a sperate palette.
This is C++ code that sends the textures to the shaders
// THIS CODE WORKS, BUT I'M NOT SURE WHY
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _renderQueue[idx]->TextureId);
glUniform1i(_glShaderTexture, 1); // what does the 1 mean here
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, _renderQueue[idx]->PaletteId);
glUniform1i(_glShaderPalette, 2); // what does the 2 mean here?
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
This is the fragment shader
uniform sampler2D texture; // New
uniform sampler2D palette; // A palette of 256 colors
varying highp vec2 texCoordOut;
void main()
{
highp vec4 palIndex = texture2D(texture, texCoordOut);
gl_FragColor = texture2D(palette, palIndex.xy);
}
As I said, the code works, but I'm unsure WHY it works. Several seemingly minor changes break it. For example, using GL_TEXTURE0, and GL_TEXTURE1 in the C++ code breaks it. Changing the numbers in glUniform1i to 0, and 1 break it. I'm guessing I do not understand something about texturing in OpenGL 3+ (maybe Texture Units???), but need some guidance to figure out what.
Since it's often confusing to newer OpenGL programmers, I'll try to explain the concept of texture units on a very basic level. It's not a complex concept once you pick up on the terminology.
The whole thing is motivated by offering the possibility of sampling multiple textures in shaders. Since OpenGL traditionally operates on objects that are bound with glBind*() calls, this means that an option to bind multiple textures is needed. Therefore, the concept of having one bound texture was extended to having a table of bound textures. What OpenGL calls a texture unit is an entry in this table, designated by an index.
If you wanted to describe this state in a C/C++ style notation, you could define the table of bound texture as an array of texture ids, where the size is the maximum number of bound textures supported by the implementation (queried with glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, ...)):
GLuint BoundTextureIds[MAX_TEXTURE_UNITS];
If you bind a texture, it gets bound to the currently active texture unit. This means that the last call to glActiveTexture() determines which entry in the table of bound textures is modified. In a typical call sequence, which binds a texture to texture unit i:
glActiveTexture(GL_TEXTUREi);
glBindTexture(GL_TEXTURE_2D, texId);
this would correspond to modifying our imaginary data structure by:
BoundTextureIds[i] = texId;
That covers the setup. Now, the shaders can access all the textures in this table. Variables of type sampler2D are used to access textures in the GLSL code. To determine which texture each sampler2D variable accesses, we need to specify which table entry each one uses. This is done by setting the uniform value to the table index:
glUniform1i(samplerLoc, i);
specifies that the sampler uniform at location samplerLoc reads from table entry i, meaning that it samples the texture with id BoundTextureIds[i].
In the specific case of the question, the first texture was bound to texture unit 1 because glActiveTexture(GL_TEXTURE1) was called before glBindTexture(). To access this texture from the shader, the shader uniform needs to be set to 1 as well. Same thing for the second texture, with texture unit 2.
(The description above was slightly simplified because it did not take into account different texture targets. In reality, textures with different targets, e.g. GL_TEXTURE_2D and GL_TEXTURE_3D, can be bound to the same texture unit.)
GL_TEXTURE1 and GL_TEXTURE2 refer to texture units. glUniform1i takes a texture unit id for the second argument for samplers. This is why they are 1 and 2.
From the OpenGL website:
The value of a sampler uniform in a program is not a texture object,
but a texture image unit index. So you set the texture unit index for
each sampler in a program.
I would like to know if GL_TEXTURE_2D is active in the shader.
I am binding a color to the shader as well as the active texture (if GL_TEXTURE_2D is set) and need to combine these two.
So if texture is bound, mix the color and the texture (sampler2D * color) and if no texture is bound, use color.
Or should I go another way about this?
It is not quite clear what you mean by 'GL_TEXTURE_2D is active' or 'GL_TEXTURE_2D is set'.
Please note the following:
glEnable(GL_TEXTURE_2D) has no effect on your (fragment) shader. It parametrizes the fixed function part of your pipeline that you just replaced by using a fragment shader.
There is no 'direct'/'clean' way of telling from inside the GLSL shader whether there is a valid texture bound to the texture unit associated with your texture sampler (to my knowledge).
Starting with GLSL 1.3 you might have luck using textureSize(sampler, 0).x > 0 to detect the presence of a valid texture associated with sampler, but that might result in undefined behavior.
The ARB_texture_query_levels extension does indeed explicitly state that textureQueryLevels(gsampler2D sampler) returns 0 if there is no texture associated with sampler.
Should you go another way about this? I think so: Instead of making a decision inside the shader, simply bind a 1x1 pixel texture of 'white' and unconditionally sample that texture and multiply the result with color, which will obviously return 1.0 * color. That is going to be more portable and faster, too.
I'm using OpenGL and GLSL to draw a texture over a simple mesh.
My problem is that when I am using glUniform1i to set the value of a sampler2D uniform, it was not set. For example in the in this code:
glUseProgram(programObject);
glUniform1i(glGetUniformLocation(programObject, "texture"), 1);
GLint val;
glGetUniformiv(programObject,
glGetUniformLocation(programObject, "texture"),
&val);
printf("Value is %d\n", val);
The value printed at command line out is 0. I have checked that the shaders are compiled correctly and the program is linked correctly. glGetUniformLocation outputs an index > 0. Furthermore, glGetError doesn't output any error at any point.
This only happens when the uniform is a sampler. As the texture is not set, quering it in the shader always returns (0, 0, 0, 1). (I have also checked, using apitrace, that my texture is correctly bound to GL_TEXTURE1, which is done inmediately after the code shown).
I have searched extensively for this problem and I have only found one instance of something similar to this here. The solution was to initialize GLEW, but this hasn't worked for me.
I'm happy to provide any extended info needed (or the trace from apitrace).
Edit
Here is the shader:
uniform sampler2D texture;
varying vec2 textureCoord;
void main() {
gl_FragColor = texture2D(texture, textureCoord);
}
Solution
I managed to solve the problem after some work.
As it turns out, this problem wasn't due to the uniform not being set, as always returning 0 for samplers regardless of actual value appears to be a quirk of the gl implementation. This happened under Intel's driver for Sandy Bridge only. Testing the code under other implementations always returned the correct sampler value.
The problem of the texture returning (0, 0, 0, 1) always was due to a mistake I made during the generation of the texture.
Now the glGerUniformiv still returns 0, but the texture used is the correct one.
Solution
I managed to solve the problem after some work.
As it turns out, this problem wasn't due to the uniform not being set, as always returning 0 for samplers regardless of actual value appears to be a quirk of the gl implementation. This happened under Intel's driver for Sandy Bridge only. Testing the code under other implementations always returned the correct sampler value.
The problem of the texture returning (0, 0, 0, 1) always was due to a mistake I made during the generation of the texture.
Now the glGerUniformiv still returns 0, but the texture used is the correct one.
Say you have something like this:
glBindTexture(GL_TEXTURE_2D, my2dTex);
glBindTexture(GL_TEXTURE_1D, my1dTex);
glBegin...
What is the correct OpenGL behavior? To draw the 1d texture, the 2d or both? For each active texture are there actually multiple textures that can be bound to it at the same time (i.e. a 1d, 2d, 3d cube map, etc.)?
The GL state for the bindings is one texture name per target (i.e. 1D/2D/3D/cube). So when calling
glBindTexture(GL_TEXTURE_2D, my2dTex)
glBindTexture(GL_TEXTURE_1D, my1dTex)
the GL will remember both settings.
Now, the answer of which one GL will use depends on whether you have a shader on.
If a shader is on, the GL will use whatever the shader says to use. (based on sampler1d/sampler2d...).
If no shader is on, then it first depends on which glEnable call has been made.
glEnable(GL_TEXTURE_2D)
glEnable(GL_TEXTURE_1D)
If both are enabled, there is a static priority rule in the spec (3.8.15 Texture Application in the GL 1.5 spec).
Cube > 3D > 2D > 1D
So in your case, if both your texture targets are enabled, the 2D one will be used.
As a side note, notice how a shader does not care whether or not the texture target is Enabled...
Edit to add:
And for the people who really want to get to the gritty details, you always have a texture bound for each target * each unit. The name 0 (the default for the binding state) corresponds to a series of texture objects, one per target. glBindTexture(GL_TEXTURE_2D, 0) and glBindTexture(GL_TEXTURE_1D, 0) both bind a texture, but not the same one...
This is historical, specified to match the behavior of GL 1.0, where texture objects did not exist yet. I am not sure what the deprecation in GL3.0 did with this, though.
I think that the 1d texture will be drawn. As far as I know, each texture unit can have only one texture bound at a time. The number of dimensions of the texture doesn't really come into it.
To have more than one texture bound you have to activate more than one texture unit (using glActiveTexture), like this:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, my2dTex);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_1D, my1dTex);
This comes from my knowledge of OpenGL 2.1 though, so please correct me if they've introduced some fancy new texture extension in a later version!
The applied texture is the last specified with BindTexture routine.
From the specification:
The new texture object bound to
target is, and remains a texture of the dimensionality and type specified by target
until it is deleted.
.... If the
bind is successful no change is made to the state of the bound texture object, and
any previous binding to target is broken.
Indeed in your example it will be applied the 1D texture, since it "overwrite" the state of the active texture unit.