2010-08-21 4 views
3

Я пишу 2-мерный плитку. В настоящее время моя программа рисования использует библиотеку C# Drawing для перерисовывания каждой видимой плитки каждый раз, когда экран обновляется. У меня есть прокрутка и масштабирование, чтобы работать, и все выглядит так, как я хочу. Но рутина медленная. Теперь я пытаюсь улучшить его. У меня есть пара вопросов:Рисование 2D-спрайтов (битовых карт) Эффективно

Во-первых, я думаю, что перерисовывать плитки при каждом обновлении не нужно (поскольку они никогда не меняются). Сейчас я пытаюсь изменить алгоритм так, чтобы он записывал всю карту в одно растровое изображение при инициализации, а затем разрезает правильную часть растрового изображения, когда пришло время рисовать. Считаете ли вы, что это правильный путь? (Я также подумал о том, чтобы оставить изображение в фоновом режиме и просто прокрутить его. Но потом я решил, что не хочу рисовать материал, который находится вне поля зрения. Однако, возможно, это дешевле, чем вырезать/вставлять ? Ошибка памяти и времени?)

Во-вторых, насколько я понимаю, процедуры C# Drawing не используют полную мощность GPU. Я думаю, что я должен попытаться сделать рисунок в OpenGL (или DirectX, но я предпочитаю первый, поскольку он является мультиплатформенным). Это поможет? Знаете ли вы, что для OpenGL используется учебник по тайному (или общему рисунку)? Ссылка на книгу также может помочь.

Я также не делаю многопоточность на данный момент (на самом деле у меня есть только смутное представление о том, что это такое). Должен ли я попытаться многопоточный ящик? Или OpenGL сделает многопоточность для графической избыточности?

Спасибо.

+0

XNA4.0 вышел через 2 недели после того, как задал свой вопрос. Я попробовал, понравился и переключился на него. XNA управляет DirectX неявно, поэтому можно просто позволить своим спрайтам всплывать, не беспокоясь ни о чем. Очень хорошо. Мой друг использует WPF. Это также прекрасно работает, но я думаю, вам нужно знать немного DirectX (не большая проблема). Еще раз спасибо за отличные ответы, ребята. – JackKane

ответ

2

Какую платформу приложения вы планируете использовать? Методы эффективного рисования очень сильно отличаются между WinForms (Win32) и WPF.

Вы правы, что процедуры рисования .NET не в полной мере используют GPU. Используя DirectX или OpenGL, одной непосредственной оптимизацией будет предварительная загрузка всех ваших фрагментов изображения (или, по крайней мере, всех фрагментов, необходимых для области непосредственного просмотра, плюс немного больше) в память графического процессора с использованием списков изображений или списков отображения. Затем вы должны нарисовать плитки на поверхности с помощью индексной нитки N в x, y. Это, как правило, намного быстрее, чем рисование на поверхности графического процессора с использованием растровых изображений, хранящихся в основной системной памяти, поскольку пиксели растровых изображений должны быть скопированы на графический процессор для каждой нарисованной плитки, и это занимает много времени. При рисовании по индексу также используется намного меньше памяти GPU, когда вы можете использовать один и тот же фрагмент изображения в нескольких местах на выходе.

OpenGL vs DirectX - ваш выбор, но IMO DirectX развивается быстрее, предоставляя больше аппаратных ускоренных функций, чем OpenGL. Драйверы OpenGL в Windows также имеют репутацию пренебрежения поставщиками оборудования. Их основное внимание уделяется их драйверам DirectX.

Продумайте, действительно ли вам требуется OpenGL или DirectX для приложения 2D-плитки.Требование OpenGL или DirectX уменьшит количество машин, особенно старых компьютеров, которые могут запускать ваше приложение. OpenGL и DirectX могут быть чрезмерными. Вы можете многое сделать с простым старым GDI, если вы умны в этом.

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

Как правило, движущиеся пиксели вокруг экрана обычно не подходят для многопоточности. У вас есть только одно устройство отображения (в большинстве случаев), так что поражение его несколькими потоками, пытающимися сменить пиксели одновременно, не работает. Заимствовать выражение из управления проектами: если женщина может создать ребенка через 9 месяцев, можете ли вы использовать 9 женщин для создания 1 ребенка в течение 1 месяца? ;>

Работы по идентификации частей вашей системы, которые не нуждаются в доступе к тем же ресурсам или устройствам. Это лучшие кандидаты для работы в параллельных потоках, чем блиты на экране.

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

+0

