我认为这里有两个可能的问题。
请记住,所有覆盖线都在这里混合两次。一旦混合到FBO纹理中,并再次在场景中混合FBO纹理时。
因此,第一种可能性是,在FBO覆盖图中绘制一条线时不启用混合。当您在混合关闭的情况下绘制RGBA曲面时,当前alpha将直接写入FBO叠加层的Alpha通道。之后,当您将FBO的整个纹理融合到场景中时,该alpha会让您的线条变得透明。因此,如果您对“世界”进行混合但不在叠加元素之间进行混合,则可能不会发生混合。
另一个相关问题:当您在FBO中以“标准”混合模式(src alpha,1 - src alpha)将另一条线叠加到另一条线上时,“混合”部分的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颜色。在这种情况下,你希望它得到正确的结果,但在其他情况下,程序员使用它来提高速度。 (通过预倍增,当执行混合操作时,它消除了每个像素的多个像素)。
希望有帮助!当图层没有按顺序混合时,正确混合就变得非常棘手,单独的混合在旧硬件上不可用,因此每次简单地绘制线条可能是最不痛苦的道路。
混合应该适用于framebuffer中的任何内容。 (这是什么混合_does_)。提供更多的数据(你使用什么混合模式,你称之为混合“不正确”?) – Bahbar 2010-01-31 10:10:45
我已经更新了更多的信息,感谢您的快速回复 – staticfloat 2010-01-31 20:28:26