Исходники.Ру - Программирование
Исходники
Статьи
Книги и учебники
Скрипты
Новости RSS
Магазин программиста

Главная » Статьи по программированию » .NET - Все статьи »

Обсудить на форуме Обсудить на форуме

Использование полноэкранного сглаживания (FSAA) в Managed DirectX.

Эта статья является фрагментом книги, повещенной программированию трёхмерной графики с использованием DirectX for NET 2.0 (окончательное название книги пока не определено). В качестве среды программирования используется Visual Studio 2005 и язык C#.

Примеры кода находятся здесь

Эта статья является фрагментом книги, повещенной программированию трёхмерной графики с использованием DirectX for NET 2.0 (окончательное название книги пока не определено). В качестве среды программирования используется Visual Studio 2005 и язык C#.
Книга рассчитана на начинающего читателя, имеющего базовые навыки работы с Visual Studio 2005. Предполагается, что читатель вполне в состоянии самостоятельно создать приложение, использующее GDI+, вроде простейшего графического редактора. Никаких начальных знаний в области трёхмерной графики не требуется.
Основной акцент сделан на как можно более понятное изложение материала.  Другая особенность книги – активное использование шейдеров (начиная со второй главы) вместо с которые начинают задействоваться начиная олеее требуется, однакофиксированного конвейера.

Все примеры книги написаны с использованием Visual C# 2005 Express и DirectX 9 SDK December 2005, который содержит Beta-версию DirectX for .NET 2.0. К моменту отправки книги в печать уже выйдут Release-версии этих продуктов. Чтобы не переписывать по несколько раз текст книги, я стараюсь не обращать внимания на различные проблемы бета версий, которые будут исправлены в следующих версиях. Если же у вас возникнут непредвиденные трудности, напишете мне на email (gsaf@sura.ru) и я обязательно постараюсь вам помочь.

В настоящее время DirectX for .NET 2.0 поставляется без какой-либо документации. Большая часть информации о DirectX for .NET 2.0 была получена путём дизассемблирования сборки Microsoft.DirectX.dll [2.0.0.0] с использованием ILDASM и .NET Reflector. Поэтому я не могу гарантировать отсутствие ошибок и неточностей в текущем варианте книги. Заранее спасибо за любые отзывы, комментарии и пожелания.

Особенно интересует мнение по следующим вопросам:

1.        Нужна ли в книге аналогия между FSAA и обработкой аудиосигналов? Или её лучше убрать?

2.        Следует ли оставить в книге описание панелей управление ATI и NVIDIA?

3.        Корректность описания SSAA и MSAA.

4.        Понятность описания процесса создания формы в конструкторе форм Visual Studio.

5.        Возникают ли проблемы при запуске примеров книги на компьютерах различных конфигураций.

6.        Корректность перевода различных терминов и т.д.

7.        Понятность изложения материала. Имеет ли смысл переписать некоторые фрагменты книги более простым языком?

Примечание

Над этим фрагментом книги ещё не работали редакторы и корректоры. Поэтому в нём наверняка есть множество стилистических ошибок и “очепяток”.

Все примеры к книге тестировались на компьютере следующей конфигурации: Pentium 4-2.8C, 1GB RAM, Windows XP Eng Service Pack 2. Использовались видеокарты: ATI Radeon 9700 Pro (с отключенным AGP), ATI Radeon 9800 XT и NVIDIA GeForce FX 5900 Ultra с последними WHQL-версиями драйверов. Часть примеров тестировалась на компьютерах с видеокартами NVIDIA GeForce2 MX, NVIDIA GeForce 6600 GT и ATI Radeon x700 Pro.

Примечание

Были обнаружены эксцессы при выполнении некоторых примеров (Ex14, Ex15, Ex25, Ex26, Ex27, Ex28, Ex29) на компьютерах с видеокартой GeForce2 MX. Проблема заключается в исчезновении изображения при увеличении размеров окна. Причины такого странного поведения программ мне пока не понятны.

Автор выражает благодарность:

q      Корпорации ATI, которая  предоставила видеокарты ATI Radeon 9700 Pro и ATI Radeon 9800 XT для тестирования примеров от книги.

q      Корпорации NVIDIA, предоставившей видеокарту NVIDIA GeForce 5900 Ultra.

q      Корпорации Microsoft, предоставившей Microsoft Visual Studio .NET 2003 Professional и Microsoft Visual Studio 2005 Beta2, а так же Microsoft Windows 2003 Server Standard.

q      Издательству BHV, которое предоставило англоязычную литературу по 3D графике.

Так же автор благодарит Игоря Рыбинского (BHV), Юрия Уральского (NVIDIA), Филиппа Герасимова (NVIDIA), Андрея Крючкова (Microsoft), Александра Ложечкина (Microsoft) за консультации и полезные советы. Отдельная благодарность выражается Геннадию Ригеру из ATI Technologies и Алексею Кряжеву (Codemasters Software), которые оказали неоценимую помощь при написании книги.

 

1.4. Полноэкранное сглаживание (FSAA)

Запустите на выполнение приложение Ex15 из раздела 1.3.1 (визуализация узора Серпинского) и внимательно рассмотрите изображение. Думаю, вы быстро заметите, что оно выглядит как-то странно – одни фрагменты узора почему-то ярче, другие – бледнее. Чтобы понять, с чем это связано необходимо внимательно рассмотреть увеличенный фрагмент узора (рисунок 1.46). Нетрудно заметить, что видеокарта визуализирует изображение попиксельно. Так как пиксели имеют квадратную форму, на краях линии образуются ярко выраженные ступеньки. Чем меньше линия, тем заметнее эти ступеньки. Когда же треугольника приближается к размеру пикселя, происходит катастрофа – размер ступенек становится соизмеримым с размером треугольника, в результате чего они начинают существенно искажать его форму (появляются несуществующие зубцы и т.д.). Это явление получило название ступенчатости изображения (aliasing). Для борьбы с ним используются различные технологии полноэкранного сглаживания (FSAA – Full Scene Antialiasing).

 

Рисунок 1.46. Увеличенный узор Серпинского

Чем же обусловлено появление этих ступенек? В процессе растеризации графического примитива (треугольника, линии или точки) графический ускоритель определяет цвет каждого пикселя на основе выборки из центра этого пикселя (рисунок 1.47). Если примитив проходит через центр пикселя, то пиксель закрашивается цветом выборки в центре пикселя, в противном случае цвет пикселя остаётся неизменным. Иными словами, изображение формируется на основе выборок в центрах пикселей, с шагом в один пиксель.

Рисунок 1.47. Растеризация отрезка шириной около одного пикселя. Каждый квадратик соответствует одному пикселю экрана. Круглые точки в центре квадратиков – выборки, на основе которых определяется цвет пикселя.

Растеризация изображения очень похожа на восстановление аудиосигнала на основе дискретных выборок (называемых так же отсчётами). На рисунке 1.48 приведено изображение синусоиды, восстановленное на основе дискретных выборок. Как видно, если выборки расположены достаточно часто, сигнал восстанавливается точно. При уменьшении частоты отсчётов наступает момент, когда сигнал  начинается восстанавливаться не корректно – вместо синусоиды получается совершенно другой, более низкочастотный, сигнал (рисунок 1.49).

Рисунок 1.48. Синусоида, восстановленная по дискретным выборкам. Рисунок взят из [20]

 

Рисунок 1.49. Некорректно восстановленный сигнал при низкой частоте выборки. Рисунок взят из [20]

Согласно теореме отсчётов сигнал может быть абсолютно точно восстановлен по своим отсчётам, взятым с частотой, не меньше удвоенной частоты данного сигнала[1]. Это условие необходимое, но не достаточное. Если частота отсчётов меньше удвоенной частоты сигналов, то сигнал уже не удастся точно восстановить. Однако если частота отчётов равна удвоенной частоте или больше её, это ещё не гарантирует, что сигнал будет точно восстановлен. В качестве примера на рисунке 1.50 приведён пример выборки с удвоенной частотой сигнала, когда по чистой случайности отсчёты выборок попали на нулевые значения функции. Полученные выборки не содержат никакой информации об амплитуде сигнала, поэтому сигнал не может быть восстановлен.

Рисунок 1.50. Частота отсчётов в два раза больше частоты сигнала. Однако сигнал не удастся восстановить, так как отсчёты попали на нулевые значения. Рисунок взят из [20]

Примечание

Именно по этой причине большинство широко распространённых аудио форматов используют частоту выборки 44.1 кГц. Человеческое ухо воспринимает звуки с частотой не более 20 кГц, поэтому чтобы сигнал в последствии можно было корректно восстановить,  выборки аудио сигнала необходимо  брать с не менее чем удвоенной частотой (40 кГц). Добавив “на всякий случай” ещё 4.1 кГц, получим искомые 44.1 кГц. Однако выборки с удвоенной частоты не всегда достаточно для абсолютно точного восстановления сигнала (ещё раз обращаю ваше внимание на выделенное курсивов слово “не менее”). В результате в последнее время получили распространение аудио форматы с повышенной частотой выборки (до 192 кГц). При этом искушённые меломаны достаточно легко различают на слух аудиозаписи, сделанные с частотой выборки 44, 96 и 192 кГц  [29].

Однако давайте вернёмся к нашему узору Серпинского. Узор строится с использованием треугольников, визуализируемых в каркасном режиме, т.е. с использованием обычных линий. Толщина каждой линии равна одному пикселю. Треугольники рекурсивно делятся до тех пор, пока размер треугольника (и длина линий, из которых он состоит) не станет соизмерим с пикселем. Проведя грубую аналогию с обработкой аудио сигнала можно предположить, что для корректной растеризации изображения необходимо выбирать информацию о цвете пикселей, по крайней мере, с два раза более высокой частотой, чем частота расположения пикселей. В противном случае изображение не будет корректно восстановлено (визуализировано), что и наблюдается в нашей программе, когда цвет пикселей определяется на основе выборок в центрах пикселей (то есть частота выборки равна частоте пикселей).

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

