我试图找出在绘制纹理时屏蔽部分的最佳方法。我的问题在于我似乎运行了我们的alpha蒙版!
我们使用openGL绘制自定义构建的2D游戏引擎。游戏是由精灵和简单的块纹理构成的。
我想要的结果是这样的:
目前我唯一可以弄清楚如何实现这一目标的方法是按顺序绘制它们(Body,Item,Arm),但我想避免这样做,以使艺术资产更容易处理。我的想法解决方案是绘制角色,然后使用alpha蒙版绘制项目,该蒙版阻挡纹理应该在手臂“下方”的区域。
我见过的其他解决方案就像this,其中使用了glBlendFuncSeparate()函数。我试图避免引入扩展,因为我当前版本的OpenGL不支持它。并不是说我反对这个想法,但是为了绘制一个alpha蒙版,它似乎有点像处理它?</ p>
我完全承认这对我来说是一个学习过程,我用它作为真正了解OpenGL处理方式的借口。有关我应该去哪里正确绘制的建议吗?有没有办法让固定管道中的OpenGL采用纹理,在其上面应用alpha蒙版,然后将其绘制到缓冲区中?我应该让我的角色分成其模型的几个部分吗?
[更新:2012年12月12日]
试图添加Tim建议的代码,但我似乎遇到了问题。当我启用模板缓冲区时,一切都被阻挡了,而不仅仅是我想要的。这是我的测试示例代码。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// 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);
// Draw our blocking poly
glBegin(GL_POLYGON);
glVertex2f( 50, 50 );
glVertex2f( 50, 50+128 );
glVertex2f( 50+128, 50+128 );
glEnd();
glStencilFunc(GL_GREATER, 0, -1);
glEnable(GL_STENCIL_TEST);
// Re enable drawing of colors
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Enable use of textures
glEnable(GL_TEXTURE_2D);
// 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();
// Swap buffers and display!
SDL_GL_SwapBuffers();
为了清楚起见,here也是我的初始化代码以设置此系统。
使用模板禁用运行代码时,我会得到:
当我使用glEnable(GL_STENCIL_TEST)时,我得到了这个:
我尝试过使用各种选项,但我看不出我的模板缓冲区阻止所有内容的明确原因。
[更新#2 8/12/12]
我们得到了一些工作代码,谢谢蒂姆!这是我最终运行正常工作。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Disable writing to any of the color fields
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilOp(GL_INCR, GL_INCR, GL_INCR);
glEnable(GL_STENCIL_TEST);
// Draw our blocking poly
glBegin(GL_POLYGON);
glVertex2f( 50, 50 );
glVertex2f( 50, 50+128 );
glVertex2f( 50+128, 50+128 );
glEnd();
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// Re enable drawing of colors
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Enable use of textures
glEnable(GL_TEXTURE_2D);
// 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();
答案 0 :(得分:1)
基本上,您可以使用图像的Z坐标来创建虚拟“图层”。然后它并不重要,你绘制它们的顺序。只需单独测试每个图像,然后在正确的Z值上绘制它。如果仍然不够,你可以使用包含每个像素“深度”的单独纹理,然后使用第二个纹理进行某种深度测试。
如果您想使用此方法,请务必致电glEnable(GL_DEPTH_TEST);
。
答案 1 :(得分:1)
这是我对于你有一个纹理和一个alpha蒙版的情况的想法:
glColorMask
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); glStencilFunc(GL_ALWAYS, 0,0);
glColorMask
glStencilFunc(GL_GREATER, 0, -1);
设置武器的模板缓冲区。这将仅绘制模板缓冲区大于零的武器纹素,并拒绝未更新模板的像素。答案 2 :(得分:0)
正如我所看到的,问题在于你有一个纹理,但是它的一部分代表了手臂,而它的一部分代表了角色的其余部分。问题是你想要在角色上绘制武器,但是将手臂拉过两者。
这意味着,在绘制两个对象时,您希望将它们放入三个不同的“层”中。这基本上没有意义,所以你有点卡住了。
这是一个想法:使用片段程序(即着色器)。
我建议你重载角色的纹理alpha通道来编码透明度和图层。例如,让我们使用0 =透明体,64 =不透明体,128 =透明臂,255 =不透明臂。
从这里,您可以绘制对象,但有条件地将对象的深度设置为三层。基本上,你编写了一个片段程序,将你的角色绘制成两个不同的层,当手臂向前拉时,角色会被向后推。绘制武器时,它会在没有着色器的情况下绘制,但会根据角色的像素深度进行测试。它的工作原理是这样的(显然未经测试)。
定义着色器my_shader,其中包含一个片段程序:
uniform sampler2D character_texture;
void main(void) {
vec4 sample = texture2D(character_texture,gl_TexCoord[0].st);
int type; //Figure out what type of character texel we're looking at
if (fabs(sample.a-0.00)<0.01) type = 0; //transparent body
else if (fabs(sample.a-0.25)<0.01) type = 1; //opaque body
else if (fabs(sample.a-0.50)<0.01) type = 2; //transparent arm
else if (fabs(sample.a-1.00)<0.01) type = 3; //opaque arm
//Don't draw transparent pixels.
if (type==0 || type==2) discard;
gl_FragColor = vec4(sample.rgb,1.0);
//Normally, you (can) write "gl_FragDepth = gl_FragCoord.z". This
//is how OpenGL will draw your weapon. However, for the character,
//we alter that so that the arm is closer and the body is farther.
//Move body farther
if (type==1) gl_FragDepth = gl_FragCoord.z * 1.1;
//Move arm closer
else if (type==3) gl_FragDepth = gl_FragCoord.z * 0.9;
}
这是绘制函数的一些伪代码:
//...
//Algorithm to draw your character
glUseProgram(my_shader);
glBindTexture(GL_TEXTURE_2D,character.texture.texture_gl_id);
glUniform1i(glGetUniformLocation(my_shader,"character_texture"),1);
character.draw();
glUseProgram(0);
//Draw your weapon
glEnable(GL_DEPTH_TEST);
character.weapon.draw();
glDisable(GL_DEPTH_TEST);
//...