我认为这里有两个可能的问题。
请记住,所有覆盖线在这里混合了两次。一次是当它们混合到 FBO 纹理中时,另一次是当 FBO 纹理混合到场景中时。
因此,第一种可能性是在 FBO 叠加层中将一条线绘制到另一条线上时您没有启用混合。当您在关闭混合的情况下绘制到 RGBA 表面时,当前的 alpha 会直接写入 FBO 叠加层的 alpha 通道。然后稍后当您在场景中混合整个 FBO 纹理时,该 alpha 使您的线条半透明。因此,如果您对“世界”进行了混合,但没有在叠加元素之间进行混合,则可能没有发生混合。
另一个相关问题:当您在 FBO 中以“标准”混合模式(src alpha,1 - src alpha)将一条线混合到另一条线时,“混合”部分的 alpha 通道将包含两个覆盖元素。这可能不是你想要的。
例如,如果您在叠加层中相互绘制两条 50% 的 alpha 线,为了在对 FBO 进行 blit 时获得等效效果,您需要 FBO 的 alpha 为...75%。(即 1 - (1-.5) * (1-0.5),如果您只在场景上绘制两条 50% 的 alpha 线会发生这种情况。但是当您绘制两条 50% 的线时,您将在 FBO 中获得 50% 的 alpha(50% 与...50% 的混合。
这就引出了最后一个问题:通过在将它们混合到世界各地之前将它们预先混合在一起,您正在改变绘制顺序。而你可能有:
混合(混合(混合(背景颜色,模型),第一行),第二行);
现在你将拥有
混合(混合(第一行,第二行),混合(背景颜色,模型))。
换句话说,将覆盖线预混合到 FBO 中会改变混合顺序,从而以您可能不想要的方式改变最终外观。
首先,解决这个问题的简单方法:不要使用 FBO。我意识到这是一种“去重新设计你的应用程序”的答案,但使用 FBO 并不是最便宜的,而且现代 GL 卡非常擅长绘制线条。所以一种选择是:不是将线条混合到 FBO 中,而是将线条几何图形写入顶点缓冲区对象 (VBO)。每次只需将 VBO 扩展一点。如果您一次绘制少于 40,000 条线,这几乎肯定会与您之前所做的一样快。
(如果你走这条路,一个提示:使用 glBufferSubData 写入行,而不是 glMapBuffer - 映射可能很昂贵,并且不适用于许多驱动程序的子范围......最好让驱动程序复制几个新顶点.)
如果这不是一个选项(例如,如果您绘制混合形状类型或使用混合 GL 状态,这样“记住”您所做的事情比仅仅累积顶点要复杂得多),那么您可能想要改变你进入 VBO 的方式。
基本上你需要做的是启用单独的混合;将叠加层初始化为黑色 + 0% alpha (0,0,0,0) 并通过“标准混合”RGB 进行混合,但添加混合 Alpha 通道。这对于 Alpha 通道仍然不太正确,但通常更接近 - 没有这个,过度绘制的区域将太透明。
然后,在绘制 FBO 的时候,使用“预乘”的 alpha,即 (one, one-minus-src-alph)。
这就是为什么需要最后一步的原因:当您绘制到 FBO 中时,您已经将每个绘制调用乘以其 alpha 通道(如果混合已打开)。由于您在黑色上绘制,因此绿色 (0,1,0,0.5) 线现在是深绿色 (0,0.5,0,0.5)。如果 alpha 打开并且您再次正常混合,则重新应用 alpha 并且您将拥有 0,0.25,0,0.5。)。只需按原样使用 FBO 颜色,就可以避免第二次 alpha 乘法。
这有时被称为“预乘”alpha,因为 alpha 已经乘以 RGB 颜色。在这种情况下,您希望它得到正确的结果,但在其他情况下,程序员使用它来提高速度。(通过预乘,它在执行混合操作时每像素删除一个 mult。)
希望有帮助!当图层没有按顺序混合时正确混合变得非常棘手,并且在旧硬件上不提供单独的混合,因此每次简单地绘制线条可能是最不痛苦的路径。