OpenGL ES 2.0:如何提高图形精灵的帧速率? [英] OpenGL ES 2.0: How to improve frame rate of drawing sprites?

查看:112
本文介绍了OpenGL ES 2.0:如何提高图形精灵的帧速率?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个动画背景层,它建立在OpenGL ES 2.0之上,并且我使用GLKView作为图形容器,并使用GLKViewController作为控制器.对于绘图,我使用GLKBaseEffect.

I have an animated background layer that is built on top of OpenGL ES 2.0 and I am using GLKView as graphics container and GLKViewController as controller. For drawing I use GLKBaseEffect.

我介绍了一个Sprite类,该类可以将png文件作为纹理加载,操纵Sprite(SRT)以及其他一些属性,例如Alpha混合等等.

I introduced a sprite class that can load png-files as textures, manipulate the sprite (SRT) and some additional properties like alpha blending and so on.

我想知道如何优化程序,因为当显示50个大小分别为128x128 px的sprite(均具有相同的texture/png文件!)时,iPhone 4S上的帧速率降至约25 FPS.

I am wondering how I could optimise my program, since the frame-rate drops on my iPhone 4S to about 25 FPS when displaying 50 sprites (all with the same texture/png-file!) with a size of 128x128 px each.

在以下各节中,我列出了程序的重要部分.目前,我为每个帧的50个精灵中的每个叫glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)(目标帧速率为60).相当于每秒3000次通话.

In the following sections I have listed the important parts of the program. Currently I call glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) for each of the 50 sprites for each of the frames (target frame rate is 60); which is equally to 3000 calls per second.

那是瓶颈吗?我该如何优化呢?

这就是我初始化子画面数组(GLKViewController.m)的方法:

This is how I initialise the sprite array (GLKViewController.m):

- (void)initParticles {
    if(sprites==nil) {
        sprites = [NSMutableArray array];
        for (int i=0; i<50; i++) {
            Sprite* sprite = [[Sprite alloc] initWithFile:@"bubble" extension:@"png" effect:effect];
            // configure some sprite properties [abbreviated]
            [sprites addObject:sprite];
        }
    }
}

这是呈现功能(GLKViewController.m):

This is the rendering function (GLKViewController.m):

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    glClearColor(0.0, 0.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    // render the bubbles
    for (Sprite* sprite in sprites) {
        [sprite render];
    }
}

以下是Sprite类(Sprite.m)的一些重要部分:

Here are some important parts of the sprite class (Sprite.m):

- (id)initWithFile:(NSString *)filename extension:(NSString*)extension effect:(GLKBaseEffect *)effect {
    if(self = [self init]) {
        self.effect = effect;
        NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], GLKTextureLoaderOriginBottomLeft, nil];
        NSError* error = nil;
        NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:nil];
        self.textureInfo = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
        if (self.textureInfo == nil) {
            NSLog(@"Error loading file: %@", [error localizedDescription]);
            return nil;
        }
        TexturedQuad newQuad;
        newQuad.bl.geometryVertex = GLKVector2Make(0, 0);
        newQuad.br.geometryVertex = GLKVector2Make(self.textureInfo.width, 0);
        newQuad.tl.geometryVertex = GLKVector2Make(0, self.textureInfo.height);
        newQuad.tr.geometryVertex = GLKVector2Make(self.textureInfo.width, self.textureInfo.height);
        newQuad.bl.textureVertex = GLKVector2Make(0, 0);
        newQuad.br.textureVertex = GLKVector2Make(1, 0);
        newQuad.tl.textureVertex = GLKVector2Make(0, 1);
        newQuad.tr.textureVertex = GLKVector2Make(1, 1);
        self.quad = newQuad;
    }
    return self;
}

- (void)render {
    [self applyBaseEffect];
    long offset = (long)&_quad;
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void*) (offset + offsetof(TexturedVertex, geometryVertex)));
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void*) (offset + offsetof(TexturedVertex, textureVertex)));
    glBlendColor(1.0, 1.0, 1.0, self.alpha);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glDisableVertexAttribArray(GLKVertexAttribPosition);
    glDisableVertexAttribArray(GLKVertexAttribTexCoord0);
}

