I'm forced to use legacy OpenGL and no shaders for an academic project (yes..). I'm rendering a 3D world with mountains and water. My goal (and problem) is to draw the skydome as reflection on the water. The skydome itself has 2 textures (night and day) which are drawn blended based on an alpha value as follow:
void Renderer::drawSkydome()
{
// Enable blending
glEnable(GL_BLEND);
// Disable depth testing
glDisable(GL_DEPTH_TEST);
glCullFace(GL_FRONT);
// Bind the vertex array object for the skydome
glBindVertexArray(instance->objects[SKYDOME].vao);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Day texture
glBindTexture(GL_TEXTURE_2D, instance->objects[SKYDOME].texture);
glDrawElements(GL_TRIANGLES, instance->objects[SKYDOME].indices.size(), GL_UNSIGNED_INT, 0);
glColor4f(1.0, 1.0, 1.0, alpha);
// Night texture
glBindTexture(GL_TEXTURE_2D, instance->objects[SKYDOME].blend_texture);
glDrawElements(GL_TRIANGLES, instance->objects[SKYDOME].indices.size(), GL_UNSIGNED_INT, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glColor4f(1.0, 1.0, 1.0, 1.0);
// Unbind the vertex array object and texture
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
// Re-enable depth testing
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
}
This just works fine. I then managed to draw objects reflections on water by using stencil test; specifically:
void Renderer::drawWater()
{
glEnable(GL_BLEND);
// Bind the water VAO
glBindVertexArray(instance->objects[WATER].vao);
// Enable two vertex arrays: co-ordinates and color.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnable(GL_STENCIL_TEST); // Enable stencil testing
glClearStencil(0); // Set clearing value for stencil buffer.
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glStencilFunc(GL_ALWAYS, 1, 1);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); // In all cases replace the stencil tag
glEnable(GL_PRIMITIVE_RESTART);
glDrawElements(GL_TRIANGLE_STRIP, instance->objects[WATER].indices.size(), GL_UNSIGNED_INT, 0);
glDisable(GL_PRIMITIVE_RESTART);
// Enable writing of the frame and depth buffers - actually drawing now begins.
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // The stencil buffer itself is not updated.
glPushMatrix();
glScalef(1.0, -1.0, 1.0);
// Bind the vertex array object for the skydome
glBindVertexArray(instance->objects[SKYDOME].vao);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindTexture(GL_TEXTURE_2D, instance->objects[SKYDOME].texture);
glDrawElements(GL_TRIANGLES, instance->objects[SKYDOME].indices.size(), GL_UNSIGNED_INT, 0);
glColor4f(1.0, 1.0, 1.0, alpha);
glBindTexture(GL_TEXTURE_2D, instance->objects[SKYDOME].blend_texture);
glDrawElements(GL_TRIANGLES, instance->objects[SKYDOME].indices.size(), GL_UNSIGNED_INT, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClie**ntState(GL_TEXTURE_COORD_ARRAY);
// Unbind the vertex array object and texture
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glPopMatrix();
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST); // Disable the stencil test
// Bind the water texture
glBindTexture(GL_TEXTURE_2D, instance->objects[WATER].texture);
// Bind the water VAO
glBindVertexArray(instance->objects[WATER].vao);
glEnable(GL_PRIMITIVE_RESTART);
glDrawElements(GL_TRIANGLE_STRIP, instance->objects[WATER].indices.size(), GL_UNSIGNED_INT, 0);
glDisable(GL_PRIMITIVE_RESTART);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
// Unbind the vertex array object and texture
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_BLEND);
}
The problem is this, the same piece of code (the one in between push and pop) for rendering the skydome which produces fine blending on the actual skydome, does not work when drawing skydome reflection on the water; specifically it only renders the night texture, no matter the value of Alpha. In other words I can't manage to draw blended day/night textures as reflection on the water (water texture itself btw has 0.5 alpha, so I'm able to see how the water texture blends with the skydome). Is it due to some strange behaviour with the stencil test I'm not aware of?
Thank you in advance for the help.
Apparently the solution was disabling GL_LIGHTING while rendering the reflected skydome as follows:
glPushMatrix();
glDisable(GL_LIGHTING); // <-----------------------------
glScalef(1.0, -1.0, 1.0);
// Bind the vertex array object for the skydome
glBindVertexArray(instance->objects[SKYDOME].vao);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindTexture(GL_TEXTURE_2D, instance->objects[SKYDOME].texture);
glDrawElements(GL_TRIANGLES, instance->objects[SKYDOME].indices.size(), GL_UNSIGNED_INT, 0);
glColor4f(1.0, 1.0, 1.0, alpha);
glBindTexture(GL_TEXTURE_2D, instance->objects[SKYDOME].blend_texture);
glDrawElements(GL_TRIANGLES, instance->objects[SKYDOME].indices.size(), GL_UNSIGNED_INT, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// Unbind the vertex array object and texture
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_LIGHTING);
glPopMatrix();
Not sure how lighting was interfering with the blending, but adding that simple disable call solved my initial answer!. Feel free to provide more accurate explanations.