Opengl es 使用OpenGl ES 2.0制作模板

Opengl es 使用OpenGl ES 2.0制作模板,opengl-es,opengl-es-2.0,libgdx,framebuffer,stencil-buffer,Opengl Es,Opengl Es 2.0,Libgdx,Framebuffer,Stencil Buffer,我正在试图找出一种方法来剪切背景纹理的某个区域,这样某个自定义图案就不会在屏幕上为该背景渲染。例如: 这个正方形可以是任何图案。 我使用帧缓冲区对象和模具缓冲区来实现这种效果。代码如下: fbo.begin(); //Disables ColorMask and DepthMask so that all the rendering is done on the Stencil Buffer Gdx.gl20.glColorMask(false, false, false, false); G

我正在试图找出一种方法来剪切背景纹理的某个区域,这样某个自定义图案就不会在屏幕上为该背景渲染。例如:

这个正方形可以是任何图案。 我使用帧缓冲区对象和模具缓冲区来实现这种效果。代码如下:

fbo.begin();
//Disables ColorMask and DepthMask so that all the rendering is done on the Stencil Buffer
Gdx.gl20.glColorMask(false, false, false, false);
Gdx.gl20.glDepthMask(false);
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl20.glStencilFunc(GL20.GL_ALWAYS, 1, 0xFFFFFFFF);
Gdx.gl20.glStencilOp(GL20.GL_REPLACE, GL20.GL_REPLACE, GL20.GL_REPLACE);

stage.getSpriteBatch().begin();
rHeart.draw(stage.getSpriteBatch(), 1); //Draws the required pattern on the stencil buffer

//Enables the ColorMask and DepthMask to resume normal rendering
Gdx.gl20.glColorMask(true, true, true, true);
Gdx.gl20.glDepthMask(true);

Gdx.gl20.glStencilFunc(GL20.GL_EQUAL, 1, 0xFFFFFFFF);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);

background.draw(stage.getSpriteBatch(), 1); //Draws the background such that the background is not rendered on the required pattern, leaving that area black.

stage.getSpriteBatch().end();
Gdx.gl20.glDisable(GL20.GL_STENCIL_TEST);
fbo.end();
Gdx.gl20.glClearColor(0, 0, 0, 0);
stage.draw();
FrameBuffer.clearAllFrameBuffers(Gdx.app);
fbo1.begin();
Gdx.gl20.glClearColor(0, 0, 0, 0);
batch.begin();
rubber.draw(batch, 1);
Gdx.gl20.glColorMask(false, false, false, true);
coverHeart.draw(batch, 1);
Gdx.gl20.glColorMask(true, true, true, false);
batch.end();        
fbo1.end();

toDrawHeart = new Image(new TextureRegion(fbo1.getColorBufferTexture()));
batch.begin();
toDrawHeart.draw(batch, 1);
batch.end();
然而,这根本不起作用。我应该如何使用模具缓冲区来实现这一点?我还面临着理解glStencilFunc和glStencilOp的一些困难。如果有人能解释一下这两个问题,那将是非常有帮助的

更新:我也尝试过使用glColorMask制作同类产品。代码如下:

fbo.begin();
//Disables ColorMask and DepthMask so that all the rendering is done on the Stencil Buffer
Gdx.gl20.glColorMask(false, false, false, false);
Gdx.gl20.glDepthMask(false);
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl20.glStencilFunc(GL20.GL_ALWAYS, 1, 0xFFFFFFFF);
Gdx.gl20.glStencilOp(GL20.GL_REPLACE, GL20.GL_REPLACE, GL20.GL_REPLACE);

stage.getSpriteBatch().begin();
rHeart.draw(stage.getSpriteBatch(), 1); //Draws the required pattern on the stencil buffer

//Enables the ColorMask and DepthMask to resume normal rendering
Gdx.gl20.glColorMask(true, true, true, true);
Gdx.gl20.glDepthMask(true);