Но мы можем пойти другим путём – увеличить число дискретных выборок на пиксель при неизменном разрешении экрана. Эта технология получила название суперсэмплинг[2] (supersampling), или сокращённо SSAA (SuperSampling AntiAliasing). Суперсэмплинг с N выборками на каждый пиксель обычно обозначается SSAA Nx. Так, SSAA 4x означает суперсэмплинг с четырьмя выборками на пиксель.

На рисунке 1.51 приведён пример определения цвета пикселей по четырём выборкам для каждого пикселя. Выборка производится с удвоенной частотой по осям x и y. Полученные выборки заносятся в видеопамять. В процессе визуализации изображения видеокарта хранит в видеопамяти памяти все выборки. Соответственно, при использовании SSAA Nx размер вспомогательного экранного буфера (Back Buffer) увеличивается в N раз – так при использовании видеорежима 1280x1024 с SSAA 4x экранный буфер будет иметь такой же размер, как и при разрешении 2560x2048 без SSAA. Пиксели этого “большого” экранного буфера часто называют субпикселями, так как каждому пикселю итогового изображения, показываемого на монитор, соответствует несколько субпикселей.

 

Рисунок 1.51. Растеризация отрезка с использованием SSAA 4x (на фоне большого белого полигона)

Если растеризуемый примитив проходит через выборку, результаты выборки заносятся в соответствующий субпиксель. Если выборка “не попадает” на объект, результаты выборки игнорируются, и содержимое субпикселя не изменяется.

Технические подробности

Графический процессор, как правило, производит вычисление выборок блоками 2x2.[36]. Каждый такой блок называется квадом[3]. Все выборки в пределах одного квада вычисляют с использованием одного и того же выражения. Если блок 2x2 попадает на край полигона, ускоритель всё равно вычисляет все выборки квада по одной и той же формуле, полагая, что все выборки попали на полигон.  В результате, если выборка в действительности не попала на полигон, её цвет вычисляется некорректно. Чтобы не “запортить” цвет субпикселей за пределами примитива, ускоритель предварительно вычисляет для каждого пикселя так называемую битовую маску покрытия (Coverage Mask), которая показывает, какие выборки покрывает примитив. Если выборка попадает на растеризуемый полигон, соответствующему биту в маске покрытия присваивается true, в противном случае – false. В кадровый буфер заносятся только те выборки, у которых соответствующие биты в маске покрытия равны true. В частности, в случае, изображённом на рисунке 1.52, две нижние выборки будут проигнорированы, поэтому два соответствующих субпикселя сохранят изначальный белый цвет.

 

Рисунок 1.52. Увеличенный фрагмент рисунка 1.51 (второй пиксель слева во второй строке сверху).

По окончанию визуализации изображения (то есть, после вызова метода Device.Present), итоговый цвет пикселя определяется на основе среднего арифметического значения всех выборок внутри пикселя. При расположении сэмплов аналогичном рисунку 1.51, цвет каждого пикселя будет определяться по формуле , где color0, color1, color2 и color3 – цвета соответствующих выборок. Эту формулу нетрудно обобщить на произвольное количество пикселей:

                               (1.22)

где

u        – цвет текущего пикселя.

u        – количество выборок на пиксель.

u       sampleColori– цвет -й выборки.

 

Реальное расположение выборок внутри пикселя – тайна за семью печатями. Эта информация является интеллектуальной собственностью разработчиков видеокарт и не подлежит разглашению. В общем случае взаимное расположение выборок может быть абсолютно любым[4] (рисунок 1.53). Если выборки расположены асимметрично относительно центра пикселя, то логично предположить, что наиболее сильное влияние на цвет пикселя должны оказывать выборки в центре пикселя, а наиболее слабое – выборки на периферии пикселя. Для реализации этого принципа можно назначить каждой выборке свой весовой коэффициент. Чем ближе расположена выборка к центру пикселя, тем больше коэффициент. В этом случае формула для вычисления цвета пикселя примет следующий вид:

                         (1.23)

где

u        – коэффициент для i–й выборки. Сумма всех коэффициентов равна 1:

                                                                                                                                   (1.24)

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

 

Рисунок 1.53. Некоторые варианты расположения выборок внутри пикселя (FSAA 4x). Рисунок взят из [22]

Использование SSAA позволяет значительно поднять качество изображения. Однако у этой технологии есть и обратная сторона медали – очень высокие требования к ресурсам компьютера. Например, использование SSAA с четырьмя выборками  на пиксель равносильно удваиванию разрешения экрана, что в некоторых случаях может привести к значительному падению производительности (иногда в 3-4 раза).

В результате была разработана оптимизированная версия технологии SSAAMSAA (MultiSampling AntiAliasing). Главная идея технологии MSAA – замена нескольких выборок на пиксель одной выборкой, общей для всех субпикселей. К примеру, если при использовании MSAA с четырьмя выборками на пиксель примитив покрывает все субпиксели пикселя (рисунок 1.54), то результаты  одной выборки (s1) заносятся во все четыре субпикселя (p1, p2, p3 и p4). Этот случай демонстрируется на рисунке 1.55. Если же примитив покрывает только два пикселя (рисунок 1.52), то и результаты выборки заносятся только в соответствующие два субпикселя (рисунок 1.56).

Рисунок 1.54. Отрезок чёрного цвета покрывает все четыре выборки. Изображение является увеличенным фрагментом рисунка 1.51 (третий пиксель слева во второй строке сверху).

 

Рисунок 1.55. Формирования цвета субпикселей при использовании MSAA 4x. Примитив проходит через все выборки.

 

Рисунок 1.56. Формирование цвета субпикселей при использовании MSAA 4x. Примитив проходит через две верхних выборки.

Примечание

Для обозначения MSAA с N субпикселями на пиксель обычно используется сокращение MSAA Nx. К примеру, MSAA 4x означает мультисэмплинг с четырьмя субпикселями на пиксель. В литературе субпиксели MSAA часто называют выборками (samples). Так, фраза “MSAA с четырьмя сэмплами[5] на пиксель” в действительности подразумевает “MSAA c четырьмя субпикселями на пиксель”. Подобные фразы обычно не вызывают путаницы, так как при MSAA всегда используется одна выборка на пиксель. Соответственно, если в тексте говорится о нескольких выборках, это означает что речь идёт либо о SSAA, либо под словам “выборки” подразумеваются субпиксели.

Нетрудно заметить, что при растеризации одноцветных примитивов, например, нашего узора Серпинского MSAA полностью аналогичен SSAA. Если растеризуется треугольник с разноцветными вершинами[6], то при использовании MSAA  качество пикселей в центре примитива будет полностью аналогично изображению, визуализированному с выключенным FSAA (во все субпиксели пикселя заносится один и тот же цвет). Качество сглаживания пикселей на краях примитивов будет практически аналогично SSAA. К примеру, если на примитив не попадает ни одна из выборок, он будет полностью прозрачным. Если при использовании MSAA 4x  примитив проходит через одну выборку, этот примитив будет вносить 25-ти процентный вклад  в цвет пикселя. Аналогично, для двух, трёх и четырёх выборок при MSAA 4x мы получим соответственно 50-ти, 75-ти и 100 процентный вклад примитива в цвет пикселя. В результате граница примитива будет такой же размытой[7], как и при использовании SSAA 4x. Качество самого примитива будет несколько ниже, чем у SSAA, так как во все субпиксели заносится одна и та же выборка. Что, впрочем, не критично: главная задача технологии MSAA – это сглаживание краёв изображения, и с ней она справляется на 5 балов.

А как обстоят дела со скоростью MSAA? Как известно, при растеризации изображения основное время занимает вычисление значений выборок[8]. Соответственно при переходе от SSAA Nx к MSAA Nx, мы получим почти N-кратный выигрыш в производительности. Полностью N-кратного прироста производительности в принципе не возможно достичь, так как результаты выборки всё равно записываются во все N субпикселей, что значительно повышает нагрузку на пропускную способность оперативной памяти. Кроме того, по окончанию визуализации необходимо понижать разрешение кадрового буфера путём усреднения субпикселей, что тоже занимает некоторое время. Тем не менее, на видеокартах с быстрой видеопамятью использование MSAA 2x или MSAA 4x может быть практически “бесплатным” в плане производительности.

В заключение раздела, мы бегло пробежимся по проблеме расположения выборки внутри пикселя. При использовании SSAA, мы определяем цвет пикселя на основе множества выборок, поэтому SSAA не критичен к расположению выборок. С MSAA всё несколько сложнее, так как цвет субпикселей определяется на основе единственной выборки. Если всё время делать выборку, к примеру, в центре пикселя, то при растеризации краёв объекта вполне вероятен неприятный эксцесс – выборка может оказаться за пределами объекта (рисунок 1.54, левое изображение), что привёт к искажению цвета пикселя. Поэтому видеокарты смещают выборку таким образом, чтобы она всё время оказывалась внутри полигона (рисунок 1.57, правое изображение).

 

Рисунок 1.57. Варианты расположения выборки для определения цвета пикселя:  в центре пикселя и внутри полигона. Рисунок взят из [22].

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

1.        При помощи панели управления драйверами видеокарты.

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

В следующих разделах мы подробно рассмотрим каждый из этих способов.

1.4.1. Включение полноэкранного сглаживания средствами драйвера

Драйвера современных видеокарт предоставляют пользователю развитые средства по управлению различными аспектами работы графических приложений, в частности, и полноэкранным сглаживанием. В этом разделе вы научитесь активировать в приложениях различные режимы полноэкранного сглаживания средствами драйверов видеокарт, использующих графические процессоры корпораций ATI и NVIDIA. Если вы уже включать FSAA средствами драйвера, можете пропустить этот раздел. Начнём с видеокарт, основанных на графических процессорах производства ATI.

 

