OpenGL: Bind FBO's depth texture to a compute shader - c++

I've been trying to render to an FBO and render two FBO's to the screen, but have been unsuccessfull to do a depth test at the merge of the two FBO's. I've tried merging the textures with an compute shader, but I am unable to read the values of the depth textures(all values are value 1, but depth test is working when I render to the FBO). Does anybody knows what I am doing wrong, or knows an other method to merge two FBO's?
This is how I create the FBO:
struct FBO {
uint color;
uint depth;
uint fbo;
};
FBO createFBO(int width, int height) {
FBO fbo;
fbo.color = createFBOTexture(width, height, false);
fbo.depth = createFBOTexture(width, height, true);
fbo.fbo = generateFramebuffer(fbo.color, fbo.depth);
return fbo;
}
uint createFBOTexture(int width, int height, bool isDepthBuffer) {
uint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
if (isDepthBuffer)
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
int i = glGetError();
if (i)
std::cout << "Error while creating the FBO: " << gluErrorString(i) << '\n';
return texture;
}
uint generateFrameBuffer(uint color, uint depth)
{
int mipmapLevel = 0;
//Generate FBO
uint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
//Attatch textures to the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, mipmapLevel);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, mipmapLevel);
//Error check
int i = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (i != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR: frambuffer is not ok, status: " << i << '\n';
else {
int i = glGetError();
if (i)
std::cout << "Error while creating the FBO: " << gluErrorString(i) << '\n';
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return fbo;
}
This is how I render to the FBO:
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_pointcloud.fbo);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawPointCloud(); //Here I draw points with the depreciated fixed pipeline
glFlush();
I have tried to bind the textures with glBindTexture(all values read where 1):
void MergeFrames::merge(TextureLoading::FBO tex0, TextureLoading::FBO tex1, GLuint result, int width, int height)
{
glUseProgram(shader);
//Bind depth textures
glActiveTexture(GL_TEXTURE0+0);
glBindTexture(GL_TEXTURE_2D, tex0.depth);
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, tex1.depth);
//Bind color textures
glBindImageTexture(2, tex0.color, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glBindImageTexture(3, tex1.color, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glBindImageTexture(4, result, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
//Dispatch the shader
glDispatchCompute(ceilf(width / 16.0f), ceilf(height / 16.0f), 1);
}
The compute shader:
#version 430
uniform sampler2D depthTex0;
uniform sampler2D depthTex1;
uniform layout(rgba8) readonly image2D colorTex0;
uniform layout(rgba8) readonly image2D colorTex1;
uniform layout(rgba8) writeonly image2D mergedColor;
layout (local_size_x = 16, local_size_y = 16) in;
void main() {
ivec2 ID = ivec2(gl_GlobalInvocationID.xy);
ivec2 size = imageSize(colorTex0);
vec2 texCoords = vec2(float(ID.x)/float(size.x),float(ID.y)/float(size.y));
float depths[2];
vec4 colors[2];
depths[0] = texture2D(depthTex0, texCoords).x;
depths[1] = texture2D(depthTex1, texCoords).x;
colors[0] = imageLoad(colorTex0, ID);
colors[1] = imageLoad(colorTex1, ID);
int i = int(depths[1] > depths[0]);
imageStore(mergedColor, ID, colors[i]);
}
I have tried to bind the textures with glBindTexture(all values read where 0):
void MergeFrames::merge(TextureLoading::FBO tex0, TextureLoading::FBO tex1, GLuint result, int width, int height)
{
glUseProgram(shader);
glBindImageTexture(0, tex0.color, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glBindImageTexture(1, tex1.color, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
glBindImageTexture(2, tex0.depth, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R16);
glBindImageTexture(3, tex1.depth, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R16);
glBindImageTexture(4, result, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
glDispatchCompute(ceilf(width / 16.0f), ceilf(height / 16.0f), 1);
}
The compute shader:
#version 430
uniform layout(rgba8) readonly image2D colorTex0;
uniform layout(rgba8) readonly image2D colorTex1;
uniform layout(r16) readonly image2D depthTex0;
uniform layout(r16) readonly image2D depthTex1;
uniform layout(rgba8) writeonly image2D mergedColor;
layout (local_size_x = 16, local_size_y = 16) in;
void main() {
ivec2 ID = ivec2(gl_GlobalInvocationID.xy);
float depths[2];
vec4 colors[2];
colors[0] = imageLoad(colorTex0, ID);
depths[0] = imageLoad(depthTex0, ID).x;
colors[1] = imageLoad(colorTex1, ID);
depths[1] = imageLoad(depthTex1, ID).x;
int i = int(depths[1] < depths[0]);
imageStore(mergedColor, ID, colors[i]);
}
And this is how I bind the indices (the indices are differt in the version where I use sampler2D instead of image2D):
MergeFrames::MergeFrames()
{
shader = OpenGL::compileComputeShader("MergeFrames.comp");
glUseProgram(shader);
glUniform1i(glGetUniformLocation(shader, "colorTex0"), 0);
glUniform1i(glGetUniformLocation(shader, "colorTex1"), 1);
glUniform1i(glGetUniformLocation(shader, "depthTex0"), 2);
glUniform1i(glGetUniformLocation(shader, "depthTex1"), 3);
glUniform1i(glGetUniformLocation(shader, "mergedColor"), 4);
}

I got the code working, by copying the data from depth texture to a texture with format GL_RED after rendering .

Related

OpenGL FBO render different textures in different texture targets

I'm trying to render to two different textures (GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1) inside my MSAA FBO, the initialization is:
// configure MSAA framebuffer
// --------------------------
glGenFramebuffers(1, &this->_MSAAid);
glBindFramebuffer(GL_FRAMEBUFFER, this->_MSAAid);
// create a multi-sampled color attachment texture
glGenTextures(1, &this->_textureMultisampleID);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, this->_textureMultisampleID);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB16F, _frameBufferSize.width, _frameBufferSize.height, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, this->_textureMultisampleID, 0);
glGenTextures(1, &this->_textureObjectIDMultisampled);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, this->_textureObjectIDMultisampled);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB16F, _frameBufferSize.width, _frameBufferSize.height, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, this->_textureObjectIDMultisampled, 0);
GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, drawBuffers);
// create an (also multi-sampled) render buffer object for depth and stencil attachments
glGenRenderbuffers(1, &this->_renderBufferObjectID);
glBindRenderbuffer(GL_RENDERBUFFER, this->_renderBufferObjectID);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, _frameBufferSize.width, _frameBufferSize.height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, this->_renderBufferObjectID);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: MSAA Framebuffer is not complete! Error: " << glCheckFramebufferStatus(GL_FRAMEBUFFER) << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
_frameBufferShader->use();
_frameBufferShader->setInt("screenTexture", 0);
then I want to copy the result inside another standard FBO, initialized like that:
// framebuffer configuration
// -------------------------
glGenFramebuffers(1, &this->_id);
glBindFramebuffer(GL_FRAMEBUFFER, this->_id);
// create a color attachment texture
glGenTextures(1, &this->_textureID);
glBindTexture(GL_TEXTURE_2D, this->_textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, _frameBufferSize.width, _frameBufferSize.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->_textureID, 0);
glGenTextures(1, &this->_textureObjectID);
glBindTexture(GL_TEXTURE_2D, this->_textureObjectID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, _frameBufferSize.width, _frameBufferSize.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, this->_textureObjectID, 0);
GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, drawBuffers);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
_frameBufferShader->use();
_frameBufferShader->setInt("screenTexture", 0);
FBO binding:
glBindFramebuffer(GL_FRAMEBUFFER, this->_MSAAid);
glViewport(0, 0, this->_frameBufferSize.width, this->_frameBufferSize.height);
glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)
glClearColor(refreshColor.coordinates.x, refreshColor.coordinates.y, refreshColor.coordinates.z, refreshColor.coordinates.w);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Rendering stuff...
After the rendering, I want to copy both the buffers to my normal FBO:
glBindFramebuffer(GL_READ_FRAMEBUFFER, this->_MSAAid);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, this->_id);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, 0, _frameBufferSize.width, _frameBufferSize.height, 0, 0, _frameBufferSize.width, _frameBufferSize.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, this->_MSAAid);
glReadBuffer(GL_COLOR_ATTACHMENT1);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, this->_id);
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glBlitFramebuffer(0, 0, _frameBufferSize.width, _frameBufferSize.height, 0, 0, _frameBufferSize.width, _frameBufferSize.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
but for some reason what I get is that in both textures (GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1) the same content is written, basically, the two textures are the same, even if in my shader code I output the result into two different color attachments, here you can see my fragment shader:
#version 330 core
layout (location = 0) out vec4 fragColor;
layout (location = 1) out vec4 idColor;
in vec2 Frag_UV;
uniform sampler2D screenTexture;
void main()
{
float gamma = 2.2;
float exposure = 1.0;
vec4 color = texture(screenTexture, Frag_UV.st);
// HDR tonemapping
color.rgb = vec3(1.0) - exp(-color.rgb * exposure);
// gamma correction
color.rgb = pow(color.rgb, vec3(1.0 / gamma));
fragColor = vec4(color.rgb, 1.0);
idColor = vec4(0, 1, 0, 1.0);
}
here is the output:
What I wish to obtain in the Scene window is to display the texture with the color attachment 0 and in the Game window the texture with the color attachment 1!
Currently these two windows shows:
Scene Window: textureObjectID -> GL_COLOR_ATTACHMENT1
Game Window: textureID -> GL_COLOR_ATTACHMENT0
The result I want is to render a different texture based on the GL_COLOR_ATTACHMENT
also, I tried to debug everything with a glReadPixel(...) for attachment 0 and for attachment 1, and what I got is actually the same value of pixel for both textures:
This is the code I used for debugging:
glBindFramebuffer(GL_READ_FRAMEBUFFER, this->sceneFrameBuffer->ID);
glReadBuffer(GL_COLOR_ATTACHMENT0);
float pixelColor[4];
glReadPixels(Input::mouse.xPosition, Input::mouse.yPosition, 1, 1, GL_RGBA, GL_FLOAT, &pixelColor);
std::cout << "Pixel Color0: ( " << pixelColor[0] << ", " << pixelColor[1] << ", " << pixelColor[2] << ", " << pixelColor[3] << " )" << std::endl;
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, this->sceneFrameBuffer->ID);
glReadBuffer(GL_COLOR_ATTACHMENT1);
float pixelColors[4];
glReadPixels(Input::mouse.xPosition, Input::mouse.yPosition, 1, 1, GL_RGBA, GL_FLOAT, &pixelColors);
std::cout << "Pixel Color1: ( " << pixelColors[0] << ", " << pixelColors[1] << ", " << pixelColors[2] << ", " << pixelColors[3] << " )" << std::endl;
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
what am I missing? can't figure it out!
(I'm using Dear ImGui in order to display textures in the windows)
In order to give the idea of what I want to achieve, I found a video that does implement the idea I wish to implement.
I have two frame buffers, both are used for the rendering of the scene and not of the screen (as I was mistakenly thinking), so I had to specify the color attachment output inside the shader that I use for the rendering of the objects and not the shader I'm using for the rendering of the scene over my quad (the "screen quad").
Screen Fragment Shader:
#version 450 core
layout (location = 0) out vec4 fragColor;
in vec2 Frag_UV;
uniform sampler2D screenTexture;
void main()
{
float gamma = 2.2;
float exposure = 1.0;
vec4 color = texture(screenTexture, Frag_UV.st);
// HDR tonemapping
color.rgb = vec3(1.0) - exp(-color.rgb * exposure);
// gamma correction
color.rgb = pow(color.rgb, vec3(1.0 / gamma));
fragColor = vec4(color.rgb, 1.0);
}
Phong Fragment Shader that I'm using for the rendering of the Objects:
#version 450 core
layout (location = 0) out vec4 FragColor;
layout (location = 1) out vec4 idColor;
//Declaring stuff...
void main()
{
vec3 viewDir = normalize(viewPos - fs_in.FragPos);
vec3 result = vec3(0.0, 0.0, 0.0);
result += calcPointLight(material, pointLight, viewDir);
idColor = vec4(vID);
FragColor = vec4(result, 1.0);
}
Now I got everything rendered to my GL_COLOR_ATTACHMENT1, thanks to everyone who commented!

OpenGL Framebuffer ColorAttachment to Compute Shader

I want to put the Color Attachment of my custom framebuffer into a compute shader for simple image processing, but I am getting a black screen only.
Here is my example code
Creating color attachment
glGenFramebuffers(1, &this->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, this->fbo);
glGenTextures(1, &this->textureColorBuffer);
glBindTexture(GL_TEXTURE_2D, this->textureColorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, this->width(), this->height(), 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
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, GL_TEXTURE_2D,
this->textureColorBuffer, 0);
Compiling and linking shader
cshader = glCreateShader(GL_COMPUTE_SHADER);
const char *csSrc[] = {
"#version 440\n",
"layout (binding = 0, rgba32f) uniform image2D destTex;\
layout (binding = 1, rgba32f) uniform image2D sourceTex;\
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\
void main() {\
vec4 texel;\
ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);\
texel = imageLoad(sourceTex, storePos);\
texel = vec4(1.0) - texel;\
imageStore(destTex, storePos, texel);\
}"
};
glShaderSource(cshader, 2, csSrc, NULL);
glCompileShader(cshader);
cshaderprogram = glCreateProgram();
glAttachShader(cshaderprogram, cshader);
glLinkProgram(cshaderprogram);
Invoke Shader and drawing texture to quad. The shader is a simple color switching shader, for testing purposes.
glUseProgram(cshaderprogram);
glUniform1i(0, 0);
glActiveTexture(GL_TEXTURE0);
glBindImageTexture(0, outputTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY,
GL_RGBA32F);
glActiveTexture(GL_TEXTURE1);
glBindImageTexture(0, textureColorBuffer, 0, GL_FALSE, 0, GL_READ_ONLY,
GL_RGBA32F);
glUniform1i(1, 1);
glDispatchCompute(width() / 16, height() / 16, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
screenProgram.bind();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindVertexArray(screenVao);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, outputTexture);
glDrawArrays(GL_TRIANGLES, 0, 6);
I am able to render the textureColorBuffer to the quad correctly and i can write to a texture. I think the problem that i do not know how to read from the framebuffer.
I hope you can help me. If there are still some questions just ask.
The binding point of sourceTex is 1 and not 0:
layout (binding = 1, rgba32f) uniform image2D sourceTex;
So you have to bind the texture to the image unit 1
glBindImageTexture( 1, // <------- 1 instead of 0
textureColorBuffer, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
Note, Images units and Texture units are different things.
Of course you can use a texture sampler uniform in the coumpute shader too. If destTex and sourceTex have the same size, you can use texelFetch with gl_GlobalInvocationID, to look up sourceTex:
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
layout (binding = 0, rgba32f) uniform image2D destTex;
layout (binding = 0) uniform sampler2D sourceTex;
void main()
{
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
vec4 texel = texelFetch(sourceTex, pos, 0);
texel = vec4(1.0) - texel;
imageStore(destTex, pos, texel);
}
In the above snippet is used the image unit 0 for destTex and the texture unit 0 for sourceTex.
By the way, are you sure that you want to do
texel = vec4(1.0) - texel;
Note, if the alpha channel of texel is 1.0, it will become completely transparent.

Load and display texture with OpenGL and OpenCV

I am a bloody newbie to OpenGL and it still looks sometimes like black magic to me. I just want to load and display an texture for testing purposes and I do not want to use the tutorial libraries to really understand what happens. But I just get a black screen and I cannot find the reason for it.
My c++ source code
int main(){
new cpp_logger();
GLint program_rgb_;
Mat img = imread("plane.jpg");
std::string file_path = "plane.jpg";
// Set viewport window size and clear color bit.
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
//set viewport
glViewport(0, 0, img.size().width, img.size().height);
// Create a Vertex Buffer Object and copy the vertex data to it
GLuint vbo;
glGenBuffers(1, &vbo);
GLfloat vertices[] = {-1, 1, -1, -1, 1, 1, 1, -1,
0, 0, 0, 1, 1, 0, 1, 1};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//create program and shader
program_rgb_ = glCreateProgram();
const char* vertexShader = read_shader("vertex.glsl"); //simple method to read the shader files
const char* fragmentShader = read_shader("fragment.glsl");
CreateShader(program_rgb_, GL_VERTEX_SHADER, vertexShader); //simple method to link and compile shader programs
CreateShader(program_rgb_, GL_FRAGMENT_SHADER, fragmentShader);
glLinkProgram(program_rgb_);
glUseProgram(program_rgb_);
//use fast 4-byte alignment (default anyway) if possible because using OpenCV
glPixelStorei(GL_UNPACK_ALIGNMENT, (img.step & 3) ? 1 : 4);
//set length of one complete row in data (doesn't need to equal image.cols)
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, img.step/img.elemSize());
flip(img, img, 0);
// Load texture
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
//set parameters
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.cols, img.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.data);
glUniform1i(glGetUniformLocation(program_rgb_,"tex"), 0);
uint8_t* result = new uint8_t[img.cols * img.rows * 4];
while(true){
GLint pos_location = glGetAttribLocation(program_rgb_, "a_position");
GLint tc_location = glGetAttribLocation(program_rgb_, "a_texCoord");
// Specify the layout of the vertex data
glEnableVertexAttribArray(pos_location);
glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, 0);
//specify color data
glEnableVertexAttribArray(tc_location);
glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, static_cast<float*>(0) + 8);
// Draw a rectangle from the 2 triangles using 6 indices
glDrawArrays(GL_TRIANGLES, 0, 8);
glReadPixels(0, 0, img.rows, img.cols, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void*)result);
auto result_ = cv::Mat(img.rows, img.cols, CV_8UC4, result);
imshow("img", result_);
if(waitKey(1) >= 0) break;
}
destroyAllWindows();
return EXIT_SUCCESS;
}
My fragment shader
#version 150 core
precision mediump float;
in vec2 texCoord;
uniform sampler2D tex;
void main()
{
gl_FragColor = texture2D(tex, texCoord);
}
my vertex shader
#version 150 core
out vec2 texCoord;
attribute vec2 a_texCoord;
attribute vec4 a_position;
void main()
{
texCoord = a_texCoord;
gl_Position = a_position;
}
Thank you a lot for your help!
EDIT
Sorry for the missunderstanding. I meant: I do not want to use the libraries like SOIL and SFML and I want to go an alternative way to fully understand what actually happens.