Gdx.gl20.glStencilFunc(GL20.GL_EQUAL, 1, 0xFFFFFFFF);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);

background.draw(stage.getSpriteBatch(), 1); //Draws the background such that the background is not rendered on the required pattern, leaving that area black.

stage.getSpriteBatch().end();
Gdx.gl20.glDisable(GL20.GL_STENCIL_TEST);
fbo.end();
Gdx.gl20.glClearColor(0, 0, 0, 0);
stage.draw();
FrameBuffer.clearAllFrameBuffers(Gdx.app);
fbo1.begin();
Gdx.gl20.glClearColor(0, 0, 0, 0);
batch.begin();
rubber.draw(batch, 1);
Gdx.gl20.glColorMask(false, false, false, true);
coverHeart.draw(batch, 1);
Gdx.gl20.glColorMask(true, true, true, false);
batch.end();        
fbo1.end();

toDrawHeart = new Image(new TextureRegion(fbo1.getColorBufferTexture()));
batch.begin();
toDrawHeart.draw(batch, 1);
batch.end();
此代码正在生成以下内容: 而不是像这样:(忽略窗口大小和色调)


注意:我正在使用libgdx库。

Gdx.gl20.glStencilFunc(gl20.GL\u替换,gl20.GL\u替换,gl20.GL\u替换)

这些参数不是glStencilFunc的正确参数。我想你指的是glStencilOp


您需要在代码中使用glGetError,它会提醒您这些类型的错误

我相信您的问题在于,您最初的
GL_REPLACE
模具操作由您的
rHeart.draw应用于所有绘制的像素,而与应用于四边形的任何纹理的形状无关

因此,模具值将应用于四边形的每一个像素,从而解决问题


如果应用在四边形上的纹理具有alpha通道,因为不支持
GL_alpha_TEST
,您可以将着色器设置为
放弃
完全透明的像素,防止它们被绘制到模具缓冲区。

绘制到
SpriteBatch
时,忽略状态更改,直到
结束()
被调用。如果要使用带有
SpriteBatch
的模具,则需要分解批处理图形。有一件事,我遗漏了FBO,但这不会有什么区别

@Override
public void create() {      
    camera = new OrthographicCamera(1, 1);
    batch = new SpriteBatch();

    texture = new Texture(Gdx.files.internal("data/badlogic.jpg"));
    texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);

    TextureRegion region = new TextureRegion(texture, 0, 0, 256, 256);

    sprite = new Sprite(region);
    sprite.setSize(1f, 1f);
    sprite.setPosition(-0.5f, -0.5f);

    spriteUpsideDown = new Sprite(new TextureRegion(texture, 1f, 1f, 0f, 0f));
    spriteUpsideDown.setSize(1f, 1f);
    spriteUpsideDown.setPosition(-0.5f, -0.5f);

    pattern = new Sprite(region);
    pattern.setSize(0.5f, 0.5f);
    pattern.setPosition(-0.25f, -0.25f);

    << Set Input Processor >>
}

@宠坏了:你用glGetError吗?嗯,我不确定。我对模板缓冲区没有经验,尽管我对它的工作原理有很好的了解,而且我觉得你那里的东西看起来很正常。你能详细说明一下在你的例子中“完全不工作”是什么意思吗?@Tim这意味着渲染的背景不包含任何已模板化的“图案”。这意味着我得到的是一个完全粉红色的屏幕,而不是一个带有黑框的粉红色屏幕(如上所示)。对于桌面,我正在使用LwjglApplication,将LwjglApplication配置对象的模具值设置为8。您确定模具可以与
SpriteBatch一起使用吗?我只是简单地看了一下,我不确定。我不确定。那么,作为替代方案,我应该尝试什么呢?为什么你会认为SpriteBatch可能无法与模具缓冲区一起工作?OpenGL ES 2.0实现不允许GL_ALPHA_测试,而Glalphafuncy对我来说根本不起作用。它创建了一个矩形遮罩,根本不关心精灵的alpha值。