ATI Catalyst Control Center

Видеокарты семейства ATI Radeon используют унифицированные драйвера под названием Catalyst. Эти драйвера подходят для всех видеокарт, использующих графические процессоры R1xx (Radeon 7xxx), R2xx (Radeon 8xxx), R3xx (Radeon 9xxx), R4xx (Radeon Xxxx) и R5xx (Radeon X1xxx), иными словами, для всех видеокарт на чипах ATI, выпущенных после 2000 года. Корпорация ATI регулярно обновляет драйвера Catalyst один раз в месяц, поэтому номера версий Catalyst имеют вид Y.M, где Y – последняя цифра номера года, а M – номер месяца. Например, название Catalyst 5.12 означает, что этот драйвер был выпущен в декабре 2005 года.

Конфигурирование настроек драйвера осуществляется с использованием утилиты Catalyst Control Center. Для запуска Catalyst Control Center щёлкните правой кнопкой мыши на рабочем столе Windows, и выберете в контекстном меню пункт ATI Catalyst (R) Control Center. По умолчанию интерфейс Catalyst Control Center находится в режиме Standard View, в котором от неопытного пользователя скрыты различные потенциально опасные опции, в том числе и управление полноэкранным сглаживанием. Для переключения расширенный режим щёлкните на кнопке View в верхней левой части диалогового окна и выберите в появившемся меню пункт Advanced View (рисунок 1.58).

Рисунок 1.58. Панель управления ATI Catalyst Control Center

Рисунок 1.59. Catalyst Control Center – вкладка управления опциями полноэкранного сглаживания

Чтобы открыть вкладку управления параметрами полноэкранного сглаживания, щелкните на узел 3D | Anti Aliasing во вкладке Graphics Setting, расположенной в левой части экрана. В правой части экрана откроется вкладка Anti-Aliasing. Чтобы разрешить драйверу вмешиваться в работу приложения, снимите флажок Let the application decide. Ползунок, расположенный внизу диалогового окна используется для задания числа субпикселей  на один пиксель при мультисэмплинге (суперсэмплинг не поддерживается[9]). При этом внесённые изменения автоматически отражаются на панели предварительного просмотра (3D Preview), расположенной чуть выше элементов управления.

Примечание

Для переключения панели 3D Preview в полноэкранный режим просто два раза щёлкните правой кнопкой мыши на этой панели. Нажатие клавиши Esc вернёт панель 3D Preview в нормальное состояние.

В частности, из рисунка 1.59 видно, видеокарта Radeon 9800XT поддерживает мультисэмплинг с использованием 2-х, 4-х или 6-ти субпикселей на пиксель. Однако собственно расположение субпикселей внутри пикселя – тайна за семью печатями, так как эта информация является интеллектуальной собственностью корпорации ATI и не подлежит разглашению. В общем случае взаимное расположение может быть абсолютно любым (рисунок 1.53). Более того, при установке флажка Temporal anti-aliasing, расположение выборок внутри пикселей постоянно меняется от кадра к кадру, что позволяет повысить качество сглаживания в анимированных сценах.

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

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

Для выключения принудительного форсирования MSAA достаточно снять флажок Let the application decide.

 

NVIDIA ForceWare Control Panel

Включение FSAA средствами драйверов NVIDIA во многом аналогично драйверам ATI. Однако есть и некоторые существенные отличия.

Видеокарты на чипах NVIDIA начиная с NV4 (RivaTNT) используют унифицированные драйвера под кодовым названием ForceWare. В отличие от корпорации ATI, NVIDIA использует классическую систему нумерации версий драйверов: номер версии формируется по схеме NN.XX (например, ForceWare 81.95), где NN – номер версии, а XX – номер подверсии. Если NVIDIA вносит в драйвер какие-то существенные изменения, то номер версии драйвера увеличивается до ближайшего числа кратного пяти и происходит так называемый выпуск нового релиза (Release). Релизы нумеруются целыми числами, кратными пяти. Таким образом, обозначение “ForceWare Release 75” подразумевает любой драйвер ForceWare, номер которого лежит в диапазоне 75.00 – 79.99.

Примечание

До Release 50 драйвера NVIDIA имели обозначение Detonator[10].

Настройка параметров визуализации осуществляется с использованием панели управления драйверами NVIDIA. Чтобы открыть эту панель, щёлкните правой кнопкой мыши на рабочем столе и выберите в контекстном меню пункт Properties (Свойства). В открывшемся диалоговом окне Display Properties (Свойства: Экран) выберите вкладку Setting и щёлкните на кнопке Advanced (Дополнительно). Появится ещё одно диалоговое окно, содержащее вкладку с названием вашей видеокарты, например, GeForce FX 5900 Ultra. Щелкните на эту вкладку, и вы попадёте в панель управления драйверами NVIDIA (рисунок 1.60).

Рисунок 1.60. Панель управления драйверами NVIDIA

Переключение между различными вкладками панели осуществляется с использованием меню, расположенном слева от диалогового окна. Чтобы открыть вкладку, отвечающую за настройку параметров визуализации, выберите пункт меню Performance & Quality Setting (Производительность и качество). Для настройки параметров найдите группу Global driver settings (Глобальные установки драйвера) и  выберите в списке элемент Antialiasing setting (Параметры сглаживания), после чего внизу окна появятся элементы управления сглаживанием (рисунок 1.60).

Чтобы разрешить драйверу вмешиваться в работу приложения, снимите флажок Application-Controlled (Управляемые приложением). Установка параметров полноэкранного сглаживания осуществляется с использованием ползунка в нижней части диалогового окна. Как видно, из рисунка 1.60, видеокарта GeForce FX 5900 Ultra поддерживает четыре режима сглаживания, перечисленные в порядке улучшения качества: 2x, 2xQ, 4x и 8xS:

q      2x – обычный мультисэмплинг с двумя субпикселями на каждый пиксель

q      2xQ – особый режим мультисэмплинга под названием Quincunx. Результаты выборки заносятся в два субпикселя[11], расположенные в левом верхнем углу и центре пикселя (рисунок 1.60). При вычислении цвета пикселя используется пять субпикселей: четыре субпикселя по краям пикселя и один субпиксель в центре пикселя. Таким образом, мы получаем качество близкое к MSAA 4x  при нагрузке на пропускную способность видеопамяти как у MSAA 2x.

q      4x – классический мультисэмплинг с четырьмя выборками на пиксель.

q      8xS – “мичуринский гибрид” SSAA 2x и MSAA 4x[12] (рисунок 1.62). При растеризации границ используется две выборки на пиксель (s1 и s2). Результаты каждой выборки заносятся соответствующие в четыре субпикселя. Это демонстрируется на рисунке 1.59, где результаты выборки s1 заносятся в субпиксели p1, p2, p3 и p4, а результаты выборки s2 – в субпиксели p5, p6, p7 и p8. Таким образом, при вычислении цвета каждого пикселя используется восьми субпикселей[13]. В результате этот режим с одной стороны похож на SSAA 2x (две выборки на пиксель), а с другой на MSAA 4x (каждая выборка заносится в четыре субпикселя). Режим 8xS обладает превосходным качеством визуализации. Обратная сторона медали – катастрофическое падение производительности. Падение производительности обусловлено двумя причинами. Во-первых, для каждого пикселя экрана необходимо вычислять две выборки, что уже само по себе снижает производительность почти в два раза. Во-вторых, огромной нагрузкой на пропускную способность видеопамять из-за восьмикратного увеличения размера экранного буфера.

Примечание

Использование SSAA ощутимо улучает качество визуализации текстурированных объектов[14]. Однако, при визуализации однотонных объектов вроде узора Серпинского SSAA является пустой тратой ресурсов.

 

Рисунок 1.61. Растеризация треугольника (на фоне большого белого полигона) с использованием NVIDIA Quincunx MSSA[15]. Показаны только выборки для определения прозрачности пикселя.

Рисунок 1.62. Растеризация треугольника с использованием гибридного режима 8xS (SSAA 2x + MSAA 4x)[16]

Попробуйте поэкспериментировать с настройками MSAA на примере вышеупомянутого приложения Ex15. Как и на видеокартах ATI, качество изображения будет заметно улучшаться пока количество субпикселей на пиксель не достигнет 4-х. Дальнейшее увеличение числа выборок практически не окажет влияния на качество изображения.

Для выключения принудительного форсирования MSAA достаточно снять флажок Let the application decide.

1.4.2. Включение MSAA из приложения

В предыдущем разделе (1.4.1) вы научились включать полноэкранное сглаживание средствами драйвера. Это позволило нам значительно повысить качество визуализации узора Серпинского (пример Ex15). Тем не менее, у этого способа есть три существенных недостатка:

1.        Далеко не все пользователи умеют пользоваться панелью управления драйвера. Не исключена вероятность того, что многие часть пользователей будут использовать ваше приложение без FSAA, списывая ступенчатость краёв объектов на “глючность” вашего приложения.

2.        Многие приложения требуют индивидуальных настроек FSAA. К примеру, на видеокарте Radeon 9800XT при использовании MSAA 6x наше приложение Ex15 демонстрирует вполне нормальную производительность. Однако, запустив на этом же режиме (MSAA 6x) знаменитый Doom3, мы получим самое настоящее слайд-шоу – частота кадров упадёт ниже 10 FPS. Поэтому если  пользователь захочет использовать наше приложение для исследования узора Серпинского, периодически поигрывая в перерывах в Doom3,  то ему придётся постоянно корректировать настройки в панели управления драйвером, от чего он вряд ли будет в восторге.

