SpriteKit Texture Atlas vs Image xcassets

Robię grę i zauważyłem, że podczas niektórych scen moje FPS spadały wokół obszaru 55-60fps (używając atlasu tekstur). To doprowadzało mnie do szału, więc postanowiłem umieścić wszystkie moje aktywa na zdjęciach.xcassets folder i voila, stały 60FPS.

Myślałem, że to przypadek lub że robię coś źle, więc postanowiłem rozpocząć nowy projekt i wykonać kilka benchmarków...


Dokumentacja Apple mówi, że używanie texture atlas poprawi wydajność aplikacji. Zasadniczo, umożliwienie aplikacji korzystania z renderowania wsadowego. Jednak...

Test ( https://github.com/JRam13/JSGlitch):

- (void)runTest
{
    SKAction *spawn = [SKAction runBlock:^{

        for (int i=0; i<10; i++) {


            SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];

            sprite.xScale = 0.5;
            sprite.yScale = 0.5;
            sprite.position = CGPointMake(0, [self randomNumberBetweenMin:0 andMax:768]);

            SKAction *action = [SKAction rotateByAngle:M_PI duration:1];

            [sprite runAction:[SKAction repeatActionForever:action]];

            SKAction *move = [SKAction moveByX:1200 y:0 duration:2];

            [sprite runAction:move];

            //notice I don't remove from parent (see test2 below)
            [self addChild:sprite];

        }

    }];

    SKAction *wait = [SKAction waitForDuration:.1];

    SKAction *sequence = [SKAction sequence:@[spawn,wait]];
    SKAction *repeat = [SKAction repeatActionForever:sequence];

    [self runAction:repeat];
}

Wyniki:

Tutaj wpisz opis obrazka

Testy wielokrotnie pokazują, że korzystanie z xcassets wypadło znacznie lepiej niż odpowiednik atlas w FPS. Atlas wydaje się zarządzać pamięcią nieznacznie lepiej niż xcassets choć.

Ktoś wie, dlaczego te wyniki pokazują, że obrazy.xcassets ma lepszą wydajność niż atlas?


Kilka hipotez, które wymyśliłem:

    Xcassets jest po prostu lepiej zoptymalizowany niż atlasy.
  • atlasy są dobre w rysowaniu wielu obrazów w jednym przebiegu losowania, ale mają większe koszty z powtarzającymi się Sprite ' ami. Jeśli to prawda, oznacza to, że jeśli twój sprite pojawi się wiele razy na ekranie (tak było w mojej oryginalnej grze), lepiej jest usunąć go z atlasu.
  • arkusze atlasu muszą być wypełnione w celu optymalizacji wydajność

Update

Do następnego testu poszedłem naprzód i usunąłem sprite z rodzica po tym, jak zniknie z ekranu. Użyłem również 7 różnych obrazów. Powinniśmy zauważyć ogromny wzrost wydajności przy użyciu atlasu ze względu na liczbę remisów, ale...

Tutaj wpisz opis obrazka

Author: Jonny Ramos, 2014-08-11

1 answers

Najpierw popraw swój test, aby dopasować to:

    for (int i=0; i<10; i++) {


        SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];

        sprite.xScale = 0.5;
        sprite.yScale = 0.5;
        float spawnY = arc4random() % 768;
        sprite.position = CGPointMake(0, spawnY);

        SKAction *action = [SKAction rotateByAngle:M_PI duration:1];

        [sprite runAction:[SKAction repeatActionForever:action]];


        SKAction *move = [SKAction moveByX:1200 y:0 duration:2];

        // next three lines replace the runAction line for move
        SKAction *remove = [SKAction removeFromParent];
        SKAction *sequence = [SKAction sequence:@[move, remove]];
        [sprite runAction:sequence];

        [self addChild:sprite];

    }
Powtórz testy, a zauważysz, że liczba klatek na sekundę nigdy się nie pogarsza. Twoje testy zasadniczo obrazowały, co się dzieje, gdy nigdy nie usuwasz węzłów, ale wciąż tworzysz nowe.

