Draw () 20 000 32 на 32 текстуры или 1 большая текстура 20 000 раз - PullRequest
5 голосов
/ 28 декабря 2010

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

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

Выбор / Метод # 1:

Semi-псевдокод:

    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 :

Semi-псевдокод:

    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 в массиве плиток карты должен будет хранить текстуру 32by32 - изображение, которое должно выделять память для пикселей RGBA 32 в 32 раза, - это то, что 4096 байт на плитку затем? Итак, какой метод и почему? Первым приоритетом является скорость, затем загрузка памяти, затем эффективность или то, во что верят ваши эксперты.

Ответы [ 2 ]

9 голосов
/ 28 декабря 2010

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

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

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

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

2 голосов
/ 28 декабря 2010

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

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

...