3.        Драйвер не всегда может корректно включить FSAA, особенно если в приложении используются различные продвинутые технологии визуализации. Вы наверняка не раз сталкивались с играми, не реагирующими на изменение настроек FSAA в панели управления драйвера.

 

Примечание

Драйвера NVIDIA ForceWare позволяют сопоставлять каждому приложению индивидуальные настройки. Однако далеко не все пользователи знают об этой возможности. Кроме того, при перестановке драйверов информация об индивидуальных настройках теряется, что очень неудобно[17].

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

Microsoft DirectX поддерживает только полноэкранное сглаживание с использованием мультисэмплинга – корпорация Microsoft, как и ATI, считает, что суперсэмплинг значительно уступает мультисэмплингу в качестве при той же производительности, и поэтому его нет смысла поддерживать.

Примечание

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

Включение MSAA осуществляется путём присваивания необходимого значения полю MultiSampleType структуры Direct3D.PresentParameters:

public MultiSampleType MultiSampleType { get; set; }
Тип MultiSampleType объявлен следующим образом:
public enum MultiSampleType
{
// Мультисэмплинг отключен
    None = 0,
// Немаскируемый режим MSAA. Параметры MSAA задаются с использованием свойства 
// PresentParams.MultiSampleQuality 
    NonMaskable = 1,
// Далее идут маскируемые режимы MSAA. Название констант однозначно определяют режим MSAA. 
// Обратите внимание - значения констант совпадают числом выборок (субпикселей) на пиксель.
// MSAA 2x
    TwoSamples = 2,
// MSAA 3x
    ThreeSamples = 3,
// MSAA 4x
    FourSamples = 4,
    FiveSamples = 5,
    SixSamples = 6,
    SevenSamples = 7,
    EightSamples = 8,
    NineSamples = 9,
    TenSamples = 10,
    ElevenSamples = 11,
    TwelveSamples = 12,
    ThirteenSamples = 13,
    FourteenSamples = 14,
    FifteenSamples = 15,
    SixteenSamples = 16,
}

 

По умолчанию полю PresentParameters.MultiSampleType присвоено значение MultiSampleType.None, то есть мультисэмплинг отключен. В DirectX существует две большие группы режимов MSAA:

1.        Маскируемые[18] (Maskable) режимы MSAA, задающиеся количеством выборок (субпикселей) на пиксель.

2.        Немаскируемые (Non Maskable) режимы MSAA, которые нумеруются целыми числами, начиная с 2.

Каждый способ имеет свои достоинства и недостатки. Достоинством первого способа является прозрачность задания качества MSAA, которое хорошо коррелирует с количеством выборок на пиксель.  Для включения, к примеру, MSAA 4x нам необходимо просто присвоить полю PresentParameters.MultiSampleType значение MultiSampleType.FourSamples:

Листинг 1.24

presentParams = new PresentParameters();
presentParams.IsWindowed = true;
presentParams.BackBufferCount = 1;
presentParams.BackBufferWidth = ClientSize.Width;
presentParams.BackBufferHeight = ClientSize.Height;
presentParams.SwapEffect = SwapEffect.Discard;
// Включаем MSAA 4x
presentParams.MultiSampleType = MultiSampleType.FourSamples;

device = new Device(0, DeviceType.Hardware, this.Handle,
    CreateFlags.HardwareVertexProcessing, presentParams);

 

Примечание

Настройки параметров MSAA в панели управления драйвера имеют приоритет перед установками программы. Например, если в драйвере включен режим MSAA 2x, а приложение пытается создать устройство, использующее MSAA 4x, то в итоге будет создано устройство, использующее режим MSAA 2x.

Как видно всё очень просто, за исключением одного  нюанса: если видеокарта не поддерживает MSAA 4x, то при создании устройства командой new Device приложение аварийно завершит работу  с исключением Direct3D.InvalidCallException. Для решения этой проблемы можно поместить оператор создания устройства в блок try…catch, предусмотрев обработчик исключения Direct3D.InvalidCallException, создающий устройство с отключенным MSAA:

Листинг 1.25

...
presentParams.MultiSampleType = MultiSampleType.FourSamples;

try
{
    device = new Device(0, DeviceType.Hardware, this.Handle,
        CreateFlags.HardwareVertexProcessing, presentParams);
}
catch (InvalidCallException) 
{
// Если не удалось создать устройство с MSAA 4x, отключаем MSAA
    presentParams.MultiSampleType = MultiSampleType.None;
    device = new Device(0, DeviceType.Hardware, this.Handle,
        CreateFlags.HardwareVertexProcessing, presentParams);
}

 

Правда, такое решение трудно назвать удовлетворительным, так как данный код всегда будет отключать MSAA на любой видеокарте, не поддерживающей MSAA 4x. Иными словами, программа будет работать по принципу либо сразу всё, либо ничего. А ведь вполне может оказаться, что видеокарта, не поддерживающая режим MSAA 4x, поддерживает MSAA 2x или MSAA 6x, или вообще какой-нибудь экзотический режим вроде MSAA 3x.

Так как наша программа не требовательна к ресурсам видеоподсистемы, мы можем избрать следующую простую стратегию выбора режима MSAA – программа планомерно перебирает все режимы MSAA от MSAA 16x до MSAA 2x, пытаясь создать устройство. Если же все попытки создания устройства потерпят крах, программа создаст устройство, не использующее MSAA. Таким образом, программа всегда будет использовать самый высококачественный режим MSAA. Этот подход демонстрируется в примере Ex25 (листинг 1.26).

Листинг 1.26

private void MainForm_Load(object sender, EventArgs e)
{
    SetStyle(ControlStyles.Opaque | ControlStyles.ResizeRedraw, true);
    MinimumSize = new System.Drawing.Size(Width - ClientSize.Width + 1,
        Height - ClientSize.Height + 1);

    presentParams = new PresentParameters();
    presentParams.IsWindowed = true;
    presentParams.BackBufferCount = 1;
    presentParams.BackBufferWidth = ClientSize.Width;
    presentParams.BackBufferHeight = ClientSize.Height;
    presentParams.SwapEffect = SwapEffect.Discard;

// Перебираем все режимы MSAA от MSAA 16x до MSAA 2x
    for (presentParams.MultiSampleType = MultiSampleType.SixteenSamples; 
        presentParams.MultiSampleType >= MultiSampleType.TwoSamples; 
        presentParams.MultiSampleType--)
    {
        try
        {
// Пытаемся создать устройство с использованием текущего режима MSAA
            device = new Device(0, DeviceType.Hardware, this.Handle,
                CreateFlags.HardwareVertexProcessing, presentParams);
// Добавляем в заголовок окна информацию о выбранном типе MSAA
            Text = String.Format("{0}: MSAA {1}x", Text,   
(int) presentParams.MultiSampleType);
// Если удалось создать устройство, прерываем цикл
            break;
        }
        catch (InvalidCallException)
        {
        }
    }

// Если устройство всё же создать не удалось
    if (device == null)
    {
// Выключаем MSAA
        presentParams.MultiSampleType = MultiSampleType.None;
// Создаём устройство
        device = new Device(0, DeviceType.Hardware, this.Handle,
            CreateFlags.HardwareVertexProcessing, presentParams);
// Добавляем в заголовок окна информацию об отключении MSAA
        Text = String.Format("{0}: No MSAA", Text);
    }

    MainForm_Resize(this, null);
}

 

Хотя пример Ex25 и работает корректно, множество попыток создания контекста устройства с постоянным перехватом исключений InvalidCallException  выглядят не особенно красиво. Поэтому  разработчики DirectX заботливо предусмотрели класс Manager, содержащий множество методов, предоставляющих программисту детальную информацию о возможностях видеосистемы компьютера. Функциональные возможности класса Manager во многом аналогичны полю Capabilities класса Device, за исключением одной важной особенности – для использования класса Manager нет необходимости создавать экземпляр класс устройства. Таким образом, класс Manager идеально подходит для получения информации о возможностях видеоподсистемы перед созданием устройства.

Для получения информации о поддерживаемых режимах MSAA в классе Managed имеется статический метод CheckDeviceMultiSampleType, объявленный следующим образом:

ResultCode CheckDeviceMultiSampleType(int adapterOrdinal, DeviceType deviceType, Format surfaceFormat, bool isWindowed, MultiSampleType sampleType);

где

u       adapterOrdinal – номер видеокарты (аналогичен одноимённому параметру конструктора класса Device)

u       DeviceType – тип устройства (аналогичен одноимённому параметру конструктора класса Device)

u       Format surfaceFormat – формат кадрового буфера (см. ниже)

u       isWindowed – является ли приложение оконным (аналогичен одноимённому параметру конструктора класса Device)

u       sampleType – тип MSAA, поддержку которого необходимо проверить

Если требуемый режим MSAA поддерживается, метод возвращает true, в противном случае false.

Большинство параметров метода CheckDeviceMultiSampleType аналогичны одноимённым параметрам конструктора класса Device. Единственный новый параметр, surfaceFormat, задаёт формат кадрового буфера, используемого для хранения изображения. Формат кадрового буфера определяет, сколько бит отводится для хранения каждого пикселя экрана, в частности, какое количество из тратится на хранение информации о каждом цветовом канале пикселя (красный, синий и зелёный) и как эти каналы расположены относительно друг-друга. Формат кадрового буфера задаётся с использованием перечислимого типа Format, названия большинства членов которого имеют следующий вид:

{C1}{L1}{C2}{L2}{C3}{L3}…

где

u       C1, C2, C3 и т.д. – идентификаторы цветовых каналов, перечисленные в порядке физического расположения внутри пикселя. В качестве идентификаторов канала обычно используются первые буквы названия каналов: R – красный (Red), G – зелёный (Green), B –голубой (Blue), A – альфа канал[19] (Alpha), X – неиспользуемые биты.

