遗留OpenGL -在模板测试产生的水反射上混合纹理

0aydgbwb  于 2023-10-18  发布在  其他
关注(0)|答案(1)|浏览(89)

我被迫使用遗留的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阿尔法,所以我能够看到水纹理如何与天空混合)。这是由于一些奇怪的行为与模具测试我不知道?
提前感谢你的帮助。

vqlkdk9b

vqlkdk9b1#

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

不知道照明是如何干扰混合,但添加简单的禁用调用解决了我最初的答案!。请提供更准确的解释。

相关问题