I want to draw a scene to a framebuffer object and later use the texture of that in another shader. For testing purposes I would just like to actually output the framebuffer object's textur. However, the corresponding part (a rectangle) is just completely black. So I'm wondering whether either the rendering to the fbo does not work or the access to that.
Here are the important code parts:
Called before rendering to the FBO:
void TextureRenderer::bind() {
glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName);
// glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, mWidth, mHeight);
}
This is the plane on which the FBO should be displayed. The first texture "mTextureId" is another texture I've loaded from a TGA file and displaying that works just fine. However, the second "mReflectionTextureId" is the one from the VBO and this is the one which I cannot access (or it really is black because there was an error before).
void WaterPlane::render(const Transform& trans) {
mat4 projection = trans.projection;
mat4 view = trans.view;
mat4 model = mat4::identitiy();
glPushAttrib(GL_ALL_ATTRIB_BITS);
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
mShader->bind();
// lets activate the textures now
glEnable(GL_TEXTURE_2D);
// bumpmap texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTextureId);
// set the texture
mShader->seti("waterBumpTextureSampler", 0);
// rendered reflection texture (has been rendered previously with the help of Framebuffer object for reflection)
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, mReflectionTextureId);
// set reflection texture
mShader->seti("renderedReflection", 1);
mShader->setMatrix("matProjection", projection, GL_TRUE);
mShader->setMatrix("matView", view, GL_TRUE);
mShader->setMatrix("matModel", model, GL_TRUE);
mShader->setf("vecTextureShift", mTextureShift);
mVboWaterPlane->render();
mShader->release();
glDisable(GL_TEXTURE_2D);
glPopClientAttrib();
glPopAttrib();
}
Finally, the water.fs shader:
#version 130
in vec4 VertPosition;
in vec4 VertNormal;
in vec4 VertColor;
in vec4 VertTexture;
uniform vec3 lightPos;
uniform sampler2D waterBumpTextureSampler;
uniform sampler2D renderedReflection; // reflection on the water
void main()
{
// completely black
gl_FragColor = texture( renderedReflection, VertTexture.xz);
// if this is actually commented in the bumpmap texture will be shown nicely
// gl_FragColor = texture( waterBumpTextureSampler, VertTexture.xz);
}
So in general displaying textures work, however displaying the texture from the framebuffer object does not (or the rendering to it previously to that did not work).
Screenshot:
EDIT:
The initialization code of the FBO:
void TextureRenderer::init() {
glGenFramebuffers(1, &mFramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName);
// The texture we're going to render to
glGenTextures(1, &mRenderedTextureId);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, mRenderedTextureId);
cout << "TextureRenderer: creating with id " << mFramebufferName << " and tex id " << mRenderedTextureId << endl;
// Give an empty image to OpenGL ( the last "0" )
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, mWidth, mHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
// Poor filtering. Needed !
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);
// The depth buffer
// TODO this is probably not needed?!?!?!
glGenRenderbuffers(1, &mDepthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, mDepthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, mWidth, mHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthRenderBuffer);
// Set "renderedTexture" as our colour attachement #0
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mRenderedTextureId, 0);
// Set the list of draw buffers.
GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
// Always check that our framebuffer is ok
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
cout << "Problem during creation of TextureRenderer" << endl;
throw std::runtime_error("Something Bad happened here");
}
unbind();
cout << "TextureRenderer: creating with id " << mFramebufferName << "...done" << endl;
}
The bind code (which is immediately called before rendering to the FBO):
void TextureRenderer::bind() {
glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName);
// glPushAttrib(GL_VIEWPORT_BIT); // http://wiki.delphigl.com/index.php/Tutorial_Framebufferobject
glViewport(0, 0, mWidth, mHeight);
}
This is now solved. The problem simply was, that I was using wrong texture coordinates in the water.fs (fragment) shader. Below the corrected variant of water.fs. Note the difference in calculation of the coordinates that are given then to the texture(...) function.
in vec4 VertPosition;
in vec4 VertNormal;
in vec4 VertColor;
in vec4 VertTexture;
in vec4 VertTexturePS;
uniform vec3 lightPos;
uniform sampler2D waterBumpTextureSampler;
uniform sampler2D texReflection; // reflection on the water
void main()
{
vec2 originalTexCoord = VertTexturePS.xy / VertTexturePS.w * 0.5 + vec2(0.5);
gl_FragColor = texture( texReflection, originalTexCoord.xy);
}
VertTexturePS is just calculated in the water.vs by this:
VertTexturePS = matProjection * matView * matModel * vec4(Position.xyz, 1);
Related
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!
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;
I am new to OpenGL. I want to read and save all the depth values from the rendered scene using framebuffers. I managed to set it up as a framebuffer attached to the depth component. But when I render the depth texture to the default framebuffer (displaying window) it only shows the color white, even though I linearized the depth value (tutorial followed from https://learnopengl.com/). I get a depth map when I access the depth value from gl_FragCoord.z in the default framebuffer fragment shader and the plot is also ok, but when sending depth as texture from a separate framebuffer to the default, the depth image is strong white.
The code that I wrote for this is given below:
Custom framebuffer vertex and fragment shader
const char* vertexShaderFBO =
"#version 330\n"
"layout (location = 0) in vec3 vp;"
"uniform mat4 camera;"
"uniform mat4 projection;"
"void main() {"
" gl_Position = camera * projection * vec4(vp.x, vp.y, vp.z, 1.0);"
"}";
const char* fragmentShaderFBO =
"#version 330\n"
"layout (location = 0) out float frag_depth;"
"float near = 0.1;"
"float far = 100;"
"float LinearizeDepth(float depth)"
"{"
" float z = depth * 2.0 - 1.0;"
" return (2.0 * near * far) / (far + near - z * (far - near));"
"}"
"void main() {"
" float linearDepth = LinearizeDepth(gl_FragCoord.z) / far;" // divided by far is just to visualize depth
" frag_depth = linearDepth ;"
"}";
Default framebuffer vertex and fragment shader
const char* vertexShader =
"#version 330\n"
"layout (location = 0) in vec3 vp;"
"uniform mat4 camera;"
"uniform mat4 projection;"
"void main() {"
" gl_Position = camera * projection * vec4(vp.x, vp.y, vp.z, 1.0);"
"}";
const char* fragmentShader =
"#version 330\n"
"out vec4 frag_colour;"
"uniform sampler2D depthSampler;"
"in vec2 texCoords;"
"void main() {"
" float depthVal = texture(depthSampler, texCoords).r;"
" frag_colour = vec4(vec3(depthVal), 1);"
"}";
Depth Texture
GLuint setDepthTexture()
{
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SCREEN_SIZE.x, SCREEN_SIZE.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
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);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
return texture;
}
Render OFF files
int renderOFF(Vertices* vertices, Faces* faces, Views* views)
{
// initializaion
...
...
glEnable(GL_DEPTH_TEST); // enable depth buffer
glDepthFunc(GL_LESS); // If pixel closer to camera then overwrite the existing pixel
...
...
// create framebuffer shader
GLuint shaderProgramFBO = createShader(vertexShaderFBO, fragmentShaderFBO);
// create renderer shader
GLuint shaderProgram = createShader(vertexShader, fragmentShader);
//set texture
GLuint depthTexture = setDepthTexture();
// set framebuffer
unsigned int fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// attach texture to framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
std::cout << "Failed to bind framebuffer" << std::endl;
return -1;
}
// Use no color attachment
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(shaderProgram);
glUniform1i(glGetUniformLocation(shaderProgram, "depthSampler"), 0);
// set camera
...
...
while(!glfwWindowShouldClose(glfWwindow))
{
// check OpenGL error
GLenum err;
while ((err = glGetError()) != GL_NO_ERROR) {
std::cout << "OpenGL error: " << err << std::endl;
}
// bind to custom framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClearColor(0, 0, 0, 1); // clear screen to black
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgramFBO);
...
glEnable(GL_DEPTH_TEST);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, faces->size, GL_UNSIGNED_INT, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// default framebuffer
glClearColor(0, 0, 0, 1); // clear screen to black
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
processKeyBoardInput(glfWwindow);
...
//glDisable(GL_DEPTH_TEST);
glBindVertexArray(vao);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glDrawElements(GL_TRIANGLES, faces->size, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(glfWwindow);
glfwPollEvents();
sleep(1);
}
glDeleteFramebuffers(1, &fbo);
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glfwTerminate();
return 0;
}
The resulted rendered image vs expected image results are given below
The fragment shader assigns the depth values in the range [near, far] to the color values in range [0.0, 1.0]. If all of the geometry is in an area close to 0.0, the rendering will appear almost black as 0.1 is rendered black and 100 is rendered white. Move the near and far plane of the viewing volume (viewing frustum) as close to the geometry as possible to take advantage of the entire range between 0.0 and 1.0.
Your fragment shader will work fine when the near plane is close to 0. As the near plane gets larger, you should use:
float linearDepth = LinearizeDepth(gl_FragCoord.z) / far;
float linearDepth = (LinearizeDepth(gl_FragCoord.z) - near) / (far - near);
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.
I have two framebuffers that I am rendering two different objects to. When I use the default framebuffer, I have both the objects rendering on the same one.
I want this behaviour to work when using multiple framebuffers! How do I merge two framebuffers and render the winning fragments on top (Depth tested)! Basically like a Photoshop Layer Merge but with depth testing!
I got as far as blitting a single framebuffer onto the default framebuffer, but I'm lost as to how I would merge two framebuffers together!
Note: I have a color and a depth attachment to the framebuffers.
Edit:
Alright. I almost have the setup of rendering to a quad working except for one little thing. My color buffes are properly sent to the shader using uniform samplers but my depth values return '0' all the time from the depth buffers.
This is how I have my depth buffers setup within the framebuffer.
glGenFramebuffers(1, &_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glGenTextures(1, &_cbo);
glGenTextures(1, &_dbo);
{
glBindTexture(GL_TEXTURE_2D, _cbo);
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_RGBA, dim.x, dim.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
{
glBindTexture(GL_TEXTURE_2D, _dbo);
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_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, dim.x, dim.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
}
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _cbo, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _dbo, 0);
This is how I send uniform samplers to the shader.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,cbo1);
glUniform1i(glGetUniformLocation(QuadShader.Program, "color1"),0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, cbo2);
glUniform1i(glGetUniformLocation(QuadShader.Program, "color2"), 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, dbo1);
glUniform1i(glGetUniformLocation(QuadShader.Program, "depth1"), 2);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, dbo2);
glUniform1i(glGetUniformLocation(QuadShader.Program, "depth2"), 3);
glBindVertexArray(BgVao);
glDrawArrays(GL_TRIANGLES, 0, 6);
This is how my shader looks:
uniform sampler2D color1;
uniform sampler2D color2;
uniform sampler2D depth1;
uniform sampler2D depth2;
out vec4 FragColor;
void main()
{
ivec2 texcoord = ivec2(floor(gl_FragCoord.xy));
vec4 depth1 = texelFetch(depth1, texcoord,0);
vec4 depth2 = texelFetch(depth2, texcoord,0);
if(depth1.z > depth2.z)
{
FragColor = texelFetch(color1, texcoord, 0);
}
else
{
FragColor = texelFetch(color2, texcoord, 0);
}
}
You will need a shader to achieve this. There is no built-in way to blit with depth values. Here is one way to do it that combines the contents of both FBOs.
Vertex shader (assumes a quad is drawn from (-1,-1) to (1,1) )
layout(location = 0) in vec4 Position;
void main()
{
// Snap the input coordinates to a quad with it lower-left at (-1, -1, 0)
// and its top-right at (1, 1, 0)
gl_Position = vec4(sign(Position.xy), 0.0, 1.0);
}
The pixel shader could look like this:
uniform sampler2D Color0;
uniform sampler2D Color1;
uniform sampler2D Depth0;
uniform sampler2D Depth1;
in vec2 TexCoords;
layout(location = 0) out vec4 FragColor;
void main()
{
ivec2 texcoord = ivec2(floor(gl_FragCoord.xy));
float depth0 = texelFetch(Depth0, texcoord, 0).r;
float depth1 = texelFetch(Depth1, texcoord, 0).r;
// possibly reversed depending on your depth buffer ordering strategy
if (depth0 < depth1) {
FragColor = texelFetch(Color0, texcoord, 0);
} else {
FragColor = texelFetch(Color1, texcoord, 0);
}
}
See also OpenGL - How to access depth buffer values? - Or: gl_FragCoord.z vs. Rendering depth to texture for how to access the depth texture.
Note that I use texelFetch() here because linearly interpolating depth values does not give valid results.
Blitting will never use the depth test, so you have to use a full-screen shader pass to combine both framebuffers. There are two options:
Combine both framebuffers into a third one. This requires that both the color attachments as well as the depth attachments of both input FBOs are textures. You then render a full-screen quad and sample from both color buffers and depth textures. You basically do the depth test manually in the shader by comparing the two depth to decide which of the two color values you use as final output color for the fragment.
You composite one of the framebuffers into the other, using the real depth test. In that case, only one of the FBOs has to use textures, the other one can use renderbuffers or the window-system provided buffers. You just have to render a full-screen quad, this time sampling the depth and color textures only from one input FBO, and render into the output FBO with depth testing enabled. YOu just set the color value as output of the fragment shader and additionally output the depth value to gl_FragDepth.
This should be possible with a fragment shader that uses the color data from both framebuffers and the depth data from both framebuffers and fills in each pixel by evaluating, for each fragment, the texture corresponding to the fragment that won the depth test.
#version 430
layout(location = 0) in vec2 tex_coord;
layout(binding = 0) uniform sampler2D color_texture_1;
layout(binding = 1) uniform sampler2D color_texture_2;
layout(binding = 2) uniform sampler2D depth_texture_1;
layout(binding = 3) uniform sampler2D depth_texture_2;
layout(location = 0) out vec4 fragment_color;
void main() {
float depth_1 = texture(depth_texture_1, tex_coord).z;
float depth_2 = texture(depth_texture_2, tex_coord).z;
if(!/*check to verify *something* was rendered here in either framebuffer*/)
discard;
else {
if(depth_1 > depth_2) //I'm pretty sure positive z values face the user
fragment_color = texture(color_texture_1, tex_coord);
else
fragment_color = texture(color_texture_2, tex_coord);
}
}
You'd render a (full-screen, presumably) quad, use a pass-through vertex shader with this fragment shader, and attach the respective textures.
I don't know what format your Depth Texture is in; my assumption is that it contains vectors representing the individual fragment coordinates, and that the z-coordinate contains its depth. If that isn't the case, you'll need to make adjustments.