XNA - Объединение спрайтов для повышения производительности рисования?

StackOverflow https://stackoverflow.com/questions/1637086

  •  06-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

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

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

Это было полезно?

Решение

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

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

Теперь, больше касаясь 2D-игр, я узнал, что чем меньше я переключал текстуры, тем выше производительность моего движка tile engine.Например, допустим, у меня есть травяная плитка и гравийная плитка.Если это две отдельные текстуры в памяти, и я рисую плитку травы, затем плитку гравия, затем плитку травы на экране, графический процессор загрузит текстуру травы, затем отключит ее, чтобы загрузить текстуру гравия, затем снова включит текстуру травы, чтобы нарисовать другую плитку травы.Это очень быстро снижает производительность!Самый простой способ обойти эту проблему - создать таблицу спрайтов, где вы помещаете плитки травы и гравия в одну текстуру и просто указываете 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 розыгрышей, потому что они включали некоторые начальные настройки (не совсем уверен, какие именно) и искажали средние значения.Я скачал одно изображение 1280х720, и для лучшего тестового примера я просто нарисовал его один раз.Для нижнего тестового примера я нарисовал одно исходное изображение в виде плиток размером 128х72, как вы просили в своем вопросе.Вот результаты.

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

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

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

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

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

Другие советы

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

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

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

  

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top