如何在另一个网格(如蒙版)后面渲染网格? [英] How to render a mesh behind another mesh, like a mask?

查看:110
本文介绍了如何在另一个网格(如蒙版)后面渲染网格?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望它在网格A(角色)位于网格B(墙)之后时仍会呈现,但具有纯灰色.

我开始使用opengles 2.0,但仍不确定是否要这样做.从我的理解来看,深度缓冲区允许网格物体在它们所包含的片段中相互竞争,还有可能涉及到各种混合功能,最后模版缓冲区看起来也将具有这种理想的功能. /p>

那么有没有一种方法可以基于失败的深度测试通过着色器输出不同的颜色?有没有办法通过混合来做到这一点?还是我必须使用模板缓冲区一些方式?

该技术又叫什么以备将来参考?我已经看到它在很多视频游戏中使用过.

解决方案

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

代码

我强烈建议您将 deep 深入到模板测试单元的文档中.这是一个非常强大的机制,经常被忽略.您的特定问题将通过以下解决.我为您准备了这个示例代码,将其与模板测试功能参考 glStencilOp .

您必须将模板缓冲区添加到帧缓冲区的像素格式–具体操作取决于平台.例如,如果您使用的是GLUT,则可以将|GLUT_STENCIL添加到glutInitDisplayMode的格式位掩码中.在iOS上,您可以在GLKView上设置属性;等等.一旦添加了模板缓冲区,就应该通过在每个图形的初始glClear调用中添加|GL_STENCIL_BUFFER_BIT来将其与其他渲染缓冲区一起清除.

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();

    /* ... */
}

I would like it so that when mesh A (the character), is behind mesh B (a wall), it is still rendered but with a solid gray color.

I'm beginning opengles 2.0 and I'm still unsure as to go about this. From what I understand the depth buffer allows meshes to fight out who will be seen in the fragments they encompass, also there are various blend functions that could possibly involved in this, finally the stencil buffer looks like it would also have this desirable functionality.

So is there a way to output different colors through the shader based on a failed depth test? Is there a way to do this through blending? Or must I use the stencil buffer some how?

And what is this technique called for future reference? I've seen it used in a lot of video games.

解决方案

This can be done using the stencil buffer. The stencil buffer gives each pixel some additional bits which can be used as a bitmask or a counter. In your case you'd configure the stencil test unit to set a specific bitmask when the depth test for the character fails (because it's obstructed by the well). Then you switch the stencil test mode operation to pass the stencil test for this specific bitmask, and render a full viewport, solid quad in the desired color, with depth testing and depth writes disabled.

Code

I strongly recommend you dive deep into the documentation for the stencil test unit. It's a very powerful mechanism, often overlooked. Your particular problem would be solved by the following. I stuggest you take this example code, read it in parallel to the stencil test functions references glStencilFunc, glStencilOp.

You must add a stencil buffer to your frame buffer's pixel format – how you do that is platform dependent. For example, if you're using GLUT, then you'd add |GLUT_STENCIL to the format bitmask of glutInitDisplayMode; on iOS you'd set a property on your GLKView; etc. Once you've added a stencil buffer, you should clear it along with your other render buffers by adding |GL_STENCIL_BUFFER_BIT to the initial glClear call of each drawing.

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();

    /* ... */
}

这篇关于如何在另一个网格(如蒙版)后面渲染网格?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