Framebuffer depth-artifacts

There's some Artifacts on my FrameBuffer Depth Texture I can't get rid off:
The Code used to init the FrameBuffer:
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &color);
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, color, 0);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, depth, 0);
GLuint attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, attachments);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cout << "FBO FEHLER" << std::endl;
}
Code used to draw the FrameBuffer:
shader->bind();
// Bind Textures
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, color);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depth);
glUniform1i(shader->getUniform("tex"), 0);
glUniform1i(shader->getUniform("depth"), 1);
glUniformMatrix4fv(shader->getUniform("matrix"), 1, GL_FALSE, glm::value_ptr(ortho));
// Draw Call
glBindBuffer(GL_ARRAY_BUFFER,fbovbo);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 20, (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 20, (void*)12);
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Unbind
shader->unbind();//*/
FragmentShader of the actual rendering:
#version 330 core
layout(location = 0) out vec4 out_color;
layout(location = 1) out vec4 out_depth;
in float temp;
void main(void){
out_color = vec4(1,0.0,0.0,1.0);
out_depth = vec4(gl_FragCoord.z);
}
FragmentShader of the FrameBuffer rendering:
#version 330 core
in vec2 fuv;
out vec4 color;
uniform sampler2D tex;
uniform sampler2D depth;
void main(){
vec4 d = texture2D(depth, fuv);
gl_FragDepth = d.a;
vec4 c = texture2D(tex,fuv);
if(c.a<0.1){
discard;
}
color = c;
//color = vec4(texture2D(depth, fuv).zzz,1.0);
//color.a = 0.8;
//color = vec4(1,0,0,0.5);
}
The red "Mesh" is behind the brown surface, but its borders still appear. thats the problem
The problem might come from the limited precision of the depth buffer. Basically, the range between near and farplane has to be represented by the depth-buffer. In your case, the depth-buffer has 8 bit, thus there are only 256 different depth values that can be represented. When two objects are closer together than this, they will be mapped to the same value in the depth buffer.
To overcome this, you can try to increase the precision of the depth buffer, for example, by using
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_SHORT, NULL);
Side-note: I'm not sure why the depth texture has four channels. If you don't need them, I would change this to a one channel format.

