我被迫在学术项目中使用旧版 OpenGL 并且不使用着色器(是的..)。 我正在渲染一个有山有水的 3D 世界。我的目标(和问题)是将天穹绘制为水面上的倒影。天穹本身有 2 个纹理(夜晚和白天),它们是根据 alpha 值混合绘制的,如下所示:
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);
}
这个效果很好。然后,我通过模板测试成功地绘制了物体在水面上的倒影;具体来说:
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);
}
问题是这样的,用于渲染天穹的同一段代码(push 和 pop 之间的代码)在实际天穹上产生精细混合,但在水面上绘制天穹反射时不起作用;具体来说,无论 Alpha 值是多少,它都只渲染夜间纹理。换句话说,我无法绘制混合的白天/夜间纹理作为水面上的反射(顺便说一句,水纹理本身有 0.5 alpha,所以我能够看到水纹理如何与天穹混合)。 是否是由于我不知道的模板测试出现了一些奇怪的行为?
提前感谢您的帮助。
显然解决方案是在渲染反射天穹时禁用 GL_LIGHTING,如下所示:
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();
不确定光照如何干扰混合,但添加简单的禁用调用解决了我最初的答案!欢迎提供更准确的解释。