我目前正在开发Android的OpenGL项目。现在,我正在尝试使用模板缓冲区为绘图时要限制的项目创建“剪辑”。我的问题是我希望能够创建一个剪辑形状,然后“删除”该剪裁形状的部分(很像在Android Canvas中使用Region.Op.UNION调用clipPath(),然后是另一个clipPath( )使用Region.Op.DIFFERENCE调用
基本上,我的意图是只使用值为1的模板缓冲位来绘制屏幕的某些部分。因此,据我所知,我应该能够使用不同的glStencilOp函数绘制到模板缓冲区,这将允许我在某些区域用1来绘制,然后可能在以后用这些区域的部分默认值0替换它们。
作为一个示例测试,我尝试使用类似的东西在屏幕上剪辑“甜甜圈”(注意:我使用LibGDX开源项目中的ShapeRenderer来绘制形状):
// Beginning LibGDX shapeRenderer.
shapeRenderer.begin(ShapeType.FILLED);
gl20.glClear(GL20.GL_STENCIL_BUFFER_BIT); // Clear stencil buffer.
gl20.glEnable(GL20.GL_STENCIL_TEST); // Enable stencil test.
gl20.glColorMask(false, false, false, false); // Disable color drawing.
gl20.glStencilMask(0xFF); // Set 0xFF as stencil mask.
// Have stencil test always fail, replace drawn stencil bits with 1.
gl20.glStencilFunc(GL20.GL_NEVER, 1, 0xFF);
gl20.glStencilOp(GL20.GL_REPLACE, GL20.GL_KEEP,GL20.GL_KEEP);
/* Draw outer circle, libGDX call. 600px radius. */
shapeRenderer.circle(screenRect.width() / 2, screenRect.height() / 2, 600);
// Now, replace newly drawn stencil bits with 0.
gl20.glStencilOp(GL20.GL_ZERO, GL20.GL_KEEP, GL20.GL_KEEP);
/* Draw inner circle, libGDX call. 200px radius. */
shapeRenderer.circle(screenRect.width() / 2, screenRect.height() / 2, 200);
// Re-enable color drawing.
gl20.glColorMask(true, true, true, true);
// Now, items drawn will be confined to areas with '1' stencil bit.
gl20.glStencilFunc(GL20.GL_EQUAL, 1, 0xFF);
gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);
gl20.glStencilMask(0x00);
/* Draw a filled, colored rectangle to the entire screen. */
shapeRenderer.setColor(Color.RED);
shapeRenderer.drawRect(screenRect);
shapeRenderer.end();
现在,据我所知,这会导致画面上出现彩色的“甜甜圈”;但是,如上面的代码所示,屏幕上没有任何内容。
但是,如果我只剪辑外圈(而不是试图摆脱内圈的“gl20.glStencilOp(GL20.GL_ZERO,GL20.GL_KEEP,GL20.GL_KEEP)”调用和随后的内圈画,一个圆圈,预定外圆的大小在屏幕上绘制。
我查看了我能找到的文档,到目前为止我读过的所有内容都表明这应该有效。这里有什么我想念的吗?非常感谢任何帮助。
答案 0 :(得分:1)
我发现了问题;我在ShapeRenderer中的一个begin()和end()调用之间绘制了两个圆圈。因此,在end()调用时绘制了两个圆。这意味着形状甚至没有绘制到模板缓冲区,因为我在end()调用之前调用了这些函数:
// Now, items drawn will be confined to areas with '1' stencil bit.
gl20.glStencilFunc(GL20.GL_EQUAL, 1, 0xFF);
gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);
gl20.glStencilMask(0x00);
如果我确保在绘制每个形状之前使用begin()调用和end()调用,它将在预期时间绘制,因此确保它将预期值绘制到模板缓冲区。
答案 1 :(得分:0)
逻辑看起来不错 - 你在绘制几何图形?
猜测,根据您在不渲染内部圆圈时看到外部圆圈呈现的事实,看起来您在两种情况下都使用外部圆形几何体(因此您设置了所有模具值,然后清除所有这些值,因此当您来到矩形时,没有任何模板值为1。
答案 2 :(得分:0)
我在WebGL中实现了您的解决方案,它运行正常(试一试):
http://ezekiel.vancouver.wsu.edu/~cs442/stackoverflow/stencil.html
以下是我模仿您的代码的方式:
gl.enable(gl.STENCIL_TEST);
gl.colorMask(false, false, false, false);
gl.stencilMask(0xFF);
gl.stencilFunc(gl.NEVER, 1, 0xFF);
gl.stencilOp(gl.REPLACE, gl.KEEP, gl.KEEP);
fillCircle(1); // radius of 1 maps to canvas width
gl.stencilOp(gl.ZERO, gl.KEEP, gl.KEEP);
fillCircle(0.333);
gl.colorMask(true, true, true, true);
gl.stencilFunc(gl.EQUAL, 1, 0xFF);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
gl.stencilMask(0x00);
gl.uniform3fv(program.color, [1, 0, 0]);
fillCircle(3); // fill whole canvas width red
你会发现你得到了你想要的东西。