FrameBuffer texture is black

Hi I want to simulate reflection and refraction of water (fixed height) so I created a class for managing the corresponding fbos

    #include "WaterFBO.h"

    int WaterFBO::REFLECTION_WIDTH = 320, 
    	WaterFBO::REFLECTION_HEIGHT = 180, 
    	WaterFBO::REFRACTION_WIDTH = 1280, 
    	WaterFBO::REFRACTION_HEIGHT = 720;

    WaterFBO::WaterFBO()
    {
    }

    void WaterFBO::createRefractionFrameBuffer()
    {
    	glGenFramebuffers(1, &reflectionFrameBuffer);
    	glBindFramebuffer(GL_FRAMEBUFFER, reflectionFrameBuffer);
    	glDrawBuffer(GL_COLOR_ATTACHMENT0);
    }

    void WaterFBO::createRefractionTextureAttachment(int width, int height)
    {
    	glGenTextures(1, &reflectionTexture);
    	glBindTexture(GL_TEXTURE_2D, reflectionTexture);
    	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (void*)nullptr);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    	glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, reflectionTexture, 0);
    }

    void WaterFBO::createReflectionFrameBuffer()
    {
    	glGenFramebuffers(1, &refractionFrameBuffer);
    	glBindFramebuffer(GL_FRAMEBUFFER, refractionFrameBuffer);
    	glDrawBuffer(GL_COLOR_ATTACHMENT0);
    }

    void WaterFBO::createReflectionTextureAttachment(int width, int height)
    {
    	glGenTextures(1, &refractionTexture);
    	glBindTexture(GL_TEXTURE_2D, refractionTexture);
    	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (void*)nullptr);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    	glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, refractionTexture, 0);
    }

    void WaterFBO::createRefractionDepthTextureAttachment(int width, int height)
    {
    	glGenTextures(1, &refractionDepthTexture);
    	glBindTexture(GL_TEXTURE_2D, refractionDepthTexture);
    	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, (void*)nullptr);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    	glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, refractionDepthTexture, 0);
    }

    void WaterFBO::createReflectionDepthBufferAttachment(int width, int height)
    {
    	glGenRenderbuffers(1, &reflectionDepthBuffer);
    	glBindRenderbuffer(GL_RENDERBUFFER, reflectionDepthBuffer);
    	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
    	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, reflectionDepthBuffer);
    }

    void WaterFBO::bindReflectionFrameBuffer()
    {
    	bindFrameBuffer(reflectionFrameBuffer, REFLECTION_WIDTH, REFLECTION_HEIGHT);
    }

    void WaterFBO::bindRefractionFrameBuffer()
    {
    	bindFrameBuffer(refractionFrameBuffer, REFRACTION_WIDTH, REFRACTION_HEIGHT);
    }

    void WaterFBO::bindFrameBuffer(GLuint frameBuffer, int width, int height)
    {
    	glBindTexture(GL_TEXTURE_2D, 0);
    	glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    	glViewport(0, 0, width, height);
    }

    void WaterFBO::unbindCurrentFrameBuffer(int width, int height)
    {
    	glBindFramebuffer(GL_FRAMEBUFFER, 0);
    	glViewport(0, 0, width, height);
    }

    void WaterFBO::initializeReflectionFrameBuffer(int width, int height)
    {
    	this->createReflectionFrameBuffer();
    	this->createReflectionTextureAttachment(REFLECTION_WIDTH, REFLECTION_HEIGHT);
    	this->createReflectionDepthBufferAttachment(REFLECTION_WIDTH, REFLECTION_HEIGHT);
    	this->unbindCurrentFrameBuffer(width, height);
    }

    void WaterFBO::initializeRefractionFrameBuffer(int width, int height)
    {
    	this->createRefractionFrameBuffer();
    	this->createRefractionTextureAttachment(REFRACTION_WIDTH, REFRACTION_HEIGHT);
    	this->createRefractionDepthTextureAttachment(REFRACTION_WIDTH, REFRACTION_HEIGHT);
    	this->unbindCurrentFrameBuffer(width, height);
    }

    GLuint WaterFBO::getReflectionTexture() const
    {
    	return reflectionTexture;
    }

    GLuint WaterFBO::getRefractionTexture() const
    {
    	return refractionTexture;
    }

    WaterFBO::~WaterFBO()
    {
    	if (glIsFramebuffer(reflectionFrameBuffer))
    		glDeleteFramebuffers(1, &refractionFrameBuffer);

    	if (glIsFramebuffer(refractionFrameBuffer))
    		glDeleteFramebuffers(1, &refractionFrameBuffer);

    	if (glIsTexture(reflectionTexture))
    		glDeleteTextures(1, &reflectionTexture);

    	if (glIsTexture(refractionTexture))
    		glDeleteTextures(1, &refractionTexture);

    	if (glIsRenderbuffer(reflectionDepthBuffer))
    		glDeleteRenderbuffers(1, &reflectionDepthBuffer);

    	if (glIsTexture(refractionDepthTexture))
    		glDeleteTextures(1, &refractionDepthTexture);
    }

