Send Depthbuffer and TextureBuffer to same Fragment OpenGL3 - c++

It might be stupid and a trivial question but since i'm kinda new with OpenGL ,I don't understand how to send color buffer and depth buffer coming from a single FBO to the fragment shader.
My FBO is generated with 1 texture buffer and 1 depth buffer
glGenTextures(1, &texture_color);
glBindTexture(GL_TEXTURE_2D, texture_color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glGenTextures(1, &texture_depth);
glBindTexture(GL_TEXTURE_2D, texture_depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
and I would like, in my fragment buffer to have
uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
to be filled with both color and depth texture...
I can send just one or the other with GlBindtexture (and it works well), but I don't success to send the 2 at the same time. Does somebody knows how to do it?
Thanks!

Ok, I might not be giant since the solution is easy, and I was just doing wrong.
I was trying to use glActiveTexture(GL_DEPTH) followed by a binding to my Texture : (glBindTexture(GL_TEXTURE_2D, visibilityFBO.getDepthTexture());) thinking it was normal to use GL_DEPTH.
But i was wrong,
and it works using :
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, visibilityFBO.getColorTexture());
glUniform1i(glGetUniformLocation(visibilityPassShader.Program, "positionTexture"), 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, visibilityFBO.getDepthTexture());
glUniform1i(glGetUniformLocation(visibilityPassShader.Program, "depthTexture"), 1);
it's the same as before, but the DEPTH is considerated as a Texture since I used glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); to produce my Depth texture. So I just have to call the next texture and bind it to be able to use it.
In the fragment, it is still :
uniform sampler2D positionTexture;
uniform sampler2D depthTexture;
In the good order.
Using OpenGL >= 4, you can use in the fragment shader
layout (binding = 0) uniform sampler2D positionTexture;
layout (binding = 1) uniform sampler2D depthTexture;
and forgive the part about glUniform1i in the source code.
Hope it can help someone!

Related

openGL run slow / process is killed on two textures

I am attempting to learn OpenGL, more or less from scratch. I seem to run into an issue when I load two different textures, and use a different one depending on the y-position of the shape. It works, but it appears that computing each frame takes a lot longer than I'd hope for. My computer seems to be completely consumed by that one task, until the window with the OpenGL code closes with the terminal telling me Killed. So I assume I am doing something very wrong and stupid.
Here is my texture shader:
#version 120
uniform sampler2D tex0;
uniform sampler2D tex1;
varying float factor; // y-coordinate passed from the vertex shader
varying vec2 intp_texture;
void main(void) {
vec4 opt0 = texture2D(tex0, intp_texture);
vec4 opt1 = texture2D(tex1, intp_texture);
if (factor < 0) {
gl_FragColor = opt0;
} else if (factor > 0) {
gl_FragColor = opt1;
} else {
gl_FragColor = mix(opt0, opt1, 0.5);
}
}
Here is what I think is the relevant part of my render function:
glEnableVertexAttribArray(texture_loc);
glBindBuffer(GL_ARRAY_BUFFER, tbuffer);
glVertexAttribPointer(texture_loc, 2, GL_FLOAT, GL_FALSE, 0, (void*) 0);
glGenTextures(2, texs);
// images for the texture
glBindTexture(GL_TEXTURE_2D, texs[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data_0);
glGenerateMipmap(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glUniform1i(tex0_loc, 0);
glBindTexture(GL_TEXTURE_2D, texs[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data_1);
glGenerateMipmap(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE1);
glUniform1i(tex1_loc, 1);
I have tried running glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data_?); only at the initialisation. The problem I have then is that then the shader doesn't seem to differentiate between tex0 sampler and tex1 sampler.
All and any input would be much appreciated! The full code is on github, too, if that is helpful.

How can I add multiple textures to my openGL program?

I am writing an openGL program and have multiple models drawn into the environment, but I don't know how to apply different textures to each of those models, so for now they all have the same texture. I've read that I need to add multiple texture units into the program or use a texture atlas. A texture atlas seems more complicated, so I'm trying to add texture units.
The way I thought this process worked is:
Generate two texture units with glGenTextures.
Bind the data of the first image to the first texture unit with glBindTexture and glTexImage2D.
Do the same with the second image.
From here, I thought I could tell openGL which texture unit I want to use using glActiveTexture. This seems to work with just one texture (i.e. skip step 3) but fails with two or more.
I'm sure I'm missing something, so could someone point me in the right direction?
//Generate textures
int texturec=2;
int w[texturec],h[texturec];
unsigned char *data[texturec];
data[0]=getImage(&w[0],&h[0],"resources/a.png");
data[1]=getImage(&w[1],&h[1],"resources/b.png");
//Apply textures
GLuint textures[texturec];
glGenTextures(texturec, textures);
//Bind a.png to the first texture unit
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[0], h[0], 0, GL_RGB, GL_UNSIGNED_BYTE, data[0]);
//Bind b.png to the second texture unit
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[1], h[1], 0, GL_RGB, GL_UNSIGNED_BYTE, data[1]);
glActiveTexture(GL_TEXTURE0);
//Not super clear on what this does, but it needs to be here.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
And here are my shaders:
Fragment:
#version 330 core
in vec2 UV;
out vec3 color;
uniform sampler2D textureSampler;
void main(){
color=texture(textureSampler,UV).rgb;
}
Vertex:
#version 330 core
layout(location=0) in vec3 vertexPos;
layout(location=1) in vec2 vertexUV;
out vec2 UV;
uniform mat4 MVP;
void main(){
gl_Position=MVP*vec4(vertexPos,1);
UV=vertexUV;
}
Edit:
Here is my new code after applying Rabid76's suggestions:
//Generate textures
int texturec=2;
int w[texturec],h[texturec];
unsigned char *data[texturec];
data[0]=getImage(&w[0],&h[0],"resources/a.png");
data[1]=getImage(&w[1],&h[1],"resources/b.png");
//Apply textures
GLuint textures[texturec];
glGenTextures(texturec, textures);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[0], h[0], 0, GL_RGB, GL_UNSIGNED_BYTE, data[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[1], h[1], 0, GL_RGB, GL_UNSIGNED_BYTE, data[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//Shaders
programID=loadShaders("shaders/vertex.shader","shaders/fragment.shader");
glUseProgram(programID);
//Use texture unit 1
glActiveTexture(GL_TEXTURE1);
GLint texLoc=glGetUniformLocation(programID, "textureSampler");
glUniform1i(texLoc, 1);
Generate two texture units with glGenTextures.
No. glGenTextures doesn't generate a texture unit.
glGenTextures reserves name value(s), which can be used for texture objects.
glBindTexture binds a named texture to a texturing target. When this function is called, then the texture object is bound to the current texture unit.
The current texture unit can be set by glActiveTexture:
e.g.
GLuint textures[texturec];
glGenTextures(texturec, textures);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
// [...]
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
// [...]
The texture objects name value and the texture unit are completely different things.
The texture unit is the binding point between the texture object and the shader program.
On the one side, the texture object has to be bound to the texture unit, on the other side the texture unit has to be set to the texture sampler uniform. So the texture unit is the "link" in between.
Since GLSL version 4.2, the texture unit can be set by a Layout Qualifier (GLSL) within the shader. The Binding point corresponds to the texture unit. e.g. binding = 1 means texture unit 1:
layout(binding = 1) uniform sampler2D textureSampler;
Alternatively the texture unit index can be assigned to the texture sampler uniform by glUniform1i:
GLint texLoc = glGetUniformLocation(programID, "textureSampler");
glUniform1i(texLoc, 1);
If the shader program uses 1 texture sampler uniform
uniform sampler2D textureSampler;
then it is sufficient to bind the proper texture object before the draw call:
glActiveTexture(GL_TEXTURE0); // this is default
glBindTexture(GL_TEXTURE_2D, textures[0]);
But if the shader program uses multiple texture sampler uniforms (of the same target), then the different texture objects have to be bound to different texture units:
e.g.
layout(binding = 3) uniform sampler2D textureSampler1;
layout(binding = 4) uniform sampler2D textureSampler2;
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, textures[1]);
respectively
layout(location = 7) uniform sampler2D textureSampler1;
layout(location = 8) uniform sampler2D textureSampler2;
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glUseProgram(programID);
glUniform1i(7, 3); // location = 7 <- texture unit 3
glUniform1i(8, 4); // location = 8 <- texture unit 4

Making position buffer for deferred rendering - noise in the generated textures

I'm trying to implement deferred shading for the first time but I'm having trouble generating the buffers. I've started trying to make just the position buffer so here is the relative code:
glGenFramebuffers(1, &gBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
glGenTextures(1, &gPosition);
glBindTexture(GL_TEXTURE_2D, gPosition);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, 1024, 1024, 0, GL_RGB, GL_FLOAT,
NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPosition, 0);
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 1024, 1024);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
The framebuffer is successfully completed and we go to the main loop:
glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
glActiveTexture(gPosition);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, 1024, 1024);
mat4 modelMatrix = mat4(1);
glUseProgram(gShader);
glUniformMatrix4fv(mgLoc, 1, GL_FALSE, &modelMatrix[0][0]);
glUniformMatrix4fv(pgLoc, 1, GL_FALSE, &projectionMatrix[0][0]);
glUniformMatrix4fv(vgLoc, 1, GL_FALSE, &viewMatrix[0][0]);
glBindVertexArray(objVAO);
glDrawArrays(GL_TRIANGLES, 0, objVertices.size());
glBindFramebuffer(GL_FRAMEBUFFER, 0);
And this is the fragment shader:
layout (location=0) out vec3 gPosition;
in vec3 vertex_world;
out vec4 FragColor;
void main()
{
FragColor=vec4(vertex_world,1.0);
}
The position buffer seems fine :
However, if you look at my shader I haven't given a value to gPosition. It seems like the buffer is just taking the output fragColor.
This is what I plan to do but it gives me wrong results:
layout (location=0) out vec3 gPosition;
in vec3 vertex_world;
void main()
{
gPosition=vertex_world;
}`
It does pass something to the position buffer but you will see that it's quite strange:
What could be wrong?
Edit/Solved
It turns out that I had to define gPosition as a vec4 in the fragment shader. It works perfectly now. So the new question is why did it work now?
glActiveTexture does not take a texture name, but selects the active texture unit (GL_TEXTURE0 + n) – yeah, the name is misleading.
Anyway, it seems like you want to bind the position buffer texture before rendering to it. Why? If you actually did that you might end up with a feedback loop – see https://www.khronos.org/opengl/wiki/Framebuffer_Object#Feedback_Loops. You're fine as long as you don't sample from it, but the mere possibility of having a feedback loop might throw you into a slower codepath. So try do not do that. You've bound the texture as an attachment to the FBO, that's enough.
As far as rendering an actual position buffer is concerned: Why do that in the first place? Just use a depth buffer texture (instead of renderbuffer) and reconstruct the position from the single depth value and un-projection.

OpenGL fragment shader in a texture

I have a simple RGBA texture that I will project on a rectangle/quad in OpenGL.
However, I want to do some operations in the rgb pixels of that texture, e.g., I want the displayed color to be some function of the RGB pixels of the original image.
My questions are: can I apply a fragment shader to a 2D texture? And if I can, How do I access the rgb value of the original texture image?
Any help would be appreciated.
You can certainly do this. Render the quad as usual and send the texture to the fragment shader as a sampler2D uniform.
Inside the fragment shader, you can then make calls to either texture or texelFetch. texture samples your texture, and texelFetch looks up an RGB texel from the texture without performing interpolation, etc.
Here is an example of what your fragment shader might look like:
Fragment shader
#version 330 core
uniform vec2 resolution;
uniform sampler2D myTexture;
out vec3 color;
void main()
{
vec2 pos = gl_FragCoord.xy / resolution.xy;
pos.y = resolution.y - pos.y;
color = texture(myTexture, pos).xyz;
}
And then on the application side:
Initialization
glGenTextures(1, &m_textureID);
glBindTexture(GL_TEXTURE_2D, m_textureID);
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_RGB, m_imageWidth, m_imageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, pImage);
m_textureUniformID = glGetUniformLocation(m_programID, "myTexture");
Render loop
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_textureID);
glUniform1i(m_textureUniformID, 0);

OpenGL & GLSL: Greyscale texture not showing

I'm trying to show a greyscale texture on the screen. I create my texture via
glGenTextures(1, &heightMap);
glBindTexture(GL_TEXTURE_2D, heightMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 512, 512, 0, GL_RED, GL_FLOAT, colorData);
colorData is a float[512*512] with values between 0.0 and 1.0.
When rendering, I use:
glBindTexture(GL_TEXTURE_2D, heightMap);
glUniform1i(shader.GetUniformLocation("textureSampler"), 0);
shader.GetUniformLocation is a function of a library we use at university. It is essentially the same as glGetUniformLocation(shader, "textureSampler"), so don't be confused by it.
I render two triangles via triangle strip. My fragment shader is:
#version 330
layout(location = 0) out vec4 frag_color;
in vec2 texCoords;
uniform sampler2D textureSampler;
void main()
{
frag_color = vec4(texture(textureSampler, texCoords).r, 0, 0, 1);
}
I know the triangles are rendered correctly (e.g. if I use vec4(1.0, 0, 0, 1) for frag_color, I get a completely red screen). However with the line above, I only get a completely black screen. Every texture value seems to be 0.0.
Does anyone have an idea, what I have done wrong? Are there mistakes in that few lines of code or are these completely correct and the error is somewhere else?
As one of the comments below says, setting glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); and glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); solves the problem. :)