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 and the quad of water is rendered, the problem is the texture is black.