Border artefact in GLSL pixelate shader - glsl

I am doing a simple pixelate shader in GLSL.
Everything is working as expected except for this border artifact that I see at pixelation borders.
The code is:
precision mediump float;
uniform sampler2D Texture0;
uniform int pixelCount;
varying vec2 fTexCoord;
void main(void)
{
float pixelWidth = 1.0/float(pixelCount);
float x = floor(fTexCoord.x/pixelWidth)*pixelWidth + pixelWidth/2.0;
float y = floor(fTexCoord.y/pixelWidth)*pixelWidth + pixelWidth/2.0;
gl_FragColor = texture2D(Texture0, vec2(x, y));
}
Please see the attached image.
I am clueless on why this is happening.
Please help me with this...

I think your problem is related to texture interpolation.
Are you using GL_NEAREST for your texture samplers (this makes the texture sampler use point sampler instead of some interpolation)?
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
Also you should probably not use mipmaps.
It would also be useful to know how the actual texture image looks like and how the geometry looks like (I assume you are rendering a single quad).

Related

Deferred Rendering not Displaying the GBuffer Textures

I'm trying to implement deferred rendering within an engine I'm developing as a personal learning, and I cannot get to understand what I'm doing wrong when it comes to render all the textures in the GBuffer to check if the implementation is okay.
The thing is that I currently have a framebuffer with 3 color attachments for the different textures of the GBuffer (color, normal and position), which I initialize as follows:
glCreateFramebuffers(1, &id);
glBindFramebuffer(GL_FRAMEBUFFER, id);
std::vector<uint> textures;
textures.resize(3);
glCreateTextures(GL_TEXTURE_2D, 3, textures.data());
for(size_t i = 0; i < 3; ++i)
{
glBindTexture(GL_TEXTURE_2D, textures[i]);
if(i == 0) // For Color Buffer
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], 0);
}
GLenum color_buffers[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers((GLsizei)textures.size(), color_buffers);
uint depth_texture;
glCreateTextures(GL_TEXTURE_2D, 1, &depth_texture);
glBindTexture(GL_TEXTURE_2D, depth_texture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, width, height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
bool fbo_status = glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
ASSERT(fbo_status, "Framebuffer Incompleted!");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
This is not reporting any errors and it seems to work since the framebuffer of the forward renderer renders properly. Then, when rendering, I run the next code after binding the framebuffer and clearing the color and depth buffers:
camera_buffer->Bind();
camera_buffer->SetData("ViewProjection", glm::value_ptr(viewproj_mat));
camera_buffer->SetData("CamPosition", glm::value_ptr(glm::vec4(view_position, 0.0f)));
camera_buffer->Unbind();
for(Entity& entity : scene_entities)
{
shader->Bind();
Texture* texture = entity.GetTexture();
BindTexture(0, texture);
shader->SetUniformMat4("u_Model", entity.transform);
shader->SetUniformInt("u_Albedo", 0);
shader->SetUniformVec4("u_Material.AlbedoColor", entity->AlbedoColor);
shader->SetUniformFloat("u_Material.Smoothness", entity->Smoothness);
glBindVertexArray(entity.VertexArray);
glDrawElements(GL_TRIANGLES, entity.VertexArray.index_buffer.count, GL_UNSIGNED_INT, nullptr);
// Shader, VArray and Textures Unbindings
}
So with this code I manage to render the 3 textures created by using the ImGui::Image function, by switching the texture index between 0, 1 or 2 as the next:
ImGui::Image((ImTextureID)(fbo->textures[0]), viewport_size, ImVec2(0, 1), ImVec2(1, 0));
Now, the color texture (at index 0) works perfectly, as the next image shows:
But when rendering the normals and position textures (indexes 2 and 3), I have no result:
Does anybody sees what I'm doing wrong? Because I've been hours and hours with this and I cannot see it. I ran this on RenderDoc and I couldn't see anything wrong, the textures displayed in RenderDoc are the same than in the engine.
The vertex shader I use when rendering the entities is the next:
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec2 a_TexCoord;
layout(location = 2) in vec3 a_Normal;
out IBlock
{
vec2 TexCoord;
vec3 FragPos;
vec3 Normal;
} v_VertexData;
layout(std140, binding = 0) uniform ub_CameraData
{
mat4 ViewProjection;
vec3 CamPosition;
};
uniform mat4 u_ViewProjection = mat4(1.0);
uniform mat4 u_Model = mat4(1.0);
void main()
{
vec4 world_pos = u_Model * vec4(a_Position, 1.0);
v_VertexData.TexCoord = a_TexCoord;
v_VertexData.FragPos = world_pos.xyz;
v_VertexData.Normal = transpose(inverse(mat3(u_Model))) * a_Normal;
gl_Position = ViewProjection * u_Model * vec4(a_Position, 1.0);
}
And the fragment one is the next, they are both pretty simple:
layout(location = 0) out vec4 gBuff_Color;
layout(location = 1) out vec3 gBuff_Normal;
layout(location = 2) out vec3 gBuff_Position;
in IBlock
{
vec2 TexCoord;
vec3 FragPos;
vec3 Normal;
} v_VertexData;
struct Material
{
float Smoothness;
vec4 AlbedoColor;
};
uniform Material u_Material = Material(1.0, vec4(1.0));
uniform sampler2D u_Albedo, u_Normal;
void main()
{
gBuff_Color = texture(u_Albedo, v_VertexData.TexCoord) * u_Material.AlbedoColor;
gBuff_Normal = normalize(v_VertexData.Normal);
gBuff_Position = v_VertexData.FragPos;
}
It is not clear from the question what exactly might be happening here, as lots of GL states - both at the time the rendering to the gbuffer, and at that time the gbuffer texture is rendered for visualization - are just unknown. However, from the images given in the question, one can not conclude that the actual color output for attachments 1 and 2 is not working.
One issue which comes to mind is alpha blending. The color values processed by the per-fragment operations after the vertex shader are always working with RGBA values - although the value of the A channel only matters if you enabled blending and use a blend function which somehow depends on the source alpha.
If you declare a custom fragment shader output as float, vec2, vec3, the remaining components stay undefined (undefined value, not undefined behavior). This does not impose a problem unless some other operations you do depend on those values.
What we also have here is a GL_RGBA16F output format (which is the right choice, because none of the 3-component RGB formats are required as color-renderable by the spec).
What might happen here is either:
Alpha blending is already turned on during rendering into the g-buffer. The fragment shader's alpha output happens to be zero, so that it appears as 100% transparent and the contents of the texture are not changed.
Alpha blending is not used during rendering into the g-buffer, so the correct contents end up in the texture, the alpha channel just happens to end up with all zeros. Now the texture might be visualized with alpha blending enbaled, ending up in a 100% transparent view.
If it is the first option, turn off blending when rendering the into the g-buffer. It would not work with deferred shading anyway. You might still run into the second option then.
If this is the second option, there is no issue at all - the lighting passes which follow will read the data they need (and ultimately, you will want to put useful information into the alpha channel to not waste it and be able to reduce the number of attachments). It is just your visualization (which I assume is for debug purposed only) is wrong. You can try to fix the visualization.
As a side note: Storing the world space position in the G-Buffer is a huge waste of bandwidth. All you need to be able to reconstruct the world space position is the depth value and the inverse of your view and projection matrices. Also storing world space position in GL_RGB16F will very easily run into precision issues if you move your camera away from world space origin.

OpenGL Fragment Shader Return Fixed Color for Texture

I have the below fragment shader which currently returns the color of a pixel from texture:
varying vec2 v_texCoord;
uniform sampler2D s_texture;
uniform vec4 vColor4;
void main()
{
gl_FragColor = texture2D( s_texture, v_texCoord );
//gl_FragColor = vColor4;
}
How do I change the fragment shader so that it returns a fixed color when a pixel is on and transparency when a pixel is off?
The TGA file I'm using contains transparency but a green and brown image (its a basic tree image - green top, brown trunk). What I'm trying to do is render the shape of the tree in one particular color (like a silhouette) instead of green, brown and transparency. If I change gl_FragColor to a set color, then the image paints as a solid rectangle -not what I want.
Is it just a matter of assigning the fixed colour and using the alpha (.a?) value returned by texture2D perhaps?
The line below gives me a white silhouette but the alpha channel is ignored so I get a white tree in a black rectangle:
gl_FragColor = texture2D( s_texture, v_texCoord ).aaaa;
UPDATE: I tried the following but it is still rendering a rectangle. It appears that the transparency isn't being loaded into my texture. It is transparent for sure with GIMP but transparency is rendering as white for me for some reason.
vec4 tmpColor = texture2D( s_texture, v_texCoord );
tmpColor.r = vColor4.r;
tmpColor.g = vColor4.g;
tmpColor.b = vColor4.b;
// gl_FragColor = texture2D( s_texture, v_texCoord );
//gl_FragColor = vColor4;
gl_FragColor = tmpColor;
My LoadTexture() function uses the following parameters:
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, TexHandle ); // Set our Tex handle as current
// Specify filtering and edge actions
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
//glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
glTexImage2D( GL_TEXTURE_2D,0,GL_RGBA, Img.GetWidth(),Img.GetHeight(),0,
GL_RGBA,GL_UNSIGNED_BYTE,Img.GetImg() );
Bits per pixel (BPP) is definitely 32 (R,G,B,A).
Sounds like you need to enable blending and a blending function (possibly specificyand equation also using glBlendEquation).
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
A great tester to see different blending equation results is here

about VTF(vertex texture fetch)

I'm studying clipmap algorithm, and I want to get elevations by VTF.
But I've got a problem when using vertex textures. I don't know what's wrong.
the related code is like this:
int width=127;
float *data=new float[width*width];
for(int i=0;i<width*width;i++)
data[i]=float(rand()%100)/100.0;
glGenTextures(1, &vertexTexture);
//glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, vertexTexture);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_LUMINANCE_FLOAT32_ATI,
width, width, 0, GL_LUMINANCE, GL_FLOAT, data);
the GLSL code in vertex shader is like this:
#version 410
uniform mat4 mvpMatrix;
uniform sampler2D vertexTexture;
in vec2 vVertex;
void main(void)
{
vec2 vTexCoords=vVertex/127.0;
float height = texture2DLod(vertexTexture, vTexCoords,0.0).x*100.0;
// I also tried texture2D(vertexTexture, vTexCoords)
// and texture(vertexTexture, vTexCoords),but they don't work.
vec4 position=vec4(vVertex.x,height,vVertex.y,1.0);
gl_Position = mvpMatrix * position;
}
I store some random floats in array data then store them with a texture,and as the vertex shader showing,I want to get some values to the y coordinate by VTF.but the result is that the height is always 0.I think something must be wrong. I don't know what's wrong and how to do it the right way.
it's solved now.the answer is here.thank you all!
Try setting the texture's minification filter to GL_NEAREST or GL_LINEAR after glTexImage2D():
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
The OpenGL default is to use mipmaps and you didn't send any which makes the texture incomplete and will disable that texture image unit.
Then you can use texture(vertexTexture, vTexCoords) inside the shader instead of the deprecated texture2DLOD() version with the explicit LOD access.

