netlib.narod.ru< Назад | Оглавление | Далее >

Использование буфера глубины

Буфер глубины (depth buffer, также часто называемый z-буфер или w-буфер) — это способ хранения в Direct3D информации о «глубине», необходимой для визуализации. Эта информация о глубине используется при растеризации для того, чтобы определить, какие пиксели блокируют (закрывают) другие. Сейчас в нашем приложении нет буфера глубины, поэтому перекрывания пикселей при растеризации не происходит. Однако, у нас вообще нет перекрывающихся пикселей, так что давайте нарисуем побольше кубов, чтобы они заслоняли друг друга. Добавьте после вызовов DrawBox следующий фрагмент кода:

DrawBox(angle / (float)Math.PI, angle / (float)Math.PI * 2.0f,
        angle / (float)Math.PI / 4.0f, 0.0f,
        (float)Math.Cos(angle), (float)Math.Sin(angle));
DrawBox(angle / (float)Math.PI, angle / (float)Math.PI / 2.0f,
        angle / (float)Math.PI * 4.0f, 5.0f,
        (float)Math.Sin(angle), (float)Math.Cos(angle));
DrawBox(angle / (float)Math.PI, angle / (float)Math.PI / 2.0f,
        angle / (float)Math.PI / 2.0f, -5.0f,
        (float)Math.Cos(angle), (float)Math.Sin(angle));

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

Добавление буфера глубины к нашему приложению является простой задачей. Вы помните параметры показа, которые мы передавали нашему конструктору устройства? Так вот, здесь мы и включаем информацию о нашем буфере глубины. Для того, чтобы добавить к устройству буфер глубины, нам надо заполнить два новых параметра:

public Microsoft.DirectX.Direct3D.DepthFormat AutoDepthStencilFormat [get, set]
public bool EnableAutoDepthStencil [get, set]

Присвойте параметру EnableAutoDepthStencil значение true, чтобы включить буфер глубины на вашем устройстве; буфер будет использовать формат, заданный в члене AutoDepthStencilFormat. Допустимые значения для этого члена из перечисления DepthFormat показаны в таблице 4.1:

Таблица 4.1. Возможные форматы буфера глубины

Значение Описание
D16 16-разрядный Z-буфер для глубины
D32 32-разрядный Z-буфер для глубины
D16Lockable 16-разрядный Z-буфер для глубины с возможностью блокировки
D32FLockable Блокируемый буфер глубины, в котором значения глубины представлены в виде стандартных чисел с плавающей точкой в формате IEEE
D15S1 16-разрядный Z-буфер, в котором 15 бит используются для канала глубины, а последний бит — для канала трафарета (канал трафарета будет обсуждаться позже)
D24S8 32-разрядный Z-буфер, в котором 24 бита используются для канала глубины, а оставшиеся 8 бит используются для канала трафарета
D24X8 32-разрядный Z-буфер, в котором 24 бита используются для канала глубины, а оставшиеся 8 бит игнорируются
D24X4S4 32-разрядный Z-буфер, в котором 24 бита используются для канала глубины, 4 бита используются для канала трафарета, а оставшиеся 4 бита игнорируются
D24FS8 Неблокируемый формат в котором 24 бита используются для хранения канала глубины (в формате с плавающей точкой), а оставшиеся 8 бит используются для канала трафарета


ВЫБОР СООТВЕТСТВУЮЩЕГО ФОРМАТА БУФЕРА ГЛУБИНЫ
Сейчас практически любая, имеющаяся на рынке видеокарта поддерживает Z-буфер; однако, в зависимости от обстоятельств, при использовании буфера глубины можно столкнуться с его недостатками. При вычислении глубины пикселя Direct3D помещает пиксель где-нибудь в диапазоне значений Z-буфера (обычно это диапазон от 0.0f до 1.0f), но распределение значений в диапазоне редко бывает однородным. На шаблон распределения значений в Z-буфере влияет отношение расстояний до ближней и дальней плоскостей отсечения.
Например, если расстояние до передней плоскости равно 1.0f, а до задней 100.0f, 90% диапазона будут использовать первые 10% буфера глубины. Для больших «наружных» сцен нет ничего необычного в гораздо более отдаленных задних плоскостях отсечения. В предыдущем примере, если расстояние до задней плоскости отсечения будет равно 1000.0f, 98% диапазона будут использовать первые 2% буфера глубины. Это приводит к появлению «артефактов» на удаленных объектах, что может быть нежелательно.
Использование в качестве буфера глубины W-буфера устраняет эту проблему, ну у него также есть свои недостатки. При использовании W-буфера возможно появление артефактов на близких объектах, вместо удаленных. Кроме того, поддержка W-буферов в видеокартах не столь широко распространена, как поддержка Z-буферов.
И еще одно замечание, относительно буферов глубины. Для увеличения производительности при визуализации с использованием буферов глубины лучще визуализировать объекты в порядке от ближних (с большим значением Z) к дальним (с меньшим Z). При растеризации сцены Direct3D сможет быстро отбросить пиксели, которые уже заслонены и полностью пропустить их рисование. Естественно, это не подходит для того случая, когда мы визуализируем данные с альфа-компонентом, но так как пока мы об этой теме не говорили, отложим обсуждение на потом.

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

presentParams.EnableAutoDepthStencil = true;
presentParams.AutoDepthStencilFormat = DepthFormat.D16;

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

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

device.Clear(ClearFlags.Target | ClearFlags.ZBuffer,
             Color.CornflowerBlue, 1.0f, 0);

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


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz