Find out if GL_TEXTURE_2D is active in shader - opengl

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.

Related

Framebuffer's RGB colors are different when alpha value is modified

I have fragment shader that writes to framebuffer's texture. I have 2 shaders that use the framebuffer's output texture. First uses just alpha and Second just RGB. When framebuffer's shader return fragmentColor.a = 0 the RGB component completely dissapear when used in Second shader even when I set fragmentColor.a to 1 manually. Is it possible to prevent this "RGB dissapear" or am I getting some bug? Yes I can generate different textures for each shader but it costs huge amount of perfomance because even with only one "draw" it's very costly. But if I could output to two textures at same time that would also solve whole problem. Anyone has any advice/solution?
You probably have blending enabled and set glBlendFunc to something like glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), which will also affect the destination alpha values. To overcome this there's separable blending, set it up with glBlendFuncSeparate[i] and choose the source and destination equations so that the RGB values are passed through as needed for your application. Use the "i" variant to set different blending functions for each fragment shader output target (if you have a single fragment shader with multiple outputs), or call the non-"i" version multiple times, before each render pass to set it up for your individual fragment shaders.

OpenGL confused about multiple textures

I'm developing a 3d program with OpenGL 3.3. So far I managed to render many cubes and some spheres. I need to texture all the faces of all the cubes with a common texture except one face which should have a different texture. I tried with a single texture and everything worked fine but when I try to add another one the program seems to behave randomly.
My questions:
is there a suitable way of passing multiple textures to the shaders?
how am I supposed to keep track of faces in order to render the right texture?
Googling I found out that it could be useful to define vertices twice, but I don't really get why.
Is there a suitable way of passing multiple textures to the shaders?
You'd use glUniform1i() along with glActiveTexture(). Thus given your fragment shader has multiple uniform sampler2D:
uniform sampler2D tex1;
uniform sampler2D tex2;
Then as you're setting up your shader, you set the sampler uniforms to the texture units you want them associated with:
glUniform1i(glGetUniformLocation(program, "tex1"), 0)
glUniform1i(glGetUniformLocation(program, "tex2"), 1)
You then set the active texture to either GL_TEXTURE0 or GL_TEXTURE1 and bind a texture.
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, texture1)
glActiveTexture(GL_TEXTURE1)
glBindTexture(GL_TEXTURE_2D, texture2)
How am I supposed to keep track of faces in order to render the right texture?
It depends on what you want.
You could decide which texture to use based the normal (usually done with tri-planar texture mapping).
You could also have another attribute that decides how much to crossfade between the two textures.
color = mix(texture(tex1, texCoord), texture(tex2, texCoord), 0.2)
Like before, you can equally have a uniform float transition. This would allow you to fade between textures, making it possible to fade between slides like in PowerPoint, so to speak.
Try reading LearnOpenGL's Textures tutorial.
Lastly there's a minimum of 80 texture units. You can check specifically how many you have available using GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.
You can use index buffers. Define the vertices once, and then use one index buffer to draw the portion of the mesh with the first texture, then use the second index buffer to draw the portion that needs the second texture.
Here's the general formula:
Setup the vertex buffer
Setup the shader
Setup the first texture
Setup and draw the index buffer for the part of the mesh that should use the first texture
Setup the second texture
Setup and draw the index buffer for the part of the mesh that should use the second texture.

GLSL : accessing framebuffer to get RGB and change it

I'd like to access framebuffer to get RGB and change their values for each pixel. It is because the glReadPixels, and glDrawPixels are too slow to use, so that i should use shaders instead of using them.
Now, I write code, and success to display three-dimensional model using GLSL shaders.
I drew two cubes as follows.
....
glDrawArrays(GL_TRIANGLES, 0, 12*6);
....
and fragment shader :
varying vec3 fragmentColor;
void main()
{
gl_FragColor = vec4(fragmentColor, 1);
}
Then, how can I access to RGB values and change it?
For example, If the pixel values at (u1, v1) on window and (u2, v2) are (0,0,255), then I want to change them to (255,0,0)
With the exception of an OpenGL ES-only extension, fragment shaders cannot just read from the current framebuffer. Otherwise, we wouldn't need blending.
You also can't just render to the image you're reading from in a shader. So if you need to do some sort of post-processing, then that is best done by rendering to a separate image. That is, you do your rendering to image 1, then bind that as a texture and change the FBO so that you're rendering to image 2.
Alternatively, if you have access to OpenGL 4.5/ARB/NV_texture_barrier, then you can use texture barriers to handle this. This permits you a single read/modify/write pass, if you bind the current framebuffer's image as a texture. You'd issue the barrier before doing your read/modify/write, then bind that texture to a sampler while still rendering to that framebuffer.
Also, this requires that the FS read from the exact texel that it would write to. Assuming a viewport anchored at 0,0, the code for this would be texelFetch(sampler, ivec2(gl_FragCoord.xy), 0). You can't read from someone else's texel and modify it.
Obviously you must be rendering to a texture; you cannot use the default framebuffer for this.
Texture barrier could be used for cases where you read from different texels than you write to. But that would require doing something similar to the first case of switching bound images. Though you wouldn't need to change the FBO exactly; you could change the region of the FBO that you render to. That is, so long as you're reading from a different area than you're rendering to, and you use barriers appropriately when switching between those regions, everything is fine.

