OpenGL ES iPhone - 画抗锯齿线条

41

通常情况下,你会使用类似以下的代码:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);

glLineWidth(2.0f);

glVertexPointer(2, GL_FLOAT, 0, points);
glEnableClientState(GL_VERTEX_ARRAY);

glDrawArrays(GL_LINE_STRIP, 0, num_points);

glDisableClientState(GL_VERTEX_ARRAY);

在 iPhone 模拟器上看起来很好,但在 iPhone 上线条变得非常细而且没有任何抗锯齿。

如何在 iPhone 上实现抗锯齿效果?


你可以将它们呈现为别名行,然后应用 Bloom 过滤器 - bobobobo
@bobobobo 这个链接已经失效了。 - TomSawyer
7个回答

62

使用透明度为0的顶点可以廉价地实现抗锯齿效果。以下示例图说明:

alt text

与AA的比较:

alt text

您可以在此处阅读有关此内容的论文:

http://research.microsoft.com/en-us/um/people/hoppe/overdraw.pdf

您可以按照以下方式进行操作:

// Colors is a pointer to unsigned bytes (4 per color).
// Should alternate in opacity.
glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
glEnableClientState(GL_COLOR_ARRAY);

// points is a pointer to floats (2 per vertex)
glVertexPointer(2, GL_FLOAT, 0, points);
glEnableClientState(GL_VERTEX_ARRAY);

glDrawArrays(GL_TRIANGLE_STRIP, 0, points_count);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);

6
有没有类似的东西(但更简单)可以用于绘制反锯齿线条 - 例如,用于绘制方程图形等。?换句话说,对于使用GL_TRIANGLE_STRIP而非GL_LINE_STRIP进行绘制的情况。我正在绘制的一切都看起来像是像素化的。我正在探索使用GL_POINT_SPRITE_OES(参考苹果的GLPaint示例代码),但这意味着需要为每个像素位置创建点...至少我是这样认为的。我希望让OpenGL-ES为我做插值。 - westsider
无法理解颜色、点等是什么。您能否直接在画圆的示例中展示一下? - TomSawyer

26

从开始,您可以使用几行额外的代码来为整个OpenGL ES场景启用反锯齿功能,这是一个简单的解决方案。(至少在SGX GPU上几乎没有性能损失)。

请阅读以下苹果Dev-Forum帖子获取源代码。同时,您还可以在我的博客上查看示例图片。


2
谢谢您发布这个问题:我差点根据SO上旧的答案开始编写一些非常晦涩的代码。 - benzado
2
您的苹果开发者论坛帖子链接已失效:我收到了一个错误页面。 - Kyle Fox
对我来说可以运行,记得你必须登录你的开发者账户才能查看论坛。 - Bersaelor
对我来说也不起作用。我有一个付费的iPhone开发者账户,但我无法登录苹果开发者论坛(任何一个)。 - mm24
可能需要在获得iOS开发者账户后再次注册论坛。这件事情已经很久以前了,所以我不记得具体细节了。我只是又登录了一次,帖子本身没问题,论坛也可以访问。 - Bersaelor

6
使用http://answers.oreilly.com/topic/1669-how-to-render-anti-aliased-lines-with-textures-in-ios-4/作为起点,我成功地获得了如下的抗锯齿线条效果: alt text 虽然它们并不完美,也没有使用Core Graphics绘制出来的线条那么漂亮,但它们还是相当不错的。实际上,我会将同一条线(顶点)绘制两次——一次用较大的纹理和颜色,另一次用较小的纹理和半透明白色。
当线条重叠过于紧密且alpha值开始积累时,就会产生一些伪影。

也许可以通过设置自定义混合函数来修复alpha? - jv42

4

解决这个限制的一种方法是将您的线条分割成纹理化的三角形带(见此处)。


3
问题在于iPhone上的OpenGl渲染到一个帧缓冲对象而不是主帧缓冲区,据我所知,FBO不支持多重采样。
有各种技巧可以尝试,比如将渲染大小增加一倍并渲染到另一个FBO中,然后依靠纹理滤波来平滑处理,但我没有尝试过,无法评论其效果。

我在OpenGL方面真的很菜。你知道我可以在哪里了解更多关于这个方法吗? - quano

2

我非常明确地记得,使用OpenGL在iPhone上没有简单的方法来实现这一点。您可以使用CGPaths和CGContextRef进行绘制,但速度会显着变慢。


我听说Quartz基本上是OpenGL的包装器。如果Quartz可以做到,你也应该能够在OpenGL中做到。CGPaths如何实现AA?我正在使用一个基于OpenGL的游戏引擎叫做Cocos2D。据我所知,你不能使用Quartz在Cocos2d层中进行绘制。 - quano
我熟悉Cocos2D。你可以随时绘制到CGImage,并从该图像创建纹理以在TextureNode中绘制。虽然我不能确定,但我不认为CGContext的方法在绘制时依赖于OpenGL。绘制完成后,该图像很可能由Quartz管理,并使用OpenGL显示。 - Ed Marty
谢谢Ed,我尝试了这种方法。与OpenGL相比,它真的很慢。如果你只需要每秒绘制一次,那么可能会起作用,但如果你需要更频繁地绘制,那么你就完蛋了。我们在cocos2d论坛上有一个关于此问题的帖子:http://www.cocos2d-iphone.org/forum/topic/2241 - quano

0
将以下代码放入您的渲染方法并设置帧缓冲区,您将获得抗锯齿外观。
/*added*/
//[_context presentRenderbuffer:GL_RENDERBUFFER];

//Bind both MSAA and View FrameBuffers.
glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, msaaFramebuffer); 
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, framebuffer );  
// Call a resolve to combine both buffers 
glResolveMultisampleFramebufferAPPLE();   
// Present final image to screen 
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
[_context presentRenderbuffer:GL_RENDERBUFFER];
/*added*/

3
你是如何准确声明“msaaFramebuffer”的? - BlueVoodoo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接