OpenGL Textures are all black in 3.3 - but work in 3.1

I'm currently working on a simple 3D scene in OpenGL3.3, but when trying to texture the objects - all of them are textured entirely black. However, if I change the context version to 3.1; it has no problem rendering the textures correctly over the models.
I'm not sure if this suggests I'm using deprecated functionality/methods, but I'm struggling to see where the problem could be.
Setting up the texture
(load texture from file)
...
glGenTextures(1, &TexID); // Create The Texture ( CHANGE )
glBindTexture(GL_TEXTURE_2D, TexID);
glTexImage2D(GL_TEXTURE_2D, 0, texture_bpp / 8, texture_width, texture_height, 0, texture_type, GL_UNSIGNED_BYTE, texture_imageData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
...
Binding the Texture to Render
// mLocation is the layout location in the shader, from glGetUniformLocation
// mTextureUnit is the specified texture unit to load into. Currently using 0.
// mTextureID is the ID of the loaded texture, as generated above.
glActiveTexture( GL_TEXTURE0 + mData.mTextureUnit );
glBindTexture( GL_TEXTURE_2D, mData.mTextureID );
glUniform1i( mLocation, mData.mTextureUnit );
Fragment Shader
uniform sampler2D diffusemap;
in vec2 passUV;
out vec3 outColour;
...
outColour = texture( diffusemap, passUV ).rgb;
All textures being used are power of 2, square sizes.
Images showing the problem.
GL3.1: http://i.imgur.com/NUgj6vA.png
GL3.3: http://i.imgur.com/oOc0jcd.png
Vertex Shader
#version 330 core
uniform mat4 p;
uniform mat4 v;
uniform mat4 m;
in vec3 vertex;
in vec3 normal;
in vec2 uv;
out vec3 passVertex;
out vec3 passNormal;
out vec2 passUV;
void main( void )
{
gl_Position = p * v * m * vec4( vertex, 1.0 );
passVertex = vec3( m * vec4( vertex, 1.0 ) );
passNormal = vec3( m * vec4( normal, 1.0 ) );
passUV = uv;
}
In the line:
glTexImage2D(GL_TEXTURE_2D, 0, texture_bpp / 8, texture_width, texture_height, 0, texture_type, GL_UNSIGNED_BYTE, texture_imageData);
The assumption that (texture_bpp / 8) will return the correct format type is incorrect. It should be one of the GLenum values that specifies the internal-format such as GL_RGBA.
Correcting it to (or whichever format matches the internal-format of the texture file) fixes the issue entirely and works on both GL3.3 and GL3.1:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture_width, texture_height, 0, texture_type, GL_UNSIGNED_BYTE, texture_imageData);
For the sake of completeness, the internal format of a texture should be an enumerator. And one of the sized enumerators, not one of the unsized ones. Please stop using GL_RGB when you can use GL_RGB8.
Answer correctly identifies the issue, but it would be helpful to have it explained why the previous assumption would work on 3.1 and not on 3.3.
The ability to use a number on the range [1, 4] was deprecated in OpenGL 3.0 and removed in OpenGL 3.1. However, at that time, there wasn't a way to say, "give me the actual core profile of OpenGL version 3.1"; the WGL/GLX_CONTEXT_CORE_PROFILE_BIT_ARBs didn't exist. Therefore, when you got a 3.1 context, it was perfectly legal for an implementation to export the ARB_compatibility extension, which still allowed all of the removed functionality.
In 3.2, the ability to explicitly select a profile was added to OpenGL. At which point, you would not get someone exposing ARB_compatibility in a core profile. That's why your code works when you ask for 3.1 (since it's free to give you 3.1 compatibility), but not when you ask for 3.3 core profile.

