Use multiple sampler2D over one input texture in OpenGL - c++

Now I have a noise texture generated by this website: https://aeroson.github.io/rgba-noise-image-generator/. I want to use 4 uniform samplers in my computing shader to get 4 random rgba values from a single noise texture. My computing shader source codes look like:
#version 430 core
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
uniform sampler2D noise_r0;
uniform sampler2D noise_i0;
uniform sampler2D noise_r1;
uniform sampler2D noise_i1;
layout (binding = 0, rgba32f) writeonly uniform image2D tilde_h0k;
layout (binding = 1, rgba32f) writeonly uniform image2D tilde_h0minusk;
uniform int N = 256;
....
// Box-Muller algorithm
vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / float(N); // Here every invocation refers to a pixel of output image
float noise00 = clamp(texture(noise_r0, texCoord).r, 0.001, 1.0);
float noise01 = clamp(texture(noise_i0, texCoord).r, 0.001, 1.0);
float noise02 = clamp(texture(noise_r1, texCoord).r, 0.001, 1.0);
float noise03 = clamp(texture(noise_i1, texCoord).r, 0.001, 1.0);
....
and in the main program, I use this code to upload my downloaded noise texture to the computing shader:
unsigned int tex_noise;
glGenTextures(1, &tex_noise);
glBindTexture(GL_TEXTURE_2D, tex_noise);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
int w_noise, h_noise, nrChannels;
unsigned char* data = stbi_load("noise.png", &w_noise, &h_noise, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w_noise, h_noise, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else std::cout << "Failed to load noise texture." << std::endl;
stbi_image_free(data);
....
....
My question is: Can I set up those sampler2D's in computing shader using this code?
glUseProgram(computeProgram);
glActiveTexture(GL_TEXTURE1);
glUniform1i(glGetUniformLocation(computeProgram, "noise_r0"), 1);
glActiveTexture(GL_TEXTURE2);
glUniform1i(glGetUniformLocation(computeProgram, "noise_i0"), 2);
glActiveTexture(GL_TEXTURE3);
glUniform1i(glGetUniformLocation(computeProgram, "noise_r1"), 3);
glActiveTexture(GL_TEXTURE4);
glUniform1i(glGetUniformLocation(computeProgram, "noise_i1"), 4);
If it is wrong, what should I do to set up those sampler2D's, and make sure that the random rgba values I get from those sampler2D's are not the same? (cause if they are the same, the Box-Muller algorithm won't work).
Thanks so much for your help!

The type of the uniform is ìmage2D, not sampler2D. To load and store an image, you must bind the texture to an image unit using glBindImageTexture. See Image Load Store. e.g.:
glBindImageTexture(1, tex_noise, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
If you want to bind a texture to a texture unit you need to select active texture unit with glActiveTexture and then bind the texture with glBindTexture:
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture_object);
You can access this texture in the shader with a uniform of type sampler2D and the texture* functions:
layout(binding = 1) uniform sampler2D myTextue;
If you want to bind a texture to a image unit, you have to use glBindImageTexture:
glBindImageTexture(1, texture_object, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
You can access this texture in the shader with a uniform of type iamge2D and and the image* functions:
layout (binding = 1, rgba32f) writeonly uniform image2D myImage;

Related

Different OpenGL Framebuffer RGBA values on NVIDIA cards

I am trying to implement a color picking algorithm, so I render my entities with a unique color on a different Framebuffer, so I can then query that Framebuffer on the pixel my mouse is on (using glReadPixels) and select the entity under the mouse cursor.
This works fine on my integrated Intel HD Graphics 4600. I am able to read back the exact value I sent on the GPU.
However running the application using my Nvidia GTX 860M, the results are not consistent. A few random pixels have the original color but most of them have the color a bit altered.
The same thing happens on another computer that has a Geforce 8600 GT.
I tried running it using NSight Graphics, which allows me to view the memory of the Textures.
The arrow points to the correct pixel color. I would expect every pixel to have the same color.
I use this union to create a unique color...
union u_picking_color {
struct s_entity *ep;
glm::vec3 color;
};
then I query the Framebuffer like this:
struct s_entity *Renderer::GetEntity(int x, int y) {
union u_picking_color picking_color = { 0 };
m_picking_fbo.SetReadTarget();
glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT, &picking_color.color);
return picking_color.ep;
}
here are the API calls used to create the Framebuffer:
glGenFramebuffers(1, &m_frameBufferId);
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferId);
glGenTextures(1, &m_colorTextureId);
glBindTexture(GL_TEXTURE_2D, m_colorTextureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorTextureId, 0);
glGenTextures(1, &m_depthTextureId);
glBindTexture(GL_TEXTURE_2D, m_depthTextureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTextureId, 0);
Also, here are the shaders used to draw on the framebuffer. They do not change the color. They only pass it through the pipeline.
Vertex:
#version 330 core
layout(location = 0) in vec3 v_Position;
//layout(location = 1) in vec3 v_Normal;
//layout(location = 2) in vec4 v_Color;
layout(location = 3) in vec3 v_PickingColor;
out vec4 color;
uniform mat4 u_ViewProjection;
void main()
{
color = vec4(v_PickingColor, 1);
gl_Position = u_ViewProjection * vec4(v_Position.x, v_Position.y, v_Position.z, 1.0f);
}
Fragment:
#version 330 core
out vec4 fragColor;
in vec4 color;
void main()
{
fragColor = color;
}
I tried disabling GL_BLEND and GL_DITHER with no success.
Turns out, even though I was using the same colour per-vertex, I should have used the 'flat' keyword on my shaders to prevent interpolation and avoid precision errors.
Vertex Shader:
flat out vec4 color;
Fragment Shader:
flat in vec4 color;

openGL single channel texture always samples 0

I'm trying to render font on screen using freetype. For that, I implemented single channel texture but it always samples 0.
cpp
unsigned char *blankData = new unsigned char[8 * 8];
for(int i = 0; i < 8 * 8; i++){
blankData[i] = 126;
}
glActiveTexture(GL_TEXTURE0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLuint m_texture2D;
glGenTextures(1, &m_texture2D);
glBindTexture(GL_TEXTURE_2D, m_texture2D);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 8, 8, 0, GL_RED, GL_UNSIGNED_BYTE, blankData);
glUniform1i(glGetUniformLocation(m_program, "texture2D"), 0);
checkGLError();
glGetError() returns GL_NO_ERROR
fragment Shader
#version 330 core
in vec2 texCoord;
in vec4 color;
uniform sampler2D texture2D;
out vec4 outColor;
void main()
{
vec4 texColor = texture(texture2D, texCoord);
outColor = vec4(texColor.r, texColor.r, texColor.r, 1.0f);
}
result
ff00ff: clear color
black: fragment shader output texcoord bottomLeft(0, 0) to topRight(1, 1)
If you are not generating mipmaps (with glGenerateMipmap) it is important to set GL_TEXTURE_MIN_FILTER. Since the default filter is GL_NEAREST_MIPMAP_LINEAR, the texture would be "Mipmap Incomplete" if you do not change the minimize function to GL_NEAREST or GL_LINEAR.
glBindTexture(GL_TEXTURE_2D, m_texture2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

OpenGL Frag Shader texture fades after every write

I have a program that takes the following texture:
which is generated via FreeType2. Basically, it's creating a texture atlas for every character that I've requested to be drawn. As you can see, the characters are bright and clear. In fact, you can see that the top-leftmost pixel of the lowercase 'i' has a value of 71 (out of 255) or 0.7098 when I inspect the texture in RenderDoc.
Next, the engine blits letters onto a Framebuffer Object. This is done via textured quads. The vertex shader:
#version 330
layout(location=0) in vec2 inVertexPosition;
layout(location=1) in vec2 inTexelCoords;
layout(location=2) in float inDepth;
out vec2 texelCoords;
out float depth;
void main()
{
gl_Position = vec4(inVertexPosition.x,-inVertexPosition.y, 0.0, 1.0);
texelCoords = vec2(inTexelCoords.x,1-inTexelCoords.y);
depth = inDepth;
}
And the frag shader:
#version 330
layout(location=0) out vec4 frag_colour;
in vec2 texelCoords;
in float depth;
uniform sampler2D uTexture;
uniform vec4 uTextColor;
void main()
{
vec4 c = texture(uTexture,texelCoords);
frag_colour = uTextColor * c.r;
gl_FragDepth = depth;
}
As you can see, it's sets the pixel color to be a factor of the red channel.
However, when I view the contents of the FBO via RenderDoc, and saved out to file here, you see this:
If you look at this without transparency (just a second layer added underneath in Gimp to illustrate better):
You can see that the text is a little faded compared to what it was before. If you look at the top-leftmost pixel of the lowercase 'i', it's now a value of 50.2, or for a range of 0-1 it's 0.50196 (via RenderDoc).
Next, when the FBO is finally put onto the screen via another textured quad it fades even more. First here's the vertex shader:
#version 330
layout(location=0) in vec2 inVertexPosition;
layout(location=1) in vec2 inTexelCoords;
varying vec2 texelCoords;
void main()
{
gl_Position = vec4(inVertexPosition.x,-inVertexPosition.y, 0.0, 1.0);
texelCoords = vec2(inTexelCoords.x,1-inTexelCoords.y);
}
and the fragment shader:
#version 330
precision highp float;
layout(location=0) out vec4 frag_colour;
varying vec2 texelCoords;
uniform sampler2D uTexture;
void main()
{
vec4 c = texture(uTexture,texelCoords);
frag_colour = c;
}
The results, as I said are more faded than before:
original:
gimp background for clarity:
now that pixel has a value of 25.1 or 0.05139.
What is causing this fading after every render?
I think it's important to note that the brighter areas don't fade.
My Framebuffer creation code
glGenFramebuffers(1, &m_framebuffer);
glGenTextures(1, &m_fboColorAttachment);
glGenTextures(1, &m_fboAdditionalInfo);
glGenTextures(1, &m_fboDepthStencil);
glCall(glBindFramebuffer,GL_FRAMEBUFFER, m_framebuffer);
/* setup color output 0 */
glBindTexture(GL_TEXTURE_2D, m_fboColorAttachment);
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_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glCall(glTexImage2D, GL_TEXTURE_2D, 0, GL_RGBA8, screenDimensionsX, screenDimensionsY, 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_fboColorAttachment, 0);
glBindTexture(GL_TEXTURE_2D, 0);
/* setup color output 1 */
glBindTexture(GL_TEXTURE_2D, m_fboAdditionalInfo);
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_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glCall(glTexImage2D, GL_TEXTURE_2D, 0, GL_R32UI, screenDimensionsX, screenDimensionsY, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, m_fboAdditionalInfo, 0);
glBindTexture(GL_TEXTURE_2D, 0);
/* setup depth and stencil */
glBindTexture(GL_TEXTURE_2D, m_fboDepthStencil);
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_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glCall(glTexImage2D, GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, screenDimensionsX, screenDimensionsY, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_fboDepthStencil, 0);
glBindTexture(GL_TEXTURE_2D, 0);
The initial (red) texture creation:
glActiveTexture(GL_TEXTURE0);
glGenTextures(1,&textureData.texture);
glBindTexture(GL_TEXTURE_2D,textureData.texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 500, 500, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
My blending is done as
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
has a value of 71 (out of 255) or 0.7098
No idea, what you even mean here. 71/255 would be 0.278. 0.7098 normalized would be 181 out of 255. Looks like your "out of 255" are just percentage values, out of 100%.
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
You use that color values from the red channel also as alpha, so, when you have blending enabled, you end up with 0.7098*0.7098=.5038. Since the result will be rounded to the nearest reprersentable value, we rather end with 181/255 * 181/255 = .50382 rounded to 128/255
it's now a value of 50.2, or for a range of 0-1 it's 0.50196
128/255 is 0.50196078....
So the solution is: disable blending for all steps when you don't need it. Or if you need it, set useful alpha values.
Side note:
now that pixel has a value of 25.1 or 0.05139.
No Idea what this means, the 25.1 does not relate to 0.05139 in any obvious way, you definitively switched the meaning of those values again.

OpenGL 3.2 Why am I getting INVALID_ENUM error for glTexStorage3D?

stbi_uc* data = stbi_load(path, &width, &height, NULL, 4);
if (data == NULL) {
return false;
}
gl_flush_errors();
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D_ARRAY, id);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA, 50, 50, 1);
This is the portion of my code where the INVALID_ENUM error is coming from, which I've narrowed down to the glTexStorage3D call. I'm also experiencing an INVALID_VALUE error directly after this block of code with:
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_CLAMP_TO_EDGE);
My goal here is to set up a texture array with my working tile instancing so I can render my tilemap in one draw call. I'm experiencing the same issue as here:
Instanced drawing with texture atlas
However, I'm not sure if I'm doing this correctly at the moment so any help or direction would be appreciated. These are my shaders as well in case they're the cause of the issue:
Fragment Shader
#version 330
// From vertex shader
in vec2 uvcoord;
// Application data
uniform sampler2DArray textures;
// uniform vec3 fcolor;
// Output color
layout(location = 0) out vec4 color;
void main()
{
color = texture(textures, vec3(uvcoord.x, uvcoord.y, 0.0));
}
Vertex Shader
#version 330
// Input attributes
in vec2 in_position;
in vec2 in_uvcoord;
in vec2 in_centre_pos;
// Passed to fragment shader
out vec2 uvcoord;
out vec2 vpos;
// Application data
uniform mat3 transform;
uniform mat3 projection;
void main()
{
uvcoord = in_uvcoord;
vpos = in_position;
vec3 pos = projection * vec3(in_position.x + in_centre_pos.x, in_position.y + in_centre_pos.y, 1.0);
gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);
}
OpenGL 4.6 API Core Profile Specification; 8.19. IMMUTABLE-FORMAT TEXTURE IMAGES; page 272:
The TexStorage* commands specify properties of the texture object bound to the target parameter of each command.
.....
Errors
An INVALID_ENUM error is generated if internalformat is one of the unsized base internal formats listed in table 8.11.
This means it is not allowed to use GL_RGBA for the 3rd paramter of glTexStorage3D.
Use GL_RGBA8 instead:
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 50, 50, 1);
You specified OpenGL 3.2, in this version function glTexStorage3D does not exist. Use glTexImage3D, which works with GL_RGBA instead of sized format GL_RGBA8 required by storage functions.

OpenGL SOIL - Failure to Load Texture

I'm following this tutorial step by step and I even copy-pasted the entire code but it still fails to load the texture. Here's my code, the parts that concern the question:
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture); // All upcoming GL_TEXTURE_2D operations now have effect on this texture object
// Set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture wrapping to GL_REPEAT (usually basic wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Load image, create texture and generate mipmaps
int width, height;
unsigned char* image = SOIL_load_image("container.jpg", &width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture when done, so we won't accidentily mess up our texture.
And here are my shaders:
#version 330 core
in vec3 ourColor;
in vec2 TexCoord;
out vec4 color;
uniform sampler2D ourTexture;
void main()
{
color = texture(ourTexture, TexCoord);
}
And
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 texCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(position, 1.0f);
ourColor = color;
TexCoord = texCoord;
}
I'm using SOIL to load image data. Is it too outdated? What should I do?
The tutorial code you are following seems to be wrong since it does not call glActiveTexture nor glUniform. See the game loop code of the other file at end of the tutorial.
Maybe you are missing something like this:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture"), 0);