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

Визуализация примитивов

Управление видовым преобразованием

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

  1. "Ручное" масштабирование примитивов таким образом, чтобы они всегда корректно отображалось независимо от размеров формы.
  2. Запретить пользователю делать окно неквадратным, то есть действовать по принципу "нет неквадратной формы - нет и проблемы".
 Искажения формы круга при непропорциональном изменении размеров окна

Рис. 2.17. Искажения формы круга при непропорциональном изменении размеров окна

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

  • Автоматическое изменение размера визуализируемого изображения для компенсации непропорционального размера формы.

Этот метод имеет важный нюанс относительно первого варианта: в данном случае трансформируются не координаты вершин примитива, а итоговое изображение13Физически этот метод все же сводится к неявной модификации координат вершин после трансформации вершинным шейдером . В разделе 2.3.1 на рисунке 2.2 была приведена схема графического конвейера. Как вы знаете, на выходе из вершинного шейдера получаются вершины в логической системе координат, в которой координаты вершин лежат в диапазоне [-1, +1]. Затем эти логические координаты трансформируются в систему координат окна посредством видового преобразования. Параметры этого преобразования задаются свойством Viewport класса GraphicsDevice: public Viewport Viewport { get; set; }.

Одноименная структура Viewport, инкапсулирующая параметры видового преобразования, определяется следующим образом:

public struct Viewport
{
// Ширина области, в которую осуществляется визуализация
public int Width { get; set; } 
// Высота области, в которую осуществляется визуализация
public int Height { get; set; } 
// Координата X левого верхнего угла области визуализация
public int X { get; set; } 
// Координата Y левого верхнего угла области визуализация
public int Y { get; set; }
…
}

Как видно, структура Viewport определяет в клиентской области окна прямоугольную область, используемую для визуализации изображения. По умолчанию при создании и сбросе устройства XNA Framework автоматически присваивает полям X и Y нулевое значение, a Width и Height - ширину и высоту клиентской области окна. Таким образом, по умолчанию клиентская область заполняет всю клиентскую область окна.

В следующем примере демонстрируется использование пользовательской области визуализации размером 100x100, расположенной в левом верхнем углу приложения (листинг 2.19).

// Пример Examples\Ch02\Ex09
private void MainForm_Load(object sender, EventArgs e)
{
// Важно! Размер формы не может быть меньше области 
визуализации, в противном случае при
// попытке визуализации в такую форму будет сгенерировано исключение
// System.InvalidOperationException
MinimumSize = SizeFromClientSize(new Size(100, 100)); ... 
}
private void MainForm_Paint(object sender, PaintEventArgs e) 
{
if (closing) return;
try 
{
if (device.GraphicsDeviceStatus == GraphicsDeviceStatus.Lost)
 throw new DeviceLostException();
if (device.GraphicsDeviceStatus == GraphicsDeviceStatus.NotReset)
 device.Reset();
// Задание параметров области визуализации.
Viewport viewport = new Viewport();
viewport.Width = 100;
viewport.Height = 100; 
// Присваиваем информацию об области визуализации структуре Viewport
device.Viewport = viewport;
// Очищаем экран
device.Clear(XnaGraphics.Color.CornflowerBlue); 
// Рисуем окружность 
...

} 
}
Листинг 2.19.

Результат визуализации приведен на рисунке 2.18. Что же изменилось в работе приложения?

  1. Размер визуализируемого изображения теперь не зависит от размера окна. Соответственно, непропорциональный размер формы больше не искажает изображение.
  2. Клиентская область формы за пределами области визуализации заполнена "мусором". В этом не ничего удивительного, ведь наше приложение оставляет содержимое формы за пределами области визуализации "как есть".
 Использование области визуализации 100x100, расположенной в левом верхнем углу окна

Рис. 2.18. Использование области визуализации 100x100, расположенной в левом верхнем углу окна

Примечание

Отладочная версия DirectX перед началом визуализации кадра автоматически закрашивает его случайным цветом, что позволяет разработчику легко обнаружить области окна, игнорируемые приложением.

Теперь мы уже можем определиться со стратегией борьбы с геометрическими искажениями в примере Ex08: перед визуализацией изображения приложение должно задать квадратную область визуализации максимально возможного размера, расположенную в клиентской области формы. При этом, во избежание артефактов по краям окна, во время очистке окна методом Clear должна применяться область визуализации размеров во всю клиентскую область формы. Учитывая, универсальность подобной технологии, методы рассчитывающие параметры области визуализации будет разумно поместить в наш класс Helper.cs (листинг 2.20).

// Сборник вспомогательных методов, полезных в хозяйстве
class Helper
{
...
// Принимает размеры клиентской области формы. Возвращает 
квадратную область визуализации
// максимально возможного размера, расположенную в центре формы.
public static Viewport SquareViewport(System.Drawing.Size clientSize)
{
Viewport viewport = new Viewport();
viewport.Width = Math.Min(clientSize.Width, clientSize.Height);
 viewport.Height = viewport.Width;
viewport.X = (clientSize.Width- viewport.Width) / 2; 
viewport.Y = (clientSize.Height - viewport.Height) / 2;
return viewport; 
}
// Принимает размеры клиентской области формы. Возвращает 
область визуализации размером во 
// всю клиентскую область формы
public static Viewport FullScreenViewport(System.Drawing.
Size clientSize) 
{
Viewport viewport = new Viewport(); viewport.Width = 
clientSize.Width; viewport.Height = clientSize.Height; return viewport;
} 
}
Листинг 2.20.

Код модифицированного приложения, использующего новые методы класса Helper, приведен в листинге 2.21.

// Пример Ch02\Ex10
private void MainForm_Paint(object sender, PaintEventArgs e)
{
if (closing) return;
try 
{
if (device.GraphicsDeviceStatus == GraphicsDeviceStatus.
Lost) throw new DeviceLostException();
if (device.GraphicsDeviceStatus == GraphicsDeviceStatus.
NotReset) device.Reset();
// Используем для визуализации всю клиентскую область окна
device.Viewport = Helper.FullScreenViewport(ClientSize);
// Очищаем экран
device.Clear(XnaGraphics.Color.CornflowerBlue);
// Используем квадратную область визуализации
device.Viewport = Helper.SquareViewport(ClientSize); 
...
} 
}
Листинг 2.21.

Результат визуализации круга в окне с неквадратной клиентской областью приведен на рисунке 2.19. Как видно, несмотря на непропорциональное изменение сторон окна, круг остался кругом.

 Круг, визуализированный с использованием квадратной области визуализации, расположенной в центре формы

Рис. 2.19. Круг, визуализированный с использованием квадратной области визуализации, расположенной в центре формы

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

Доработайте приложение, визуализирующее график косинуса из практического упражнения №2.1, заменив примитивы PrimitiveType.PointList на PrimitiveType.LineStrip. Так же добавьте в приложение высотную закраску: когда функция принимает значение 1, график должен окрашиваться зеленым цветом, а при -1 – красным. Остальные точки графика принимают промежуточные цвета (рисунок 2.20). Для вычисления цвета промежуточных точек можно воспользоваться следующими формулами:

red=(0.5-0.5-\cos\alpha)^{0.3}*255//
green=(0.5+0.5-\cos\alpha)^{0.3}-255
( 2.3)

где

  • red - красная составляющая цвета
  • green - зеленая составляющая цвета

Примечание

Если же убрать операцию возведения в степень, то график функции будет заметно терять яркость в окрестностях y равного 0, что смотрится не особо красиво.

 График синуса с высотной закраской

Рис. 2.20. График синуса с высотной закраской
Андрей Леонов
Андрей Леонов

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