u       L1, L2, L3 – количество бит, отводимых для хранения каждого цветового канала.

В этой главе мы будем использовать широко распространенный формат Format.X8R8G8B8, известный большинству пользователей как “32-х битный цвет”. Из названия формата Format.X8R8G8B8 можно сделать следующие выводы о внутреннем устройстве этого формата:

1.        Для хранения каждого пикселя отводится 32-бита (8+8+8+8=32)

2.        Для хранения каждого цветового канала отводится 8 бит (один байт). Следовательно, этот формат позволяет использовать 28=256 градаций яркости красного, зелёного и синего цвета. Суммарное количество цветовых отсеков равно 28·28·28=224=16777216.

3.        Эти 32 бита распределяются следующим образом: биты с 0-го по 7-й не используются, с биты 8-го по 15-й используются для хранения яркости красного цвета, с 16-го по 23-й бит – яркости зелёного цвета, и, наконец, с 24-го по 31-й бит – яркости синего цвета. Использование дополнительных 8-ми бит (с 0-го по 7-й) позволяет увеличить размер пикселя с 24-х до 32-х бит, что положительно сказывается на производительности видеоподсистемы. Дело в том, что современные процессоры обрабатывают информацию порциями по 8, 16, 32 или 64 бит. В результате запись в оперативную память порции данных размером 24 бита требует две операции записи (сначала запись 16-ти бит, а затем 8-ми), в то время как запись 32-х бит происходит за один присест.

Примечание

В DirectX имеется и 24-х битный Format.R8G8B8, не использующий дополнительные биты. Однако большинство видеокарт[20] его не поддерживают из-за более низкой производительности, по сравнению с Format.X8R8G8B8.

Использование метода CheckDeviceMultiSampleType позволит нам легко переписать код примера Ex25 без использования блока trycatch (Ex26):

 

 

Листинг 1.27

presentParams = new PresentParameters();
presentParams.IsWindowed = true;
presentParams.BackBufferCount = 1;
presentParams.BackBufferWidth = ClientSize.Width;
presentParams.BackBufferHeight = ClientSize.Height;
// Задаём формат экранного буфера
presentParams.BackBufferFormat = Format.X8R8G8B8;
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.MultiSampleType = MultiSampleType.None;

// Перебираем все типы MSAA с MSAA 16x до MSAA 2x
for (MultiSampleType mt = MultiSampleType.SixteenSamples; mt >= MultiSampleType.TwoSamples; mt--)
{
// Если текущий типа MSAA поддерживает MSAA
    if (Manager.CheckDeviceMultiSampleType(0, DeviceType.Hardware, Format.X8R8G8B8, true,
        mt))
    {
// Устанавливает этот режим
        presentParams.MultiSampleType = mt;
// Изменяем заголовок окна
        Text = String.Format("{0}: MSAA {1}x", Text, (int) mt);
        break;
    }
}

// Если видеокарта не поддерживает не один из режимов MSAA, изменяем заголовок 
// соответствующим образом
if (presentParams.MultiSampleType == MultiSampleType.None)
    Text = String.Format("{0}: No MSAA", Text);

// Создаём устройство
device = new Device(0, DeviceType.Hardware, this.Handle,
    CreateFlags.HardwareVertexProcessing, presentParams);

 

Обратите внимание на то явное задание формата вспомогательного  буфера (в котором собственно и рисуется изображение):

presentParams.BackBufferFormat = Format.X8R8G8B8;

По умолчанию свойству PresentParameters.BackBufferFormat присвоено значение Format.Unknown, то есть DirectX самостоятельно выбирает формат пикселей, наиболее оптимальный с его точки зрения.  С другой стороны информация о поддерживаемых режимах MSAA, полученная нами с использованием метода  верна только для формата Format.X8R8G8B8. Вполне вероятно, что для других форматов вроде Format.X8B8G8R8, Format.R8G8B8 или Format.A8R8G8B8 список поддерживаемых режимов MSAA будет несколько иным. Поэтому мы обязаны явно задавать формат кадрового буфера – оставив значение Format.Unknown мы рискуем однажды получить исключение Direct3D.InvalidCallException.

Перейдём ко второму способу задания режимов MSAA – так называемым немаскируемым режимам. Если присвоить свойству PresentParameters.MultiSampleType значение MultiSampleType.NonMaskable, то режим MSAA будет определяться значением поля PresentParameters.MultiSampleQuality:

public int MultiSampleQuality { get; set; }

Данное поле может принимать целые значения от нуля и выше, причём, чем большее значение присвоено этому полю, тем лучше качество MSAA. Нуль соответствует наихудшему качеству FSAA. В общем случае, “уровни качества” MultiSampleQuality являются абстрактным понятием, привязанным к конкретной видеокарте. Единственное, что можно наверняка сказать об уровне качества с номером N, это то, что этот уровень качества лучше N-1, однако при этом уступает по качеству уровню качеству N+1. Как сильно различаются между собой уровни качества N-1, N и N+1 и какое количество сколько сэмплов на пиксель они используют – тайна за семью печатями. Например, на видеокарте ATI Radeon 9800XT второй уровень качества соответствует[21] MSAA 6x, а на видеокарте NVIDIA GeForce FX 5900 Ultra – MSAA 4x.

Однако нумерация немаскируемых режимов MSAA по уровням качества имеет и существенный плюс перед  прямым заданием количества выборок на пиксель – в отличие от маскируемых режимов MSAA, она позволяет использовать различные нестандартные режимы MSAA вроде NVIDIA Quincunx (см. раздел NVIDIA ForceWare Control Panel). Более того, на многих старых видеокартах, не поддерживающих канонический MSAA (например, NVIDIA GeForce2), использование  немаскируемых режимов MSAA является  единственным способом включения FSAA. Кроме того, режим MultiSampleType.NonMaskable позволяет приложению легко изменять качество MSAA, не задумываясь о количестве выборок на пиксель: для увеличения качества MSAA достаточно увеличить значение поля PresentParameters.MultiSampleQuality на единицу, а для понижения качества – уменьшить на единицу.

Определение максимального поддерживаемого уровня качества MSAA осуществляется с использованием перегруженного метода Manager.CheckDeviceMultiSampleType, с дополнительным параметром:

public static bool CheckDeviceMultiSampleType(int adapterOrdinal, DeviceType deviceType, Format surfaceFormat, bool isWindowed, MultiSampleType sampleType, out int qualityLevels);

где

int qualityLevels – возвращает количество поддерживаемых уровней качества MSAA. Для маскируемых режимов значение этого параметра всегда равно 1.

Примечание

При использовании маскируемых режимов MSAA свойство PresentParameters.MultiSampleQuality всегда должно быть равно нулю. Если вы измените значение этого свойства на ненулевое значение, то при создании устройства, использующее маскируемый режим MSAA, скорее всего получите исключение Direct3D.InvalidCallException.

В листинге 1.28 приведён исходный код примера Ex27, использующего максимальное качество немаскируемого MSAA, поддерживаемое видеокартой:

Листинг 1.28.

presentParams = new PresentParameters();
presentParams.IsWindowed = true;
presentParams.BackBufferCount = 1;
presentParams.BackBufferWidth = ClientSize.Width;
presentParams.BackBufferHeight = ClientSize.Height;
presentParams.BackBufferFormat = Format.X8R8G8B8;
presentParams.SwapEffect = SwapEffect.Discard;

int qualityLevels;
// Проверяем поддержку NonMaskable MSAA, и попутно получаем информацию о количестве уровней 
// качества MSAA
if (Manager.CheckDeviceMultiSampleType(0, DeviceType.Hardware, Format.X8R8G8B8, true,  
        MultiSampleType.NonMaskable, out qualityLevels))
{
// Если видеокарта поддерживает немаскируемый режим MSAA
// то задаём соответствующий тип MSAA
    presentParams.MultiSampleType = MultiSampleType.NonMaskable;
// Устанавливаем максимальное качество MSAA
    presentParams.MultiSampleQuality = qualityLevels - 1;
// Выводим в заголовке окна информацию об уровне качества MSAA
    Text += ": MSAA Quality Level - " + presentParams.MultiSampleQuality;
}
else
{
// Выключаем MSAA
    presentParams.MultiSampleType = MultiSampleType.None;
// Выводим соответствующую информацию в заголовке устройства
    Text += ": no MSAA";
}

device = new Device(0, DeviceType.Hardware, this.Handle,  CreateFlags.HardwareVertexProcessing, presentParams);

 

Как видно, исходный код пример Ex27, использующего немаскируемый режим MSAA, получился более компактным, чем код примера Ex26 (маскируемый MSAA). Кроме того, у примера Ex27 есть одно важное преимущество – в некоторых случаях он может демонстрировать более высокое качество MSAA по сравнению с примером Ex26. Так, например, на GeForce2 пример Ex26 запустится с отключенным MSAA, в то время как пример Ex27 будет использовать немаскируемый режим MSAA 1-го уровня качества[22].

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

“Научите” программу из  практического упражнения №8 (построение фигуры Листажу) автоматически использовать наилучшее качество  MSAA, поддерживаемое текущей видеокартой.

 

1.4.3. Создание диалогового окна для выбора режима MSAA

В прошлом разделе мы создали несколько приложений, автоматически использующих MSAA максимального качества. В идеальном мире такой подход вполне оправдан, но, к сожалению, наш мир далёк от идеального, и  агрессивное использование высококачественных режимов чревато рядом потенциальных неприятностей:

q      Многие видеокарты класса Low End существенно теряют производительность[23] при использовании высококачественных режимов MSAA.

q      В редких случаях видеокарта (и/или драйвер) могут “подглючивать” при использовании некоторых режимов MSAA.

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