Я использую Windows Forms.Я даже не знал, что WPF существует, пока вы не упомянули об этом. Я вижу, что он похож на Forms, за исключением того, что он использует DirectX. Возможно, я попытаюсь перенести мое приложение в WPF, чтобы узнать, что произойдет. *** Я загружаю растровые изображения в основную память с помощью GDI - я прочитаю и попытаюсь загрузить их в графический процессор. Между твоими и ответами Блама, я думаю, я поеду с DirectX, если в GDI не будет загружаться память. На данный момент я избегу многопоточности. *** Спасибо, что ответили так хорошо и так быстро! – JackKane

+0

Поскольку приложения WinForms - это просто приложения Win32, им будет предложено перерисовать их область окна, когда она будет скрыта, а затем снова обнаружена. Большинство оконных красок кода используют простой подход и просто перерисовывают все в окне. Для лучшей производительности, особенно при больших нагрузках на чертеж, вы должны обратить внимание на отсекающий прямоугольник и только перерисовать часть вашего окна, которая фактически недействительна. Это также послужит вам для прокрутки, так как прокрутка на 10 пикселей исключает только 10 пикселей в нижней части окна, а не всего окна. – dthorpe

+0

WPF использует совершенно другую парадигму рисования и требует очень разных методов оптимизации. WPF кэширует обрамленное изображение, так что перерисовка при обнаружении происходит быстро и без вызова вашего кода. В WPF-приложении нет цикла WM_PAINT (с которым вы связаны). WPF может использовать DirectX под капотом для его рисования, поэтому у вас может быть больше шансов воспользоваться преимуществами ресурсов графического процессора, используя обычные элементы управления WPF и объекты по сравнению с WinForms. – dthorpe

2

Если вы хотите использовать OpenGL, ваш лучший выбор для 2d будет SDL. Использование OpenGL с C# никогда не будет таким переносимым просто из-за того, что он будет использовать .NET-оболочки.

XNA - отличный инструмент для написания игр на C#, он должен обеспечивать гораздо большую скорость и гибкость, чем SDL (особенно порт .net), а также дополнительные возможности (но более насыщенные).

Для вашего вопроса прокрутки или прокрутки лучший маршрут будет прокручиваться. Память намного меньше, чем у процессора, когда вы рисуете с использованием GDI + (что использует System.Drawing). Вы всегда можете разбить карту на разделы и прокрутить их, а затем загрузить, когда это необходимо, если это так.

+0

Вы правы! Мне удалось заставить алгоритм разрезания работать, и он был еще медленнее предыдущего. Затем я получил прокрутку, чтобы работать (это было проще, чем я думал), и это кажется более быстрым (хотя оно прикручивало масштабирование - теперь я перерисовываю большой растровый рисунок при масштабировании, что заставляет действие зависать на секунду). Спасибо за ссылку SDL, я рассмотрю ее. – JackKane

+0

Я слышал о XNA. Я попытался установить его несколько дней назад, установка не удалась, и я забыл об этом. Это действительно стоит? Похоже, мне нужна другая программа типа «gamemaker». – JackKane

+0

Nononono, XNA * - это более удобный для пользователя тип фреймворка, но это не значит, что он похож на gamemaker. Ознакомьтесь с некоторыми учебниками, чтобы вы могли понять, как это работает, а затем решить для себя. Как я уже сказал, он должен быть намного быстрее, чем SDL, и предоставляет гораздо больше возможностей. Плюс XNA сделан для C# :) – Blam

2

Я не знаком с OpenGL, но я написал механизм на основе плитки в ManagedDX (позже портирован на XNA). ManagedDX лишен, но есть проект SlimDX, который все еще находится в активной разработке.

С DX вы можете загрузить каждую отдельную плиту в Texture. (Например, используя Texture.FromFile() или Texture.FromStream()), и попробуйте один экземпляр Sprite. Это очень хорошо. Я группирую текстуры в простой класс с Point или Vector2 для их местоположения, устанавливая их только тогда, когда местоположение изменяется, а не каждый раз, когда вызывается метод draw. Я кэширую плитки в памяти только для непосредственного экрана и одного или двух фрагментов за пределами, нет необходимости в более чем том, поскольку файл IO достаточно быстр, чтобы извлекать новые плитки по мере прокрутки.

struct Tile 
{ 
    public Point Location; 
    public Texture Texture; 
} 

Device device; 
Sprite sprite; 
List<Tile> tiles = new List<Tile>(); 

.ctor() { 
    this.device = new Device(...) 
    this.sprite = new Sprite(this.device); 
} 

void Draw() { 
    this.device.Clear(ClearFlags.Target, Color.CornflowerBlue, 1.0f, 0); 
    this.device.BeginScene(); 
    this.sprite.Begin(SpriteFlags.AlphaBlend); 
    foreach (Tile tile in this.tiles) { 
     this.sprite.Draw2D(tile.Texture, 
      new Point(0, 0), 0.0f, tile.Location, Color.White); 
    } 
    this.sprite.End(); 
    this.device.EndScene(); 
    this.device.Present(); 
}