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

Сортировка по глубине и Z-буферизация

Легко понять, что когда вы рисуете составляющие сцену объекты сеток, те объекты, которые находятся далеко от зрителя, должны закрываться теми объектами, которые расположены ближе к зрителю. Это называется сортировкой по глубине (depth sorting) и для нее есть два общепринятых метода.

Первый метод называется алгоритм художника (painter's algorithm). В нем объекты разделяются на образующие их полигоны, которые затем сортируются в порядке от дальних к ближним, чтобы затем рисовать их в таком порядке. Рисование подобным образом гарантирует, что полигон всегда будет рисоваться поверх тех полигонов, которые находятся за ним.

Второй, и наиболее часто используемый в видеокартах, метод сортировки по глубине называется методом Z-буфера (Z-Buffer method). Он работает попиксельно, назначая каждому пикселю z-значение (расстояние от зрителя).

При записи каждого пикселя визуализатор проверяет, нет ли уже на том же самом месте пикселя с меньшим z-значением. Если нет, пиксель рисуется; если есть — пиксель игнорируется. Иллюстрация этой концепции приведена на рис. 2.23.


Рис. 2.23. Когда один пиксель перекрывается другим, будет нарисован только пиксель с меньшим z-значением

Рис. 2.23. Когда один пиксель перекрывается другим, будет нарисован только пиксель с меньшим z-значением. Здесь будут нарисованы только три пикселя, поскольку два более далеких пикселя закрываются близлежащими пикселями


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

Сперва нужно выбрать точность буфера (16, 24 или 32 разряда), указав соответствующее значение D3DFORMAT. Вы можете обнаружить, что вам на выбор предлагается несколько значений для Z-буфера, но я сосредоточусь на использовании D3DFMT_D16 (16-разрядный) и D3DFMT_D32 (32-разрядный).

Различная точность используется по двум причинам — из-за занимаемой памяти и из-за качества. В плане занимаемой памяти 32-разрядный Z-буфер требует гораздо больше места для хранения, чем 16-разрядный, так что везде, где возможно, старайтесь обходиться 16-разрядным Z-буфером.

Что касается качества, то при наличии множества перекрывающихся объектов использование 16-разрядного буфера может приводить к тому, что из-за малой точности буфера будет нарисован неправильный пиксель. Переход к 32-разрядному буферу решает вопросы точности, но за счет того, что Z-буфер будет использовать в два раза больше памяти. Вам не стоит беспокоиться; в мире компьютерных игр скорость и оптимизация более важны, так что оставайтесь с 16-разрядным Z-буфером.

Вернемся назад, к установке параметров показа, где для разрешения использования Z-буфера в вашем приложении надо добавить следующие две строки кода:

d3dp.EnableAutoDepthStencil = TRUE;
d3dp.AutoDepthStencilFormat = D3DFMT_D16; // или D3DFMT_D32

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

// g_pD3DDevice = ранее инициализированный объект устройства

// Для включения Z-буфера используйте:
g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);

// Для выключения Z-буфера используйте:
g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);

 

ПРИМЕЧАНИЕ
Хотя может казаться логичным держать Z-буфер включенным все время, можно получить некоторый выигрыш в скорости, если отключать его, когда он не нужен. Когда вы рисуете изображения, такие как экранные меню, вам нужен полный контроль над тем что и где будет нарисовано, так что не стесняйтесь включать и выключать Z-буфер как считаете целесообразным.

Если вы уже попробовали новые возможности Z-буфера, то, возможно, заметили, что кое-что работает неправильно. Например, после нескольких кадров экран не обновляется, или расположенные вдалеке объекты обрезаются. Это вызвано тем, что вы должны очищать Z-буфер перед каждым кадром, а также необходимо скорректировать матрицу проекции, чтобы учесть заданные параметры расстояния.

Чтобы очищать Z-буфер перед каждым кадром, замените вызов IDirect3DDevice9::Clear на следующий:

g_pD3DDevice->Clear(0, NULL,
    D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
    D3DCOLOR_RGBA(0.0f, 0.0f, 0.0f, 0.0f) 1.0f, 0);

Обратите внимание на появившийся в коде флаг D3DCLEAR_ZBUFFER. Он сообщает функции очистки, что надо очистить Z-буфер, заполнив его указанным значением (пятый аргумент, который в данном примере равен 1.0). Значение должно находиться в диапазоне от 0.0 (минимальная глубина Z-буфера) до 1.0 (максимальная глубина Z-буфера).

Использование значения 1.0 говорит функции очистки, что все значения глубины нужно установить на максимум. Если вы хотите при очистке Z-буфера установить половину максимального значения, укажите в параметре 0.5. Остался только один вопрос — что такое максимальное значение?

Z-буфер измеряет расстояние от точки просмотра, и при визуализации объекты, находящиеся дальше максимальной дистанции просмотра (и те объекты, которые находятся слишком близко) не рисуются. Минимальная и максимальная дистанция просмотра задаются при инициализации матрицы проекции (с помощью D3DX), как показано в следующем фрагменте кода:

// Устанавливаем минимальную дистанцию 1.0,
// а максимальную 1000.0
D3DXMatrixPerspectiveFovLH(&MatrixProj, D3DX_PI/4,
                           1.0f, 1.0f, 1000.0f);

Последние два значения, это именно то, что нам надо корректировать — минимальная и максимальная дистанция соответственно. Поэкспериментируйте с этими значениями, чтобы увидеть, как они работают; следует помнить, что увеличение расстояния между минимальной и максимальной дистанциями ухудшает качество Z-буферизации. Обычные значения дистанций: 1.0 для минимума и 1000.0, 2000.0 или 5000.0 для максимума.


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

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