Java 使用半透明纹理来;面具;背景的一部分

Java 使用半透明纹理来;面具;背景的一部分,java,opengl,lwjgl,stencil-buffer,Java,Opengl,Lwjgl,Stencil Buffer,我正在尝试创建一个“雾中的洞”效果。我有一个背景网格图像,重叠在上面,我有一个“雾”纹理,我用它来显示某些区域不在视图中。我正试图从“雾”中切出一大块,以显示当前正在查看的区域。我试图“遮住”屏幕上的一部分雾 我制作了一些图片来帮助解释我的目标: 背景: “遮罩图像”(完全透明必须在内部,而不是外缘,我将使用它): 雾(对不起,很难看到……大部分是透明的): 我想要的最终产品: 我试过: 模具缓冲区:我得到了充分的工作,除了一个事实。。。我不知道如何保持“遮罩”图像的褪色透明度 glB

我正在尝试创建一个“雾中的洞”效果。我有一个背景网格图像,重叠在上面,我有一个“雾”纹理,我用它来显示某些区域不在视图中。我正试图从“雾”中切出一大块,以显示当前正在查看的区域。我试图“遮住”屏幕上的一部分雾

我制作了一些图片来帮助解释我的目标:
背景:

“遮罩图像”(完全透明必须在内部,而不是外缘,我将使用它):

雾(对不起,很难看到……大部分是透明的):

我想要的最终产品:

我试过:

  • 模具缓冲区:我得到了充分的工作,除了一个事实。。。我不知道如何保持“遮罩”图像的褪色透明度
  • glBlendFunc:我尝试了许多不同版本的参数和许多其他方法(glColorMask、glBlendEquation、glBlendFuncSeparate),我是从使用我在这个网站上找到的一些参数开始的:。我使用了“glBlendFunc(GL_ZERO,GL_ONE_减去SRC_ALPHA)”,因为这似乎是我想要的,但是。。。这就是最终发生的结果:(很难说这里发生了什么,但是……背景中有雾覆盖了网格。尽管如此,面具最终只是一个完全不透明的黑色斑点,而它应该是雾中的透明部分。
以前的一些代码:

glEnable(GL_BLEND); // This is not really called here... It is called on the init function of the program as it is needed all the way through the rendering cycle.
renderFogTexture(delta, 0.55f); // This renders the fog texture over the background the 0.55f is the transparency of the image. 
glBlendFunc(GL_ZERO, GL11.GL_ONE_MINUS_SRC_ALPHA); // This is the one I tried from one of the many website I have been to today.
renderFogCircles(delta); // This just draws one (or more) of the mask images to remove the fog in key places.

(我本来会发布更多的代码,但在我尝试了很多东西之后,我开始删除一些旧代码,因为它变得非常混乱(我在块注释中“备份了它们”)

您当前采用的方法将不起作用,因为一旦您在整个屏幕上画出雾,就无法“擦除”它

如果您使用的是固定管道:

您可以使用多文本(glTexEnv)使用固定管道在一次过程中组合雾和圆形纹理。如果您以前没有使用过此功能,则可能会有点混乱,您可能需要花一些时间研究手册页。您将执行一些操作,如将雾绑定到glActiveTexture 0,将蒙版绑定到glActiveTexture 1,启用多文本,然后将它们与ith glTexEnv。我记不清这个的确切参数

如果正在使用着色器,请执行以下操作:

使用多重纹理着色器,将雾alpha与圆形纹理相乘(将圆形区域中的alpha归零),然后在一次过程中将此组合纹理混合到背景中。这可能是一种概念上更简单的方法,但不确定是否使用着色器


我不确定是否有一种方法可以做到这一点,即在单独的过程中绘制雾和遮罩,因为它们都有自己的alpha值,因此很难将它们组合起来以获得正确的颜色结果。

这是可行的,前提是您目前没有对帧缓冲区的alpha执行任何操作

步骤1:确保帧缓冲区的alpha已清除为零。因此,您的glClearColor调用需要将alpha设置为零。然后像正常情况一样调用glClear

第2步:在绘制“雾”之前绘制遮罩图像。正如Tim所说,一旦与雾混合,就无法撤消该操作。因此,您首先需要那里的遮罩数据

但是,您还需要专门渲染遮罩。您只希望遮罩修改帧缓冲区的alpha。您不希望它与RGB颜色混淆。为此,请使用此函数:。这将关闭对颜色的RGB部分的写入;因此,只修改alpha

您的遮罩纹理在可见处似乎为零,在不可见处似乎为一。但是,算法需要相反的结果,因此您应该修复纹理或使用将有效翻转alpha的
glTexEnv
模式

在此步骤之后,帧缓冲区的alpha值应为0(我们希望看到雾),alpha值应为1(我们不希望看到雾)

另外,渲染遮罩后,不要忘记撤消
glColorMask
调用。您需要恢复这些颜色

第3步:渲染雾。这很简单;要使遮罩工作,您需要一个特殊的混合模式。例如:

glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ZERO, GL_ONE);
RGB和A混合部分之间的分离很重要。您不希望更改帧缓冲区的alpha(以防您要渲染多个雾层)


完成了。

如果使用RGB混合方程(1减去α,α),并且正如您所说的“在我们想要看到雾的地方,α是0”,那么结果颜色将是((1-0)*fog_RGB+0*DST_RGB)。这将使雾完全不透明,不是吗?雾层的alpha值不需要在RGB计算中的某个位置使用吗?我将对此进行测试,不过,我相信反转遮罩可能对我不起作用。renderFogCircles()渲染多个圆,它们可能重叠,也可能不重叠。如果alpha反转,这不会导致奇怪的图形问题吗?无论如何……我将很快对其进行测试以确保。当前遮罩(但白色而非黑色)似乎能提供所需的效果。在上面的遮罩上反转alpha似乎会产生完全相反的效果。(边缘是透明的)尽管如此,还是有一些问题……不管我使用什么透明度值,这段代码似乎都会让所有的雾变成不透明的白色。(我用我在别处使用的参数“glBlendFunc(GL_SRC_ALPHA,GL_ONE_减去_SRC_ALPHA”)撤消上面的glBlendFunc)雾似乎不再与背景混合。@Nicolas Tim在对这个答案的第一次评论中说得很对。我深入了解了这一点,发现您建议的glBlendFunc参数存在一个重大问题。无论我如何更改这些设置,似乎都会使雾图像(目标)完全不透明。(我无法更改不透明度