我正在努力将单个像素绘制到a UIView
来创建分形图像.我的问题是我的渲染速度.我目前正在运行此循环260,000次,但想渲染更多像素.实际上,在iPad Mini上运行大约需要5秒钟.
我UIBezierPath
之前使用的是,但这甚至有点慢(大约7秒).我一直在寻找NSBitMap
东西,但我不确定这是否会加速它或如何实现它.
我还在考虑尝试将我的循环中的像素存储到一个数组中,然后在循环后将它们全部绘制在一起.尽管如此,我不太确定存储然后从数组中检索像素的最佳过程是什么.
任何加速这个过程的帮助都会很棒.
for (int i = 0; i < 260000; i++) { float RN = drand48(); for (int i = 1; i < numBuckets; i++) { if (RN < bucket[i]) { col = i; CGContextSetFillColor(context, CGColorGetComponents([UIColor colorWithRed:(colorSelector[i][0]) green:(colorSelector[i][1]) blue:(colorSelector[i][2]) alpha:(1)].CGColor)); break; } } xT = myTextFieldArray[1][1][col]*x1 + myTextFieldArray[1][2][col]*y1 + myTextFieldArray[1][5][col]; yT = myTextFieldArray[1][3][col]*x1 + myTextFieldArray[1][4][col]*y1 + myTextFieldArray[1][6][col]; x1 = xT; y1 = yT; if (i > 10000) { CGContextFillRect(context, CGRectMake(xOrigin+(xT-xMin)*sizeScalar,yOrigin-(yT-yMin)*sizeScalar,.5,.5)); } else if (i < 10000) { if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } } else if (i == 10000) { if (xMax - xMin > yMax - yMin) { sizeScalar = 960/(xMax - xMin); yOrigin=1000-(1000-sizeScalar*(yMax-yMin))/2; } else { sizeScalar = 960/(yMax - yMin); xOrigin=(1000-sizeScalar*(xMax-xMin))/2; } } }
编辑
我创建了一个多维数组来存储UIColors,所以我可以使用位图来绘制我的图像.它明显更快,但我的颜色现在不能正常工作.
这是我将UIColors存储到数组中的位置:
int xPixel = xOrigin+(xT-xMin)*sizeScalar; int yPixel = yOrigin-(yT-yMin)*sizeScalar; pixelArray[1000-yPixel][xPixel] = customColors[col];
这是我的绘图材料:
CGDataProviderRef provider = CGDataProviderCreateWithData(nil, pixelArray, 1000000, nil); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGImageRef image = CGImageCreate(1000, 1000, 8, 32, 4000, colorSpace, kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipLast, provider, nil, //No decode NO, //No interpolation kCGRenderingIntentDefault); // Default rendering CGContextDrawImage(context, self.bounds, image);
不仅颜色不是它们应该是的颜色,而且每次渲染我的图像时,颜色都与前一次完全不同.我一直在用颜色测试不同的东西,但我仍然不知道为什么颜色是错误的,而且我更加困惑他们如何不断变化.
每像素绘图 - 每个像素的复杂计算,如分形渲染 - 是您可以要求计算机执行的最难的事情之一.这里的每个其他答案都涉及其难度的一个方面,但这并不是全部.(幸运的是,这种渲染也是现代硬件优化的东西,如果你知道要问什么.我会做到的.)
@jcaron和@JustinMeiners都注意到CoreGraphics中的矢量绘图操作(甚至是矩形填充)会对基于CPU的光栅化造成损失.操纵位图数据的缓冲区会更快,但速度要快得多.
将缓冲区放到屏幕上也需要时间,特别是如果你不得不经历一个创建位图图像缓冲区然后在CG上下文中绘制它们的过程 - 那就是在CPU上进行大量的顺序绘图工作内存带宽可以复制该缓冲区.所以@JustinMeiners是正确的,直接访问GPU纹理内存将是一个很大的帮助.
但是,如果你仍在用CPU代码填充你的缓冲区,你仍然会受到两个成本的阻碍(充其量,如果你天真地这样做会更糟):
顺序工作以渲染每个像素
渲染时从纹理内存到帧缓冲区的内存传输成本
@JustinMeiners的回答对他的用例很有用 - 图像序列是预先渲染的,所以他确切地知道每个像素将是什么,他只需将其转换为纹理记忆.但是您的用例需要大量的每像素计算.
幸运的是,每像素计算是GPU的设计目标!欢迎来到像素着色器的世界.对于屏幕上的每个像素,您可以运行一个独立的计算来确定该点与分形集之间的关系,从而确定绘制它的颜色.可以同时为多个像素并行运行该计算,并且输出直接进入屏幕,因此没有内存开销将位图转储到帧缓冲区.
在iOS上使用像素着色器的一种简单方法是SpriteKit - 它可以为您处理大部分必要的OpenGL/Metal设置,因此您需要编写的是GLSL中的每像素算法(实际上,GLSL的子集是在Metal支持的设备上自动翻译为金属着色器语言).这是一个很好的教程,这是另一个关于iOS的OpenGL ES像素着色器.