Опубликован: 28.04.2009 | Доступ: свободный | Студентов: 1763 / 86 | Оценка: 4.36 / 4.40 | Длительность: 16:40:00
Специальности: Программист
Лекция 3:

Усложненные технологии визуализации

Практическое упражнение №3.1.

Напишите приложение, отображающее круг. В правой части окна должны быть расположены элементы управления, позволяющие задавать различные параметры изображения: радиус круга, количество секторов в круге, режим визуализации круга (поточечный, каркасный или с закраской) и цвет круга (рисунок 3.5).

 Иллюстрация к практическому упражнению №3.1

Рис. 3.5. Иллюстрация к практическому упражнению №3.1

Для ограничения области визуализации XNA Framework воспользуйтесь компонентом XnaPanel из примера Ch03\Ex02. Существует два способа добавления компонента XnaPanel в окно Toolbox:

  1. одключить к решению проект XnaPanel из примера Ch03\Ex01. Для этого во вкладке Solution Explorer щелкнете правой кнопкой мыши на узле с названием решения ( Solution ) и выберете в контекстном меню пункт Add | Existing Project… . Укажите в открывшемся окне файл проекта компонента PanelDX (Examples\Ch03\Ex01 - XnaPanel\XnaPanel\XnaPanel.csproj) и нажмите Ok. После компиляции подключенного проекта (Ctrl + Shift + B) компонент Xna Panel автоматически появится в окне Toolbox.
  2. Добавить в окно ToolBox компонент из сборки примера Ex01. Для этого щелкните правой кнопкой мыши на поверхности окна ToolBox и выберите в контекстном меню пункт Choose Items…. Откроется диалоговое окно Choose Toolbox Items…. Щелкните на кнопку Browse… и укажите сборку с компонентом PanelDX (Examples\Ch03\Ex01 - XnaPanel\XnaPanel\bin\Release\XnaPanel.dll) . Наконец, нажмите кнопку Ok, после чего на панели Toolbox появится компонент XnaPanel.

Какой из этих двух вариантов выбрать – решать вам, но лично мне больше симпатизирует первый подход.

3.2. Полноэкранный режим

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

  1. В полноэкранном режиме пользователь полностью погружается в виртуальный мир, не отвлекаясь на различные элементы интерфейса Windows вроде панели задач ( Taskbar ).
  2. Контроль всего пространства экрана позволяет переключать экранный и задний ( back ) буферы без необходимости копирования информации между буферами: при показе итогового изображения XNA Framework просто делает задний буфер экранным, а экранный задним.
  3. При запуске приложения на компьютере с недостаточно мощной видеокартой пользователь может повысить производительность путем уменьшения разрешения экрана и глубины цвета.

К недостаткам полноэкранного режима можно отнести несколько усложнение кода приложения и невозможность использования элементов управления Windows Forms, что затрудняет применение полноэкранного режима в различных утилитах.

Переход полноэкранный режим осуществляется путем создания графического устройства ( GraphicsDevice ) с соответствующим образом настроенной структурой PresentationParameters. Легко догадаться, что свойству IsFullScreen необходимо присвоить значение true:

presentParams = new PresentationParameters();
presentParams.IsFullScreen = true;

Кроме того, приложение должно задать параметры используемого видеорежима, а именно:

  1. Разрешение экрана.
  2. Формат пикселей экрана (количество бит на пиксель и т.п.).
  3. Частоту вертикальной развертки.

Разрешение5Количество пикселей по высоте и ширине экрана и вспомогательных ( back ) буферов задается свойствами BackBufferWidth и BackBufferHeight структуры PresentationParameters. Например:

// Используем видеорежим с разрешением 640 x 480 
presentParams.BackBufferWidth = 640; 
presentParams.BackBufferHeight = 480;

Любой видеорежим характеризуется определенным форматом пикселей, используемым для хранения информации о цвете пикселей. Формат пикселей определяет, сколько бит отводится для хранения каждого цвета и как распределены биты между различными цветовыми каналами. Формат пикселей заднего буфера задается свойством BackBufferFormat структуры PresentationParameters:

