Нарисуйте () 20000 текстур 32 на 32 или 1 большую текстуру 20000 раз

Я программирую на C # с использованием .NET Framework 4 и стремлюсь создать игру на основе плитки с XNA. У меня одна большая текстура (256 пикселей на 4096 пикселей). Помните, что это игра, основанная на плитках, поэтому эта текстура настолько массивна только потому, что содержит много плиток, каждая из которых имеет размер 32 на 32 пикселя. Я думаю, что эксперты точно знают, что такое тайловая игра. Ориентация ортогональна (как шахматная доска), а не изометрична.

В методе Game.Draw () у меня есть два варианта, один из которых будет невероятно более эффективным, чем другой.

Вариант / метод №1:

Полупсевдокод:

    public void Draw()
    {
        // map tiles are drawn left-to-right, top-to-bottom
        for (int x = 0; x < mapWidth; x++)
        {
            for (int y = 0; y < mapHeight; y++)
            {
                SpriteBatch.Draw(
                    MyLargeTexture, // One large 256 x 4096 texture
                    new Rectangle(x, y, 32, 32), // Destination rectangle - ignore this, its ok
                    new Rectangle(x, y, 32, 32), // Notice the source rectangle 'cuts out' 32 by 32 squares from the texture corresponding to the loop
                    Color.White); // No tint - ignore this, its ok
            }
        }
    }

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

Вариант / метод № 2:

Полупсевдокод:

    public void Draw()
    {
        // map tiles are drawn left-to-right, top-to-bottom
        for (int x = 0; x < mapWidth; x++)
        {
            for (int y = 0; y < mapHeight; y++)
            {
                Texture2D tileTexture = map.GetTileTexture(x, y); // Getting a small 32 by 32 texture (different each iteration of the loop)

                SpriteBatch.Draw(
                    tileTexture,
                    new Rectangle(x, y, 32, 32), // Destination rectangle - ignore this, its ok
                    new Rectangle(0, 0, tileTexture.Width, tileTexture.Height), // Notice the source rectangle uses the entire texture, because the entire texture IS 32 by 32
                    Color.White); // No tint - ignore this, its ok
            }
        }
    }

Подпись: Итак, второй метод заключается в многократном рисовании множества мелких текстур.

Вопрос: какой метод и почему? Лично я считаю, что было бы намного эффективнее использовать первый метод. Если вы подумаете о том, что это означает для массива тайлов на карте (представьте себе большую карту с 2000 на 2000 тайлов, скажем), каждый объект Tile должен содержать только 2 целых числа для позиций X и Y источника. прямоугольник в одной большой текстуре - 8 байт. Однако, если вы используете метод № 2, каждый объект Tile в массиве тайлов карты должен будет хранить текстуру 32 на 32 - изображение, которое должно выделять память для пикселей RGBA 32 на 32 раза - это 4096 байт на плитку. тогда? Итак, какой метод и почему? Первым приоритетом является скорость, затем загрузка памяти, затем эффективность или что-то еще, что вы думаете, эксперты.


person Jason    schedule 28.12.2010    source источник


Ответы (2)


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

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

SpriteBatch автоматически объединяет ваши спрайты в пакеты, где это возможно, чтобы свести к минимуму смены текстур и, следовательно, отрисовывать отправленные команды. Вот почему у него есть возможность выполнять сортировку по текстуре. Это также причина, по которой существует параметр source-rectangle - чтобы разрешить использование листов спрайтов - чтобы можно было рисовать больше спрайтов без изменения текстуры.

(Фактически, команды рисования, которые вы отправляете на графический процессор, даже если вы не используете SpritBatch, называются «пакетами». Когда вы отправляете слишком много, вы становитесь «ограниченным пакетом». Удивительно легко стать ограниченным пакетом - a несколько сотен партий - это очень приблизительная оценка лимита.)

person Andrew Russell    schedule 28.12.2010

Соглашаться. Чем меньше текстур вы извлечете, тем быстрее это будет, потому что это минимизирует изменения состояния на графическом процессоре.

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

person The ZMan    schedule 28.12.2010