OpenGL - 具有多个纹理的蒙版

发布于 2024-10-18 14:33:54 字数 259 浏览 5 评论 0原文

我根据以下概念在OpenGL中实现了遮罩:

  • 遮罩由黑色和白色组成。
  • 前景纹理应该仅在蒙版的白色部分可见。
  • 背景纹理应该仅在蒙版的黑色部分可见。

我可以使用 glBlendFunc() 使白色部分或黑色部分按预期工作,但不能同时使两者工作,因为前景层不仅混合到蒙版上,而且还混合到背景层上。

有谁知道如何以最好的方式实现这一目标?我一直在网上搜索并阅读了一些有关片段着色器的内容。这是要走的路吗?

I have implemented masking in OpenGL according to the following concept:

  • The mask is composed of black and white colors.
  • A foreground texture should only be visible in the white parts of the mask.
  • A background texture should only be visible in the black parts of the mask.

I can make the white part or the black part work as supposed by using glBlendFunc(), but not the two at the same time, because the foreground layer not only blends onto the mask, but also onto the background layer.

Is there anyone who knows how to accomplish this in the best way? I have been searching the net and read something about fragment shaders. Is this the way to go?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

尬尬 2024-10-25 14:33:54

这应该可行:

glEnable(GL_BLEND);
// Use a simple blendfunc for drawing the background
glBlendFunc(GL_ONE, GL_ZERO);
// Draw entire background without masking
drawQuad(backgroundTexture);
// Next, we want a blendfunc that doesn't change the color of any pixels,
// but rather replaces the framebuffer alpha values with values based
// on the whiteness of the mask. In other words, if a pixel is white in the mask,
// then the corresponding framebuffer pixel's alpha will be set to 1.
glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ZERO);
// Now "draw" the mask (again, this doesn't produce a visible result, it just
// changes the alpha values in the framebuffer)
drawQuad(maskTexture);
// Finally, we want a blendfunc that makes the foreground visible only in
// areas with high alpha.
glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
drawQuad(foregroundTexture);

这相当棘手,所以如果有任何不清楚的地方请告诉我。

创建 GL 时,不要忘记请求 alpha 缓冲区语境。否则,可以获得没有 alpha 缓冲区的上下文。

编辑:在这里,我做了一个插图。
illustration

编辑:自从写下这个答案后,我了解到有更好的方法可以做到这:

  • 如果您仅限于 OpenGL 的固定功能管道,请使用纹理环境
  • 。如果您可以使用着色器,请使用片段着色器。

这个答案中描述的方式有效,并且在性能上并不比这两个更好的选项特别差,但不太优雅且不太灵活。

This should work:

glEnable(GL_BLEND);
// Use a simple blendfunc for drawing the background
glBlendFunc(GL_ONE, GL_ZERO);
// Draw entire background without masking
drawQuad(backgroundTexture);
// Next, we want a blendfunc that doesn't change the color of any pixels,
// but rather replaces the framebuffer alpha values with values based
// on the whiteness of the mask. In other words, if a pixel is white in the mask,
// then the corresponding framebuffer pixel's alpha will be set to 1.
glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ZERO);
// Now "draw" the mask (again, this doesn't produce a visible result, it just
// changes the alpha values in the framebuffer)
drawQuad(maskTexture);
// Finally, we want a blendfunc that makes the foreground visible only in
// areas with high alpha.
glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
drawQuad(foregroundTexture);

This is fairly tricky, so tell me if anything is unclear.

Don't forget to request an alpha buffer when creating the GL context. Otherwise it's possible to get a context without an alpha buffer.

Edit: Here, I made an illustration.
illustration

Edit: Since writing this answer, I've learned that there are better ways to do this:

  • If you're limited to OpenGL's fixed-function pipeline, use texture environments
  • If you can use shaders, use a fragment shader.

The way described in this answer works and is not particularly worse in performance than these 2 better options, but is less elegant and less flexible.

守望孤独 2024-10-25 14:33:54

Stefan Monov 的答案很好!但对于那些仍然有问题让他的答案起作用的人:

  1. 您需要检查 GLES20.glGetIntegerv(GLES20.GL_ALPHA_BITS, ib) - 您需要非零结果。
  2. 如果你得到 0 - 转到 EGLConfig 并确保传递 alpha 位

    <前><代码>EGL14.EGL_RED_SIZE,8,
    EGL14.EGL_GREEN_SIZE, 8,
    EGL14.EGL_BLUE_SIZE, 8,
    EGL14.EGL_ALPHA_SIZE, 8, <- 我没有这个并且花了很多时间
    EGL14.EGL_DEPTH_SIZE, 16,

Stefan Monov's is great answer! But for those who still have issues to get his answer working:

  1. you need to check GLES20.glGetIntegerv(GLES20.GL_ALPHA_BITS, ib) - you need non zero result.
  2. if you got 0 - goto EGLConfig and ensure that you pass alpha bits

    EGL14.EGL_RED_SIZE, 8,
    EGL14.EGL_GREEN_SIZE, 8,
    EGL14.EGL_BLUE_SIZE, 8,
    EGL14.EGL_ALPHA_SIZE, 8, <- i havn't this and spent a much of time
    EGL14.EGL_DEPTH_SIZE, 16,
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文