- (void)applyBaseEffect {
    self.effect.texture2d0.name = self.textureInfo.name;
    self.effect.texture2d0.envMode = GLKTextureEnvModeModulate;
    self.effect.texture2d0.target = GLKTextureTarget2D;
    self.effect.texture2d0.enabled = GL_TRUE;
    self.effect.useConstantColor = GL_TRUE;
    self.effect.constantColor = GLKVector4Make(self.tint.r*self.alpha, self.tint.g*self.alpha, self.tint.b*self.alpha, self.alpha);
    self.effect.transform.modelviewMatrix = GLKMatrix4Multiply(GLKMatrix4Identity, [self modelMatrix]);
    [self.effect prepareToDraw];
}

- (GLKMatrix4)modelMatrix {
    GLKMatrix4 modelMatrix = GLKMatrix4Identity;
    modelMatrix = GLKMatrix4Translate(modelMatrix, self.position.x, self.position.y, 0);
    modelMatrix = GLKMatrix4Rotate(modelMatrix, self.rotation, 0, 0, 1);
    modelMatrix = GLKMatrix4Scale(modelMatrix, self.scale, self.scale, 0);
    modelMatrix = GLKMatrix4Translate(modelMatrix, -self.normalSize.width/2, -self.normalSize.height/2, 0);
    return modelMatrix;
}

EDIT-1:以下是一些性能指标(似乎与GPU绑定)

EDIT-1: Here are some performance indicators (seems to be GPU-bound)

EDIT-2:当我添加view.drawableMultisample行时,无论我使用哪一行(无/4x),我的iPhone 4S的帧频都从25提高到45.奇怪-我的渲染代码似乎不受MSAA的影响,相反.

EDIT-2: The frame rate improved from 25 to 45 on my iPhone 4S when I added the view.drawableMultisample line regardless of which line I used (none / 4x). Strange - my rendering code seems not to be affected by MSAA, rather on the contrary.

GLKView *view = (GLKView*)self.view;
view.context = context;
view.drawableMultisample = GLKViewDrawableMultisampleNone;
//view.drawableMultisample = GLKViewDrawableMultisample4x;

推荐答案

经过另外两个小时的深入研究,我终于找到了导致性能大幅下降的原因.如评论中所述,性能下降的重要性随着视图控制器中包含的按钮的增加而增加.因为我要用圆角和阴影装饰按钮,所以我要照顾好……这是UIView类的原始类别的一部分,目的是装饰UI元素:

After another two hours intensive research I finally found the cause for the massive performance hit. As described in a comment, the significance of the performance drop grew with increasing buttons that were contained within a view controller. Since I am decorating my buttons with rounded corners and a drop shadows, I looked after that... Here's a part of my original category on the UIView class for the purpose of decorating UI elements:

#import "UIView+Extension.h"

@implementation UIView (Extension)

- (void)styleViewWithRoundedEdges:(BOOL)rounded shadowed:(BOOL)shadowed {
    if (rounded) {
        self.layer.cornerRadius = 3.0;
    }
    if (shadowed) {
        self.layer.shadowColor = [UIColor blackColor].CGColor;
        self.layer.shadowOffset = CGSizeMake(2.0, 2.0);
        self.layer.shadowOpacity = 0.25;
        self.layer.shadowRadius = 1.0;
    }
}

@end

关闭阴影后,帧速率立即变为恒定的60 FPS.

As soon as I switched off the drop shadow, the frame rate turned into constant 60 FPS.

快速搜索将我定向到此SO线程.

添加这两行可以解决问题:

Adding these two lines solved the problem:

self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = UIScreen.mainScreen.scale;

现在,在具有60 FPS的iPhone 4S上,我可以轻松地将100个精灵与线性+径向背景渐变着色器结合使用.

I now render easily 100 sprites combined with the linear+radial background gradient shader on a iPhone 4S with 60 FPS :-D.

但是非常感谢你们的耐心和帮助!让我知道何时可以退货!

But thank you guys so much for your patience and help! Let me know when I can return the favour!

这篇关于OpenGL ES 2.0:如何提高图形精灵的帧速率?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