【问题标题】:Stenciling using OpenGl ES 2.0使用 OpenGL ES 2.0 进行模板制作
【发布时间】:2012-06-18 18:46:03
【问题描述】:

我正在尝试找出一种方法来剪切背景纹理的某个区域,以便某个自定义图案不会在该背景的屏幕上呈现。例如:

这个正方形可以是任何图案。 我正在使用 Frame Buffer Object 和 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);
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();

但是这根本不起作用。我应该如何使用 Stencil Buffers 来做到这一点?我在理解 glStencilFunc 和 glStencilOp 时也遇到了一些困难。如果有人能对这两个有所了解,那将非常有帮助。

更新:我也尝试过使用 glColorMask 制作类似的东西。代码如下:

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 库。

【问题讨论】:

  • 您能否详细说明在您的情况下“根本不工作”是什么意思?
  • @Tim 这意味着正在渲染的背景不包含任何已被模板打印出来的“图案”。这意味着我得到的是一个完全粉红色的屏幕,而不是一个带有黑框的粉红色(如上所示)。
  • 另外请注意,我使用的是 libgdx 库。对于桌面,我使用 LwjglApplication,将 LwjglApplicationConfiguration 对象的模板值设置为 8。
  • 您确定模板可以与SpriteBatch 一起使用吗?我想简单看看code,我不确定。
  • 我不确定。那么作为替代方案,我应该尝试什么?为什么你会认为 SpriteBatch 可能不适用于 Stencil Buffers?

标签: opengl-es opengl-es-2.0 libgdx framebuffer stencil-buffer


【解决方案1】:

Gdx.gl20.glStencilFunc(GL20.GL_REPLACE, GL20.GL_REPLACE, GL20.GL_REPLACE);

这些不是 glStencilFunc 的正确参数。我想你的意思是 glStencilOp 在这里。

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

【讨论】:

  • @Spoilt:你使用 glGetError 吗?
  • 嗯,我不确定。我对模板缓冲区没有经验,但我很清楚它是如何工作的,而且你在那里的东西对我来说看起来很正常。
【解决方案2】:

我相信你的问题是你的初始GL_REPLACE 模板操作被你的rHeart.draw 应用到所有绘制的像素上,而不管应用在四边形上的任何纹理的形状。

因此,模板值将应用于四边形的每个像素,这会导致您遇到问题。

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

【讨论】:

  • OpenGL ES 2.0 实现不允许 GL_ALPHA_TEST 和 glAlphaFunc
【解决方案3】:

在绘制到 SpriteBatch 时,将忽略状态更改,直到调用 end()。如果您想在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 >>
}

输入处理器允许通过键盘(桌面上的libgdx)设置两个布尔标志breakBatch1breakBatch2,用于中断SpriteBatch绘图。

@Override
public void render() {      
    Gdx.gl.glClearColor(1, 1, 1, 1);
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_STENCIL_BUFFER_BIT);
    batch.setProjectionMatrix(camera.combined);

    // setup drawing to stencil buffer
    Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
    Gdx.gl20.glStencilFunc(GL20.GL_ALWAYS, 0x1, 0xffffffff);
    Gdx.gl20.glStencilOp(GL20.GL_REPLACE, GL20.GL_REPLACE, GL20.GL_REPLACE);
    Gdx.gl20.glColorMask(false, false, false, false);

    // draw base pattern
    batch.begin();
    pattern.draw(batch);

    if(breakBatch1) { batch.end(); batch.begin(); }

    // fix stencil buffer, enable color buffer
    Gdx.gl20.glColorMask(true, true, true, true);
    Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);

    // draw where pattern has NOT been drawn
    Gdx.gl20.glStencilFunc(GL20.GL_NOTEQUAL, 0x1, 0xff);
    sprite.draw(batch);

    if(breakBatch2) { batch.end(); batch.begin(); }

    // draw where pattern HAS been drawn.
    Gdx.gl20.glStencilFunc(GL20.GL_EQUAL, 0x1, 0xff);
    spriteUpsideDown.draw(batch);
    batch.end();
}

【讨论】:

  • 这对我来说根本不起作用。它创建了一个矩形遮罩,根本不关心精灵的 alpha 值。
猜你喜欢
  • 2013-01-22
  • 1970-01-01
  • 2011-11-26
  • 2014-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-29
相关资源
最近更新 更多