GLSL shader render to texture not saving alpha value - opengl

UPDATE: Danvil solved it in a comment below. My texture format was GL_RGB not GL_RGBA which of course means that the alpha values aren't kept. Don't know why I didn't realize... Thanks Danvil.
I am rendering to a texture using a GLSL shader and then sending that texture as input to a second shader. For the first texture I am using RGB channels to send color data to the second GLSL shader, but I want to use the alpha channel to send a floating point number that the second shader will use as part of its program. The problem is that when I read the texture in the second shader the alpha value is always 1.0. I tested this in the following way:
at the end of the first shader I did this:
gl_FragColor = vec4(r, g, b, 0.1);
and then in the second texture I read the value of the first texture using something along the lines of
vec4 f = texture2D(previous_tex, pos);
if (f.a != 1.0) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
No pixels in my output are black, whereas if I change the above code to read
gl_FragColor = vec4(r, g, 0.1, 1.0); //Notice I'm now sending 0.1 for blue
and in the second shader
vec4 f = texture2D(previous_tex, pos);
if (f.b != 1.0) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
All the appropriate pixels are black. This means that for some reason when I set the alpha value to something other than 1.0 in the first shader and render to a texture, it is still seen as being 1.0 by the second shader.
Before I render to texture I glDisable(GL_BLEND);
It seems pretty clear to me that the problem has to do with OpenGL handling alpha values in some way that isn't obvious to me since I can use the blue channel in the way I want, and figured someone out there will instantly see the problem.
Also, the way I invoke the shader programs is by drawing a quad (I'm rendering to a framebuffer that has a texture):
gl.glUseProgram(shaderprogram);
gl.glUniform1iARB(gl.glGetUniformLocationARB(shaderprogram, "previous_tex"), 1);
gl.glDisable(GL.GL_BLEND);
gl.glBegin(GL.GL_QUADS);
{
gl.glVertex3f(0.0f, 1.0f, 1.0f);
gl.glVertex3f(1.0f, 1.0f, 1.0f);
gl.glVertex3f(1.0f, 0.0f, 1.0f);
gl.glVertex3f(0.0f, 0.0f, 1.0f);
}
gl.glEnd();
gl.glUseProgram(0);

Related

Artifacts with rendering texture with horizontal and vertical lines with OpenGL

I created 8x8 pixel bitmap letters to render them with OpenGL, but sometimes, depending on scaling I get weird artifacts as shown below in the image. Texture filtering is set to nearest pixel. It looks like rounding issue, but how could there be some if the line is perfectly horizontal.
Left original 8x8, middle scaled to 18x18, right scaled to 54x54.
Vertex data are unsigned bytes in format (x-offset, y-offset, letter). Here is full code:
vertex shader:
#version 330 core
layout(location = 0) in uvec3 Data;
uniform float ratio;
uniform float font_size;
out float letter;
void main()
{
letter = Data.z;
vec2 position = vec2(float(Data.x) / ratio, Data.y) * font_size - 1.0f;
position.y = -position.y;
gl_Position = vec4(position, 0.0f, 1.0f);
}
geometry shader:
#version 330 core
layout (points) in;
layout (triangle_strip, max_vertices = 4) out;
uniform float ratio;
uniform float font_size;
out vec3 texture_coord;
in float letter[];
void main()
{
// TODO: pre-calculate
float width = font_size / ratio;
float height = -font_size;
texture_coord = vec3(0.0f, 0.0f, letter[0]);
gl_Position = gl_in[0].gl_Position + vec4(0.0f, height, 0.0f, 0.0f);
EmitVertex();
texture_coord = vec3(1.0f, 0.0f, letter[0]);
gl_Position = gl_in[0].gl_Position + vec4(width, height, 0.0f, 0.0f);
EmitVertex();
texture_coord = vec3(0.0f, 1.0f, letter[0]);
gl_Position = gl_in[0].gl_Position + vec4(0.0f, 0.0f, 0.0f, 0.0f);
EmitVertex();
texture_coord = vec3(1.0f, 1.0f, letter[0]);
gl_Position = gl_in[0].gl_Position + vec4(width, 0.0f, 0.0f, 0.0f);
EmitVertex();
EndPrimitive();
}
fragment shader:
#version 330 core
in vec3 texture_coord;
uniform sampler2DArray font_texture_array;
out vec4 output_color;
void main()
{
output_color = texture(font_texture_array, texture_coord);
}
I had the same problem developing with Freetype and OpenGL. And after days of researching and scratching my head, I found the solution. In my case, I had to explicitly call the function 'glBlendColor'. Once, I did that, I did not observe any more artifacts.
Here is a snippet:
//Set Viewport
glViewport(0, 0, FIXED_WIDTH, FIXED_HEIGHT);
//Enable Blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendColor(1.0f, 1.0f, 1.0f, 1.0f); //Without this I was having artifacts: IMPORTANT TO EXPLICITLY CALLED
//Set Alignment requirement to 1 byte
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
I figured out the solution after reviewing the source code of this OpenGL-Freetype library on github: opengl-freetype library
Well, when using nearest filtering, you will see such issues if your sample location is very close to the boundary between two texels. And since the tex coords are to be interpolated separately for each fragment you are drawing, slight numerical inaccuracies will result in jumping between those two texels.
When you draw an 8x8 texture to an 18x18 pixel big rectangle, and your rectangle is perfectly aligned to the putput pixel raster, you are almost guaranteed to trigger that behavior:
Looking at the texel coodinates will then reveal that for the very bottom output pixel, the texture coords would be interpolated to 1/(2*18) = 1/36. Going one pixel up will add 1/18 = 2/36 to the t coordinate. So for the fifth row from the bottom, it would be 9/36.
So for the 8x8 texel big texture you are sampling from, you are actually sampling at unnormalized texel coordinates (9/36)*8 == 2.0. This is exactly the boundary between the second and third row of your texture. Since the texture coordinates for each fragment are interpolated by a barycentric interpolation between the tex coords assigned to the three vertices froming the triangle, there can be slight inaccuracies. And even the slightest possible inaccuracy representable in floating point format would result in flipping between two texels in this case.
I think your approach is just not good. Scaling bitmap fonts is always problematic (maybe besides integral scale factors). If you want nicely looking scalable texture fonts, I recommend you to look into signed distance fields. It is quite a simple and powerful technique, and there are tools available to generate the necessary distance field textures.
If you are looking for a quick hack, you coud also just offset your output rectangle slightly. You basically must make sure to keep the offset in [-0.5,0.5] pixels (so that never different fragments are generated during rasterization, and you must make sure that all the potential sample locations will never lie close to an integer, so the offset will depend on the actual scale factor.

OpenGL 3.0 Framebuffer outputting to attachments without me specifying?

Ok so I have a framebuffer with a bunch of attachments attached. The attachments are Color, Bloom, Velocity and Depth.
I start by clearing the framebuffer to the values of my choosing with the following code.
// Clear Color Buffer
float colorDefaultValue[4] = { 0.5, 0.5, 0.5, 1.0 };
glClearBufferfv(GL_COLOR, 0, colorDefaultValue);
// Clear Bloom Buffer
float bloomDefaultValue[4] = { 0.0, 0.0, 1.0, 1.0 };
glClearBufferfv(GL_COLOR, 1, bloomDefaultValue);
// Clear Depth Buffer
float depth[1] = { 1.0 };
glClearBufferfv(GL_DEPTH, 0, depth);
Then I proceed to render the scene using my main shader.
As you can see in the code below, Ive specified the outputs.
// Layouts
layout (location = 0) out vec4 o_vFragColor;
layout (location = 1) out vec4 o_vBloomColor;
And then i output values in the fragment shader to them.
o_vFragColor = vec4(color, alpha);
float brightness = dot(o_vFragColor.rgb, vec3(0.2126, 0.2126, 0.2126));
if(brightness > 1.0)
o_vBloomColor = vec4(o_vFragColor.rgb, 1.0);
Now, my question is: If a fragment is not bright enough, why does it output black to the bloom attachment? I haven't specified for it to output anything yet it adjusts it anyway.
For example, if I clear the bloom buffer to green
// Clear Bloom Buffer
float bloomDefaultValue[4] = { 0.0, 1.0, 0.0, 1.0 };
glClearBufferfv(GL_COLOR, 1, bloomDefaultValue);
and I dont output any value to the bloom attachment in the fragment shader, I get a black in the bloom buffer. You can see it it the following image.
BloomBuffer
The parts of the image where the buffer is green is where no geometry was drawn. The black parts are parts of the image that contained geometry that was not bright enough and therefore should have not outputted anything to the bloom buffer, yet they clearly did output something, black in this case.
Purple parts are fragments that are beyind the brightness threshold and working as intended.
What with the black?
You cannot write to a color buffer conditionally from within a fragment shader.
An output fragment always has values for each active color buffer, even if you didn't write them. This is true even if you don't declare a variable for that output value. If no value gets written to a particular fragment output location, then the value used will be undefined. But it will be something.
You can do conditional writing based on color masking. But that is a per-draw-call thing, not something that can be done in the fragment shader. You could employ blending in that color buffer, using an alpha of 0 to mean "don't write", and an alpha of 1 to replace what's there.

alpha not changing transparency of object using glsl shader

How come when i manually change the alpha value in array, being passed to shader, the result is the same for both 0.0f and 1.0f?
I was expecting the object to be drawn with some level of transparency, depending on alpha value.
I'm not using any textures. I always see my red object against a black background.
accessing glsl variable from java ..
float[] color = {1.0f, 0.0f, 0.0f, 1.0f};
gl2.glGetUniformLocation(shaderProgram, "vColor");
gl2.glUniform4fv(mColorHandle, 1, color, 0);
glsl, fragment shader ..
#version 120
uniform vec4 vColor;
void main() {
gl_FragColor = vColor;
gl_FragColor.a = 0.0; // does not make object transparent
// gl_FragColor.a = 1.0; // does not make object transparent
}
Needed to enable blending ..
gl2.glEnable(GL.GL_BLEND);
gl2.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);

OpenGL ES 2.0 Objects disappearing when depth test enabled

Edit: This turned out to be correct, hopefully it still helps others with similar issues.
Is there a piece I'm missing in setting up the depth testing pipeline in OpenGL ES 2.0 (using EGL)?
I've found many questions about this but all were solved by either correctly setting up the depth buffer on context initialization:
EGLint egl_attributes[] = {
...
EGL_DEPTH_SIZE, 16,
...
EGL_NONE };
if (!eglChooseConfig(
m_eglDisplay, egl_attributes, &m_eglConfig, 1, &numConfigs)) {
cerr << "Failed to set EGL configuration" << endl;
return EGL_FALSE;
}
or by properly enabling and clearing the depth buffer, and doing so after the context has been initialized:
// Set the viewport
glViewport(0, 0, m_display->width(), m_display->height());
// Enable culling and depth testing
glEnable(GL_CULL_FACE);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
// Clear the color and depth buffers
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepthf(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw elements
m_Program->drawAll();
Commenting out the glEnable(GL_DEPTH_TEST) I have a scene but without the depth test occlusion I would love to have.
In a shader, outputting the z component of gl_Position visually works as expected (z values are in the range [0, 1]):
// Vertex Shader
uniform mat4 u_matrix;
attribute vec4 a_position;
varying float v_depth;
void main() {
vec4 v_position = u_matrix * a_position;
v_depth = v_position.z / v_position.w;
gl_Position = v_position;
}
// Fragment shader
varying float v_depth;
void main() {
gl_FragColor = vec4((v_depth < 0.0) ? 1.0 : 0.0,
v_depth,
(v_depth > 1.0) ? 1.0 : 0.0,
1.0);
}
All objects are a shade of pure green, darker for nearer and brighter for further, as expected. Sadly some further (brighter) objects are drawn over nearer (darker) objects.
Any ideas what I'm missing? (If nothing else I hope this summarises some issues others have been having).
It appears I wasn't missing anything. I had a rogue polygon (in a different shader program) that, when depth was enabled occluded everything. The above is a correct setup.

What's the best way to draw a fullscreen quad in OpenGL 3.2?

I'm doing ray casting in the fragment shader. I can think of a couple ways to draw a fullscreen quad for this purpose. Either draw a quad in clip space with the projection matrix set to the identity matrix, or use the geometry shader to turn a point into a triangle strip. The former uses immediate mode, deprecated in OpenGL 3.2. The latter I use out of novelty, but it still uses immediate mode to draw a point.
I'm going to argue that the most efficient approach will be in drawing a single "full-screen" triangle. For a triangle to cover the full screen, it needs to be bigger than the actual viewport. In NDC (and also clip space, if we set w=1), the viewport will always be the [-1,1] square. For a triangle to cover this area just completely, we need to have two sides to be twice as long as the viewport rectangle, so that the third side will cross the edge of the viewport, hence we can for example use the following coordiates (in counter-clockwise order): (-1,-1), (3,-1), (-1,3).
We also do not need to worry about the texcoords. To get the usual normalized [0,1] range across the visible viewport, we just need to make the corresponding texcoords for the vertices tiwce as big, and the barycentric interpolation will yield exactly the same results for any viewport pixel as when using a quad.
This approach can of course be combined with attribute-less rendering as suggested in demanze's answer:
out vec2 texcoords; // texcoords are in the normalized [0,1] range for the viewport-filling quad part of the triangle
void main() {
vec2 vertices[3]=vec2[3](vec2(-1,-1), vec2(3,-1), vec2(-1, 3));
gl_Position = vec4(vertices[gl_VertexID],0,1);
texcoords = 0.5 * gl_Position.xy + vec2(0.5);
}
Why will a single triangle be more efficient?
This is not about the one saved vertex shader invocation, and the one less triangle to handle at the front-end. The most significant effect of using a single triangle will be that there are less fragment shader invocations
Real GPUs always invoke the fragment shader for 2x2 pixel sized blocks ("quads") as soon as a single pixel of the primitive falls into such a block. This is necessary for calculating the window-space derivative functions (those are also implicitly needed for texture sampling, see this question).
If the primitive does not cover all 4 pixels in that block, the remaining fragment shader invocations will do no useful work (apart from providing the data for the derivative calculations) and will be so-called helper invocations (which can even be queried via the gl_HelperInvocation GLSL function). See also Fabian "ryg" Giesen's blog article for more details.
If you render a quad with two triangles, both will have one edge going diagonally across the viewport, and on both triangles, you will generate a lot of useless helper invocations at the diagonal edge. The effect will be worst for a perfectly square viewport (aspect ratio 1). If you draw a single triangle, there will be no such diagonal edge (it lies outside of the viewport and won't concern the rasterizer at all), so there will be no additional helper invocations.
Wait a minute, if the triangle extends across the viewport boundaries, won't it get clipped and actually put more work on the GPU?
If you read the textbook materials about graphics pipelines (or even the GL spec), you might get that impression. But real-world GPUs use some different approaches like Guard-band clipping. I won't go into detail here (that would be a topic on it's own, have a look at Fabian "ryg" Giesen's fine blog article for details), but the general idea is that the rasterizer will produce fragments only for pixels inside the viewport (or scissor rect) anyway, no matter if the primitive lies completely inside it or not, so we can simply throw bigger triangles at it if both of the following are true:
a) the triangle does only extend the 2D top/bottom/left/right clipping planes (as opposed to the z-Dimension near/far ones, which are more tricky to handle, especially because vertices may also lie behind the camera)
b) the actual vertex coordinates (and all intermediate calculation results the rasterizer might be doing on them) are representable in the internal data formats the GPU's hardware rasterizer uses. The rasterizer will use fixed-point data types of implementation-specific width, while vertex coords are 32Bit single precision floats. (That is basically what defines the size of the Guard-band)
Our triangle is only factor 3 bigger than the viewport, so we can be very sure that there is no need to clip it at all.
But is it worth it?
Well, the savings on fragment shader invocations are real (especially when you have a complex fragment shader), but the overall effect might be barely measurable in a real-world scenario. On the other hand, the approach is not more complicated than using a full-screen quad, and uses less data, so even if might not make a huge difference, it won't hurt, so why not using it?
Could this approach be used for all sorts of axis-aligned rectangles, not just fullscreen ones?
In theory, you can combine this with the scissor test to draw some arbitrary axis-aligned rectangle (and the scissor test will be very efficient, as it just limits which fragments are produced in the first place, it isn't a real "test" in HW which discards fragments). However, this requires you to change the scissor parameters for each rectangle you want to draw, which implies a lot of state changes and limits you to a single rectangle per draw call, so doing so won't be a good idea in most scenarios.
You can send two triangles creating a quad, with their vertex attributes set to -1/1 respectively.
You do not need to multiply them with any matrix in the vertex/fragment shader.
Here are some code samples, simple as it is :)
Vertex Shader:
const vec2 madd=vec2(0.5,0.5);
attribute vec2 vertexIn;
varying vec2 textureCoord;
void main() {
textureCoord = vertexIn.xy*madd+madd; // scale vertex attribute to [0-1] range
gl_Position = vec4(vertexIn.xy,0.0,1.0);
}
Fragment Shader :
varying vec2 textureCoord;
void main() {
vec4 color1 = texture2D(t,textureCoord);
gl_FragColor = color1;
}
No need to use a geometry shader, a VBO or any memory at all.
A vertex shader can generate the quad.
layout(location = 0) out vec2 uv;
void main()
{
float x = float(((uint(gl_VertexID) + 2u) / 3u)%2u);
float y = float(((uint(gl_VertexID) + 1u) / 3u)%2u);
gl_Position = vec4(-1.0f + x*2.0f, -1.0f+y*2.0f, 0.0f, 1.0f);
uv = vec2(x, y);
}
Bind an empty VAO. Send a draw call for 6 vertices.
To output a fullscreen quad geometry shader can be used:
#version 330 core
layout(points) in;
layout(triangle_strip, max_vertices = 4) out;
out vec2 texcoord;
void main()
{
gl_Position = vec4( 1.0, 1.0, 0.5, 1.0 );
texcoord = vec2( 1.0, 1.0 );
EmitVertex();
gl_Position = vec4(-1.0, 1.0, 0.5, 1.0 );
texcoord = vec2( 0.0, 1.0 );
EmitVertex();
gl_Position = vec4( 1.0,-1.0, 0.5, 1.0 );
texcoord = vec2( 1.0, 0.0 );
EmitVertex();
gl_Position = vec4(-1.0,-1.0, 0.5, 1.0 );
texcoord = vec2( 0.0, 0.0 );
EmitVertex();
EndPrimitive();
}
Vertex shader is just empty:
#version 330 core
void main()
{
}
To use this shader you can use dummy draw command with empty VBO:
glDrawArrays(GL_POINTS, 0, 1);
This is similar to the answer by demanze, but I would argue it's easier to understand. Also this is only drawn with 4 vertices by using TRIANGLE_STRIP.
#version 300 es
out vec2 textureCoords;
void main() {
const vec2 positions[4] = vec2[](
vec2(-1, -1),
vec2(+1, -1),
vec2(-1, +1),
vec2(+1, +1)
);
const vec2 coords[4] = vec2[](
vec2(0, 0),
vec2(1, 0),
vec2(0, 1),
vec2(1, 1)
);
textureCoords = coords[gl_VertexID];
gl_Position = vec4(positions[gl_VertexID], 0.0, 1.0);
}
The following comes from the draw function of the class that draws fbo textures to a screen aligned quad.
Gl.glUseProgram(shad);
Gl.glBindBuffer(Gl.GL_ARRAY_BUFFER, vbo);
Gl.glEnableVertexAttribArray(0);
Gl.glEnableVertexAttribArray(1);
Gl.glVertexAttribPointer(0, 3, Gl.GL_FLOAT, Gl.GL_FALSE, 0, voff);
Gl.glVertexAttribPointer(1, 2, Gl.GL_FLOAT, Gl.GL_FALSE, 0, coff);
Gl.glActiveTexture(Gl.GL_TEXTURE0);
Gl.glBindTexture(Gl.GL_TEXTURE_2D, fboc);
Gl.glUniform1i(tileLoc, 0);
Gl.glDrawArrays(Gl.GL_QUADS, 0, 4);
Gl.glBindTexture(Gl.GL_TEXTURE_2D, 0);
Gl.glBindBuffer(Gl.GL_ARRAY_BUFFER, 0);
Gl.glUseProgram(0);
The actual quad itself and the coords are got from:
private float[] v=new float[]{ -1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
The binding and set up of the vbo's I leave to you.
The vertex shader:
#version 330
layout(location = 0) in vec3 pos;
layout(location = 1) in vec2 coord;
out vec2 coords;
void main() {
coords=coord.st;
gl_Position=vec4(pos, 1.0);
}
Because the position is raw, that is, not multiplied by any matrix the -1, -1::1, 1 of the quad fit into the viewport. Look for Alfonse's tutorial linked off any of his posts on openGL.org.