Następnie dodaj następującą linię do kontrolera ViewController po skonfigurowaniu widoku skview:

skView.showsDrawCount = YES;

To pozwoli Ci zobaczyć liczbę remisów i prawidłowo zrozumieć, gdzie uzyskujesz wzrost wydajności z SKTextureAtlas.

Teraz , zamiast mieć tylko jeden obraz, zebrać 3 obrazy i zmodyfikować test, wybierając losowy jeden z tych obrazów za każdym razem, gdy tworzy węzeł, możesz zrobić coś takiego:

 NSArray *imageNames = @[@"image-0", @"image-1", @"image-2"];
 NSString *imageName = imageNames[arc4random() % imageNames.count];

W kodzie utwórz swój sprite z tą nazwą obrazu za każdym razem przez pętlę. ie:

SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:imageName];

W teście SKTextureAtlas, użyj tej samej nazwy obrazka oczywiście, aby utworzyć każdy sprite.

Teraz... powtórz swoje testy i zanotuj liczbę losowań w każdym test.

To powinno dać namacalny przykład na czym polega renderowanie wsadowe za pomocą SKTextureAtlas.

Nie chodzi o renderowanie tego samego obrazu sprite ' a tysiące razy.

Chodzi o rysowanie wielu różnych obrazów sprite ' ów w tym samym przebiegu losowania.

Prawdopodobnie istnieje pewien narzut w uzyskaniu tej optymalizacji renderowania, ale myślę, że liczba losowań powinna być sama w sobie wyjaśniająca, dlaczego ten narzut jest sporny, gdy wszystkie rzeczy są brane pod uwagę.

Teraz możesz hipotez jeszcze:)

UPDATE

Jak wspomniano w komentarzach, mój post miał na celu ujawnienie, dlaczego twój test nie był dobrym testem na korzyści płynące z SKTextureAtlas i był wadliwy, jeśli chce analizować go w znaczący sposób. Twój test był jak test na odrę ze świnką.

Poniżej znajduje się projekt github, który zebrałem, aby wskazać, gdzie sktextureatlas jest odpowiedni i rzeczywiście lepszy od xcassets.

Atlas-porównanie

Po prostu uruchom projekt na urządzeniu, a następnie dotknij, aby przełączać się między testami. Możesz powiedzieć, kiedy testuje się z SKTextureAtlas, ponieważ liczba losowań będzie wynosić 1, a liczba klatek na sekundę będzie wynosić 60 klatek na sekundę.

Wyizolowałem to, co zostanie zoptymalizowane za pomocą SKTextureAtlas. Jest to animacja 60 klatek i 1600 węzłów odtwarzających tę animację. Wyrównuję ich ramki startowe tak, że wszystkie nie są na tej samej ramce w tym samym czasie. Zatrzymałem też wszystko. jednolite dla obu testów, tak aby było to bezpośrednie porównanie.

To nie jest dokładne, aby ktoś myślał, że używanie SKTextureAtlas po prostu zoptymalizuje wszystkie renderowanie. Optymalizacja polega na zmniejszeniu liczby losowań poprzez renderowanie wsadowe. Tak więc, jeśli spowolnienie liczby klatek na sekundę nie jest czymś, co można poprawić poprzez renderowanie wsadowe, SKTexture atlas jest niewłaściwym narzędziem do tego zadania. prawda ?

Podobne do łączenia obiektów, gdzie można uzyskać optymalizację poprzez Nie tworzenie i zabijanie swojej gry obiekty stale, ale zamiast tego wykorzystuj je ponownie z puli obiektów. Jednak jeśli nie są stale tworzenia i zabijania obiektów w grze, pooling nie będzie optymalizacji gry.

Bazując na tym, co opisałeś w dzienniku dyskusyjnym jako problem Twojej gry, pooling jest prawdopodobnie odpowiednim narzędziem do tego zadania w Twoim przypadku.

 14
Author: prototypical,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-12 06:00:23