旧版 OpenGL - 在通过模板测试生成的水反射上混合纹理

问题描述 投票:0回答:1

我被迫在学术项目中使用旧版 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,所以我能够看到水纹理如何与天穹混合)。 是否是由于我不知道的模板测试出现了一些奇怪的行为?

提前感谢您的帮助。

opengl legacy blending stencil-buffer
1个回答
0
投票

显然解决方案是在渲染反射天穹时禁用 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();

不确定光照如何干扰混合,但添加简单的禁用调用解决了我最初的答案!欢迎提供更准确的解释。

© www.soinside.com 2019 - 2024. All rights reserved.