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.
Related
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.
I am trying to pass a float* that contains 128*128 float to a shader. Since this array is too big, I am trying to pass by a texture to get my float* in my shader. The problem is I don't know how to use this array inside my shader.
I print my float* before sending it to my shader, and It contains number between -1 and 1.
My goal is to simulate waves on water with perlin noise, so my array of float is perlin noises.
So I instantiate my noise texture like this :
_perlin_noise = new float[_dimension * _dimension];
//... I put float inside my _perlin_noise variable
//Then I instantiate my texture :
glGenTextures(1, &_perlin_noise_text);
glBindTexture(GL_TEXTURE_2D, _perlin_noise_text);
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_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, _dimension, _dimension, 0,
GL_RED, GL_FLOAT, _perlin_noise);
glActiveTexture(0);
glBindTexture(GL_TEXTURE_2D, 0);
My water use two textures : One texture is full blue, the other is a texture of foam.
So now I have a third texture that is my perlin noise. And I want to ajust the height of my vertices by perlin noise.
So before anything, I alocate uniform variable to my shader like this :
main_water_shader->use();
glUniform1i(glGetUniformLocation(main_water_shader->getProgram(), "main_water_texture"), 0);
glUniform1i(glGetUniformLocation(main_water_shader->getProgram(), "foam_texture"), 1);
glUniform1i(glGetUniformLocation(main_water_shader->getProgram(), "perlin_noise"), 2);
Then I want to ajust vertices's height in my vertex shader, but I don't know how to do it. I tried to do that in my vertex shader :
uniform sampler2D perlin_noise;
//some other uniform...
void main()
{
//calculating vertex height
float height = float( texture2D(perlin_noise, vec2(x, y)) );
vec3 new_vertex_position = vertex_position;
new_vertex_position.y = height;
//Standard stuff
vs_position = vec4(ModelMatrix * vec4(new_vertex_position, 1.f)).xyz;
vs_texcoord = vec2(vertex_texcoord.x, vertex_texcoord.y );
vs_normal = mat3(ModelMatrix) * vertex_normal;
gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * vec4(new_vertex_position, 1.f);
}
Nothing change, the height of my vertices is still the same. And if I try to display my perlin_noise texture in my fragment shader onto a plan, I get this :
You can see my plane (which is very large) with a black and white texture on it that is repeated. So I guess my perlin_noise texture does contains something (even if it is a bit weird), but I can't figure out how to use it in my vertex shader.
EDIT : In my screenshoot, I also use a vertex shader with height ajusted with perlin noise, but as you can see, my plane is plane, so It does not seems to work.
EDIT2 : If I'm not clear enough, tell me
For testing purposes I want to display the first slice of a 3D texture. However it seems that the other slices are also displayed.
My vertex shader:
#version 130
attribute vec4 position;
varying vec2 texcoord;
void main()
{
gl_Position = position;
texcoord = position.xy * vec2(0.5) + vec2(0.5);
}
The fragment shader:
#version 130
uniform sampler3D textures[1];
varying vec2 texcoord;
void main()
{
gl_FragColor = texture3D(textures[0], vec3(texcoord.x, texcoord.y, 0));
}
I bind the texture from my C++ code using
glTexImage3D(GL_TEXTURE_3D,0,GL_LUMINANCE,rows-1,cols-1,dep- 1,0,GL_RED,GL_UNSIGNED_SHORT, vol.data());
This is how it looks; the whole head should not be visible, only the upper portion of it.
When you use linear filtering (value GL_LINEAR for the GL_TEXTURE_MIN_FILTER and/or GL_TEXTURE_MAG_FILTER texture parameters), the value of your samples will generally be determined by the two slices closest to your 3rd texture coordinate.
If the size of your 3D texture in the 3rd dimension is d, the position of the first slice in texture coordinate space is 0.5 / d. This is easiest to understand if you picture each slice having a certain thickness in texture coordinate space. Since you have d slices, and the texture coordinate range is [0.0, 1.0], each slice has thickness 1.0 / d. Therefore, the first slice extends from 0.0 to 1.0 / d, and its center is at 0.5 / d.
When you use 0.0 for the 3rd texture coordinate, this is not the center of the first slice, and linear sampling comes into play. Since 0.0 is at the edge of the texture, the wrap modes become critical. The default wrap mode is GL_REPEAT, meaning that sampling at the edges acts as if the texture was repeated. With this setting, the neighbor of the first slice is the last slice, and texture coordinate 0.0 is exactly in the middle between the first slice and the last slice.
The consequence is that linear sampling with texture coordinate 0.0 will give you the average of the first slice and the last slice.
While GL_REPEAT is the default for the wrap modes, it is rarely what you want, unless your texture really contains a repeating pattern. It's certainly not the right setting in this case. What you need here is:
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
TASK BACKGROUND
I am trying to implement SSAO after OGLDev Tutorial 45, which is based on a Tutorial by John Chapman. The OGLDev Tutorial uses a highly simplified method which samples random points in a radius around the fragment position and steps up the AO factor depending on how many of the sampled points have a depth greater than the actual surface depth stored at that location (the more positions around the fragment lie in front of it the greater the occlusion).
The 'engine' i use does not have as modular deferred shading as OGLDev, but basically it first renders the whole screen colors to a framebuffer with a texture attachment and a depth renderbuffer attachment. To compare the depths, the fragment view space positions are rendered to another framebuffer with texture attachment.
Those texture are then postprocessed by the SSAO shader and the result is drawn to a screen filling quad.
Both textures on their own draw fine to the quad and the shader input uniforms seem to be ok also, so thats why i havent included any engine code.
The Fragment Shader is almost identical, as you can see below. I have included some comments that serve my personal understanding.
#version 330 core
in vec2 texCoord;
layout(location = 0) out vec4 outColor;
const int RANDOM_VECTOR_ARRAY_MAX_SIZE = 128; // reference uses 64
const float SAMPLE_RADIUS = 1.5f; // TODO: play with this value, reference uses 1.5
uniform sampler2D screenColorTexture; // the whole rendered screen
uniform sampler2D viewPosTexture; // interpolated vertex positions in view space
uniform mat4 projMat;
// we use a uniform buffer object for better performance
layout (std140) uniform RandomVectors
{
vec3 randomVectors[RANDOM_VECTOR_ARRAY_MAX_SIZE];
};
void main()
{
vec4 screenColor = texture(screenColorTexture, texCoord).rgba;
vec3 viewPos = texture(viewPosTexture, texCoord).xyz;
float AO = 0.0;
// sample random points to compare depths around the view space position.
// the more sampled points lie in front of the actual depth at the sampled position,
// the higher the probability of the surface point to be occluded.
for (int i = 0; i < RANDOM_VECTOR_ARRAY_MAX_SIZE; ++i) {
// take a random sample point.
vec3 samplePos = viewPos + randomVectors[i];
// project sample point onto near clipping plane
// to find the depth value (i.e. actual surface geometry)
// at the given view space position for which to compare depth
vec4 offset = vec4(samplePos, 1.0);
offset = projMat * offset; // project onto near clipping plane
offset.xy /= offset.w; // perform perspective divide
offset.xy = offset.xy * 0.5 + vec2(0.5); // transform to [0,1] range
float sampleActualSurfaceDepth = texture(viewPosTexture, offset.xy).z;
// compare depth of random sampled point to actual depth at sampled xy position:
// the function step(edge, value) returns 1 if value > edge, else 0
// thus if the random sampled point's depth is greater (lies behind) of the actual surface depth at that point,
// the probability of occlusion increases.
// note: if the actual depth at the sampled position is too far off from the depth at the fragment position,
// i.e. the surface has a sharp ridge/crevice, it doesnt add to the occlusion, to avoid artifacts.
if (abs(viewPos.z - sampleActualSurfaceDepth) < SAMPLE_RADIUS) {
AO += step(sampleActualSurfaceDepth, samplePos.z);
}
}
// normalize the ratio of sampled points lying behind the surface to a probability in [0,1]
// the occlusion factor should make the color darker, not lighter, so we invert it.
AO = 1.0 - AO / float(RANDOM_VECTOR_ARRAY_MAX_SIZE);
///
outColor = screenColor + mix(vec4(0.2), vec4(pow(AO, 2.0)), 1.0);
/*/
outColor = vec4(viewPos, 1); // DEBUG: draw view space positions
//*/
}
WHAT WORKS?
The fragment colors texture is correct.
The texture coordinates are those of a screen filling quad to which we draw and are transformed to [0, 1]. They yield equivalent results as vec2 texCoord = gl_FragCoord.xy / textureSize(screenColorTexture, 0);
The (perspective) projection matrix is the one the camera uses, and it works for that purpose. In any case, this doesnt seem to be the issue.
The random sample vector components are in range [-1, 1], as intended.
The fragment view space positions texture seems ok:
WHAT'S WRONG?
When i set the AO mixing factor at the bottom of the fragment shader to 0, it runs smooth to the fps cap (even though the calculations are still performed, at least i guess the compiler wont optimize that :D ). But when the AO is mixed in it takes up to 80 ms per frame draw (getting slower with time, as if the buffers were filling up), and the result is really interesting and confusing:
Obviously the mapping seems far off, and the flickering noise seems very random, as if it corresponded directly to the random sample vectors.
I found it most interesting that the draw time increased massively only on the addition of the AO factor, not due to the occlusion calculation. Is there an issue in the draw buffers?
The issue appeared to be linked to the chosen texture types.
The texture with handle viewPosTexture needed to explicitly be defined as a float texture format GL_RGB16F or GL_RGBA32F, instead of just GL_RGB. Interestingly, the seperate textures were drawn fine, the issues arised in combination only.
// generate screen color texture
// note: GL_NEAREST interpolation is ok since there is no subpixel sampling anyway
glGenTextures(1, &screenColorTexture);
glBindTexture(GL_TEXTURE_2D, screenColorTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, windowWidth, windowHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, NULL);
// generate depth renderbuffer. without this, depth testing wont work.
// we use a renderbuffer since we wont have to sample this, opengl uses it directly.
glGenRenderbuffers(1, &screenDepthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, screenDepthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, windowWidth, windowHeight);
// generate vertex view space position texture
glGenTextures(1, &viewPosTexture);
glBindTexture(GL_TEXTURE_2D, viewPosTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, windowWidth, windowHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
The slow drawing might be caused by the GLSL mix function. Will investigate further on that.
The flickering was due to the regeneration and passing of new random vectors in each frame. Just passing enough random vectors once solves the issue. Otherwise it might help to blur the SSAO result.
Basically, the SSAO works now! Now its just more or less apparent bugs.
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).