XNA - объединить спрайты для лучшей производительности рисования? - PullRequest
3 голосов
/ 28 октября 2009

Я где-то читал, что при рендеринге большого количества трехмерных объектов их можно объединить в гигантскую сетку, чтобы можно было сделать только один вызов рисования. Поэтому позвольте, цитата: "GPU делает свое волшебство", в то время как процессор свободен для других вызовов , кроме розыгрыша.

Итак, на мой вопрос, возможно ли это сделать в 2D-среде с производительностью в виду?

Например, скажем, у нас есть простая система плиток, и вместо того, чтобы делать вызовы рисования для каждой плитки в представлении, вместо этого объединит все плитки , чтобы сформировать большой спрайт, а затем вызвать рисование для это.

Любое понимание этого вопроса - советы, ссылки или еще что-то - очень ценится, поскольку у меня нет опыта работы с графикой.

Редактировать: Извините за мое плохое объяснение. Я создаю плитку для личного пользования и хочу, чтобы она была максимально универсальной. Поэтому я хочу оптимизировать на случай, если в ближайшем будущем мне нужно будет нарисовать много плиток.

Я делаю использование листа листов, но я имел в виду вопрос, если объединение всех плиток, которые должны быть вытянуты из листа, в новую Texture2D, получит производительность. Например:

У нас есть 128x72 плиток для рисования на экране. Вместо того, чтобы перебирать все плитки и вызывать рисование для каждой плитки, которую мы рисуем, мы объединяем все плитки в новый спрайт размером 1280x720 и рисуем его. Таким образом, метод draw () будет вызываться только один раз за кадр . Мой вопрос заключался в том, улучшит ли это производительность, как если бы 3D-объекты были объединены в одну сетку.

Поскольку информация, которую я собрал, заключается в том, что вызов draw () - это подрыв производительности, и его следует вызывать как можно меньше. Кто-нибудь подтвердит или опровергнет? :)

Ответы [ 4 ]

10 голосов
/ 29 октября 2009

У меня нет опыта работы с XNA и 3D, но я дам вам несколько советов по 2D-играм. Я потратил некоторое время на создание движка плиток в XNA в начале этого года и задумался о том же. Я думаю, что короткий ответ здесь - да, объединение ваших плиток в больший спрайт - хорошая идея, если вы беспокоитесь о производительности. Тем не менее, есть гораздо более длинный ответ, если вы заинтересованы.

В целом, когда дело доходит до оптимизации производительности, ответ почти всегда - «не делай этого». Если вы уверены, что вам нужно оптимизировать производительность, следующий ответ почти всегда - «пока не делайте». Наконец, если вы попытаетесь оптимизировать производительность, самое важное, что вы можете сделать, - это использовать тесты для сбора точных измерений производительности до и после изменений. Без этого вы не знаете, добьетесь ли вы успеха!

Теперь, когда речь шла больше о 2D-играх, я узнал, что в моем движке я вижу гораздо лучшую производительность, чем меньше я переключаю текстуры. Например, скажем, у меня есть плитка для травы и гравия. Если это две отдельные текстуры в памяти, и я рисую плитку травы, затем плитку гравия, затем плитку травы на экран, графический процессор загрузит текстуру травы, затем выключит ее, чтобы загрузить текстуру гравия, а затем переключит текстура травы обратно, чтобы нарисовать другую плитку травы. Это убивает производительность очень быстро! Самый простой способ обойти это - создать таблицу спрайтов, в которой вы поместите свои травы и гравийные плитки в одну текстуру и просто скажете SpriteBatch рисовать из разных областей на одной и той же текстуре каждый раз.

Еще одна вещь, которую нужно учитывать, это то, сколько плиток вы будете рисовать на экране одновременно. Я не помню конкретно, но я рисовал тысячи плиток одновременно (в уменьшенном виде). Я заметил, что когда я использовал плитки большего размера и нарисовал их меньше, как вы предлагаете в своем вопросе, эта производительность также улучшилась. Это не было таким большим улучшением, как то, что я описал в предыдущем абзаце, и я все равно рекомендую вам измерить изменения производительности, вызванные различными реализациями. Кроме того, если вы рисуете лишь дюжину или несколько сотен плиток, возможно, не стоит пытаться оптимизировать это прямо сейчас (см. 2-й абзац).

