netlib.narod.ru | < Назад | Оглавление | Далее > |
Процесс инициализации Direct3D требует знакомства с рядом основных концепций компьютерной графики и базовыми типами Direct3D. В данном разделе мы познакомимся с этими идеями и типами, чтобы в дальнейшем сосредоточиться на обсуждении инициализации Direct3D.
Поверхность (surface) — это прямоугольный массив пикселей, используемый Direct3D в основном для хранения двухмерных изображений. Основные параметры поверхности представлены на рис. 1.2. Обратите внимание, что хотя мы представляем данные поверхности в виде матрицы, в действительности данные пикселей хранятся в линейном массиве.
Рис. 1.2. Поверхность |
Ширина и высота поверхности измеряются в пикселах. Шаг (pitch) поверхности измеряется в байтах. Более того, шаг поверхности может отличаться от ее ширины в зависимости от используемого оборудования. Вы не должны считать, что шаг = ширина * sizeof(пиксель).
В коде поверхность представляется интерфейсом IDirect3DSurface9. Он предоставляет методы для прямого чтения и записи данных поверхности, а также методы для получения информации о поверхности. Вот наиболее важные методы интерфейса IDirect3DSurface9:
LockRect — Этот метод позволяет получить указатель на память поверхности. После этого, используя арифметику указателей, мы можем читать и записывать отдельные пиксели поверхности.
UnlockRect — После того, как мы вызвали метод LockRect и завершили работу с памятью поверхности, нам следует разблокировать поверхность, вызвав этот метод.
GetDesc — Метод возвращает параметры поверхности, заполняя структуру D3DSURFACE_DESC.
Принимая во внимание наличие такого параметра, как шаг поверхности, блокировка поверхности и запись отдельных пикселей могут вызвать затруднения. Поэтому мы приводим фрагмент кода в котором поверхность блокируется и заполняется пикселями красного цвета:
// Предполагается, что _surface - указатель на интерфейс IDirect3DSurface9 // Предполагается, что у поверхности 32-разрядный формат пикселей // Получаем описание поверхности D3DSURFACE_DESC surfaceDesc; _surface->GetDesc(&surfaceDesc); // Получаем указатель на данные пикселей поверхности D3DLOCKED_RECT lockedRect; _surface->LockRect( &lockedRect, // получаемый указатель на данные 0, // блокируем всю поверхность 0); // дополнительных параметров блокировки нет // Перебираем все пиксели поверхности и делаем их красными DWORD* imageData = (DWORD*)lockedRect.pBits; for(int i = 0; i < surfaceDesc.Height; i++) { for(int j = 0; j < surfaceDesc.Width; j++) { // индекс в текстуре, обратите внимание, что мы используем шаг и // делим его на 4, поскольку шаг задается в байтах, // а каждый пиксель занимает 4 байта. int index = i * lockedRect.Pitch / 4 + j; imageData[index] = 0xffff0000; // красный цвет } } _surface->UnlockRect();
Структура D3DLOCKED_RECT определена следующим образом:
typedef struct _D3DLOCKED_RECT { INT Pitch; // шаг поверхности void *pBits; // указатель на начало памяти поверхности } D3DLOCKED_RECT;
Приведем несколько комментариев к коду блокировки поверхности. Очень важно предположение о 32-разрядном формате пикселей, поскольку мы выполняем приведение к типу DWORD, который является 32-разрядным. Благодаря этому мы можем считать, что каждое значение DWORD представляет один пиксель. И не заморачивайтесь о том, как 0xffff0000 представляет красный цвет — мы поговорим об этом в главе 4.
Множественная выборка (multisampling) — это техника, использующаяся для сглаживания ступенчатых линий на изображении, представленном в виде матрицы пикселей. Наиболее частое применение множественной выборки — полноэкранное сглаживание (full-screen antialiasing) (рис. 1.3).
Рис. 1.3. Слева изображена линия с зазубренным краем. Справа — та же линия, но с использованием множественной выборки, выглядящая более гладкой |
Перечисление D3DMULTISAMPLE_TYPE содержит константы, позволяющие задать уровень множественной выборки для поверхности.
D3DMULTISAMPLE_NONE — Множественная выборка не используется.
D3DMULTISAMPLE_1_SAMPLE...D3DMULTISAMPLE_16_SAMPLE — Устанавливает уровень множественной выборки от 1 до 16.
От типа множественной выборки зависит уровень качества. Тип констант — DWORD.
В примерах из этой книги множественная выборка не используется, поскольку она сильно замедляет работу приложений. Если вы захотите добавить ее, не забудьте вызвать метод IDirect3D9::CheckDeviceMultiSampleType, чтобы проверить поддерживает ли используемое устройство множественную выборку и определить допустимые уровни качества.
При создании поверхностей или текстур нам часто надо будет определить формат пикселей ресурсов Direct3D. Формат определяется как член перечисления D3DFORMAT. Вот некоторые форматы:
D3DFMT_R8G8B8 — 24-разрядный формат пикселей, где, начиная с самого левого разряда, 8 бит отведены для красного цвета, 8 бит — для зеленого и 8 бит — для синего.
D3DFMT_X8R8G8B8 — 32-разрядный формат пикселей, где, начиная с самого левого разряда, 8 бит не используются, 8 бит отведены для красного цвета, 8 бит — для зеленого и 8 бит — для синего.
D3DFMT_A8R8G8B8 — 32-разрядный формат пикселей, где, начиная с самого левого разряда, 8 бит используются для альфа-канала, 8 бит отведены для красного цвета, 8 бит — для зеленого и 8 бит — для синего.
D3DFMT_A16B16G16R16F — 64-разрядный формат пикселей с плавающей запятой. Начиная с самого левого разряда, 16 бит используются для альфа-канала, 16 бит отведены для синего цвета, 16 бит — для зеленого и 16 бит — для красного.
D3DFMT_A32B32G32R32F — 128-разрядный формат пикселей с плавающей запятой. Начиная с самого левого разряда, 32 разряда используются для альфа-канала, 32 разряда отведены для синего цвета, 32 разряда — для зеленого и 32 разряда — для красного.
Полный список поддерживаемых форматов пикселей приведен в описании перечисления D3DFORMAT в документации к SDK.
Поверхности и другие ресурсы Direct3D могут быть размещены в различных областях памяти. Используемая область памяти задается с помощью одной из констант перечисления D3DPOOL. Доступны следующие варианты:
D3DPOOL_DEFAULT — Выбор используемого по умолчанию пула памяти позволяет Direct3D размещать ресурс в той области памяти, которая наиболее подходит для ресурсов данного типа с учетом его использования. Это может быть видеопамять, память AGP или системная память. Обратите внимание, что ресурсы, размещаемые в пуле по умолчанию, должны быть уничтожены (освобождены) до вызова метода IDirect3DDevice9::Reset, и могут быть повторно инициализированы после сброса.
D3DPOOL_MANAGED — ресурсы размещаются в пуле памяти, управляемом Direct3D (это значит, что при необходимости они могут автоматически перемещаться устройством в видеопамять или память AGP). Кроме того, в системной памяти хранится резервная копия ресурса. Если приложение получает доступ или изменяет ресурс, работа ведется с копией в системной памяти. Затем, если надо, Direct3D автоматически обновляет данные в видеопамяти.
D3DPOOL_SYSTEMMEM — Ресурс будет размещен в системной памяти.
D3DPOOL_SCRATCH — Указывает, что ресурс будет размещен в системной памяти. Отличие этого пула от D3DPOOL_SYSTEMMEM в том, что ресурс не должен соответствовать налагаемым графическим устройствам ограничениям. Следовательно, у графического устройства нет доступа к такому ресурсу. Тем не менее, эти ресурсы могут применяться в операциях копирования как в качестве источника, так и в качестве приемника.
Direct3D управляет набором поверхностей, обычно двумя или тремя, который называется цепочка обмена (swap chain) и представляется интерфейсом IDirect3DSwapChain9. Мы не будем подробно говорить об этом интерфейсе, поскольку всю работу берет на себя Direct3D и вмешиваться в его действия приходится очень редко. Вместо этого мы поговорим о его назначении и общих принципах работы.
Цепочка обмена и, говоря более точно, техника переключения страниц, используется для достижения плавности анимации. На рис. 1.4 показана цепочка обмена, состоящая из двух поверхностей.
Рис. 1.4. Цепочка обмена из двух поверхностей (первичного и вторичного буфера) |
На рис. 1.4 в первичном буфере (front buffer) находится та поверхность, которая в данный момент отображается на экране монитора. Монитор не показывает изображение находящееся в первичном буфере мгновенно; например, при установленной для монитора частоте кадров 60 Гц, вывод изображения занимает одну шестидесятую секунды. Частота кадров в приложении часто отличается от частоты кадров монитора (например, приложение может визуализировать кадр быстрее, чем монитор отобразит его). Мы не хотим обновлять содержимое первичного буфера, занося в него следующий кадр, в то время, когда монитор еще не закончил отображать текущий, но мы также не хотим останавливать визуализацию кадров, чтобы подождать, пока монитор полностью выведет текущий кадр. Поэтому мы визуализируем кадр во внеэкранной поверхности (вторичном буфере, back buffer); затем, когда монитор закончит отображение поверхности из первичного буфера, мы перемещаем этот буфер в конец цепочки обмена, и передвигаем в цепочке вторичный буфер, чтобы он стал первичным.
Этот процесс называется показом (presenting). На рис. 1.5 показана цепочка обмена до и после показа.
Рис. 1.5. Показ. Используя содержащую две поверхности цепочку обмена, мы видим, что основу показа составляет переключение поверхностей |
Таким образом, структура кода визуализации будет следующей:
Визуализировать вторичный буфер.
Показать вторичный буфер.
Перейти к пункту 1.
Буфер глубины (depth buffer) — это поверхность, которая содержит не изображение, а информацию о глубине отдельных пикселей. Каждому пикселю в окончательном изображении соответствует элемент буфера глубины. Так, если размер окончательного изображения 640 × 480 пикселей, в буфере глубины должно быть 640 × 480 элементов.
На рис. 1.6 показана простая сцена, где одни объекты частично скрывают другие, находящиеся позади них. Чтобы определить, пиксели какого объекта находятся поверх всех других, Direct3D использует технологию, называемую буфером глубины (depth buffer) или z-буферизацией (z-buffering).
Рис. 1.6. Группа объектов, частично закрывающих друг друга |
Буфер глубины работает путем вычисления значения глубины каждого пикселя и последующего выполнения проверки глубины. Проверка глубины заключается в сравнении значений глубины пикселов, расположенных в заданной позиции. Сравнение выигрывает тот пиксель, который находится ближе всего к камере, и именно он будет сохранен. Это имеет смысл, поскольку самый близкий к камере пиксель скрывает все остальные пиксели, находящиеся позади него.
Формат буфера глубины определяет точность сравнения глубины пикселей. То есть 24-разрядный буфер глубины обеспечвает более высокую точность, чем 16-разрядный. Большинство приложений замечательно работают с 24-разрядным буфером глубины, хотя Direct3D поддерживает и 32-разрядный буфер.
D3DFMT_D32 — 32-разрядный буфер глубины.
D3DFMT_D24S8 — 24-разрядный буфер глубины с 8 разрядами, зарезервированными для буфера трафарета.
D3DFMT_D24X8 — 24-разрядный буфер глубины.
D3DFMT_D24X4S4 — 24-разрядный буфер глубины с 4 разрядами, зарезервированными под буфер трафарета.
D3DFMT_D16 — 16-разрядный буфер глубины.
Вершины представляют собой основные строительные блоки трехмерной геометрии и могут обрабатываться двумя различными способами: программно (программная обработка вершин) или аппаратурой видеокарты (аппаратная обработка вершин). Программная обработка вершин всегда поддерживается и может быть использована. Аппаратная обработка вершин, с другой стороны, может использоваться только если она поддерживается установленной видеокартой.
Аппаратная обработка вершин всегда предпочтительнее, поскольку выполняется гораздо быстрее, чем программная. Кроме того, аппаратная обработка вершин освобождает центральный процессор, который, благодаря этому, может выполнять другие задачи.
Каждой возможности, предлагаемой Direct3D соответствует член данных или бит в структуре D3DCAPS9. Идея состоит в том, чтобы инициализировать экземпляр структуры D3DCAPS9 на основании фактических возможностей конкретного устройства. Затем, в нашем приложении, мы можем проверить, поддерживает ли устройство требуемую возможность, проверив соответствующий член данных или бит в экземпляре D3DCAPS9.
Это иллюстрирует следующий пример. Предположим, мы хотим проверить способно ли устройство осуществлять аппаратную обработку вершин (или, другими словами, поддерживает ли устройство аппаратную обработку преобразований и расчета освещения). Посмотрев описание структуры D3DCAPS9 в документации SDK, мы обнаружим, что бит D3DDEVCAPS_HWTRANSFORMANDLIGHT в члене данных D3DCAPS9::DevCaps указывает, поддерживает ли устройство аппаратную обработку преобразований и расчета освещенности. Следовательно наша проверка, подразумевая, что caps — это экземпляр структуры D3DCAPS9, будет выглядеть следующим образом:
bool supportsHardwareVertexProcessing; // Если бит установлен, значит данная возможность // поддерживается устройством if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) { // Бит установлен - возможность поддерживается supportsHardwareVertexProcessing = true; } else { // Бит сброшен - возможность не поддерживается hardwareSupportsVertexProcessing = false; }
netlib.narod.ru | < Назад | Оглавление | Далее > |