Для начала нам надо определиться, каким образом пользователь будет задавать режим MSAA. В разделе 1.4.2 говорилось, что DirectX позволяет задавать режим MSAA двумя способами: с использованием маскируемого и не маскируемого MSAA. Каждый способ имеет свои достоинства и недостатки: маскируемые режимы MSAA позволяют естественно задавать качество MSAA, в то время как немаскируемые режимы позволяют использовать нестандартные режимы MSAA. Не мудрствуя лукаво, мы встроим в пример Ex15 (узор Серпинского) поддержку обоих режимов, предоставив пользователю свободу выбора.

Для хранения информации о настройках приложения мы создадим свой собственный класс Config. Для этого щёлкните правой кнопкой мыши на название проекта в панели Solution Explore, и выберите контекстом меню пункт Add | New Item… (рисунок 1.63). В открывшемся диалоговом окне (рисунок 1.64) выберите значок Class и введите название нашего класса (Config). Нажмите Ok, после чего Visual Studio создаст заготовку класса. Добавьте в класс два поля для хранения параметров MSAA (листинг 1.29)

Листинг 1.29.

namespace ApplicationConfig
{
    public class Config
    {
// Тип MSAA
        public MultiSampleType multiSampleType = MultiSampleType.None;
// Качество MSAA
        public int multiSampleQuality = 0;
    }
}

 

Рисунок 1.63. Добавление в проект нового класса

 

Рисунок 1.64. Диалоговое окно Add New Item…

После этого добавьте в класс MainForm (главная форма приложения) поле config, в котором будет храниться информация о приложении (листинг 1.30).

Листинг 1.30.

...
using ApplicationConfig;

public partial class MainForm : Form
{
// Объявляем поле для хранения информации о настройках приложения
    Config config;
...
    private void MainForm_Load(object sender, EventArgs e)
    {
...
// Создаём экземпляр класса
        config = new Config();

        presentParams = new PresentParameters();
        presentParams.IsWindowed = true;
        presentParams.BackBufferCount = 1;
        presentParams.BackBufferWidth = ClientSize.Width;
        presentParams.BackBufferHeight = ClientSize.Height;
        presentParams.SwapEffect = SwapEffect.Discard;
// Задаём параметры устройства на основе поля config
        presentParams.MultiSampleType = config.multiSampleType;
        presentParams.MultiSampleQuality = config.multiSampleQuality;

        device = new Device(0, DeviceType.Hardware, this.Handle,
            CreateFlags.HardwareVertexProcessing, presentParams);
...
    }
}

Теперь мы можем приступать к созданию диалогового окна выбора режима MSAA. Щелкните правой кнопкой мыши на названии проекта в панели Solution Explore, и выберите контекстом меню пункт Add | New Item… . В открывшемся диалоговом окне  выберите значок Windows Form и введите название нашего класса формы (SettingsForm). Нажмите кнопку Ok и Visual Studio создаст заготовку новой формы.

Чтобы вы могли получить представление о конечном результате, на рисунках 1.65 и 1.66 приведён внешний вид формы, которую мы сейчас создадим. Я советую вам запустить пример Ex28 и попробовать “поиграться” с различными параметрами MSAA.

Рисунок 1.65. Диалоговое окно «Параметры визуализации». Настройки Maskable MSAA

 

Рисунок 1.66. Диалоговое окно «Параметры визуализации». Настройки Non Maskable MSAA

Тип MSAA задается с использованием переключателей в верхней части диалогового окна. Переключатель (RadioButton) «Количество сэмплов на пиксель» соответствует маскируемому MSAA, а «Производительность/Качество» – немаскируемому MSAA. В нижней части диалогового окна расположены элементы управления для выбора настроек MSAA – выпадающий список (ComboBox) поддерживаемых режимов MSAA при использовании Maskable MSAA (рисунок 1.61) и ползунок (TrackBar) «Скорость/Качество» при использовании Non Maskable MSAA (рисунок 1.62). Для применения настроек, необходимо нажать кнопку Применить, в противном случае – Отмена.

Приступим к созданию формы. Для начала установите свойство формы Start Position в значение CenterParent, а FormatBorderStyle – в значение FixedToolWindow. Добавьте на форму два компонента GroupBox с заголовками «Параметры MSAA» и «Задание MSAA с использованием». Поместите вовнутрь второй группы два переключателя и назовите их maskedMsaaRadioButton (надпись «Количество сэмплов на пиксель») и nonMaskedMsaaRadioButton (надпись «Производительность/Качество»).

Разместите чуть ниже группы с заголовком «Задание MSAA с использованием» компонент Panel и назовите его maskedMsaaPanel. Поместите на него компонент ComboBox и переименуйте его msaaComboBox. Свойству DropDownStyle  выпадающего списка msaaComboBox присвойте значение DropDownList.

Рисунок 1.67. Диалоговое окно «Параметры визуализации» в режиме конструктора. Выделена панель maskedMsaaPanel.

Поместите на форму поверх (не на сам компонент!) компонента maskedMsaaPanel ещё один компонент Panel, и назовите его nonMaskedMsaaPanel. Разместите на этом компоненте компонент TrackBar и переименуйте его в msaaQualityLevelTrackBar. Присвойте свойству LargeChange этого компонента значение 1, а свойству Maximum – значение 0.

Примечание

Для быстрого переключения между перекрывающимися  maskedMsaaPanel и nonMaskedMsaaPanel можно воспользоваться пунктами контекстного меню Bring to Front и Bring to Back

Наконец, поместите в нижней части формы кнопки okButton (Применить) и cancelButton (Отмена). Свойству DialogResult кнопки cancelButton присвойте значение Cancel.

Теперь мы можем приступать к программированию логики формы. Для начала мы реализуем следующую простую функциональность. При нажатии переключателя maskedMsaaRadioButton должна отобразиться панель maskedMsaaPanel, а панель nonMaskedMsaaPanel – скрыться. При нажатии nonMaskedMsaaRadioButton всё должно происходить с точностью наоборот. Если же не нажата ни одна из радио кнопок  – обе панели должны исчезнуть.

Выберите переключатель  maskedMsaaRadioButton и создайте обработчик события CheckedChanged (листинг 1.31). После чего выделите переключатель nonMaskedMsaaRadioButton и назначьте в качестве обработчика события нажатия CheckedChanged аналогичный обработчик переключателя maskedMsaaRadioButton (функцию maskedMsaaRadioButton_CheckedChanged).

Листинг 1.31

private void maskedMsaaRadioButton_CheckedChanged(object sender, EventArgs e)
{
// Если нажата радио кнопка "Количество сэмплов на пиксель"
    if (maskedMsaaRadioButton.Checked == true)
    {
        maskedMsaaPanel.Visible = true;
        nonMaskedMsaaPanel.Visible = false;
    }
    Else
// Если нажата радио кнопка "Производительность/Качество"
        if (nonMaskedMsaaRadioButton.Checked == true)
        {
            maskedMsaaPanel.Visible = false;
            nonMaskedMsaaPanel.Visible = true;
        }
        else
        {
// Если не нажата не одна из радио кнопок
            maskedMsaaPanel.Visible = false;
            nonMaskedMsaaPanel.Visible = false;
        }
}

 

Следующий этап – написание конструктора формы (листинг 1.32):

Листинг 1.32.

// Ссылка на экземпляр класса Config, передаваемый конструкту формы. Модификация полей 
// объекта автоматически затрагивает и оригинал
Config config;

// Конструктор. Принимает в качестве параметра экземпляр класса Config
public SettingForm(Config config)
{
    InitializeComponent();

// Сохраняем ссылку на класс config в поле объекта
    this.config = config;

// Формируем список поддерживаемых режимов Maskable MSAA
    msaaComboBox.Items.Add("1 (MSAA Отключен)");
// Перебриваем режимы маскируемые режимы от MSAA 2x до MSAA 16x
    for (MultiSampleType m=MultiSampleType.TwoSamples; m <= MultiSampleType.SixteenSamples;   m++)
// Если текущий режим MSAA поддерживается
        if (Manager.CheckDeviceMultiSampleType(0, DeviceType.Hardware, Format.X8R8G8B8,  
true, m))
// Добавляем его в список. Обратите внимание на приведение переменной m к типу int. Если 
// этого не сделать, то, к примеру, для значения MultiSampleType.TwoSamples метод ToString() 
// возвратит строку "TwoSamples" вместо "2"
            msaaComboBox.Items.Add(((int)m).ToString());

// Запрашиваем количество поддерживаемых уровней качества Non Maskable MSAA
    int qualityLevels;
    if (Manager.CheckDeviceMultiSampleType(0, DeviceType.Hardware, Format.X8R8G8B8, true,
        MultiSampleType.NonMaskable, out qualityLevels))
    {
// Задаём максимальное значение полосы прокрутки.
        msaaQualityLevelTrackBar.Maximum = qualityLevels;
    }

// Далее настраиваем интерфейс формы исходя из текущих значений полей ссылки на config

// Если используется режим MSAA
    if (config.multiSampleType == MultiSampleType.NonMaskable)
    {
// Включаем переключатель "Производительность/Качество". Переключатель "Количество сэмплов на 
// пиксель" автоматически "отожмётся"
        nonMaskedMsaaRadioButton.Checked = true;

// Если config.multiSampleQuality находится в допустимом диапазоне
        if ((config.multiSampleQuality >= 0) &&
            (config.multiSampleQuality < msaaQualityLevelTrackBar.Maximum))
        {
// Задаём положение ползунка
            msaaQualityLevelTrackBar.Value = config.multiSampleQuality + 1;
        }
        else
// Если значение config.multiSampleQuality является некорректным, сбрасываем оба 
// переключателя
            nonMaskedMsaaRadioButton.Checked = false;
        }
    }
    else
    {
// Включаем переключатель "Количество сэмплов на пиксель" 
        maskedMsaaRadioButton.Checked = true;
// Если MSAA отключен
        if (config.multiSampleType == MultiSampleType.None)
// Выбираем первый элемент выпадающего списка ("1 (MSAA Отключен)")
            msaaComboBox.SelectedIndex = 0;
        else
// Выбираем элемент исходя из его значения
            msaaComboBox.SelectedItem = ((int)config.multiSampleType).ToString();
    }
} 