Texture mapping on a cylinder

I want to apply an uniform checkerboard texture to a cylinder surface of height h, and semiradii (a,b).
I've implemented this shader:
Vertex shader:
varying vec2 texture_coordinate;
float twopi = 6.283185307;
float pi=3.141592654;
float ra = 1.5;
float rb= 1.0;
void main()
{
// Transforming The Vertex
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
// -pi/2 < theta < pi/2
float theta = (atan2( rb*gl_Vertex.y , ra*gl_Vertex.x)+pi*0.5)/pi;
// Passing The Texture Coordinate Of Texture Unit 0 To The Fragment Shader
texture_coordinate = vec2( theta , -(-gl_Vertex.z+0.5) );
}
Fragment shader:
varying vec2 texture_coordinate;
uniform sampler2D my_color_texture;
void main()
{
// Sampling The Texture And Passing It To The Frame Buffer
gl_FragColor = texture2D(my_color_texture, texture_coordinate);
}
while on client side I've specified the following options:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
My texture is a 3768x1200 checkerboard. Now I would like that the texture is applied in order to keep the checkerboard uniform (squares without stretch), but I obtain a correct aspect ratio only in the less curved part of the surface, while on the more curved parts the tiles are stretched.
I would like to understand how to apply the texture without distorting and stretching it, maybe by repeating the texture instead of stretching it.
I also have a problem of strange flickering on the borders of the texture, where the two borders intersect, how to solve it (it can be seen in the second image)?
You can modify the texture coordinates to "shrink" it on an object a bit. What you can't do is to parametrize the texture coordinates to scale non-linearly.
So, the options are:
Quantize the sampling, modifying texture coordinates to better accomodate the non-circularity (dynamic, but quality is low when using low-poly tesselation; it's the simplest solution to implement, though).
Use fragment shader to scale texture coordinates non-linearly (possibly a bit more complicated, but dynamic and giving quite good results, depending on the texture size, filtering used and the texture contents(!))
Modify the texture (static solution - will work only for given Ra/Rb ratio. However, the quality will be the best possible).
As to the flickering on the borders, you have to generate mipmaps for your textures.
Let me know if you need more information.