public SurfaceFormat BackBufferFormat { get; set; }

где

  • SurfaceFormat - перечислимый тип, используемый для задания формата пикселей (таблица 3.1).

В качестве формата экранного буфера автоматически используется формат, наиболее близкий к формату заднего буфера. Например, если вы укажете для заднего буфера формат SurfaceFormat.Color, в качестве формата экранного буфера будет выбран формат SurfaceFormat.Bgr32. Обычно это не существенно, ведь альфа-канал все равно не оказывает никакого влияния на отображаемом на экране изображении; тем не менее, в некоторых немногочисленных ситуациях этот нюанс все же приходится учитывать.

Таблица 3.1. Характеристика форматов пикселей, соответствующих значениям перечислимого типа SurfaceFormat
Значение Может использоваться в качестве формата экранного буфера Размер в битах
Весь пиксель Красный канал Зеленый канал Синий канал Альфа канал
Unknown ? ? ? ? ?
Rgba1010102 X 32 10 10 10 2
Color 32 8 8 8 8
Bgr32 X 32 8 8 8 -
Bgr565 X 16 5 6 5 -
Bgra5551 16 5 5 5 1

По умолчанию свойство SurfaceFormat равно SurfaceFormat.Unknown. В оконном режиме это значение указывает на необходимость использования в качестве формата заднего буфера такой же формат пикселей, как у рабочего стола. Например, если вы используете в Windows 32-х битный видеорежим, задний буфер будет использоваться формат SurfaceFormat.Bgr32. Эта особенность позволила нам не утруждать себя выбором формата заднего буфера для оконных приложений первой и второй глав книги.

Однако применение формата SurfaceFormat.Unknown для полноэкранного графического устройства приводит к генерации исключения System.InvalidOperationException. Так что при создании устройства, использующего полноэкранный режим, приложение обязано явно указывать формат пикселей заднего буфера. В нашем первом приложении мы, не мудрствуя лукаво, будем использовать формат SurfaceFormat.Bgr32, поддерживаемый всеми видеокартами, совместимыми с XNA Framework: presentParams.BackBufferFormat = SurfaceFormat.Bgr32 ;

Примечание

Должно быть, вы заметили, что пиксели формата SurfaceFormat.Bgr32 имея размер 32 бита, содержат всего 24 бита полезной информации (для красного, синего и зеленого каналов отведено по 8 бит). Такая избыточность обусловлена тем, что современные процессоры умеют работать только с типами данных разрядностью 8, 16, 32 и 64 бит. Соответственно, 24-х битные типы данных пришлось бы эмулировать посредством 8, 16 и 32-х разрядных типов, что неминуемо увеличило количество операций, требуемых для считывания и записи значения пикселя и, соответственно, ощутимо снизило производительность. Например, для записи 24-х битного значения необходимо загрузить регистр 32 бита, модифицировать 24 бита, и записать полученное 32-х битное значение обратно в память.

И, наконец, последней характеристикой любого графического режима является частота обновления экрана. Для современных электронно-лучевых трубок нормой является частота обновления порядка 85 герц и выше, так как при более низких частотах становится заметным мерцание монитора. Мониторы LCD менее критичны к низкой частоте обновления экрана, однако редкий современный LCD -монитор поддерживает частоту смены кадров более 60 Гц. Частота обновления экрана задается свойством FullScreenRefreshRateInHz структуры PresentationParameters:

public int FullScreenRefreshRateInHz { get; set; }

В оконном режиме этому свойству присевается нулевое значение, ведь окно все равно может обновляться с частотой, отличной от частоты обновления, используемой рабочим столом. В полноэкранном режиме нулевое значение параметра FullScreenRefreshRateInHz, означает, что приложение отдает выбор частоты обновления экрана на откуп Windows и драйверам видеокарты/монитора. Так как при указании частоты обновления неподдерживаемой текущей видеоподсистемой может быть сгенерировано исключение System. InvalidOperationException, мы пока не будем пытаться самостоятельно выбирать частоту обновления экрана.

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