Как видно, конструктор формы является довольно тривиальным. Первым делом, конструктор сохраняет ссылку на экземпляр класса Config, которая используется для возврата результата диалогового окна. Затем программа определяет перечень поддерживаем режимов MSAA и заносит их в комбинированный список msaaComboBox и устанавливает диапазон, в которых может перемещаться ползунок msaaQualityLevelTrackBar. Далее программа выставляет положение начальные значения всех элементов управления диалогового окна в соответствии с параметром config, проверяя при этом корректность значений полей параметра config.

Заключительный этап создания диалогового окна  «Параметры визуализации» – определение обработчика события нажатия кнопки «Применить» (листинг 1.33).

Листинг 1.33.

private void okButton_Click(object sender, EventArgs e)
{
// Если включен переключатель "Количество сэмплов на пиксель"
    if (maskedMsaaRadioButton.Checked == true)
    {
// Если не выбран не один из пунктов выпадающего списка, выводим сообщение об ошибке
        if (msaaComboBox.SelectedIndex == -1)
        {
            MessageBox.Show("Укажите режим MSAA", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }

        try
        {
// Преобразовать выбранное значение из выпадающего списка к MultiSampleType
            config.multiSampleType = (MultiSampleType)Convert.ToInt32(msaaComboBox.SelectedItem);
        }
        catch (FormatException)
        {
// Если не удалось, значит выбрано значение "1 (MSAA Отключен)"
            config.multiSampleType = MultiSampleType.None;
        }
// Присваиваем значению качеству MSAA нулевое значение
        config.multiSampleQuality = 0;
    }
    else
// Если нажат переключатель "Производительность/Качество"
        if (nonMaskedMsaaRadioButton.Checked == true)
        {
// Если ползунок находится в крайнем левом положении
            if (msaaQualityLevelTrackBar.Value == 0)
            {
// Значит MSAA отключен
                config.multiSampleType = MultiSampleType.None;
                config.multiSampleQuality = 0;
            }
            else
            {
// Выставляем настройки для Non Maskable MSAA
                config.multiSampleType = MultiSampleType.NonMaskable;
                config.multiSampleQuality = msaaQualityLevelTrackBar.Value-1;
            }
        }
        else
        {
// Если не включен ни один из переключателей, значит что-то не так
            MessageBox.Show("Укажите режим MSAA", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }

// Возвращаем значение DialogResult.OK
    this.DialogResult = DialogResult.OK;
}

 

После создания диалогового окна «Параметры визуализации» мы можем приступать к интеграции его с приложением. Для начала поместите на форму компонент MenuStrip и  создайте меню «Файл» с двумя вложенными пунктами «Параметры визуализации» и «Выход».

В листинге 1.34 приведён текст обработчика пункта меню «Параметры визуализации». Как видно, при выборе пункта меню «Параметры визуализации» программа выводит на экран пункт диалоговое окно «Параметры визуализации». Если пользователь подтверждает выбранные настройки нажатием кнопки «Применить», приложение обновляет структуру presentParams с учётом поля config и сбрасывает устройство с использованием обновлённой структуры presentParams. Новые установки MSAA вступают в силу сразу же после сброса устройства.

Листинг 1.34

private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
{
// Создаём новое диалоговое окно. По завершению работы обработчика диалоговое окно удаляется
    using (SettingForm settingForm = new SettingForm(config))
    {
// Выводим на экран диалоговое окно
        if (settingForm.ShowDialog() == DialogResult.OK)
        {
// Если в диалоговом окне была нажата кнопка "Применить"
// Обновляем структуру presentParams
            presentParams.MultiSampleType = config.multiSampleType;
            presentParams.MultiSampleQuality = config.multiSampleQuality;

// Сбрасываем устройство
            device.Reset(presentParams);

// Перерисовываем содержимое формы
            Invalidate();
        }
    }
}

 

В заключении создайте тривиальный обработчик выхода из программы для пункта «Выход»:

 

Листинг 1.35

private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
    Close();
}

 

На этом приложение можно считать законченным (Ex28). Однако его пользовательский интерфейс пока ещё далёк от совершенства – после каждого запуска приложения параметры MSAA приходится задавать заново. Не думаю, что пользователи будут этого в восторге перспективы открывать диалоговое окно «Параметры визуализации».

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

q      Использование файлов собственного формата. Плюсы: высокая гибкость, малый размер файла. Минусы: большая трудоёмкость реализации, файл не возможно редактировать средствами стандартных редакторов.

q      Использование .INI файлов. Плюсы: файл можно легко редактировать в текстовом редакторе. Минусы: жесткие ограничения на структуру файла.

q      Хранение настроек приложения в реестре. Плюсы – относительная простота реализации и гибкость. Минусы: невозможность переноса настроек на другой компьютер, при некорректной деинсталляции приложения настройки могут остаться храниться в реестре мёртвым грузом.

q      Использование XML файлов. Плюсы: простота реализации, можно редактировать в любом текстовом редакторе, высокая гибкость формата. Минусы – большой объём из-за высокой избыточности данных.

Давайте попробуем сформулировать требования к конфигурационному файлу нашего приложения:

q      Файл должен быть текстовым – это позволит нам легко проверить содержимое файла в любом текстовом редакторе, что значительно облегчит отладку приложения.

q      Простота реализации – в современном быстроменяющемся мире скорость разработки решает всё.

q      Простота переноса настроек – очень полезная возможность, к примеру, при переустановке операционной системы.

Сопоставив эти требования с плюсами и минусами вышеприведённых файловых форматов нетрудно заметить, что данным требованиям наиболее полно удовлетворяет формат XML. Его мы и будем использовать.

Для начала мы добавим в класс Config метод Save, сохраняющий содержимое объекта этого класса в XML файл (листинг 1.36).

Листинг 1.36

public void Save(string filename)
{
// Создаём файловый поток для записи в файл с именем filename. Если файл уже существует, он 
// перезаписывается. По завершению работы кода в блоке using, файл автоматически закрывается.
    using (FileStream fs = new StreamWriter(filename))
    {
// Создаём объект класса XmlSerializer для работы с объектами класса Config
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(Config));
// Выполняем сериализацию объекта в файл fs
        xmlSerializer.Serialize(fs, this);
    }
}

Как видно, в .NET Framework перевод содержимого класса  в XML файл осуществляется очень просто: программа открывает файл для записи, выполняет сериализацию текущего экземпляра класса Config в этот файл и закрывает файл. Создаваемый XML-файл имеет примерно следующий вид (MSAA 4x):


<?xml version="1.0" encoding="utf-8"?>

<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <multiSampleType>FourSamples</multiSampleType>

  <multiSampleQuality>0</multiSampleQuality>

</Config>

Думаю, вы без труда самостоятельно разберётесь в структуре этого файла.

Восстановление содержимого объекта класса Config из файла формата XML не намного сложнее:

Листинг 1.37

// Статический метод, возвращающий ссылку на экземпляр класса, созданного на основе XML-файла 
public static Config CreateFromFile(string filename) 
{
    Config config;
// Открываем файл для чтения
    using (FileStream fs = new FileStream(filename, FileMode.Open))
    {
// Создаём объект класса XmlSerializer для работы с объектами класса Config
        XmlSerializer xmlSerilizer = new XmlSerializer(typeof(Config));
// Создаем экземпляр класса Config на основе XML-файла
        config = (Config)xmlSerilizer.Deserialize(fs);
    }

// Возвращаем ссылку на созданный XML-файл
    return config;
}

 

Информацию о работе с файлами в .NET Framework можно найти в [33], основы работы форматом XML  хорошо описаны в [31] и [32].

Располагая классом Config, умеющим сохранять и восстанавливать себя из XML-файл, мы можем легко модифицировать обработчики событий Load и Close (листинг 1.38):

Листинг 1.38