Then I render the world on fbos with different pov

	camera.mirorY();
	waterFbo.bindReflectionFrameBuffer();
	renderWorld(glm::vec4(0,1,0,-1));
	camera.mirorY();

	waterFbo.bindRefractionFrameBuffer();
	renderWorld(glm::vec4(0, -1, 0, 1));

	waterFbo.unbindCurrentFrameBuffer(window.getSize().x, window.getSize().y);

Then I draw the world and the water right after, like that :

    glUseProgram(shader.getProgramID());

    glBindVertexArray(vao);

    glUniform1i(glGetUniformLocation(shader.getProgramID(), "reflectionTexture"), 0);
    glUniform1i(glGetUniformLocation(shader.getProgramID(), "refractionTexture"), 1);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, waterFBO.getReflectionTexture());

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, waterFBO.getRefractionTexture());


    glUniformMatrix4fv(glGetUniformLocation(shader.getProgramID(), "model"), 1, GL_FALSE, value_ptr(model));
    glUniformMatrix4fv(glGetUniformLocation(shader.getProgramID(), "view"), 1, GL_FALSE, value_ptr(view));
    glUniformMatrix4fv(glGetUniformLocation(shader.getProgramID(), "projection"), 1, GL_FALSE, value_ptr(projection));


    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (void*)0);

    glBindVertexArray(0);

    glUseProgram(0);

The problem is that both reflectionTexture and refractionTexture are black. I know that they are correctly sent to the shader because glGetUniformLocation is > 0. The world rendering is also working with the clip distance and pov are ok. Therefore, the problem might be with fbos, this is the first time I use them. I know that some code of WaterFBO is redundant, it will be factorized after.

Here is the vertex shader

    #version 430 core

    layout (location = 0) in vec3 vertex;

    out vec4 clipSpace;

    uniform mat4 view;
    uniform mat4 model;
    uniform mat4 projection;


    void main()
    {
    	vec4 world_position = model * vec4(vertex, 1.0f);
    	clipSpace = projection * view * world_position;
    	gl_Position = clipSpace;
    }

and the fragment shader

    #version 430

    in vec4 clipSpace;

    out vec4 out_color;

    uniform sampler2D reflectionTexture;
    uniform sampler2D refractionTexture;

    void main()
    {
    	vec2 ndc = (clipSpace.xy/clipSpace.w)/2.0 + 0.5;
    	vec2 refractTexCoords = vec2(ndc.x, ndc.y);
    	vec2 reflectTexCoords = vec2(ndc.x, -ndc.y); 
    	vec4 reflectionColour = texture(reflectionTexture, reflectTexCoords);
    	vec4 refractionColour = texture(refractionTexture, refractTexCoords); 

    	out_color = mix(reflectionColour, refractionColour, 0.5);
    }

Thank you for your help !

PS : I didn’t forget to initialize fbos :slight_smile: and the quad of water is rendered, the problem is the texture is black.

Anyone ? If there is someting unclear or missing do not hesitate to tell me :slight_smile: