2

我正在尝试编写一个GPUImageFilter子类,它可能会呈现数千个羽毛圆圈(是的,它是笔触)。我目前的方法包括一个glDrawArrays绘制一吨正方形的调用,以及一个顶点属性,每个顶点属性通知片段着色器每个的质心在哪里,以便着色器可以绘制一个圆,其 alpha 值向边缘逐渐变细(最远质心)。

这在我的测试设备(iPad Mini)上非常快,除非有(a)超过 1,000 个圆圈或(b)圆圈真的很大。多边形很快,但着色器速度很快。

我想知道将圆圈直接渲染到字节缓冲区是否会更快,并让 GPUImage(使用GPUImageRawDataInput)尽可能地抓取字节以渲染(通过其他过滤器)到屏幕。

Accelerate 框架是我知道如何在 iOS 上操作字节的最快方法。例如,我发现我可以使用以下方法非常快速地用 vDSP 填充 RGBA 缓冲区:

const int iValue = [RGBA colour as int];

vDSP_vfilli(&iValue, (int*)bytes, 1, width * height);

谁能建议我如何使用vDSPorvImage函数集将羽化圆渲染到我的字节缓冲区中?唯一能想到的方法涉及太多for循环而无法执行。

4

2 回答 2

3

要绘制许多羽化圆,您可能找不到比使用许多四边形和片段着色器更好的方法。您在这里似乎遇到的性能问题是需要在单个帧中将任意数量的重叠圆形元素混合在一起。您不仅要处理大量并行像素,而且还有大量可能影响每个像素的圆。

我在 Molecules 应用程序中遇到了类似的问题,并在这个问题中询问了如何调整我的着色器。在分子的情况下,我正在绘制棱角分明的球体冒名顶替者,但我仍然需要将数千个或非常大的尺寸混合在一起。

您可以立即采取一些措施来提高片段着色器的性能(不幸的是,如果没有您正在使用的代码,我只能猜测您是否正在这样做)。首先,如果着色器中有分支,请移除分支。使用step()(最有可能smoothstep()在您的情况下)替换 if 语句。其次,将你能做的任何计算转移到你的顶点着色器。顶点着色器只为您的四边形的每个顶点运行一次,而不是您的片段着色器每个像素运行一次。我为四个顶点中的每一个传递了一个标准化的 -1,-1 到 1,1 坐标,这使得在我的片段着色器中计算到中心点的距离变得更简单。

禁用混合极大地加快了这些设备上的渲染速度,但我认为您在这里无法做到这一点。您可能可以使用 iOS 6 中的新帧缓冲区获取操作做一些聪明的事情来提高混合性能,但我不确定这是否会有所帮助。

到目前为止,最大的性能胜利将来自于尝试减少你需要做的绘图量。在我的例子中,我能够在我的球体冒名顶替者所在的位置后面绘制一系列不透明的正方形(最终迭代中的八边形),并使用深度缓冲区丢弃在任何条件下都不可见的像素。这导致性能提高了 6 倍。如果您的圈子的某些部分是不透明的,您也许可以像这样进行预通行证。

不过,鉴于这是一个笔触,在我看来,您应该能够进行更简单的优化,因为您只绘制从帧到帧发生变化的任何内容。您绘制的画笔图像的旧版本可以存储到仅使用新画笔笔触绘制的平面纹理中(并再次保存为存储的纹理)。您不需要为每一帧重新绘制所有笔触,这应该会显着减少渲染负载。

于 2013-09-20T16:22:49.913 回答
0

使用 vImage 有几种方法可以做到这一点,但没有打算这样做——它不做矢量图形——所以你最好将缓冲区变成 CGbitmapContext 并使用 CG 在其中绘制圆圈,或使用 Brad Larson 已经建议的各种方法。

无论如何,为了完整起见,如果所有圆圈的大小和颜色都相同,您可以绘制一个圆圈,然后使用 vImage/Alpha.h 中的 alpha 混合函数之一重复将其合成到位。我想 vImageDilate 会将黑场上的亮点扩展为任意形状,包括圆形,但这可能很昂贵,可能非常昂贵。不过,它可以让您更好地控制颜色。同样,各种卷积可能会以圆形图案模糊亮点。如果其中任何一种方法,我都会感到非常惊讶,除了 alpha 方法可能比 CG 更快。

于 2014-09-10T05:06:50.847 回答