如何在另一个网格后面渲染网格,就像面具一样?

时间:2013-09-14 11:13:36

标签: c++ opengl-es opengl-es-2.0 shader

我想这样,当网格A(角色)位于网格B(墙壁)后面时,它仍然会被渲染,但是颜色为灰色。

我正在开始使用opengles 2.0,我仍然不确定是否会这样做。根据我的理解,深度缓冲区允许网格对抗将在其包含的片段中看到的人,也有可能涉及的各种混合函数,最后模板缓冲区看起来也会具有这种理想的功能。 / p>

那么有没有办法根据失败的深度测试通过着色器输出不同的颜色?有没有办法通过混合来做到这一点?或者我必须使用模板缓冲区吗?

这种技术是什么需要将来参考?我已经看到它在很多电子游戏中使用过。

1 个答案:

答案 0 :(得分:5)

这可以使用模板缓冲区完成。模板缓冲器为每个像素提供一些额外的位,可用作位掩码或计数器。在您的情况下,您将配置模板测试单元以在角色的深度测试失败时设置特定的位掩码(因为它被井阻塞)。然后切换模板测试模式操作以通过此特定位掩码的模板测试,并以所需颜色渲染完整视口,实心四边形,并禁用深度测试和深度写入。

代码

我强烈建议您将潜入模板测试单元的文档中。这是一个非常强大的机制,经常被忽视。您的特定问题将通过以下方式解决。我觉得你拿这个示例代码,并参考模板测试函数引用glStencilFuncglStencilOp

您必须为帧缓冲区的像素格式添加模板缓冲区 - 您如何做到这一点与平台有关。例如,如果您正在使用GLUT,那么您需要将|GLUT_STENCIL添加到glutInitDisplayMode的格式位掩码中;在iOS上,您在GLKView上设置了一个属性;等。添加模板缓冲区后,应将|GL_STENCIL_BUFFER_BIT添加到每个绘图的初始glClear调用中,将其与其他渲染缓冲区一起清除。

GLint const silouhette_stencil_mask = 0x1;

void display()
{
    /* ... */    

    glEnable(GL_DEPTH_TEST);
    glDepthMask(GL_TRUE);
    glDepthFunc(GL_LESS);

    glDisable(GL_STENCIL_TEST);
    /* The following two are not necessary according to specification.
     * But drivers can be buggy and this makes sure we don't run into
     * issues caused by not wanting to change the stencil buffer, but
     * it happening anyway due to a buggy driver.
     */
    glStencilFunc(GL_NEVER, 0, 0);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

    draw_the_wall();

    glEnable(GL_STENCIL_TEST);
    glStencilFunc(GL_ALWAYS, silouhette_stencil_mask, 0xffffffff);
    glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);

    draw_the_character();

    glStencilFunc(GL_EQUAL, silouhette_stencil_mask, 0xffffffff);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

    glDisable(GL_DEPTH_TEST);
    glDepthMask(GL_FALSE);

    draw_full_viewport_solid_color();

    /* ... */
}