Read from one texture and write to a separate texture with in the same frame buffer

I have a Framebuffer with 2 textures attached is it possible to read from texture A and write to texture B, in the same fragment shader function ?
Thanks.
This is trickier than I expected. I thought that as long as you don't sample from and render to the same texture you would be fine, no matter if the texture is attached to an FBO. But while trying to find some conclusive spec quotes to back this up, things became much less clear.
The 4.5 spec does contain a phrase that seems to confirm my initial instinct (emphasis added):
Specifically, the values of rendered fragments are undefined if any shader stage fetches texels and the same texels are written via fragment shader outputs, even if the reads and writes are not in the same draw call
The interesting aspect is that the "written via fragment shader outputs" does not appear in spec versions up to and including 4.4. I don't know if adding this in 4.5 was intended as just a clarification, or if the rules for feedback loops were relaxed in 4.5. I couldn't find anything in the change log that would provide more background on the change.
Up to 4.4, the spec says that if a texture is attached to the current draw framebuffer, and is sampled, you have a feedback loop. Since nothing says otherwise, this would include the situation where the texture is attached to the FBO, but not used as a draw buffer.
I wouldn't be surprised if things mostly work fine as long as you don't render to and sample from the same texture. But to be completely safe, particularly if you don't rely on having OpenGL 4.5, you should un-attach the sampled texture from the FBO. Not including it in the list of draw buffers would be insufficient.
Extending Reto's answer.
You can read from texture A and write to texture B, BUT you cannot do this:
uniform sampler2D B; // Sampler for texture B.
layout (location = 0) out vec3 A; // Write to texture
A = texture(B,Texcoord);
This is invalid, and you must use a tertiary variable.
You cannot read and write to the texture on the same draw call, but you can read from one texture and write to another texture that both reside on the same framebuffer in the same draw call. You have to make sure when you bind the frame buffer you bind it like this.
glbindframebuffer(GL_FRAMEBUFFER, fboHandle)
This is because the framebuffer will be written to and read from and the `GL_FRAMEBUFFER, will allow you to do this.

Can a GL_FLOAT texture be assigned to a FBO as a COLOR attachment?

For offscreen rendering to a texture, I'm attaching at the attachment GL_COLOR_ATTACHMENT0 a texture defined by
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_FLOAT,NULL);
I then render to the FBO using a fragment shader that outputs a vec4, so normally, that should be ok. To check that I display the texture correctly, I use the function
glTexSubImage2D()
to add some grey pixels in the middle of the texture. The texture IS correctly displayed (I can perfectly see these pixels at the right place), but the rest of the texture is only noisy artifacts (when it's not black).
Does this come from the fact that I use GL_FLOAT for a GL_RGBA texture? If yes, how can I, in GLSL, convert a uvec4 to vec4? The output of my main shader is a vec4, and I don't know how to convert the uvec4 output of a usampler2D texture to my final vec4.
Thank you for any answer you might provide :)
EDIT : I found the solution : I didn't clear the GL_COLOR_BUFFER_BIT between my 2 renders.
I know this question was self-answered, but a discussion need to be had about this:
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_FLOAT,NULL);
That does not create a floating-point texture. It creates a texture that contains normalized, unsigned integers.
The actual format of a texture is the third parameter; that defines what the texture actually contains. The last three parameters define how you are trying to upload data to the texture; if the pointer is NULL (and no PBO is bound), then the parameters mean nothing.