我使用 OpenGL ES 在 iPhone 4S 上为每一帧绘制了 2560 个非常纤细的多边形。问题是我的帧率在 30 左右,这对我的口味来说不够流畅。我认为它应该比这更快。
那正确吗?
请帮助我找出可以改进的地方。
更新:我在主线程上进行渲染。关于执行渲染操作的线程是否有任何建议?
一点背景:我正在尝试在 iPhone 视图坐标中制作大小为 320x200 的平滑滚动(目标是 60 FPS)波形,因此在视网膜显示器上为 640x400 像素。我的测试设备是 iPhone 4S。在 iOS 6 和 6.1 中,我可以通过正常的 UIKit 绘图操作轻松实现这一点。然而,由于我将设备更新到 iOS 7,它变得慢了很多,所以我决定使用 OpenGL ES,因为我读了很多次,它可以更快地进行 2D 绘图。
我使用 OpenGL ES 2.0 实现了绘制波形,但现在它在设备上比使用 UIKit 快一点。和 UIKit 一样,速度很大程度上取决于被绘制的像素数,这让我想知道发生了什么。
波形由条形/矩形组成,每个矩形的宽度正好是 1 个像素。我每像素列绘制两个条,每个条由两个多边形组成,这意味着我为每帧绘制 1280 个条或 2560 个多边形。多边形非常纤细。它们中的每一个的宽度最多为 1 个像素。我认为使用 OpenGL ES 以 60FPS 绘制应该没问题。
我画一个这样的条:
- (void) glFillRect: (Float32)x0 : (Float32)y0 : (Float32)x1 : (Float32)y1 {
glEnableVertexAttribArray(GLKVertexAttribPosition);
GLfloat vertices[8];
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, 0, vertices);
GLfloat* vp = vertices;
*vp++ = x0; *vp++ = y0;
*vp++ = x1; *vp++ = y0;
*vp++ = x0; *vp++ = y1;
*vp++ = x1; *vp++ = y1;
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(GLKVertexAttribPosition);
}
调用上述方法的代码如下。_maxDrawing
和 _avgDrawing
是我的效果,在应用启动时是这样组成的:
_maxDrawing = [[GLKBaseEffect alloc] init];
_maxDrawing.useConstantColor = GL_TRUE;
_maxDrawing.constantColor = GLKVector4Make(0.075f, 0.1f, 0.25f, 1.0f);
我后来调整了投影矩阵,使我的 OpenGL ES 绘图坐标与我的视图的视图坐标对齐,这是 2D 绘图的标准方法。
[_maxDrawing prepareToDraw];
x_Cu = [self transformViewXToWaveformX:rect.origin.x];
for (Float32 x_Vu = rect.origin.x; x_Vu < viewEndX_Vu; x_Vu += onePixelInViewUnits) {
x_Cu += onePixelInContentUnits;
if (x_Cu < 0 || x_Cu >= waveformEndX_Cu) {
continue;
}
SInt64 frameIdx = (SInt64) x_Cu;
CBWaveformElement element;
element = [self.dataSource getElementContainingFrame:frameIdx];
prevMax = curMax;
curMax = futureMax;
futureMax = element.max;
smoothMax = prevMax * 0.25 + curMax * 0.5 + futureMax * 0.25;
if (smoothMax < curMax)
smoothMax = curMax;
Float32 barHeightHalf = smoothMax * heightScaleHalf;
Float32 barY0 = viewHeightHalf - barHeightHalf;
Float32 barY1 = viewHeightHalf + barHeightHalf;
[self glFillRect: x_Vu : barY0 : x_Vu + onePixelInViewUnits : barY1];
}
[_avgDrawing prepareToDraw];
x_Cu = [self transformViewXToWaveformX:rect.origin.x];
for (Float32 x_Vu = rect.origin.x; x_Vu < viewEndX_Vu; x_Vu += onePixelInViewUnits) {
x_Cu += onePixelInContentUnits;
if (x_Cu < 0 || x_Cu >= waveformEndX_Cu) {
continue;
}
SInt64 frameIdx = (SInt64) x_Cu;
CBWaveformElement element;
element = [self.dataSource getElementContainingFrame:frameIdx];
Float32 barHeightHalf = element.avg * heightScaleHalf;
Float32 barY0 = viewHeightHalf - barHeightHalf;
Float32 barY1 = viewHeightHalf + barHeightHalf;
[self glFillRect: x_Vu : barY0 : x_Vu + onePixelInViewUnits : barY1];
}
当我取出所有的 OpenGL 调用时,一帧的执行时间约为 1 毫秒,这意味着它理论上可以达到 1000 FPS。所有其他时间(大约 33 毫秒)都用于绘图。