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.
Related
I am trying to use mipmapping with vulkan. I do understand that I should use vkCmdBlit between each layer for each image, but before doing that, I just wanted to know how to change the layer in GLSL.
Here is what I did.
First I load and draw a texture (using layer 0) and there was no problem. The "rendered image" is the texture I load, so it is good.
Second, I use this shader (so I wanted to use the second layer (number 1)) but the "rendered image" does not change :
#version 450
layout(set = 0, binding = 0) uniform sampler2D tex;
in vec2 texCoords;
layout(location = 0) out vec4 outColor;
void main() {
outColor = textureLod(tex, texCoords, 1);
}
According to me, the rendered image should be changed, but not at all, it is always the same image, even if I increase the "1" (the number of the layer).
Third instead changing anything in the glsl code, I change the layer number into the ImageSubresourceRange to create the imageView, and the "rendered image" changed, so it seems normal to me and when I will use vkCmdBlit, I must see the original image in lower resolution.
The real problem is, when I try to use a mipmapping (through mipmapping) in GLSL, it does not affect at all the rendered image, but in C++ it does (and that seems fair).
here is (all) my source code
https://github.com/qnope/Vulkan-Example/tree/master/Mipmap
Judging by your default sampler creation info (https://github.com/qnope/Vulkan-Example/blob/master/Mipmap/VkTools/System/sampler.cpp#L28) you always set the maxLod member of your samplers to zero, so your lod is always clamped between 0.0 and 0.0 (minLod/maxLod). This would fit the behaviour you described.
So try setting the maxLod member of your sampler creation info to the actual number of mip maps in your texture and changing the lod level in the shader shoudl work fine.
Does the OpenGL standard mandate what the result of a texture2d operation should be given a uniform sampler2D that the program hasn't bound to a texture unit?
For example in the pixel shader:
layout(binding=0) uniform sampler2D Map_Diffuse;
...
texture2D(Map_Diffuse, attrib_Fragment_Texture)
Where in the program:
::glActiveTexture(GL_TEXTURE0);
::glBindTexture(GL_TEXTURE_2D, 0);
For context I'm wondering whether I can use the same shader for textured and non-textured entities, where (hopefully) I only need to make sure nothing is bound to GL_TEXTURE_2D for texture2d() to return 0, 0, 0, 1. Otherwise I'll need one shader for each permutation.
The way I read the spec, it's guaranteed to return black. The following quotes are copied from the 3.3 spec.
In section 2.11.7 "Shader Execution" under "Vertex Shaders", on page 81:
Using a sampler in a vertex or geometry shader will return (R,G,B,A) = (0,0,0,1) if the sampler’s associated texture is not complete, as defined in section 3.8.14.
and equivalent in section 3.9.2 "Shader Execution" under "Fragment Shaders", on page 188:
Using a sampler in a fragment shader will return (R,G,B,A) = (0,0,0,1) if the sampler’s associated texture is not complete, as defined in section 3.8.14.
In section 3.8.14 "Texture Completeness", it says:
A texture is said to be complete if all the image arrays and texture parameters required to utilize the texture for texture application are consistently defined.
Now, it doesn't explicitly say anything about texture objects that don't even exist. But since texture names that don't reference a texture object (which includes 0) certainly don't have "all the image arrays and texture parameters consistently defined", I would argue that they fall under "not complete" in the definitions above.
Does the OpenGL standard mandate what the result of a texture2d
operation should be given a uniform sampler2D that the program hasn't
bound to a texture unit?
When a texture sampler is unbound to a texture object, it is by default bound to texture object 0/null, this is like null in C/C++. When accessing object null, from my experience you get zero values For example:
vec2 Data = texture(unboundSampler, textureCoords);
Data will often be zoroes, but my assumption is this implementation dependent, some drivers may crash.
For context I'm wondering whether I can use the same shader for
textured and non-textured entities
In my engine I solved this by creating a default white texture that is 4 white pixels. Generated by code when the engine is initialized. When I want to use a shader that has a texture sampler and the corresponding material doesn't have a texture I assign the default white texture. This way I can reuse the same shader. If you care so much about performance you might want to use a shader without textures for non textured objects.
The standard doesn't talk about the implementation but it encourages you to think about the zero object as non-functional object. https://www.opengl.org/wiki/OpenGL_Object#Object_zero
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 have a shader with a _color uniform and a sampler. Now I want to draw with _color ONLY if the sampler was not set. Is there any way to figure that our within the shader? (Unfortunately the sampler returns 1,1,1,1 when not assigned, which makes mixing it via alpha impossible)
You cannot do that. The sampler is an opaque handle which just references a texture unit. I'm not sure if the spec guarantees that (1,1,1,1) when sampling from a unit where no texture is bound, or if that is undefined behavior.
What you can do is just use another uniform to switch betwenn using the sampler or the uniform color, or just use different shaders and switch between those. There are also the possibilities of subprograms here, but I don't know if that would be the right appraoch for such a simple problem.
I stumbled over this question trying to solve a similar problem.
Since GLSL 4.30
int textureQueryLevels( gsamplerX sampler);
Is a build-in function. In the GLSL spec. p. 151 it says
The value zero will be returned if no texture or an incomplete texture is associated with sampler.
In the OpenGL-Forms I found an entry to this question suggesting to use
ivecY textureSize(gsamplerX sampler,int lod);
and testing if the texture size is greater than zero. But this is, to my understanding, not covered by the standard. In the section 11.1.3.4 of the OpenGL specification it is said that
If the computed texture image level is outside the range [levelbase,q], the results are undefined ...
Edit:
I just tried this method on my problem and as it turns out nvidia has some issues with this function, resulting in a non zero value when no texture is bound. (See nvidia bug report from 2015)
sampler2d affects x y and z so if check for those with the parametric w as fourth parameter u can check if u gave in texture
vec4 texturecolor ;
texturecolor=texture2D(sampler, uv)*vec4(color,1.0);
if( texturecolor == vec4(0,0,0,1))
{
texturecolor = vec4(color,1.0);
}
Let's say I have this scene
And I want to add depth information from a custom made fragment shader.
Now the intuitive thing to do would be to draw a quad over my teapot without depth test enabled but with glDepthMask( 1 ) and glColorMask( 0, 0, 0, 0 ). Write some fragments gl_FragDepth and discard some other fragments.
if ( gl_FragCoord.x < 100 )
gl_FragDepth = 0.1;
else
discard;
For some reason, on a NVidia Quadro 600 and K5000 it works as expected but on a NVidia K3000M and a Firepro(dont't remember which one), all the area covered by my discarded fragments is given the depth value of the quad.
Can't I leave the discarded fragments depth values unmodified?
EDIT I have found a solution to my problem. It turns out that as Andon M. Coleman and Matt Fishman pointed out, I have early_fragment_test enabled but not because I enabled it, but because I use imageStore, imageLoad.
With the little time I had to address the problem, I simply copied the content of my current depth buffer just before the "add depth pass" to a texture. Assigned it to a uniform sampler2D. And this is the code in my shader:
if ( gl_FragCoord.x < 100 )
gl_FragDepth = 0.1;
else
{
gl_FragDepth = texture( depthTex, gl_PointCoord ).r;
color = vec4(0.0,0.0,0.0,0.0);
return;
}
This writes a completely transparent pixel with an unchanged z value.
Well, it sounds like a driver bug to me -- discarded fragments should not hit the depth buffer. You could bind the original depth buffer as a texture, sample it using the gl_FragCoord, and then write the result back instead of using discard. That would add an extra texture lookup -- but it might be a suitable workaround.
EDIT: From section 6.4 of the GLSL 4.40 Specification:
The discard keyword is only allowed within fragment shaders. It can be
used within a fragment shader to abandon the operation on the current
fragment. This keyword causes the fragment to be discarded and no
updates to any buffers will occur. Control flow exits the shader, and
subsequent implicit or explicit
derivatives are undefined when this exit is non-uniform. It would
typically be used within a conditional statement, for example:
if (intensity < 0.0) discard;
A fragment shader may test a fragment’s
alpha value and discard the fragment based on that test. However, it
should be noted that coverage testing occurs after the fragment shader
runs, and the coverage test can change the alpha value.if
(emphasis mine)
Posting a separate answer, because I found some new info in the OpenGL spec:
If early fragment tests are enabled, any depth value computed by the
fragment shader has no effect. Additionally, the depth buffer, stencil
buffer, and occlusion query sample counts may be updated even for
fragments or samples that would be discarded after fragment shader
execution due to per-fragment operations such as alpha-to-coverage or
alpha tests.
Do you have early fragment testing enabled? More info: Early Fragment Test