private void MainForm_Load(object sender, EventArgs e)
{
    SetStyle(ControlStyles.Opaque | ControlStyles.ResizeRedraw, true);
    MinimumSize = new System.Drawing.Size(Width - ClientSize.Width + 1,
        Height - ClientSize.Height + 1);

    try
    {
// Пытаемся загрузить экземпляр класса config из файла
        config = Config.CreateFromFile("config.xml");
    }
// Если файл не был найден
    catch (System.IO.FileNotFoundException)
    {
// Создаём новый класс config с настройками по умолчанию
        config = new Config();
// Выводим диалоговое окно "Настройки визуализации", чтобы пользователь смог подстроить
// настройки под себя
        using (SettingForm settingForm = new SettingForm(config))
            settingForm.ShowDialog();
    }
// Если XML файл имеет некорректный формат (скорее всего повреждён)
    catch (InvalidOperationException)
    {
// Выводим соответствующее предупреждение
        MessageBox.Show("Некорректный формат файла config.xml. Возможно файл повреждён.",  
 "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Stop);
// Выводим диалоговое окно, чтобы пользователь смог подправить параметры
        config = new Config();
        using (SettingForm settingForm = new SettingForm(config))
            settingForm.ShowDialog();
    }

// Заполняем структуру presentParams необходимыми параметрами
    presentParams = new PresentParameters();
    presentParams.IsWindowed = true;
    presentParams.BackBufferCount = 1;
    presentParams.BackBufferWidth = ClientSize.Width;
    presentParams.BackBufferHeight = ClientSize.Height;
    presentParams.SwapEffect = SwapEffect.Discard;

// Выполняем цикл до тех пор, пока не получится создать устройство
    do
    {
        try
        {
// Заполняем структуру presentParams на основе объекта config
            presentParams.MultiSampleType = config.multiSampleType;
            presentParams.MultiSampleQuality = config.multiSampleQuality;

// Пытаемся создать новое устройство
            device = new Device(0, DeviceType.Hardware, this.Handle,
                CreateFlags.HardwareVertexProcessing, presentParams);
        }
// Если устройство создать не удалось.
        catch (InvalidCallException)
        {
// Выводим диалоговое окно с предупреждением
            MessageBox.Show("Не могу создать устройство с заданными настройками. Попробуйте изменить" +
            " настройки", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
// Открываем диалоговое окно "Параметры визуализации", чтобы пользователь исправил настройки
            using (SettingForm settingForm = new SettingForm(config))
// Если пользователь нажал кнопку отмена - выходим из программы
                if (settingForm.ShowDialog() == DialogResult.Cancel)
                {
                    Close();
                    return;
                }
        }
    } while (device == null);

// Выполняем обработчик события Resize, в котором расположен 
    MainForm_Resize(this, null);
}

private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
{
// Сохраняем настройки в файл приложения
    config.Save("config.xml");

// Удаляем устройство
    device.Dispose();
    device = null;
}

 

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

q      Конфигурационный файл может отсутствовать. Например, стёрт пользователем.

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

q      Конфигурационный файл может содержать устаревшие данные. Допустим, пользователь ATI Radeon 9800 XT, использующий режим MSAA 6x, обновляет видеокарту на NVIDIA GeForce 6600 GT, не поддерживающую этот режим MSAA. После смены видеокарты на GeForce наше приложение считает настройки из файла config.xml и попытается создать устройство, использующее MSAA 6x, что, разумеется, вызовет исключение Direct3D.InvalidCallException. Если его не перехватить, программа аварийно завершит работу.

Обработка подобных исключительных ситуаций (так называемая “дуракоустойчивость”) является признаком качественного приложения, которое никогда не “вылетает в Windows” из-за пустяков. Полученное приложение можно найти на CD диске с книгой в каталоге Ch01\Ex29.

Примечание

По умолчанию при запуске приложения Visual Studio 2005 делает текущим каталог с exe-файлом приложения (например, ...\Ex29\ bin\Debug или ...\Ex29\ bin\Release). В результате Release и Debug версии будут использовать разные файлы config.xml. Чтобы заставить Debug и Release версии использовать и тот же текущий каталог (соответственно, и общий файл config.xml) необходимо в окне Solution Explorer  щёлкнуть два раза левой кнопкой мыши на узле Properties, выбрать в открывшемся окне вкладку Debug и ввести  в поле Working Directory путь к общему текущему каталогу для Debug и Release версий (рисунок 1.68).

Рисунок 1.68. Задание текущего каталога.

 

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

В приложение из практического упражнения №8 (Ex24), визуализирующее фигуру Листажу, добавьте возможность выбора режимов MSAA с использованием диалогового окна.

 

Подсказка

Можно значительно упростить себе работу, если воспользоваться классом Config и диалоговым оконном «Параметры визуализации» из примера Ex29. Для подключения класса Config к своему проекту щёлкните правой кнопкой мыши на названии проекта в окне Solution Explorer и выберите в контекстом меню Add | Existing Item. В открывшемся диалоговом окне выберите файл config.cs и нажмите кнопку Add, после чего Visual Studio автоматически скопирует этот файл в каталог с вашем проектом и подключит. Для подключения к проекту диалогового окна «Параметры визуализации» повторите эти действия для файла SettingForm.cs.


Список использованной литературы

1.        Фень Юань. Программирование графики для Windows

2.        Константин Максимов. Совершенство графики в GDI+. Программист №2, 2002

3.        Том Миллер. Managed DirectX. Программирование графики и игр

4.        Станислав Горнаков. DirectX 9. Уроки программирования на C++

5.        Н. Секунов. Обработка звука на PC

6.        Стив Тейксейра, Ксавье Пачеко. Borland Delphi 6. Руководство разработчика.

7.        Ксавье Пачеко. Delphi for .NET. Руководство разработчика.

8.        Джон Роббинс. Отладка приложений для Microsoft .NET и Microsoft Windows

9.        Брайан Джонсон, Крейг Скибо, Марк Янг. Основы Microsoft Visual Studio .NET 2003

10.     Михаил Краснов. DirectX. Графика в проектах Delphi

11.     Т.А, Блинова, В.Н. Пореев. Компьютерная графика

12.     Джеффри Рихтер. Программирование на платформе .NET Framework

13.     Владислав Чистяков. Нововведения в C# 2.0. RSDN №6, 2003

14.     И.И. Кантор. Высокоскоростные железнодорожные магистрали

15.     Мейсон Ву и др. OpenGL. Официальное руководство программиста

16.     Эдвард Эйнджел. Интерактивная компьютерная графика. Вводный курс на базе OpenGL.

17.     М.Я. Выгодский. Справочник по высшей математике для ВУЗов и ВТУЗов.

18.     Френсис Хилл. OpenGL. Программирование трёхмерной графики.

19.     Adobe Photoshop CS. Официальный учебный курс

20.     Andrew Flavell. MIP-MAP Filtering в процессе выполнения приложения. (www.ixbt.com)

21.     Андрей Воробьев. Александр Медведев. Обзор NVIDIA GeForce3. (www.ixbt.com)

22.     DirectX Documentation for C++ (DirectX SDK)

23.     DirectX Documentation for Managed Language (DirectX SDK)

24.     Александр Медведев. NVIDIA GeForce FX или «Начало киносеанса». (www.ixbt.com)

25.     Андрей Воробьев. Александр Медведев. NVIDIA GeForce FX 5800 Ultra 128MB. (www.ixbt.com)

26.     ForceWare Graphics Driver User Guide (www.nvidia.com)

27.     Н.И.Мусхелишвили. Курс Аналитической геометрии.

28.     А.И. Плис, Н.А. Сливина. MathCAD. Математический практикум.

29.     Евгений Козловский. Затоваренная звукотара. Компьютера №44, 2003

30.     Эндрю Троелсен. C# и платформа .NET

31.     Андрей Корявченко. Конфигурирование .NET-приложений (www.rsdn.ru)

32.     Krassilchik Lucy. XmlSerializer - и как с ним бороться (www.gotdotnet.ru)

33.     Чарльз Петцольд.  Программирование для Microsoft Windows на С#.

34.     Джон Коннелл. Разработка элементов управления Microsoft .NET на Microsoft Visual Basic .NET

35.     Dave Barron. Multi-Sampling Anti-Aliasing Explained (http://www.firingsquad.com)

36.     Александр Медведев. DX Current. Настоящее аппаратного ускорения графики  (www.ixbt.com)

37.     Дейв Шрайнер. OpenGL. Официальный справочник.

 

 



[1] Используется упрощённая формулировка теоремы. Более подробную информацию о теореме отсчётов (известную как теорема Котельникова или предел Найквиста) можно найти в [5].

[2] В DirectX SDK Documentation эта технология называется oversampling.

[3] Использование квадов обусловлено особенностью архитектуры современных графических процессоров. Все современные графические процессоры являются векторными, то есть могут выполнять одну операцию сразу над несколькими пикселями экрана (квадом).

[4] Скорее всего, решётка из выборок повёрнута относительно экрана для эффективного сглаживания наклонных линий, которые наиболее часто подвержены эффекту ступенчатости. Таким образом, вариант, изображенный в левом верхнем угле рисунка 1.53, является наименее вероятным.

[5] В технической литературе слово sample (выборка) часто не переводят на русский язык.

[6] То есть поверхность примитива не является одноцветной

[7] Подробное исследование качества MSAA, а так же сравнение MSAA с SSAA можно найти, к примеру, в [21]

[8] При использовании сложных шейдеров (см. глава 3) на вычисление одной выборки может тратиться до нескольких сотен тактов GPU.

[9] Разработчики из ATI считают, что суперсэмплинг значительно уступает мультисэмплингу по соотношению качество/производительность, поэтому реализация аппаратного суперсэмплинга является нерациональной тратой транзисторов графического процессора.

[10] Название Detonator очень хорошо сочеталось с RivaTNT (NV4) и RivaTNT2 (NV5) – названиями графических процессоров NVIDIA, которые должны были “взорвать” рынок графических ускорителей того времени.

[11] Отсюда и цифра 2 в названии 2xQ

[12] Часто сокращёно обозначается SSAA 2x + MSAA 4x

[13] Этим и обусловлена цифра 8 в названии режима FSAA (8xS)

[14] Использование текстур будет рассмотрено в третьей главе

[15] Внимание. Детали реализации могут отличаться от рисунка.

[16] Внимание. Детали реализации (например, расположение выборок внутри пикселей) могут существенно отличаться от рисунка.

[17] Особенно если учесть частоту выхода новых версий драйверов

[18] При использовании этих режимов MSAA программист имеет возможность управлять отдельными выборками внутри пикселя при помощи битой маски. Отсюда и название маскируемые режимы MSAA.

[19] Альфа канал используется для имитации эффектов прозрачности

[20] Например, видеокарты семейств ATI Radeon и NVIDIA GeForce

[21] На текущей версии драйверов на момент написания книги

[22] По видимости, это одна из модификаций MSAA 4x

[23] Иногда в несколько раз


Может пригодится:


Автор: Сергей Гайдуков
Прочитано: 12071
Рейтинг:
Оценить: 1 2 3 4 5

Комментарии: (1)

Прислал: ko4egar
Спасибо автору!!! Статья очень помогла.

Добавить комментарий
Ваше имя*:
Ваш email:
URL Вашего сайта:
Ваш комментарий*:
Код безопастности*:

Рассылка новостей
Рейтинги
© 2007, Программирование Исходники.Ру