编辑
混合画笔 -> 图层 -> 背景
好的,glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 正在将画笔笔触混合到画笔纹理中,但纹理中生成的 alpha 值是错误的。每个添加的片段需要 1. 将它的 alpha 添加到最终的 alpha 值 - 它必须为交互移除恰好那么多的光 2. 按余数缩放前一个 alpha - 之前的表面将光减少前一个值,但是因为添加了一个新的表面,它们减少的光线更少。我不确定这是否有意义,但它导致了这个......
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
现在画笔纹理的颜色通道包含要与背景混合的总颜色(预乘 alpha),而 alpha 通道给出权重(或颜色遮盖背景的量)。由于颜色预先与 alpha 相乘,默认的 RenderTexture 混合 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA 会随着 alpha 缩放再次,从而使整体颜色变暗。您现在需要使用以下函数将画笔纹理与背景混合,我认为这必须在 Cocos2D 中设置:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
希望这是可能的。我还没有考虑过如何管理设置画笔纹理以与GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA 混合的可能性,但它可能需要浮点纹理和/或额外的通道来划分/标准化 alpha,这听起来痛苦。
或者,在绘制之前将背景添加到渲染纹理中,并在不混合任何图层的情况下保留该背景。
这对我有用:
glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
fbo.bind();
glClear(GL_COLOR_BUFFER_BIT);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
drawTexture(brush1);
drawTexture(brush2);
fbo.unbind();
drawTexture(grassTex); //tex alpha is 1.0, so blending doesn't affect background
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
drawTexture(fbo.getColour(0)); //blend in the brush layer
画笔图层不透明度
使用GL_ONE, GL_ONE_MINUS_SRC_ALPHA 会导致库在图层混合中实现不透明度的问题,因为它假定颜色乘以 alpha。通过减小opacity 的值,在混合过程中画笔层的 alpha 会按比例缩小。 GL_ONE_MINUS_SRC_ALPHA 然后会导致背景颜色的数量增加,但是 GL_ONE 将 100% 的画笔层相加并使图像过饱和。
imo最简单的解决办法就是自己想办法通过全局图层不透明度来缩小颜色,继续使用GL_ONE, GL_ONE_MINUS_SRC_ALPHA。
- 如果库支持它,实际上使用
GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_ALPHA 可能是一个答案,但显然它不支持。
- 您可以使用固定管道渲染来缩放颜色:
glColor4f(opacity, opacity, opacity, opacity),但这将需要第二个渲染目标并手动进行混合,类似于上面的代码,您在其中为背景绘制一个全屏四边形,然后再次为画笔层。
- 如果您手动进行混合,使用片段着色器而不是
glColor 方法会更可靠。如果您想使用更复杂的混合功能,这将允许更大的控制,特别是在涉及 0 到 1 范围之外的划分和临时:
gl_FragColour = texture(brushTexture, coord) * layerOpacity;
结束编辑
标准的 alpha 混合函数是 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);,而不是 GL“初始”/默认函数。
像在 glBlendFuncSeparate 中那样对 alpha 值求和会使 alpha 过度饱和,并且下面的颜色会被完全替换。饱和度混合可能会产生不错的结果:glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE)。如果支持,也可能值得尝试 glBlendEquationSeparate 和 MAX 混合。使用 MAX 的好处是减少线条绘图代码中的重叠伪影(硬三角形位) - 例如替换颜色,但仅在达到总 alpha 值 X 之前。 编辑:这两种情况都需要在每次笔画后进行混合和清除。
我只能假设将渲染纹理混合到背景上确实有效。(不适用于当前图层值)
在旁注中,基本上不相关,还有“Under Blending”,您可以在其中保留透射率值而不是 alpha/不透明度(来自 here):
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_DST_ALPHA, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);