Просто чтобы вы знали, что я не полностью это придумываю, вот ссылка на пост от Шона Харгривза об обмене текстурами, спрайт-листах и ​​т. Д. Вероятно, есть лучшие посты на форумах XNA, а также в блоге Шона Харгривза, если Вы ищете по теме.

http://forums.xna.com/forums/p/24254/131437.aspx#131437

Обновление:

Поскольку вы обновили свой вопрос, позвольте мне обновить мой пост. Я решил просто сравнить некоторые образцы, чтобы дать вам представление о возможных различиях в производительности. В моей функции Draw () у меня есть следующее:

        GraphicsDevice.Clear(Color.CornflowerBlue);

        Stopwatch sw = new Stopwatch();
        sw.Start();

        spriteBatch.Begin();

#if !DEBUG
        spriteBatch.Draw(tex, new Rectangle(0, 0, 
                         GraphicsDevice.Viewport.Width,
                         GraphicsDevice.Viewport.Height), 
                         Color.White);            
#else
        for (int i = 0; i < 128; i++)
            for (int j = 0; j < 72; j++)
            {
                Rectangle r = new Rectangle(i * 10, j * 10, 10, 10);
                spriteBatch.Draw(tex, r, r, Color.White);
            }
#endif
        spriteBatch.End();

        sw.Stop();

        if (draws > 60)
        {
            numTicks += sw.ElapsedTicks;
        }
        draws++;

        if (draws % 100 == 0)
            Console.WriteLine("avg ticks: " + numTicks / (draws - 60));

        base.Draw(gameTime);

Просто опустите восклицательный знак в операторе "#if! DEBUG", чтобы переключиться между двумя методами. Я пропустил первые 60 розыгрышей, потому что они включали некоторую начальную настройку (не совсем уверен, что) и искажали средние значения. Я скачал одно изображение 1280x720, и для верхнего контрольного примера я просто нарисовал его один раз. Для нижнего контрольного примера я нарисовал одно исходное изображение размером 128x72, как вы и задали в своем вопросе. Вот результаты.

Рисование одного изображения:

avg ticks: 68566
avg ticks: 73668
avg ticks: 82659
avg ticks: 81654
avg ticks: 81104
avg ticks: 84664
avg ticks: 86626
avg ticks: 88211
avg ticks: 87677
avg ticks: 86694
avg ticks: 86713
avg ticks: 88116
avg ticks: 89380
avg ticks: 92158

Рисование 128x72 плиток:

avg ticks: 7902592
avg ticks: 8052819
avg ticks: 8012696
avg ticks: 8008819
avg ticks: 7985545
avg ticks: 8028217
avg ticks: 8046837
avg ticks: 8291755
avg ticks: 8309384
avg ticks: 8336120
avg ticks: 8320260
avg ticks: 8322150
avg ticks: 8381845
avg ticks: 8364629

Как вы можете видеть, разница между ними на пару порядков, так что она довольно значительная. Тестировать подобные вещи довольно просто, и я бы порекомендовал вам запустить собственные тесты для своей конкретной установки, чтобы учесть то, что я мог пропустить.

3 голосов
/ 29 октября 2009

Чем меньше графическая карта должна переключать текстуры, тем выше производительность. Вы можете сортировать по текстуре в методе SpriteBatch.Begin (), если хотите, чтобы графическая карта переключала текстуры как можно меньше.

Я кладу свои плитки / спрайты в листы, когда это имеет смысл. Например, один символ может быть на листе, а один слой плиток может быть на одном листе. До сих пор это работало довольно хорошо.

Я бы сказал, что не оптимизируйте, пока вам не придется. Если ваши игры запускаются достаточно быстро, поэтому стоит заняться оптимизацией.

1 голос
/ 18 октября 2012

Прямоугольник r = новый прямоугольник (i * 10, j * 10, 10, 10);

Создание множества новых объектов вызовет сборку мусора, которая может сильно замедлиться! Вы не должны размещать новые объекты в больших циклах:

0 голосов
/ 16 августа 2010

Производительность не является универсальным императивом или заповедью от Бога; это средство для достижения цели. Если то, что у вас есть, работает достаточно хорошо, вам буквально нечего улучшать. Поддержание «наилучшей возможной производительности в любое время» - это определение преждевременной оптимизации, и оно вызовет больше головной боли, чем предотвращает.

...