opengl shader problems with mrt

I have two textures with same size attached to one fbo, and I want to render another texture into one of the attached textures, and I want to render a blue shape of the figure of the input texture to the other fbo attached texture.
the (updated) vertex shader:
#version 330
in vec2 coord;
out vec2 f_coord;
void main() {
gl_Position = vec4(coord, 0.0, 1.0);
f_coord = (1.0+coord)/2.0;
}
the (updated) fragment shader:
#version 330
uniform sampler2D my_texture;
in vec2 f_coord;
out vec4 FragData[2];
void main() {
if(texture(my_texture,f_coord).a == 0.0)
discard;
FragData[0]=texture(my_texture,f_coord);
FragData[1]=vec4(0.5, 0.5, 1.0, 1.0);
}
With this fragment shader everything works fine. The texture and the blue stamp of the texture contures are rendered properly.
Here is a screenshot:
http://s14.directupload.net/file/d/3487/kvkqdbl7_png.htm
But if I want to render the texture into gl_FragData[1] and the blue conture stamp into gl_FragData[0]
#version 330
uniform sampler2D my_texture;
in vec2 f_coord;
out vec4 FragData[2];
void main() {
if(texture(my_texture,f_coord).a == 0.0)
discard;
FragData[0]=vec4(0.5, 0.5, 1.0, 1.0);
FragData[1]=texture(my_texture,f_coord);
}
than I get two totally blue textures. The strange thing is: Both target textures are totally blue, but I have set the glViewport just to a part of the texture.
Here a screenshot:
http://s1.directupload.net/file/d/3487/9loqibdc_png.htm
The fbo attachments have the half screen size
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT), 0, GL_RGBA, GL_BYTE, 0);
So I can render both textures to the screen for checking.
This is how I created the framebufferobject
void init_fbo()
{
glGenTextures(1, &fbo.texture0);
glBindTexture(GL_TEXTURE_2D, fbo.texture0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT), 0, GL_RGBA, GL_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glGenTextures(1, &fbo.texture1);
glBindTexture(GL_TEXTURE_2D, fbo.texture1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT), 0, GL_RGBA, GL_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &fbo.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
fbo.texture0, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D,
fbo.texture1, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
I use those global struct variables
struct
{
GLuint fbo;
GLuint texture0;
GLuint texture1;
} fbo;
struct
{
GLuint program;
GLint uni_texture;
GLint att_coord;
} shader_fbo;
struct
{
GLuint program;
GLint uni_texture;
GLint att_coord;
} shader_screen;
And this is my render function
void render()
{
GLenum buffers[2];
GLfloat vertices[] = { -1.0, -1.0,
-1.0, 1.0,
1.0, -1.0,
1.0, 1.0 };
GLubyte indices[] = { 0, 1, 2,
1, 2, 3 };
/*render to mrt fbo*/
glUseProgram(shader_fbo.program);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.texID);
glUniform1i(shader_fbo.uni_texture, 0);
glEnableVertexAttribArray(shader_fbo.att_coord);
glVertexAttribPointer(shader_fbo.att_coord,
2,
GL_FLOAT,
GL_FALSE,
0,
vertices);
glBindFramebuffer(GL_FRAMEBUFFER, fbo.fbo);
buffers[0] = GL_COLOR_ATTACHMENT0;
buffers[1] = GL_COLOR_ATTACHMENT1;
glDrawBuffers(2, buffers);
glViewport(0, 0,
texture.width, texture.height);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.texID);
glUniform1i(shader_fbo.uni_texture, 0);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
glDisableVertexAttribArray(shader_fbo.att_coord);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
/*render both textures now to screen*/
glUseProgram(shader_screen.program);
glEnableVertexAttribArray(shader_screen.att_coord);
glVertexAttribPointer(shader_screen.att_coord,
2,
GL_FLOAT,
GL_FALSE,
0,
vertices);
/*render the first texture to the left side of the screen*/
glViewport(0, 0,
glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT));
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, fbo.texture0);
glUniform1i(shader_screen.uni_texture, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
/*render the second texture to the right side of the screen*/
glViewport(glutGet(GLUT_WINDOW_WIDTH)/2, 0,
glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, fbo.texture1);
glUniform1i(shader_screen.uni_texture, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
glutSwapBuffers();
}