如何使用带有 alpha 掩码的模板缓冲区

Posted

技术标签:

【中文标题】如何使用带有 alpha 掩码的模板缓冲区【英文标题】:How to use a stencil buffer with an alpha mask 【发布时间】:2012-08-15 05:39:22 【问题描述】:

我正在尝试使用带有 alpha 掩码的模板缓冲区来防止绘制部分纹理。

初始化代码

if(SDL_Init(SDL_INIT_EVERYTHING) < 0) 
    fprintf(stderr,"%s:%d\n    SDL_Init call failed.\n",__FILE__,__LINE__);
    return false;


// Request use of the stencil buffer
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 1 );

if((Surf_Display = SDL_SetVideoMode(WWIDTH, WHEIGHT, 32,  SDL_GL_DOUBLEBUFFER | SDL_OPENGL | SDL_RESIZABLE)) == NULL) 
    fprintf(stderr,"%s:%d\n    SDL_SetVideoMode call failed.\n",__FILE__,__LINE__);
    return false;


// Init GLDebug system
GLDebug::Init();

// Init GL system
glClearColor(0, 0, 0, 1);

glClearDepth(1.0f);

glViewport(0, 0, WWIDTH, WHEIGHT);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

glOrtho(0, WWIDTH,  WHEIGHT, 0, 1, -1);

glMatrixMode(GL_MODELVIEW);

glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);

glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POLYGON_SMOOTH);

glLoadIdentity();

来源

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

// Enable use of textures
glEnable(GL_TEXTURE_2D);

// Disable writing to any of the color fields
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); 
glStencilFunc(GL_ALWAYS, 0,0);
glEnable(GL_ALPHA_TEST);
glEnable(GL_STENCIL_TEST);

glBindTexture(GL_TEXTURE_2D,(&StencilTex)[0]);

// Draw our stencil buffer texture
glBegin(GL_POLYGON);                                   
    glTexCoord2d( 0, 0 );    glVertex2f( 50,     50 );
    glTexCoord2d( 0, 1 );    glVertex2f( 50,     50+128 );
    glTexCoord2d( 1, 1 );    glVertex2f( 50+128, 50+128 );
    glTexCoord2d( 1, 0 );    glVertex2f( 50+128, 50 );
glEnd();

glDisable(GL_ALPHA_TEST);

// Re enable drawing of colors
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

glStencilFunc(GL_GREATER, 0, -1);

// Bind desired texture for drawing
glBindTexture(GL_TEXTURE_2D,(&texture)[0]);

// Draw the box with colors (this should be masked off)
glBegin(GL_QUADS);                                   
    glTexCoord2d( 0, 0 );    glVertex2f( 50,     50 );
    glTexCoord2d( 0, 1 );    glVertex2f( 50,     50+128 );
    glTexCoord2d( 1, 1 );    glVertex2f( 50+128, 50+128 );
    glTexCoord2d( 1, 0 );    glVertex2f( 50+128, 50 );
glEnd();
glDisable(GL_STENCIL_TEST);

// Swap buffers and display!
SDL_GL_SwapBuffers();

我将从蒂姆发布的this 问题中删除参考。我的设置适用于像素的原始绘图,但我不能 A)使这个过程应该如何工作或 B)让它从 alpha 纹理工作。我得到的只是黑屏或完整的纹理。

有人愿意将其分解为合理的步骤吗?我对 glStencilOp 和 glStencilFunc 选项的工作原理有一个模糊的理解,但是它们与使用 alpha 测试和模板测试的关系让我感到困惑。我们如何决定只保留纹理中的 alpha 层?

复习:

我有一个要绘制到场景中的纹理,但我需要屏蔽掉非常特定的区域。 无法在运行时修改对象的 Alpha 纹理以实现此效果。 我正在使用固定管道,我计划稍后学习如何使用 VBO。 调用第二个纹理时,给定的代码不会绘制任何内容。

[编辑 0]

公认的解决方案有效!这是我所期望的最终代码。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

// // Enable use of textures
glEnable(GL_TEXTURE_2D);

// Disable writing to any of the color fields
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); 

glAlphaFunc(GL_GREATER, 0.05);
glStencilFunc(GL_ALWAYS, 0,0);

glEnable(GL_STENCIL_TEST);
glEnable(GL_ALPHA_TEST);

glBindTexture(GL_TEXTURE_2D,(&StencilTex)[0]);

// Draw our blocking poly
glBegin(GL_POLYGON);                                   
    glTexCoord2d( 0, 0 );    glVertex2f( 50,     50 );
    glTexCoord2d( 0, 1 );    glVertex2f( 50,     50+128 );
    glTexCoord2d( 1, 1 );    glVertex2f( 50+128, 50+128 );
    glTexCoord2d( 1, 0 );    glVertex2f( 50+128, 50 );
glEnd();
glDisable(GL_ALPHA_TEST);


// Re enable drawing of colors
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

glStencilFunc(GL_LESS, 0, -1);

// Bind desired texture for drawing
glBindTexture(GL_TEXTURE_2D,(&texture)[0]);

// Draw the box with colors
glBegin(GL_QUADS);                                   
    glTexCoord2d( 0, 0 );    glVertex2f( 50,     50 );
    glTexCoord2d( 0, 1 );    glVertex2f( 50,     50+128 );
    glTexCoord2d( 1, 1 );    glVertex2f( 50+128, 50+128 );
    glTexCoord2d( 1, 0 );    glVertex2f( 50+128, 50 );
glEnd();
glDisable(GL_STENCIL_TEST);


// Swap buffers and display!
SDL_GL_SwapBuffers();

【问题讨论】:

【参考方案1】:

我看到您已启用 alpha 测试,但我没有看到任何设置 alpha 函数的调用 (glAlphaFunc)?

如果不设置 alpha 函数,则 alpha 测试始终通过。您必须告诉状态机要丢弃哪些像素。

通常我会将其设置为:

glAlphaFunc(GL_GREATER, 0.05); //reject any pixels with alpha less than 0.05

很抱歉,如果您没有从我之前的回答中清楚地理解,但如果您对模板功能的工作方式感到困惑,您可以随时查阅他们的参考页面glStencilFuncglStencilOp

【讨论】:

完全符合我的预期,蒂姆,你太棒了!谢谢您的帮助。我也已将来源发布到您建议的解决方案中。

以上是关于如何使用带有 alpha 掩码的模板缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

使用纹理更改帧部分的 alpha 值

模板匹配:为 minMaxLoc 创建掩码的有效方法?

.Net - 在文件名中使用带有掩码的 FileIOPermission

带有特定掩码的Matlab imcrop

如何在 Laravel 和 Vue 中使用表单掩码

带有域掩码的 WordPress 站点的 htaccess 重定向不起作用