presentParams = new PresentationParameters();
presentParams.BackBufferCount = 1;
presentParams.SwapEffect = SwapEffect.Discard;
// Используем полноэкранный режим 640Ч480, 
32 бита на пиксель, частота обновления выбирается
// автоматически
presentParams.IsFullScreen = true;
presentParams.BackBufferWidth = 640;
presentParams.BackBufferHeight = 480;
presentParams.BackBufferFormat = SurfaceFormat.Bgr32;
presentParams.FullScreenRefreshRateInHz = 0;
GraphicsDeviceCapabilities caps =
GraphicsAdapter.DefaultAdapter.GetCapabilities(DeviceType.Hardware);
CreateOptions options = CreateOptions.SingleThreaded; if
(caps.DeviceCapabilities.SupportsHardwareTransformAndLight)
options |= CreateOptions.HardwareVertexProcessing;
else
options |= CreateOptions.SoftwareVertexProcessing;
device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, 
DeviceType.Hardware, this.Handle, options, presentParams);
Листинг 3.4.

Так же необходимо подправить код обработчика событий Resize. Дело в том, что даже в полноэкранном режиме форма продолжает жить своей жизнью и в ряде случаях (при переключении в другое приложение путем нажатия клавиш alt + tab ) Windows может самостоятельно изменять размер формы, что, разумеется, приводит к генерации события Resize. Но так как в полноэкранном режиме размер формы некоим образом не связан с разрешением экрана, приложение не должно изменять размер заднего ( back ) буфера:

private void MainForm_Resize(object sender, EventArgs e)
{
// Если приложение находится в полноэкранном режиме, 
оно не должно отслеживать изменение
// размера формы
if ((!presentParams.IsFullScreen) && 
(WindowState != FormWindowState.Minimized))
{
presentParams.BackBufferWidth = ClientSize.Width;
presentParams.BackBufferHeight = ClientSize.Height;
device.Reset(presentParams); 
} 
}
Листинг 3.5.

Визуализация сцены осуществляется аналогично оконному режиму:

private void MainFormPaint(object sender, PaintEventArgs e) 
{
if (closing)
return;
try 
{
if (device.GraphicsDeviceStatus == GraphicsDeviceStatus.Lost)
throw new DeviceLostException();
if (device.GraphicsDeviceStatus == GraphicsDeviceStatus.NotReset)
device.Reset(presentParams);
// Задаем область визуализации размеров во весь экран
device.Viewport = Helper.FullScreenViewport presentParams); 
// Очищаем весь экран
device.Clear(XnaGraphics.Color.CornflowerBlue);
// Используем квадратную область визуализации 
(во избежание геометрических искажений 
// изображения)
device.Viewport = Helper.SquareViewport(presentParams);
// Рисуем CD-диск (см. раздел 2.6.3)
}
catch (DeviceNotResetException)
{
Invalidate() ;
}
catch (DeviceLostException)
{
}
}
Листинг 3.6.

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

// Вычисление квадратной области визуализации
public static Viewport SquareViewport(PresentationParameters 
presentParams)
{
return SquareViewport(new System.Drawing.Size(presentParams.
BackBufferWidth,
presentParams.BackBufferHeight)); }
// Вычисление области визуализации размеров во весь экран
public static Viewport FullScreenViewport(PresentationParameters 
presentParams)
{
return FullScreenViewport(new System.Drawing.Size(presentParams.
BackBufferWidth,
presentParams.BackBufferHeight));

}
Листинг 3.7.

Готовое приложение, визуализирующее изображение CD-диска в полноэкранном режиме (рисунок 3.6), находится в каталоге Examples\Ch03\Ex03.

 CD-диск, визуализированный полноэкранном режиме (640x480x32bpp)

Рис. 3.6. CD-диск, визуализированный полноэкранном режиме (640x480x32bpp)
Андрей Леонов
Андрей Леонов

Reference = add reference, в висуал студия 2010 не могу найти в вкладке Solution Explorer, Microsoft.Xna.Framework. Его нету.

Олег Корсак
Олег Корсак
Латвия, Рига
Александр Петухов
Александр Петухов
Россия, Екатеринбург