我认为这里可能有两个问题。
请记住,所有叠加线都会混合两次。一次是在它们混合到 FBO 纹理时,另一次是在 FBO 纹理覆盖场景时混合。
因此,第一个可能的问题是在 FBO 叠加层中绘制一条线覆盖另一条线时,您没有启用混合。当您使用关闭混合的 RGBA 表面进行绘制时,当前 alpha 直接写入 FBO 叠加层的 alpha 通道中。然后稍后当整个 FBO 纹理覆盖在场景上时,该 alpha 使您的线条半透明。因此,如果您针对“世界”进行混合,但不进行叠加元素之间的混合,则可能不会发生混合。
另一个相关的问题:在 FBO 中以“标准”混合模式(src alpha,1 - src alpha)混合一条线覆盖另一条线时,“混合”部分的 alpha 通道将包含两个叠加元素的 alpha 的混合。这可能不是您想要的。
例如,如果您在叠加层中绘制两条 50% 的 alpha 线,那么在复制 FBO 时,您需要 FBO 的 alpha 是 ...75%。也就是说,1 -(1-.5)*(1-0.5),这是当您在场景中绘制两条 50% 的 alpha 线时会发生的情况。但是当您绘制两条 50% 的线时,您将在 FBO 中获得 50% 的 alpha(50% 与...50% 的混合。
这带来了最后一个问题:通过在将它们混合到世界之前彼此预混合叠加层,您正在更改绘制顺序。尽管您可能会有:
blend(blend(blend(background color, model), first line), second line);
现在您将会有:
blend(blend(first line, second line), blend(background color, model))。
换句话说,在 FBO 中预混合叠加线会更改混合顺序,从而以您可能不希望的方式更改最终外观。
首先,解决这个问题的简单方法是:不要使用帧缓冲对象(FBO)。我知道这是一个“重新设计应用程序”的答案,但是使用FBO并不是最便宜的选择,而现代GL卡在绘制线条方面非常出色。所以一个选择是:将线条几何图形写入顶点缓冲对象(VBO)而不是混合到FBO中。每次简单地扩展一下VBO即可。如果您一次绘制的线条少于,比如说,40,000条,那么这几乎肯定和之前做的一样快。
(如果您采取这种方法,请注意一个提示:使用glBufferSubData将线条写入VBO,而不是使用glMapBuffer - 在许多驱动程序上,映射可能很昂贵,并且不能在子范围上工作... 最好只是让驱动程序复制一些新的顶点。)
如果这不是一个选项(例如,如果您绘制了混合各种类型的形状或使用了混合各种GL状态,以至于“记住”您所做的事情比累积顶点更加复杂),那么您可能需要改变将图形绘制到VBO的方式。
基本上,您需要启用分离混合;将覆盖层初始化为黑色+0%的alpha(0,0,0,0),并按标准混合RGB和叠加混合alpha通道进行混合。这对于alpha通道仍然不是完全正确的,但通常更接近 - 如果没有这样做,则过度绘制区域将过于透明。
然后,在绘制FBO时,使用“预乘”alpha,即(一,一减源alpha)。
这是为什么需要最后一步:当您绘制到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颜色中。在这种情况下,您希望获得正确的结果,但在其他情况下,程序员使用它来提高速度。(通过预乘法,当执行混合操作时,每个像素上就可以少一次乘法运算。)
希望这能帮助到您!当图层未按顺序混合并且旧硬件上不可用单独混合时,正确地进行混合变得非常棘手,因此每次简单地绘制线条可能是最不痛苦的方法。